Index ETH internal transactions
This commit is contained in:
parent
c374ef86fd
commit
e3bb706ea2
@ -701,9 +701,9 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
||||
continue
|
||||
}
|
||||
// filter only transactions of this contract
|
||||
filter.Vout = i + 1
|
||||
filter.Vout = i + db.ContractIndexOffset
|
||||
}
|
||||
t, err := w.getEthereumToken(i+1, addrDesc, c.Contract, details, int(c.Txs))
|
||||
t, err := w.getEthereumToken(i+db.ContractIndexOffset, addrDesc, c.Contract, details, int(c.Txs))
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, 0, 0, err
|
||||
}
|
||||
|
||||
@ -70,6 +70,7 @@ func init() {
|
||||
BlockChainFactories["Ethereum"] = eth.NewEthereumRPC
|
||||
BlockChainFactories["Ethereum Classic"] = eth.NewEthereumRPC
|
||||
BlockChainFactories["Ethereum Testnet Ropsten"] = eth.NewEthereumRPC
|
||||
BlockChainFactories["Ethereum Testnet Ropsten Archive"] = eth.NewEthereumRPC
|
||||
BlockChainFactories["Ethereum Testnet Goerli"] = eth.NewEthereumRPC
|
||||
BlockChainFactories["Bcash"] = bch.NewBCashRPC
|
||||
BlockChainFactories["Bcash Testnet"] = bch.NewBCashRPC
|
||||
|
||||
@ -110,8 +110,11 @@ const (
|
||||
// BitcoinType
|
||||
cfAddressBalance
|
||||
cfTxAddresses
|
||||
|
||||
__break__
|
||||
|
||||
// EthereumType
|
||||
cfAddressContracts = cfAddressBalance
|
||||
cfAddressContracts = iota - __break__ + cfAddressBalance - 1
|
||||
cfInternalData
|
||||
cfContracts
|
||||
)
|
||||
|
||||
@ -3,6 +3,7 @@ package db
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
|
||||
vlq "github.com/bsm/go-vlq"
|
||||
"github.com/flier/gorocksdb"
|
||||
@ -12,6 +13,9 @@ import (
|
||||
"github.com/trezor/blockbook/bchain/coins/eth"
|
||||
)
|
||||
|
||||
const InternalTxIndexOffset = 1
|
||||
const ContractIndexOffset = 2
|
||||
|
||||
// AddrContract is Contract address with number of transactions done by given address
|
||||
type AddrContract struct {
|
||||
Contract bchain.AddressDescriptor
|
||||
@ -108,6 +112,11 @@ func isZeroAddress(addrDesc bchain.AddressDescriptor) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
const transferTo = int32(0)
|
||||
const transferFrom = ^int32(0)
|
||||
const internalTransferTo = int32(1)
|
||||
const internalTransferFrom = ^int32(1)
|
||||
|
||||
func (d *RocksDB) addToAddressesAndContractsEthereumType(addrDesc bchain.AddressDescriptor, btxID []byte, index int32, contract bchain.AddressDescriptor, addresses addressesMap, addressContracts map[string]*AddrContracts, addTxCount bool) error {
|
||||
var err error
|
||||
strAddrDesc := string(addrDesc)
|
||||
@ -127,7 +136,11 @@ func (d *RocksDB) addToAddressesAndContractsEthereumType(addrDesc bchain.Address
|
||||
}
|
||||
if contract == nil {
|
||||
if addTxCount {
|
||||
ac.NonContractTxs++
|
||||
if index == internalTransferFrom || index == internalTransferTo {
|
||||
ac.InternalTxs++
|
||||
} else {
|
||||
ac.NonContractTxs++
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// do not store contracts for 0x0000000000000000000000000000000000000000 address
|
||||
@ -138,15 +151,21 @@ func (d *RocksDB) addToAddressesAndContractsEthereumType(addrDesc bchain.Address
|
||||
i = len(ac.Contracts)
|
||||
ac.Contracts = append(ac.Contracts, AddrContract{Contract: contract})
|
||||
}
|
||||
// index 0 is for ETH transfers, contract indexes start with 1
|
||||
// index 0 is for ETH transfers, index 1 (InternalTxIndexOffset) is for internal transfers, contract indexes start with 2 (ContractIndexOffset)
|
||||
if index < 0 {
|
||||
index = ^int32(i + 1)
|
||||
index = ^int32(i + ContractIndexOffset)
|
||||
} else {
|
||||
index = int32(i + 1)
|
||||
index = int32(i + ContractIndexOffset)
|
||||
}
|
||||
if addTxCount {
|
||||
ac.Contracts[i].Txs++
|
||||
}
|
||||
} else {
|
||||
if index < 0 {
|
||||
index = transferFrom
|
||||
} else {
|
||||
index = transferTo
|
||||
}
|
||||
}
|
||||
}
|
||||
counted := addToAddressesMap(addresses, strAddrDesc, btxID, index)
|
||||
@ -160,10 +179,23 @@ type ethBlockTxContract struct {
|
||||
addr, contract bchain.AddressDescriptor
|
||||
}
|
||||
|
||||
type ethInternalTransfer struct {
|
||||
internalType bchain.EthereumInternalTransactionType
|
||||
from, to bchain.AddressDescriptor
|
||||
value big.Int
|
||||
}
|
||||
|
||||
type ethInternalData struct {
|
||||
internalType bchain.EthereumInternalTransactionType
|
||||
contract bchain.AddressDescriptor
|
||||
transfers []ethInternalTransfer
|
||||
}
|
||||
|
||||
type ethBlockTx struct {
|
||||
btxID []byte
|
||||
from, to bchain.AddressDescriptor
|
||||
contracts []ethBlockTxContract
|
||||
btxID []byte
|
||||
from, to bchain.AddressDescriptor
|
||||
contracts []ethBlockTxContract
|
||||
internalData *ethInternalData
|
||||
}
|
||||
|
||||
func (d *RocksDB) processAddressesEthereumType(block *bchain.Block, addresses addressesMap, addressContracts map[string]*AddrContracts) ([]ethBlockTx, error) {
|
||||
@ -184,12 +216,12 @@ func (d *RocksDB) processAddressesEthereumType(block *bchain.Block, addresses ad
|
||||
if err != bchain.ErrAddressMissing {
|
||||
glog.Warningf("rocksdb: addrDesc: %v - height %d, tx %v, output", err, block.Height, tx.Txid)
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
if err = d.addToAddressesAndContractsEthereumType(to, btxID, transferTo, nil, addresses, addressContracts, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockTx.to = to
|
||||
}
|
||||
if err = d.addToAddressesAndContractsEthereumType(to, btxID, 0, nil, addresses, addressContracts, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockTx.to = to
|
||||
}
|
||||
// there is only one input address in EthereumType transaction, store it in format txid ^0
|
||||
if len(tx.Vin) == 1 && len(tx.Vin[0].Addresses) == 1 {
|
||||
@ -198,12 +230,68 @@ func (d *RocksDB) processAddressesEthereumType(block *bchain.Block, addresses ad
|
||||
if err != bchain.ErrAddressMissing {
|
||||
glog.Warningf("rocksdb: addrDesc: %v - height %d, tx %v, input", err, block.Height, tx.Txid)
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
if err = d.addToAddressesAndContractsEthereumType(from, btxID, transferFrom, nil, addresses, addressContracts, !bytes.Equal(from, to)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockTx.from = from
|
||||
}
|
||||
if err = d.addToAddressesAndContractsEthereumType(from, btxID, ^int32(0), nil, addresses, addressContracts, !bytes.Equal(from, to)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// process internal data
|
||||
eid, _ := tx.CoinSpecificData.(bchain.EthereumSpecificData)
|
||||
if eid.InternalData != nil {
|
||||
blockTx.internalData = ðInternalData{
|
||||
internalType: eid.InternalData.Type,
|
||||
}
|
||||
// index contract creation
|
||||
if eid.InternalData.Type == bchain.CREATE {
|
||||
to, err = d.chainParser.GetAddrDescFromAddress(eid.InternalData.Contract)
|
||||
if err != nil {
|
||||
if err != bchain.ErrAddressMissing {
|
||||
glog.Warningf("rocksdb: addrDesc: %v - height %d, tx %v, create contract", err, block.Height, tx.Txid)
|
||||
}
|
||||
// set the internalType to CALL if incorrect contract so that it is not breaking the packing of data to DB
|
||||
blockTx.internalData.internalType = bchain.CALL
|
||||
} else {
|
||||
blockTx.internalData.contract = to
|
||||
if err = d.addToAddressesAndContractsEthereumType(to, btxID, internalTransferTo, nil, addresses, addressContracts, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
// index internal transfers
|
||||
if len(eid.InternalData.Transfers) > 0 {
|
||||
blockTx.internalData.transfers = make([]ethInternalTransfer, len(eid.InternalData.Transfers))
|
||||
for i := range eid.InternalData.Transfers {
|
||||
iti := &eid.InternalData.Transfers[i]
|
||||
ito := &blockTx.internalData.transfers[i]
|
||||
to, err = d.chainParser.GetAddrDescFromAddress(iti.To)
|
||||
if err != nil {
|
||||
// do not log ErrAddressMissing, transactions can be without to address (for example eth contracts)
|
||||
if err != bchain.ErrAddressMissing {
|
||||
glog.Warningf("rocksdb: addrDesc: %v - height %d, tx %v, internal transfer %d to", err, block.Height, tx.Txid, i)
|
||||
}
|
||||
} else {
|
||||
if err = d.addToAddressesAndContractsEthereumType(to, btxID, internalTransferTo, nil, addresses, addressContracts, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ito.to = to
|
||||
}
|
||||
from, err = d.chainParser.GetAddrDescFromAddress(iti.From)
|
||||
if err != nil {
|
||||
if err != bchain.ErrAddressMissing {
|
||||
glog.Warningf("rocksdb: addrDesc: %v - height %d, tx %v, internal transfer %d from", err, block.Height, tx.Txid, i)
|
||||
}
|
||||
} else {
|
||||
if err = d.addToAddressesAndContractsEthereumType(from, btxID, internalTransferFrom, nil, addresses, addressContracts, !bytes.Equal(from, to)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ito.from = from
|
||||
}
|
||||
ito.internalType = iti.Type
|
||||
ito.value = iti.Value
|
||||
}
|
||||
}
|
||||
blockTx.from = from
|
||||
}
|
||||
// store erc20 transfers
|
||||
erc20, err := d.chainParser.EthereumTypeGetErc20FromTx(&tx)
|
||||
@ -249,14 +337,95 @@ func (d *RocksDB) processAddressesEthereumType(block *bchain.Block, addresses ad
|
||||
return blockTxs, nil
|
||||
}
|
||||
|
||||
var ethZeroAddress []byte = make([]byte, eth.EthereumTypeAddressDescriptorLen)
|
||||
|
||||
func packEthInternalData(data *ethInternalData) []byte {
|
||||
// allocate enough for type+contract+all transfers with bigint value
|
||||
buf := make([]byte, 0, (2*len(data.transfers)+1)*(eth.EthereumTypeAddressDescriptorLen+16))
|
||||
appendAddress := func(a bchain.AddressDescriptor) {
|
||||
if len(a) != eth.EthereumTypeAddressDescriptorLen {
|
||||
buf = append(buf, ethZeroAddress...)
|
||||
} else {
|
||||
buf = append(buf, a...)
|
||||
}
|
||||
}
|
||||
varBuf := make([]byte, maxPackedBigintBytes)
|
||||
|
||||
// internalType is one bit (CALL|CREATE), it is joined with count of internal transfers*2
|
||||
l := packVaruint(uint(data.internalType)&1+uint(len(data.transfers))<<1, varBuf)
|
||||
buf = append(buf, varBuf[:l]...)
|
||||
if data.internalType == bchain.CREATE {
|
||||
appendAddress(data.contract)
|
||||
}
|
||||
for i := range data.transfers {
|
||||
t := &data.transfers[i]
|
||||
buf = append(buf, byte(t.internalType))
|
||||
appendAddress(t.from)
|
||||
appendAddress(t.to)
|
||||
l = packBigint(&t.value, varBuf)
|
||||
buf = append(buf, varBuf[:l]...)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func (d *RocksDB) unpackEthInternalData(buf []byte) (*bchain.EthereumInternalData, error) {
|
||||
id := bchain.EthereumInternalData{}
|
||||
v, l := unpackVaruint(buf)
|
||||
id.Type = bchain.EthereumInternalTransactionType(v & 1)
|
||||
id.Transfers = make([]bchain.EthereumInternalTransfer, v>>1)
|
||||
if id.Type == bchain.CREATE {
|
||||
addresses, _, _ := d.chainParser.GetAddressesFromAddrDesc(buf[l : l+eth.EthereumTypeAddressDescriptorLen])
|
||||
l += eth.EthereumTypeAddressDescriptorLen
|
||||
if len(addresses) > 0 {
|
||||
id.Contract = addresses[0]
|
||||
}
|
||||
}
|
||||
var ll int
|
||||
for i := range id.Transfers {
|
||||
t := &id.Transfers[i]
|
||||
t.Type = bchain.EthereumInternalTransactionType(buf[l])
|
||||
l++
|
||||
addresses, _, _ := d.chainParser.GetAddressesFromAddrDesc(buf[l : l+eth.EthereumTypeAddressDescriptorLen])
|
||||
l += eth.EthereumTypeAddressDescriptorLen
|
||||
if len(addresses) > 0 {
|
||||
t.From = addresses[0]
|
||||
}
|
||||
addresses, _, _ = d.chainParser.GetAddressesFromAddrDesc(buf[l : l+eth.EthereumTypeAddressDescriptorLen])
|
||||
l += eth.EthereumTypeAddressDescriptorLen
|
||||
if len(addresses) > 0 {
|
||||
t.To = addresses[0]
|
||||
}
|
||||
t.Value, ll = unpackBigint(buf[l:])
|
||||
l += ll
|
||||
}
|
||||
return &id, nil
|
||||
}
|
||||
|
||||
func (d *RocksDB) GetEthereumInternalData(txid string) (*bchain.EthereumInternalData, error) {
|
||||
btxID, err := d.chainParser.PackTxid(txid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
val, err := d.db.GetCF(d.ro, d.cfh[cfInternalData], btxID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer val.Free()
|
||||
buf := val.Data()
|
||||
if len(buf) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return d.unpackEthInternalData(buf)
|
||||
}
|
||||
|
||||
func (d *RocksDB) storeAndCleanupBlockTxsEthereumType(wb *gorocksdb.WriteBatch, block *bchain.Block, blockTxs []ethBlockTx) error {
|
||||
pl := d.chainParser.PackedTxidLen()
|
||||
buf := make([]byte, 0, (pl+2*eth.EthereumTypeAddressDescriptorLen)*len(blockTxs))
|
||||
varBuf := make([]byte, vlq.MaxLen64)
|
||||
zeroAddress := make([]byte, eth.EthereumTypeAddressDescriptorLen)
|
||||
appendAddress := func(a bchain.AddressDescriptor) {
|
||||
if len(a) != eth.EthereumTypeAddressDescriptorLen {
|
||||
buf = append(buf, zeroAddress...)
|
||||
buf = append(buf, ethZeroAddress...)
|
||||
} else {
|
||||
buf = append(buf, a...)
|
||||
}
|
||||
@ -266,7 +435,29 @@ func (d *RocksDB) storeAndCleanupBlockTxsEthereumType(wb *gorocksdb.WriteBatch,
|
||||
buf = append(buf, blockTx.btxID...)
|
||||
appendAddress(blockTx.from)
|
||||
appendAddress(blockTx.to)
|
||||
l := packVaruint(uint(len(blockTx.contracts)), varBuf)
|
||||
// internal data - store the number of addresses, with odd number the CREATE tx type
|
||||
var internalDataTransfers uint
|
||||
if blockTx.internalData != nil {
|
||||
wb.PutCF(d.cfh[cfInternalData], blockTx.btxID, packEthInternalData(blockTx.internalData))
|
||||
internalDataTransfers = uint(len(blockTx.internalData.transfers)) * 2
|
||||
if blockTx.internalData.internalType == bchain.CREATE {
|
||||
internalDataTransfers++
|
||||
}
|
||||
}
|
||||
l := packVaruint(internalDataTransfers, varBuf)
|
||||
buf = append(buf, varBuf[:l]...)
|
||||
if internalDataTransfers > 0 {
|
||||
if blockTx.internalData.internalType == bchain.CREATE {
|
||||
appendAddress(blockTx.internalData.contract)
|
||||
}
|
||||
for j := range blockTx.internalData.transfers {
|
||||
c := &blockTx.internalData.transfers[j]
|
||||
appendAddress(c.from)
|
||||
appendAddress(c.to)
|
||||
}
|
||||
}
|
||||
// contracts - store the number of address pairs
|
||||
l = packVaruint(uint(len(blockTx.contracts)), varBuf)
|
||||
buf = append(buf, varBuf[:l]...)
|
||||
for j := range blockTx.contracts {
|
||||
c := &blockTx.contracts[j]
|
||||
@ -323,8 +514,33 @@ func (d *RocksDB) getBlockTxsEthereumType(height uint32) ([]ethBlockTx, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// internal data
|
||||
var internalData *ethInternalData
|
||||
cc, l := unpackVaruint(buf[i:])
|
||||
i += l
|
||||
if cc > 0 {
|
||||
internalData = ðInternalData{}
|
||||
// odd count of internal transfers means it is CREATE transaction with the contract added to the list
|
||||
if cc&1 == 1 {
|
||||
internalData.internalType = bchain.CREATE
|
||||
internalData.contract, i, err = getAddress(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
internalData.transfers = make([]ethInternalTransfer, cc/2)
|
||||
for j := range internalData.transfers {
|
||||
t := &internalData.transfers[j]
|
||||
t.from, i, err = getAddress(i)
|
||||
t.to, i, err = getAddress(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
// contracts
|
||||
cc, l = unpackVaruint(buf[i:])
|
||||
i += l
|
||||
contracts := make([]ethBlockTxContract, cc)
|
||||
for j := range contracts {
|
||||
contracts[j].addr, i, err = getAddress(i)
|
||||
@ -337,10 +553,11 @@ func (d *RocksDB) getBlockTxsEthereumType(height uint32) ([]ethBlockTx, error) {
|
||||
}
|
||||
}
|
||||
bt = append(bt, ethBlockTx{
|
||||
btxID: txid,
|
||||
from: from,
|
||||
to: to,
|
||||
contracts: contracts,
|
||||
btxID: txid,
|
||||
from: from,
|
||||
to: to,
|
||||
internalData: internalData,
|
||||
contracts: contracts,
|
||||
})
|
||||
}
|
||||
return bt, nil
|
||||
@ -349,7 +566,7 @@ func (d *RocksDB) getBlockTxsEthereumType(height uint32) ([]ethBlockTx, error) {
|
||||
func (d *RocksDB) disconnectBlockTxsEthereumType(wb *gorocksdb.WriteBatch, height uint32, blockTxs []ethBlockTx, contracts map[string]*AddrContracts) error {
|
||||
glog.Info("Disconnecting block ", height, " containing ", len(blockTxs), " transactions")
|
||||
addresses := make(map[string]map[string]struct{})
|
||||
disconnectAddress := func(btxID []byte, addrDesc, contract bchain.AddressDescriptor) error {
|
||||
disconnectAddress := func(btxID []byte, internal bool, addrDesc, contract bchain.AddressDescriptor) error {
|
||||
var err error
|
||||
// do not process empty address
|
||||
if len(addrDesc) == 0 {
|
||||
@ -382,10 +599,18 @@ func (d *RocksDB) disconnectBlockTxsEthereumType(wb *gorocksdb.WriteBatch, heigh
|
||||
c.TotalTxs--
|
||||
}
|
||||
if contract == nil {
|
||||
if c.NonContractTxs > 0 {
|
||||
c.NonContractTxs--
|
||||
if internal {
|
||||
if c.InternalTxs > 0 {
|
||||
c.InternalTxs--
|
||||
} else {
|
||||
glog.Warning("AddressContracts ", addrDesc, ", InternalTxs would be negative, tx ", hex.EncodeToString(btxID))
|
||||
}
|
||||
} else {
|
||||
glog.Warning("AddressContracts ", addrDesc, ", EthTxs would be negative, tx ", hex.EncodeToString(btxID))
|
||||
if c.NonContractTxs > 0 {
|
||||
c.NonContractTxs--
|
||||
} else {
|
||||
glog.Warning("AddressContracts ", addrDesc, ", EthTxs would be negative, tx ", hex.EncodeToString(btxID))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
i, found := findContractInAddressContracts(contract, c.Contracts)
|
||||
@ -409,21 +634,41 @@ func (d *RocksDB) disconnectBlockTxsEthereumType(wb *gorocksdb.WriteBatch, heigh
|
||||
}
|
||||
for i := range blockTxs {
|
||||
blockTx := &blockTxs[i]
|
||||
if err := disconnectAddress(blockTx.btxID, blockTx.from, nil); err != nil {
|
||||
if err := disconnectAddress(blockTx.btxID, false, blockTx.from, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
// if from==to, tx is counted only once and does not have to be disconnected again
|
||||
if !bytes.Equal(blockTx.from, blockTx.to) {
|
||||
if err := disconnectAddress(blockTx.btxID, blockTx.to, nil); err != nil {
|
||||
if err := disconnectAddress(blockTx.btxID, false, blockTx.to, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if blockTx.internalData != nil {
|
||||
if blockTx.internalData.internalType == bchain.CREATE {
|
||||
if err := disconnectAddress(blockTx.btxID, true, blockTx.internalData.contract, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for j := range blockTx.internalData.transfers {
|
||||
t := &blockTx.internalData.transfers[j]
|
||||
if err := disconnectAddress(blockTx.btxID, true, t.from, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
// if from==to, tx is counted only once and does not have to be disconnected again
|
||||
if !bytes.Equal(t.from, t.to) {
|
||||
if err := disconnectAddress(blockTx.btxID, true, t.to, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, c := range blockTx.contracts {
|
||||
if err := disconnectAddress(blockTx.btxID, c.addr, c.contract); err != nil {
|
||||
if err := disconnectAddress(blockTx.btxID, false, c.addr, c.contract); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
wb.DeleteCF(d.cfh[cfTransactions], blockTx.btxID)
|
||||
wb.DeleteCF(d.cfh[cfInternalData], blockTx.btxID)
|
||||
}
|
||||
for a := range addresses {
|
||||
key := packAddressKey([]byte(a), height)
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/juju/errors"
|
||||
"github.com/trezor/blockbook/bchain"
|
||||
"github.com/trezor/blockbook/bchain/coins/eth"
|
||||
"github.com/trezor/blockbook/tests/dbtestdata"
|
||||
)
|
||||
@ -33,10 +34,11 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo
|
||||
}
|
||||
}
|
||||
if err := checkColumn(d, cfAddresses, []keyPair{
|
||||
{addressKeyHex(dbtestdata.EthAddr3e, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T1, []int32{^0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr55, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{1}) + txIndexesHex(dbtestdata.EthTxidB1T1, []int32{0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr20, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^0, ^1}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddrContract4a, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr3e, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^1, 1, ^1}) + txIndexesHex(dbtestdata.EthTxidB1T1, []int32{^0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr55, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{2}) + txIndexesHex(dbtestdata.EthTxidB1T1, []int32{0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr20, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^0, ^2}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr9f, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^1, 1}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddrContract4a, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{0, 1}), nil},
|
||||
}); err != nil {
|
||||
{
|
||||
t.Fatal(err)
|
||||
@ -44,10 +46,26 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo
|
||||
}
|
||||
|
||||
if err := checkColumn(d, cfAddressContracts, []keyPair{
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "010100", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "020102", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser), "020100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser), "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "010100", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "010002", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "010101", nil},
|
||||
}); err != nil {
|
||||
{
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := checkColumn(d, cfInternalData, []keyPair{
|
||||
{
|
||||
dbtestdata.EthTxidB1T2,
|
||||
"06" +
|
||||
"01" + dbtestdata.EthAddr9f + dbtestdata.EthAddrContract4a + "030f4240" +
|
||||
"00" + dbtestdata.EthAddr3e + dbtestdata.EthAddr9f + "030f4241" +
|
||||
"00" + dbtestdata.EthAddr3e + dbtestdata.EthAddr3e + "030f4242",
|
||||
nil,
|
||||
},
|
||||
}); err != nil {
|
||||
{
|
||||
t.Fatal(err)
|
||||
@ -62,9 +80,13 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo
|
||||
{
|
||||
"0041eee8",
|
||||
dbtestdata.EthTxidB1T1 +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + "00" +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + "00" + "00" +
|
||||
dbtestdata.EthTxidB1T2 +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) +
|
||||
"06" +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser) +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) +
|
||||
"02" +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser),
|
||||
@ -97,15 +119,18 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB) {
|
||||
}
|
||||
}
|
||||
if err := checkColumn(d, cfAddresses, []keyPair{
|
||||
{addressKeyHex(dbtestdata.EthAddr3e, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T1, []int32{^0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr55, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{1}) + txIndexesHex(dbtestdata.EthTxidB1T1, []int32{0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr20, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^0, ^1}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddrContract4a, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr55, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^2, 1}) + txIndexesHex(dbtestdata.EthTxidB2T1, []int32{^0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr9f, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T1, []int32{0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr4b, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^0, 1, ^2, 2, ^1}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr7b, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^1, 2}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr3e, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^1, 1, ^1}) + txIndexesHex(dbtestdata.EthTxidB1T1, []int32{^0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr55, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{2}) + txIndexesHex(dbtestdata.EthTxidB1T1, []int32{0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr20, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^0, ^2}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr9f, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^1, 1}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddrContract4a, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{0, 1}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr55, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^3, 2}) + txIndexesHex(dbtestdata.EthTxidB2T1, []int32{^0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr9f, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{1, 1}) + txIndexesHex(dbtestdata.EthTxidB2T1, []int32{0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr4b, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^0, ^1, 2, ^3, 3, ^2}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddr7b, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^2, 3}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddrContract0d, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{1}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddrContract47, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{0}), nil},
|
||||
{addressKeyHex(dbtestdata.EthAddrContract4a, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^1}), nil},
|
||||
}); err != nil {
|
||||
{
|
||||
t.Fatal(err)
|
||||
@ -113,13 +138,14 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB) {
|
||||
}
|
||||
|
||||
if err := checkColumn(d, cfAddressContracts, []keyPair{
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "010100", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "020102", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser), "040200" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "01", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser), "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "010100", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "010100", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser), "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "020102", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "030104", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser), "010101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser), "010000" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "01", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser), "010001", nil},
|
||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract47, d.chainParser), "010100", nil},
|
||||
}); err != nil {
|
||||
{
|
||||
@ -127,13 +153,39 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := checkColumn(d, cfInternalData, []keyPair{
|
||||
{
|
||||
dbtestdata.EthTxidB1T2,
|
||||
"06" +
|
||||
"01" + dbtestdata.EthAddr9f + dbtestdata.EthAddrContract4a + "030f4240" +
|
||||
"00" + dbtestdata.EthAddr3e + dbtestdata.EthAddr9f + "030f4241" +
|
||||
"00" + dbtestdata.EthAddr3e + dbtestdata.EthAddr3e + "030f4242",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
dbtestdata.EthTxidB2T2,
|
||||
"05" + dbtestdata.EthAddrContract0d +
|
||||
"00" + dbtestdata.EthAddr4b + dbtestdata.EthAddr9f + "030f424a" +
|
||||
"02" + dbtestdata.EthAddrContract4a + dbtestdata.EthAddr9f + "030f424b",
|
||||
nil,
|
||||
},
|
||||
}); err != nil {
|
||||
{
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := checkColumn(d, cfBlockTxs, []keyPair{
|
||||
{
|
||||
"0041eee9",
|
||||
dbtestdata.EthTxidB2T1 +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser) + "00" +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser) + "00" + "00" +
|
||||
dbtestdata.EthTxidB2T2 +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract47, d.chainParser) +
|
||||
"05" +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser) +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser) +
|
||||
"08" +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) +
|
||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) +
|
||||
@ -152,6 +204,19 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB) {
|
||||
}
|
||||
}
|
||||
|
||||
func formatInternalData(in *bchain.EthereumInternalData) *bchain.EthereumInternalData {
|
||||
out := *in
|
||||
if out.Type == bchain.CREATE {
|
||||
out.Contract = eth.EIP55AddressFromAddress(out.Contract)
|
||||
}
|
||||
for i := range out.Transfers {
|
||||
t := &out.Transfers[i]
|
||||
t.From = eth.EIP55AddressFromAddress(t.From)
|
||||
t.To = eth.EIP55AddressFromAddress(t.To)
|
||||
}
|
||||
return &out
|
||||
}
|
||||
|
||||
// TestRocksDB_Index_EthereumType is an integration test probing the whole indexing functionality for EthereumType chains
|
||||
// It does the following:
|
||||
// 1) Connect two blocks (inputs from 2nd block are spending some outputs from the 1st block)
|
||||
@ -195,14 +260,27 @@ func TestRocksDB_Index_EthereumType(t *testing.T) {
|
||||
|
||||
// get transactions for various addresses / low-high ranges
|
||||
verifyGetTransactions(t, d, "0x"+dbtestdata.EthAddr55, 0, 10000000, []txidIndex{
|
||||
{"0x" + dbtestdata.EthTxidB2T2, ^2},
|
||||
{"0x" + dbtestdata.EthTxidB2T2, 1},
|
||||
{"0x" + dbtestdata.EthTxidB2T2, ^3},
|
||||
{"0x" + dbtestdata.EthTxidB2T2, 2},
|
||||
{"0x" + dbtestdata.EthTxidB2T1, ^0},
|
||||
{"0x" + dbtestdata.EthTxidB1T2, 1},
|
||||
{"0x" + dbtestdata.EthTxidB1T2, 2},
|
||||
{"0x" + dbtestdata.EthTxidB1T1, 0},
|
||||
}, nil)
|
||||
verifyGetTransactions(t, d, "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eBad", 500000, 1000000, []txidIndex{}, errors.New("Address missing"))
|
||||
|
||||
id, err := d.GetEthereumInternalData(dbtestdata.EthTxidB1T1)
|
||||
if err != nil || id != nil {
|
||||
t.Errorf("GetEthereumInternalData(%s) = %+v, want %+v, err %v", dbtestdata.EthTxidB1T1, id, nil, err)
|
||||
}
|
||||
id, err = d.GetEthereumInternalData(dbtestdata.EthTxidB1T2)
|
||||
if err != nil || !reflect.DeepEqual(id, formatInternalData(dbtestdata.EthTx2InternalData)) {
|
||||
t.Errorf("GetEthereumInternalData(%s) = %+v, want %+v, err %v", dbtestdata.EthTxidB1T2, id, formatInternalData(dbtestdata.EthTx2InternalData), err)
|
||||
}
|
||||
id, err = d.GetEthereumInternalData(dbtestdata.EthTxidB2T2)
|
||||
if err != nil || !reflect.DeepEqual(id, formatInternalData(dbtestdata.EthTx4InternalData)) {
|
||||
t.Errorf("GetEthereumInternalData(%s) = %+v, want %+v, err %v", dbtestdata.EthTxidB2T2, id, formatInternalData(dbtestdata.EthTx4InternalData), err)
|
||||
}
|
||||
|
||||
// GetBestBlock
|
||||
height, hash, err := d.GetBestBlock()
|
||||
if err != nil {
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user