diff --git a/api/xpub.go b/api/xpub.go index 00c91696..089a5acc 100644 --- a/api/xpub.go +++ b/api/xpub.go @@ -34,9 +34,17 @@ type xpubTxid struct { type xpubTxids []xpubTxid -func (a xpubTxids) Len() int { return len(a) } -func (a xpubTxids) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a xpubTxids) Less(i, j int) bool { return a[i].height >= a[j].height } +func (a xpubTxids) Len() int { return len(a) } +func (a xpubTxids) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a xpubTxids) Less(i, j int) bool { + // if the heights are equal, make inputs less than outputs + hi := a[i].height + hj := a[j].height + if hi == hj { + return (a[i].inputOutput & txInput) >= (a[j].inputOutput & txInput) + } + return hi > hj +} type xpubAddress struct { addrDesc bchain.AddressDescriptor diff --git a/db/rocksdb.go b/db/rocksdb.go index b3cb5893..0ec55b03 100644 --- a/db/rocksdb.go +++ b/db/rocksdb.go @@ -353,37 +353,44 @@ type outpoint struct { index int32 } +// TxInput holds input data of the transaction in TxAddresses type TxInput struct { AddrDesc bchain.AddressDescriptor ValueSat big.Int } +// Addresses converts AddressDescriptor of the input to array of strings func (ti *TxInput) Addresses(p bchain.BlockChainParser) ([]string, bool, error) { return p.GetAddressesFromAddrDesc(ti.AddrDesc) } +// TxOutput holds output data of the transaction in TxAddresses type TxOutput struct { AddrDesc bchain.AddressDescriptor Spent bool ValueSat big.Int } +// Addresses converts AddressDescriptor of the output to array of strings func (to *TxOutput) Addresses(p bchain.BlockChainParser) ([]string, bool, error) { return p.GetAddressesFromAddrDesc(to.AddrDesc) } +// TxAddresses stores transaction inputs and outputs with amounts type TxAddresses struct { Height uint32 Inputs []TxInput Outputs []TxOutput } +// AddrBalance stores number of transactions and balances of an address type AddrBalance struct { Txs uint32 SentSat big.Int BalanceSat big.Int } +// ReceivedSat computes received amount from total balance and sent amount func (ab *AddrBalance) ReceivedSat() *big.Int { var r big.Int r.Add(&ab.BalanceSat, &ab.SentSat) @@ -547,15 +554,18 @@ func (d *RocksDB) processAddressesBitcoinType(block *bchain.Block, addresses add return nil } +// addToAddressesMap maintains mapping between addresses and transactions in one block +// the method assumes that outpus in the block are processed before the inputs +// the return value is true if the tx was processed before, to not to count the tx multiple times func addToAddressesMap(addresses addressesMap, strAddrDesc string, btxID []byte, index int32) bool { - // check that the address was used already in this block + // check that the address was already processed in this block // if not found, it has certainly not been counted at, found := addresses[strAddrDesc] if found { - // check that the address was already used in this tx + // if the tx is already in the slice, append the index to the array of indexes for i, t := range at { if bytes.Equal(btxID, t.btxID) { - at[i].indexes = append(at[i].indexes, index) + at[i].indexes = append(t.indexes, index) return true } } diff --git a/db/rocksdb_ethereumtype.go b/db/rocksdb_ethereumtype.go index 2ce35924..e7cc5912 100644 --- a/db/rocksdb_ethereumtype.go +++ b/db/rocksdb_ethereumtype.go @@ -219,7 +219,7 @@ func (d *RocksDB) processAddressesEthereumType(block *bchain.Block, addresses ad glog.Warningf("rocksdb: GetErc20FromTx %v - height %d, tx %v, transfer %v", err, block.Height, tx.Txid, t) continue } - if err = d.addToAddressesAndContractsEthereumType(from, btxID, ^int32(i), contract, addresses, addressContracts, true); err != nil { + if err = d.addToAddressesAndContractsEthereumType(to, btxID, int32(i), contract, addresses, addressContracts, true); err != nil { return nil, err } eq := bytes.Equal(from, to) @@ -227,7 +227,7 @@ func (d *RocksDB) processAddressesEthereumType(block *bchain.Block, addresses ad j++ bc.addr = from bc.contract = contract - if err = d.addToAddressesAndContractsEthereumType(to, btxID, int32(i), contract, addresses, addressContracts, !eq); err != nil { + if err = d.addToAddressesAndContractsEthereumType(from, btxID, ^int32(i), contract, addresses, addressContracts, !eq); err != nil { return nil, err } // add to address to blockTx.contracts only if it is different from from address diff --git a/db/rocksdb_test.go b/db/rocksdb_test.go index 068a86ed..ac938968 100644 --- a/db/rocksdb_test.go +++ b/db/rocksdb_test.go @@ -484,6 +484,10 @@ func TestRocksDB_Index_BitcoinType(t *testing.T) { verifyGetTransactions(t, d, dbtestdata.Addr8, 0, 1000000, []txidIndex{ {dbtestdata.TxidB2T2, 0}, }, nil) + verifyGetTransactions(t, d, dbtestdata.Addr6, 0, 1000000, []txidIndex{ + {dbtestdata.TxidB2T2, ^0}, + {dbtestdata.TxidB2T1, 0}, + }, nil) verifyGetTransactions(t, d, "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eBad", 500000, 1000000, []txidIndex{}, errors.New("checksum mismatch")) // GetBestBlock