Ensure ordering of address and xpub txs in the same block
parent
3551c90590
commit
3d10d9c2c5
14
api/xpub.go
14
api/xpub.go
|
@ -34,9 +34,17 @@ type xpubTxid struct {
|
||||||
|
|
||||||
type xpubTxids []xpubTxid
|
type xpubTxids []xpubTxid
|
||||||
|
|
||||||
func (a xpubTxids) Len() int { return len(a) }
|
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) 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) 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 {
|
type xpubAddress struct {
|
||||||
addrDesc bchain.AddressDescriptor
|
addrDesc bchain.AddressDescriptor
|
||||||
|
|
|
@ -353,37 +353,44 @@ type outpoint struct {
|
||||||
index int32
|
index int32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TxInput holds input data of the transaction in TxAddresses
|
||||||
type TxInput struct {
|
type TxInput struct {
|
||||||
AddrDesc bchain.AddressDescriptor
|
AddrDesc bchain.AddressDescriptor
|
||||||
ValueSat big.Int
|
ValueSat big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Addresses converts AddressDescriptor of the input to array of strings
|
||||||
func (ti *TxInput) Addresses(p bchain.BlockChainParser) ([]string, bool, error) {
|
func (ti *TxInput) Addresses(p bchain.BlockChainParser) ([]string, bool, error) {
|
||||||
return p.GetAddressesFromAddrDesc(ti.AddrDesc)
|
return p.GetAddressesFromAddrDesc(ti.AddrDesc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TxOutput holds output data of the transaction in TxAddresses
|
||||||
type TxOutput struct {
|
type TxOutput struct {
|
||||||
AddrDesc bchain.AddressDescriptor
|
AddrDesc bchain.AddressDescriptor
|
||||||
Spent bool
|
Spent bool
|
||||||
ValueSat big.Int
|
ValueSat big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Addresses converts AddressDescriptor of the output to array of strings
|
||||||
func (to *TxOutput) Addresses(p bchain.BlockChainParser) ([]string, bool, error) {
|
func (to *TxOutput) Addresses(p bchain.BlockChainParser) ([]string, bool, error) {
|
||||||
return p.GetAddressesFromAddrDesc(to.AddrDesc)
|
return p.GetAddressesFromAddrDesc(to.AddrDesc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TxAddresses stores transaction inputs and outputs with amounts
|
||||||
type TxAddresses struct {
|
type TxAddresses struct {
|
||||||
Height uint32
|
Height uint32
|
||||||
Inputs []TxInput
|
Inputs []TxInput
|
||||||
Outputs []TxOutput
|
Outputs []TxOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddrBalance stores number of transactions and balances of an address
|
||||||
type AddrBalance struct {
|
type AddrBalance struct {
|
||||||
Txs uint32
|
Txs uint32
|
||||||
SentSat big.Int
|
SentSat big.Int
|
||||||
BalanceSat big.Int
|
BalanceSat big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReceivedSat computes received amount from total balance and sent amount
|
||||||
func (ab *AddrBalance) ReceivedSat() *big.Int {
|
func (ab *AddrBalance) ReceivedSat() *big.Int {
|
||||||
var r big.Int
|
var r big.Int
|
||||||
r.Add(&ab.BalanceSat, &ab.SentSat)
|
r.Add(&ab.BalanceSat, &ab.SentSat)
|
||||||
|
@ -547,15 +554,18 @@ func (d *RocksDB) processAddressesBitcoinType(block *bchain.Block, addresses add
|
||||||
return nil
|
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 {
|
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
|
// if not found, it has certainly not been counted
|
||||||
at, found := addresses[strAddrDesc]
|
at, found := addresses[strAddrDesc]
|
||||||
if found {
|
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 {
|
for i, t := range at {
|
||||||
if bytes.Equal(btxID, t.btxID) {
|
if bytes.Equal(btxID, t.btxID) {
|
||||||
at[i].indexes = append(at[i].indexes, index)
|
at[i].indexes = append(t.indexes, index)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
glog.Warningf("rocksdb: GetErc20FromTx %v - height %d, tx %v, transfer %v", err, block.Height, tx.Txid, t)
|
||||||
continue
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
eq := bytes.Equal(from, to)
|
eq := bytes.Equal(from, to)
|
||||||
|
@ -227,7 +227,7 @@ func (d *RocksDB) processAddressesEthereumType(block *bchain.Block, addresses ad
|
||||||
j++
|
j++
|
||||||
bc.addr = from
|
bc.addr = from
|
||||||
bc.contract = contract
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
// add to address to blockTx.contracts only if it is different from from address
|
// add to address to blockTx.contracts only if it is different from from address
|
||||||
|
|
|
@ -484,6 +484,10 @@ func TestRocksDB_Index_BitcoinType(t *testing.T) {
|
||||||
verifyGetTransactions(t, d, dbtestdata.Addr8, 0, 1000000, []txidIndex{
|
verifyGetTransactions(t, d, dbtestdata.Addr8, 0, 1000000, []txidIndex{
|
||||||
{dbtestdata.TxidB2T2, 0},
|
{dbtestdata.TxidB2T2, 0},
|
||||||
}, nil)
|
}, 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"))
|
verifyGetTransactions(t, d, "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eBad", 500000, 1000000, []txidIndex{}, errors.New("checksum mismatch"))
|
||||||
|
|
||||||
// GetBestBlock
|
// GetBestBlock
|
||||||
|
|
Loading…
Reference in New Issue