Fix indexing of coinbase transactions
This commit is contained in:
parent
d569a08cf8
commit
f78b050234
@ -42,6 +42,9 @@ func (p *BaseParser) KeepBlockAddresses() int {
|
|||||||
|
|
||||||
// PackTxid packs txid to byte array
|
// PackTxid packs txid to byte array
|
||||||
func (p *BaseParser) PackTxid(txid string) ([]byte, error) {
|
func (p *BaseParser) PackTxid(txid string) ([]byte, error) {
|
||||||
|
if txid == "" {
|
||||||
|
return nil, ErrTxidMissing
|
||||||
|
}
|
||||||
return hex.DecodeString(txid)
|
return hex.DecodeString(txid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,9 @@ var (
|
|||||||
// ErrAddressMissing is returned if address is not specified
|
// ErrAddressMissing is returned if address is not specified
|
||||||
// for example To address in ethereum can be missing in case of contract transaction
|
// for example To address in ethereum can be missing in case of contract transaction
|
||||||
ErrAddressMissing = errors.New("Address missing")
|
ErrAddressMissing = errors.New("Address missing")
|
||||||
|
// ErrTxidMissing is returned if txid is not specified
|
||||||
|
// for example coinbase transactions in Bitcoin
|
||||||
|
ErrTxidMissing = errors.New("Txid missing")
|
||||||
)
|
)
|
||||||
|
|
||||||
type ScriptSig struct {
|
type ScriptSig struct {
|
||||||
|
|||||||
@ -335,25 +335,25 @@ func appendPackedAddrID(txAddrs []byte, addrID []byte, n uint32, remaining int)
|
|||||||
return txAddrs
|
return txAddrs
|
||||||
}
|
}
|
||||||
|
|
||||||
func findAndRemoveUnspentAddr(unspentAddrs []byte, vout uint32) ([]byte, uint32, []byte) {
|
func findAndRemoveUnspentAddr(unspentAddrs []byte, vout uint32) ([]byte, []byte) {
|
||||||
// the addresses are packed as lenaddrID addrID vout, where lenaddrID and vout are varints
|
// the addresses are packed as lenaddrID addrID vout, where lenaddrID and vout are varints
|
||||||
for i := 0; i < len(unspentAddrs); {
|
for i := 0; i < len(unspentAddrs); {
|
||||||
l, lv1 := unpackVarint(unspentAddrs[i:])
|
l, lv1 := unpackVarint(unspentAddrs[i:])
|
||||||
// index of vout of address in unspentAddrs
|
// index of vout of address in unspentAddrs
|
||||||
j := i + int(l) + lv1
|
j := i + int(l) + lv1
|
||||||
if j >= len(unspentAddrs) {
|
if j >= len(unspentAddrs) {
|
||||||
glog.Error("rocksdb: Inconsistent data in unspentAddrs")
|
glog.Error("rocksdb: Inconsistent data in unspentAddrs ", hex.EncodeToString(unspentAddrs), ", ", vout)
|
||||||
return nil, 0, unspentAddrs
|
return nil, unspentAddrs
|
||||||
}
|
}
|
||||||
n, lv2 := unpackVarint(unspentAddrs[j:])
|
n, lv2 := unpackVarint(unspentAddrs[j:])
|
||||||
if uint32(n) == vout {
|
if uint32(n) == vout {
|
||||||
addrID := append([]byte(nil), unspentAddrs[i+lv1:j]...)
|
addrID := append([]byte(nil), unspentAddrs[i+lv1:j]...)
|
||||||
unspentAddrs = append(unspentAddrs[:i], unspentAddrs[j+lv2:]...)
|
unspentAddrs = append(unspentAddrs[:i], unspentAddrs[j+lv2:]...)
|
||||||
return addrID, uint32(n), unspentAddrs
|
return addrID, unspentAddrs
|
||||||
}
|
}
|
||||||
i += j + lv2
|
i = j + lv2
|
||||||
}
|
}
|
||||||
return nil, 0, unspentAddrs
|
return nil, unspentAddrs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *RocksDB) writeAddressesUTXO(wb *gorocksdb.WriteBatch, block *bchain.Block, op int) error {
|
func (d *RocksDB) writeAddressesUTXO(wb *gorocksdb.WriteBatch, block *bchain.Block, op int) error {
|
||||||
@ -397,6 +397,10 @@ func (d *RocksDB) writeAddressesUTXO(wb *gorocksdb.WriteBatch, block *bchain.Blo
|
|||||||
for i, input := range tx.Vin {
|
for i, input := range tx.Vin {
|
||||||
btxID, err := d.chainParser.PackTxid(input.Txid)
|
btxID, err := d.chainParser.PackTxid(input.Txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// do not process inputs without input txid
|
||||||
|
if err == bchain.ErrTxidMissing {
|
||||||
|
continue
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// try to find the tx in current block
|
// try to find the tx in current block
|
||||||
@ -412,7 +416,7 @@ func (d *RocksDB) writeAddressesUTXO(wb *gorocksdb.WriteBatch, block *bchain.Blo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var addrID []byte
|
var addrID []byte
|
||||||
addrID, _, unspentAddrs = findAndRemoveUnspentAddr(unspentAddrs, input.Vout)
|
addrID, unspentAddrs = findAndRemoveUnspentAddr(unspentAddrs, input.Vout)
|
||||||
if addrID == nil {
|
if addrID == nil {
|
||||||
glog.Warningf("rocksdb: height %d, tx %v vout %v in inputs but missing in unspentTxs", block.Height, tx.Txid, input.Vout)
|
glog.Warningf("rocksdb: height %d, tx %v vout %v in inputs but missing in unspentTxs", block.Height, tx.Txid, input.Vout)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -491,3 +491,61 @@ func TestRocksDB_Index_UTXO(t *testing.T) {
|
|||||||
// disconnect the 2nd block, verify that the db contains only the 1st block
|
// disconnect the 2nd block, verify that the db contains only the 1st block
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_findAndRemoveUnspentAddr(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
unspentAddrs string
|
||||||
|
vout uint32
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
want2 string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "3",
|
||||||
|
args: args{
|
||||||
|
unspentAddrs: "029c0010517a0115887452870212709393588893935687040e64635167006868060e76519351880087080a7b7b0115870a3276a9144150837fb91d9461d6b95059842ab85262c2923f88ac0c08636751680e04578710029112026114",
|
||||||
|
vout: 3,
|
||||||
|
},
|
||||||
|
want: "64635167006868",
|
||||||
|
want2: "029c0010517a0115887452870212709393588893935687040e76519351880087080a7b7b0115870a3276a9144150837fb91d9461d6b95059842ab85262c2923f88ac0c08636751680e04578710029112026114",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "10",
|
||||||
|
args: args{
|
||||||
|
unspentAddrs: "029c0010517a0115887452870212709393588893935687040e64635167006868060e76519351880087080a7b7b0115870a3276a9144150837fb91d9461d6b95059842ab85262c2923f88ac0c08636751680e04578710029112026114",
|
||||||
|
vout: 10,
|
||||||
|
},
|
||||||
|
want: "61",
|
||||||
|
want2: "029c0010517a0115887452870212709393588893935687040e64635167006868060e76519351880087080a7b7b0115870a3276a9144150837fb91d9461d6b95059842ab85262c2923f88ac0c08636751680e04578710029112",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "not there",
|
||||||
|
args: args{
|
||||||
|
unspentAddrs: "029c0010517a0115887452870212709393588893935687040e64635167006868060e76519351880087080a7b7b0115870a3276a9144150837fb91d9461d6b95059842ab85262c2923f88ac0c08636751680e04578710029112026114",
|
||||||
|
vout: 11,
|
||||||
|
},
|
||||||
|
want: "",
|
||||||
|
want2: "029c0010517a0115887452870212709393588893935687040e64635167006868060e76519351880087080a7b7b0115870a3276a9144150837fb91d9461d6b95059842ab85262c2923f88ac0c08636751680e04578710029112026114",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
b, err := hex.DecodeString(tt.args.unspentAddrs)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
got, got2 := findAndRemoveUnspentAddr(b, tt.args.vout)
|
||||||
|
h := hex.EncodeToString(got)
|
||||||
|
if !reflect.DeepEqual(h, tt.want) {
|
||||||
|
t.Errorf("findAndRemoveUnspentAddr() got = %v, want %v", h, tt.want)
|
||||||
|
}
|
||||||
|
h2 := hex.EncodeToString(got2)
|
||||||
|
if !reflect.DeepEqual(h2, tt.want2) {
|
||||||
|
t.Errorf("findAndRemoveUnspentAddr() got2 = %v, want %v", h2, tt.want2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user