Add extended index option - vin.txid

This commit is contained in:
Martin Boehm 2023-02-08 00:19:34 +01:00
parent d52832f6f7
commit 708f96cf57
4 changed files with 116 additions and 25 deletions

View File

@ -844,6 +844,10 @@ func (w *Worker) txFromTxAddress(txid string, ta *db.TxAddresses, bi *db.BlockIn
if err != nil {
glog.Errorf("tai.Addresses error %v, tx %v, input %v, tai %+v", err, txid, i, tai)
}
if w.db.HasExtendedIndex() {
vin.Txid = tai.Txid
vin.Vout = tai.Vout
}
aggregateAddresses(addresses, vin.Addresses, vin.IsAddress)
}
vouts := make([]Vout, len(ta.Outputs))
@ -882,6 +886,11 @@ func (w *Worker) txFromTxAddress(txid string, ta *db.TxAddresses, bi *db.BlockIn
Vin: vins,
Vout: vouts,
}
if w.chainParser.SupportsVSize() {
r.VSize = int(ta.VSize)
} else {
r.Size = int(ta.VSize)
}
return r
}

View File

@ -415,6 +415,9 @@ type outpoint struct {
type TxInput struct {
AddrDesc bchain.AddressDescriptor
ValueSat big.Int
// extended index properties
Txid string
Vout uint32
}
// Addresses converts AddressDescriptor of the input to array of strings
@ -424,9 +427,10 @@ func (ti *TxInput) Addresses(p bchain.BlockChainParser) ([]string, bool, error)
// TxOutput holds output data of the transaction in TxAddresses
type TxOutput struct {
AddrDesc bchain.AddressDescriptor
Spent bool
ValueSat big.Int
AddrDesc bchain.AddressDescriptor
Spent bool
ValueSat big.Int
// extended index properties
SpentTxid string
SpentIndex uint32
SpentHeight uint32
@ -442,6 +446,8 @@ type TxAddresses struct {
Height uint32
Inputs []TxInput
Outputs []TxOutput
// extended index properties
VSize uint32
}
// Utxo holds information about unspent transaction output
@ -596,13 +602,21 @@ func (d *RocksDB) processAddressesBitcoinType(block *bchain.Block, addresses add
}
blockTxIDs[txi] = btxID
ta := TxAddresses{Height: block.Height}
if d.extendedIndex {
if tx.VSize > 0 {
ta.VSize = uint32(tx.VSize)
} else {
ta.VSize = uint32(len(tx.Hex))
}
}
ta.Outputs = make([]TxOutput, len(tx.Vout))
txAddressesMap[string(btxID)] = &ta
blockTxAddresses[txi] = &ta
for i, output := range tx.Vout {
for i := range tx.Vout {
output := &tx.Vout[i]
tao := &ta.Outputs[i]
tao.ValueSat = output.ValueSat
addrDesc, err := d.chainParser.GetAddrDescFromVout(&output)
addrDesc, err := d.chainParser.GetAddrDescFromVout(output)
if err != nil || len(addrDesc) == 0 || len(addrDesc) > maxAddrDescLen {
if err != nil {
// do not log ErrAddressMissing, transactions can be without to address (for example eth contracts)
@ -652,7 +666,8 @@ func (d *RocksDB) processAddressesBitcoinType(block *bchain.Block, addresses add
ta := blockTxAddresses[txi]
ta.Inputs = make([]TxInput, len(tx.Vin))
logged := false
for i, input := range tx.Vin {
for i := range tx.Vin {
input := &tx.Vin[i]
tai := &ta.Inputs[i]
btxID, err := d.chainParser.PackTxid(input.Txid)
if err != nil {
@ -695,6 +710,8 @@ func (d *RocksDB) processAddressesBitcoinType(block *bchain.Block, addresses add
spentOutput.SpentTxid = tx.Txid
spentOutput.SpentIndex = uint32(i)
spentOutput.SpentHeight = block.Height
tai.Txid = input.Txid
tai.Vout = input.Vout
}
if len(spentOutput.AddrDesc) == 0 {
if !logged {
@ -951,10 +968,14 @@ func (d *RocksDB) packTxAddresses(ta *TxAddresses, buf []byte, varBuf []byte) []
buf = buf[:0]
l := packVaruint(uint(ta.Height), varBuf)
buf = append(buf, varBuf[:l]...)
if d.extendedIndex {
l = packVaruint(uint(ta.VSize), varBuf)
buf = append(buf, varBuf[:l]...)
}
l = packVaruint(uint(len(ta.Inputs)), varBuf)
buf = append(buf, varBuf[:l]...)
for i := range ta.Inputs {
buf = appendTxInput(&ta.Inputs[i], buf, varBuf)
buf = d.appendTxInput(&ta.Inputs[i], buf, varBuf)
}
l = packVaruint(uint(len(ta.Outputs)), varBuf)
buf = append(buf, varBuf[:l]...)
@ -964,13 +985,38 @@ func (d *RocksDB) packTxAddresses(ta *TxAddresses, buf []byte, varBuf []byte) []
return buf
}
func appendTxInput(txi *TxInput, buf []byte, varBuf []byte) []byte {
func (d *RocksDB) appendTxInput(txi *TxInput, buf []byte, varBuf []byte) []byte {
la := len(txi.AddrDesc)
l := packVaruint(uint(la), varBuf)
buf = append(buf, varBuf[:l]...)
buf = append(buf, txi.AddrDesc...)
l = packBigint(&txi.ValueSat, varBuf)
buf = append(buf, varBuf[:l]...)
var l int
if d.extendedIndex {
if txi.Txid == "" {
// coinbase transaction
la = ^la
}
l = packVarint(la, varBuf)
buf = append(buf, varBuf[:l]...)
buf = append(buf, txi.AddrDesc...)
l = packBigint(&txi.ValueSat, varBuf)
buf = append(buf, varBuf[:l]...)
if la >= 0 {
btxID, err := d.chainParser.PackTxid(txi.Txid)
if err != nil {
if err != bchain.ErrTxidMissing {
glog.Error("Cannot pack txid ", txi.Txid)
}
btxID = make([]byte, d.chainParser.PackedTxidLen())
}
buf = append(buf, btxID...)
l = packVaruint(uint(txi.Vout), varBuf)
buf = append(buf, varBuf[:l]...)
}
} else {
l = packVaruint(uint(la), varBuf)
buf = append(buf, varBuf[:l]...)
buf = append(buf, txi.AddrDesc...)
l = packBigint(&txi.ValueSat, varBuf)
buf = append(buf, varBuf[:l]...)
}
return buf
}
@ -1049,7 +1095,7 @@ func packAddrBalance(ab *AddrBalance, buf, varBuf []byte) []byte {
l = packBigint(&ab.BalanceSat, varBuf)
buf = append(buf, varBuf[:l]...)
for _, utxo := range ab.Utxos {
// if Vout < 0, utxo is marked as spent
// if Vout < 0, utxo is marked as spent and removed from the entry
if utxo.Vout >= 0 {
buf = append(buf, utxo.BtxID...)
l = packVaruint(uint(utxo.Vout), varBuf)
@ -1067,11 +1113,16 @@ func (d *RocksDB) unpackTxAddresses(buf []byte) (*TxAddresses, error) {
ta := TxAddresses{}
height, l := unpackVaruint(buf)
ta.Height = uint32(height)
if d.extendedIndex {
vsize, ll := unpackVaruint(buf[l:])
ta.VSize = uint32(vsize)
l += ll
}
inputs, ll := unpackVaruint(buf[l:])
l += ll
ta.Inputs = make([]TxInput, inputs)
for i := uint(0); i < inputs; i++ {
l += unpackTxInput(&ta.Inputs[i], buf[l:])
l += d.unpackTxInput(&ta.Inputs[i], buf[l:])
}
outputs, ll := unpackVaruint(buf[l:])
l += ll
@ -1082,12 +1133,35 @@ func (d *RocksDB) unpackTxAddresses(buf []byte) (*TxAddresses, error) {
return &ta, nil
}
func unpackTxInput(ti *TxInput, buf []byte) int {
al, l := unpackVaruint(buf)
ti.AddrDesc = append([]byte(nil), buf[l:l+int(al)]...)
al += uint(l)
ti.ValueSat, l = unpackBigint(buf[al:])
return l + int(al)
func (d *RocksDB) unpackTxInput(ti *TxInput, buf []byte) int {
if d.extendedIndex {
al, l := unpackVarint(buf)
var coinbase bool
if al < 0 {
coinbase = true
al = ^al
}
ti.AddrDesc = append([]byte(nil), buf[l:l+al]...)
al += l
ti.ValueSat, l = unpackBigint(buf[al:])
al += l
if !coinbase {
l = d.chainParser.PackedTxidLen()
ti.Txid, _ = d.chainParser.UnpackTxid(buf[al : al+l])
al += l
var i uint
i, l = unpackVaruint(buf[al:])
ti.Vout = uint32(i)
al += l
}
return al
} else {
al, l := unpackVaruint(buf)
ti.AddrDesc = append([]byte(nil), buf[l:l+int(al)]...)
al += uint(l)
ti.ValueSat, l = unpackBigint(buf[al:])
return l + int(al)
}
}
func (d *RocksDB) unpackTxOutput(to *TxOutput, buf []byte) int {

View File

@ -1016,21 +1016,28 @@ func Test_packTxAddresses_unpackTxAddresses(t *testing.T) {
},
{
name: "extendedIndex 1",
hex: "e0390317a9149eb21980dc9d413d8eac27314938b9da920ee53e8705021918f2c017a91409f70b896169c37981d2b54b371df0d81a136a2c870501dd7e28c017a914e371782582a4addb541362c55565d2cdf56f6498870501a1e35ec0052fa9141d9ca71efa36d814424ea6ca1437e67287aebe348705012aadcac000b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa38400081ce8685592ea91424fbc77cdc62702ade74dcf989c15e5d3f9240bc870501664894c02fa914afbfb74ee994c7d45f6698738bc4226d065266f7870501a1e35ec0effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75ef17a1f4233276a914d2a37ce20ac9ec4f15dd05a7c6e8e9fbdb99850e88ac043b9943603376a9146b2044146a4438e6e5bfbc65f147afeb64d14fbb88ac05012a05f2007c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25a9956d8396f32a",
hex: "e0398241032ea9149eb21980dc9d413d8eac27314938b9da920ee53e8705021918f2c0c50c7ce2f5670fd52de738288299bd854a85ef1bb304f62f35ced1bd49a8a810002ea91409f70b896169c37981d2b54b371df0d81a136a2c870501dd7e28c0e96672c7fcc8da131427fcea7e841028614813496a56c11e8a6185c16861c495012ea914e371782582a4addb541362c55565d2cdf56f6498870501a1e35ec0ed308c72f9804dfeefdbb483ef8fd1e638180ad81d6b33f4b58d36d19162fa6d8106052fa9141d9ca71efa36d814424ea6ca1437e67287aebe348705012aadcac000b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa38400081ce8685592ea91424fbc77cdc62702ade74dcf989c15e5d3f9240bc870501664894c02fa914afbfb74ee994c7d45f6698738bc4226d065266f7870501a1e35ec0effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75ef17a1f4233276a914d2a37ce20ac9ec4f15dd05a7c6e8e9fbdb99850e88ac043b9943603376a9146b2044146a4438e6e5bfbc65f147afeb64d14fbb88ac05012a05f2007c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25a9956d8396f32a",
data: &TxAddresses{
Height: 12345,
VSize: 321,
Inputs: []TxInput{
{
AddrDesc: addressToAddrDesc("2N7iL7AvS4LViugwsdjTB13uN4T7XhV1bCP", parser),
ValueSat: *big.NewInt(9011000000),
Txid: "c50c7ce2f5670fd52de738288299bd854a85ef1bb304f62f35ced1bd49a8a810",
Vout: 0,
},
{
AddrDesc: addressToAddrDesc("2Mt9v216YiNBAzobeNEzd4FQweHrGyuRHze", parser),
ValueSat: *big.NewInt(8011000000),
Txid: "e96672c7fcc8da131427fcea7e841028614813496a56c11e8a6185c16861c495",
Vout: 1,
},
{
AddrDesc: addressToAddrDesc("2NDyqJpHvHnqNtL1F9xAeCWMAW8WLJmEMyD", parser),
ValueSat: *big.NewInt(7011000000),
Txid: "ed308c72f9804dfeefdbb483ef8fd1e638180ad81d6b33f4b58d36d19162fa6d",
Vout: 134,
},
},
Outputs: []TxOutput{
@ -1072,9 +1079,10 @@ func Test_packTxAddresses_unpackTxAddresses(t *testing.T) {
},
{
name: "extendedIndex empty address",
hex: "baef9a1501000204d2020002162e010162fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db03e039",
hex: "baef9a152d01010204d2020002162e010162fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db03e039",
data: &TxAddresses{
Height: 123456789,
VSize: 45,
Inputs: []TxInput{
{
AddrDesc: []byte(nil),

View File

@ -59,8 +59,8 @@
</div>
<div class="row footer">
<div class="col-sm-12 col-md-4">
{{if $tx.FeesSat}}
Fee {{amountSpan $tx.FeesSat $data "txvalue copyable ms-3"}}
{{if $tx.FeesSat}}{{$fpb := feePerByte $tx}}
Fee {{amountSpan $tx.FeesSat $data "txvalue copyable ms-3"}}{{if $fpb}} <span class="fw-normal small">({{$fpb}})</span>{{end}}
{{end}}
</div>
<div class="col-sm-12 col-md-8 text-end">