Fix indexing of coinbase transactions

This commit is contained in:
Martin Boehm 2018-04-20 23:53:17 +02:00
parent d569a08cf8
commit f78b050234
4 changed files with 75 additions and 7 deletions

View File

@ -42,6 +42,9 @@ func (p *BaseParser) KeepBlockAddresses() int {
// PackTxid packs txid to byte array
func (p *BaseParser) PackTxid(txid string) ([]byte, error) {
if txid == "" {
return nil, ErrTxidMissing
}
return hex.DecodeString(txid)
}

View File

@ -14,6 +14,9 @@ var (
// ErrAddressMissing is returned if address is not specified
// for example To address in ethereum can be missing in case of contract transaction
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 {

View File

@ -335,25 +335,25 @@ func appendPackedAddrID(txAddrs []byte, addrID []byte, n uint32, remaining int)
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
for i := 0; i < len(unspentAddrs); {
l, lv1 := unpackVarint(unspentAddrs[i:])
// index of vout of address in unspentAddrs
j := i + int(l) + lv1
if j >= len(unspentAddrs) {
glog.Error("rocksdb: Inconsistent data in unspentAddrs")
return nil, 0, unspentAddrs
glog.Error("rocksdb: Inconsistent data in unspentAddrs ", hex.EncodeToString(unspentAddrs), ", ", vout)
return nil, unspentAddrs
}
n, lv2 := unpackVarint(unspentAddrs[j:])
if uint32(n) == vout {
addrID := append([]byte(nil), unspentAddrs[i+lv1:j]...)
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 {
@ -397,6 +397,10 @@ func (d *RocksDB) writeAddressesUTXO(wb *gorocksdb.WriteBatch, block *bchain.Blo
for i, input := range tx.Vin {
btxID, err := d.chainParser.PackTxid(input.Txid)
if err != nil {
// do not process inputs without input txid
if err == bchain.ErrTxidMissing {
continue
}
return err
}
// 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
addrID, _, unspentAddrs = findAndRemoveUnspentAddr(unspentAddrs, input.Vout)
addrID, unspentAddrs = findAndRemoveUnspentAddr(unspentAddrs, input.Vout)
if addrID == nil {
glog.Warningf("rocksdb: height %d, tx %v vout %v in inputs but missing in unspentTxs", block.Height, tx.Txid, input.Vout)
continue

View File

@ -491,3 +491,61 @@ func TestRocksDB_Index_UTXO(t *testing.T) {
// 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)
}
})
}
}