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

View File

@ -415,6 +415,9 @@ type outpoint struct {
type TxInput struct { type TxInput struct {
AddrDesc bchain.AddressDescriptor AddrDesc bchain.AddressDescriptor
ValueSat big.Int ValueSat big.Int
// extended index properties
Txid string
Vout uint32
} }
// Addresses converts AddressDescriptor of the input to array of strings // 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 // 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
// extended index properties
SpentTxid string SpentTxid string
SpentIndex uint32 SpentIndex uint32
SpentHeight uint32 SpentHeight uint32
@ -442,6 +446,8 @@ type TxAddresses struct {
Height uint32 Height uint32
Inputs []TxInput Inputs []TxInput
Outputs []TxOutput Outputs []TxOutput
// extended index properties
VSize uint32
} }
// Utxo holds information about unspent transaction output // Utxo holds information about unspent transaction output
@ -596,13 +602,21 @@ func (d *RocksDB) processAddressesBitcoinType(block *bchain.Block, addresses add
} }
blockTxIDs[txi] = btxID blockTxIDs[txi] = btxID
ta := TxAddresses{Height: block.Height} 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)) ta.Outputs = make([]TxOutput, len(tx.Vout))
txAddressesMap[string(btxID)] = &ta txAddressesMap[string(btxID)] = &ta
blockTxAddresses[txi] = &ta blockTxAddresses[txi] = &ta
for i, output := range tx.Vout { for i := range tx.Vout {
output := &tx.Vout[i]
tao := &ta.Outputs[i] tao := &ta.Outputs[i]
tao.ValueSat = output.ValueSat 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 || len(addrDesc) == 0 || len(addrDesc) > maxAddrDescLen {
if err != nil { if err != nil {
// do not log ErrAddressMissing, transactions can be without to address (for example eth contracts) // 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 := blockTxAddresses[txi]
ta.Inputs = make([]TxInput, len(tx.Vin)) ta.Inputs = make([]TxInput, len(tx.Vin))
logged := false logged := false
for i, input := range tx.Vin { for i := range tx.Vin {
input := &tx.Vin[i]
tai := &ta.Inputs[i] tai := &ta.Inputs[i]
btxID, err := d.chainParser.PackTxid(input.Txid) btxID, err := d.chainParser.PackTxid(input.Txid)
if err != nil { if err != nil {
@ -695,6 +710,8 @@ func (d *RocksDB) processAddressesBitcoinType(block *bchain.Block, addresses add
spentOutput.SpentTxid = tx.Txid spentOutput.SpentTxid = tx.Txid
spentOutput.SpentIndex = uint32(i) spentOutput.SpentIndex = uint32(i)
spentOutput.SpentHeight = block.Height spentOutput.SpentHeight = block.Height
tai.Txid = input.Txid
tai.Vout = input.Vout
} }
if len(spentOutput.AddrDesc) == 0 { if len(spentOutput.AddrDesc) == 0 {
if !logged { if !logged {
@ -951,10 +968,14 @@ func (d *RocksDB) packTxAddresses(ta *TxAddresses, buf []byte, varBuf []byte) []
buf = buf[:0] buf = buf[:0]
l := packVaruint(uint(ta.Height), varBuf) l := packVaruint(uint(ta.Height), varBuf)
buf = append(buf, varBuf[:l]...) 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) l = packVaruint(uint(len(ta.Inputs)), varBuf)
buf = append(buf, varBuf[:l]...) buf = append(buf, varBuf[:l]...)
for i := range ta.Inputs { 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) l = packVaruint(uint(len(ta.Outputs)), varBuf)
buf = append(buf, varBuf[:l]...) buf = append(buf, varBuf[:l]...)
@ -964,13 +985,38 @@ func (d *RocksDB) packTxAddresses(ta *TxAddresses, buf []byte, varBuf []byte) []
return buf 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) la := len(txi.AddrDesc)
l := packVaruint(uint(la), varBuf) var l int
buf = append(buf, varBuf[:l]...) if d.extendedIndex {
buf = append(buf, txi.AddrDesc...) if txi.Txid == "" {
l = packBigint(&txi.ValueSat, varBuf) // coinbase transaction
buf = append(buf, varBuf[:l]...) 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 return buf
} }
@ -1049,7 +1095,7 @@ func packAddrBalance(ab *AddrBalance, buf, varBuf []byte) []byte {
l = packBigint(&ab.BalanceSat, varBuf) l = packBigint(&ab.BalanceSat, varBuf)
buf = append(buf, varBuf[:l]...) buf = append(buf, varBuf[:l]...)
for _, utxo := range ab.Utxos { 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 { if utxo.Vout >= 0 {
buf = append(buf, utxo.BtxID...) buf = append(buf, utxo.BtxID...)
l = packVaruint(uint(utxo.Vout), varBuf) l = packVaruint(uint(utxo.Vout), varBuf)
@ -1067,11 +1113,16 @@ func (d *RocksDB) unpackTxAddresses(buf []byte) (*TxAddresses, error) {
ta := TxAddresses{} ta := TxAddresses{}
height, l := unpackVaruint(buf) height, l := unpackVaruint(buf)
ta.Height = uint32(height) ta.Height = uint32(height)
if d.extendedIndex {
vsize, ll := unpackVaruint(buf[l:])
ta.VSize = uint32(vsize)
l += ll
}
inputs, ll := unpackVaruint(buf[l:]) inputs, ll := unpackVaruint(buf[l:])
l += ll l += ll
ta.Inputs = make([]TxInput, inputs) ta.Inputs = make([]TxInput, inputs)
for i := uint(0); i < inputs; i++ { 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:]) outputs, ll := unpackVaruint(buf[l:])
l += ll l += ll
@ -1082,12 +1133,35 @@ func (d *RocksDB) unpackTxAddresses(buf []byte) (*TxAddresses, error) {
return &ta, nil return &ta, nil
} }
func unpackTxInput(ti *TxInput, buf []byte) int { func (d *RocksDB) unpackTxInput(ti *TxInput, buf []byte) int {
al, l := unpackVaruint(buf) if d.extendedIndex {
ti.AddrDesc = append([]byte(nil), buf[l:l+int(al)]...) al, l := unpackVarint(buf)
al += uint(l) var coinbase bool
ti.ValueSat, l = unpackBigint(buf[al:]) if al < 0 {
return l + int(al) 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 { 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", name: "extendedIndex 1",
hex: "e0390317a9149eb21980dc9d413d8eac27314938b9da920ee53e8705021918f2c017a91409f70b896169c37981d2b54b371df0d81a136a2c870501dd7e28c017a914e371782582a4addb541362c55565d2cdf56f6498870501a1e35ec0052fa9141d9ca71efa36d814424ea6ca1437e67287aebe348705012aadcac000b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa38400081ce8685592ea91424fbc77cdc62702ade74dcf989c15e5d3f9240bc870501664894c02fa914afbfb74ee994c7d45f6698738bc4226d065266f7870501a1e35ec0effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75ef17a1f4233276a914d2a37ce20ac9ec4f15dd05a7c6e8e9fbdb99850e88ac043b9943603376a9146b2044146a4438e6e5bfbc65f147afeb64d14fbb88ac05012a05f2007c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25a9956d8396f32a", hex: "e0398241032ea9149eb21980dc9d413d8eac27314938b9da920ee53e8705021918f2c0c50c7ce2f5670fd52de738288299bd854a85ef1bb304f62f35ced1bd49a8a810002ea91409f70b896169c37981d2b54b371df0d81a136a2c870501dd7e28c0e96672c7fcc8da131427fcea7e841028614813496a56c11e8a6185c16861c495012ea914e371782582a4addb541362c55565d2cdf56f6498870501a1e35ec0ed308c72f9804dfeefdbb483ef8fd1e638180ad81d6b33f4b58d36d19162fa6d8106052fa9141d9ca71efa36d814424ea6ca1437e67287aebe348705012aadcac000b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa38400081ce8685592ea91424fbc77cdc62702ade74dcf989c15e5d3f9240bc870501664894c02fa914afbfb74ee994c7d45f6698738bc4226d065266f7870501a1e35ec0effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75ef17a1f4233276a914d2a37ce20ac9ec4f15dd05a7c6e8e9fbdb99850e88ac043b9943603376a9146b2044146a4438e6e5bfbc65f147afeb64d14fbb88ac05012a05f2007c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25a9956d8396f32a",
data: &TxAddresses{ data: &TxAddresses{
Height: 12345, Height: 12345,
VSize: 321,
Inputs: []TxInput{ Inputs: []TxInput{
{ {
AddrDesc: addressToAddrDesc("2N7iL7AvS4LViugwsdjTB13uN4T7XhV1bCP", parser), AddrDesc: addressToAddrDesc("2N7iL7AvS4LViugwsdjTB13uN4T7XhV1bCP", parser),
ValueSat: *big.NewInt(9011000000), ValueSat: *big.NewInt(9011000000),
Txid: "c50c7ce2f5670fd52de738288299bd854a85ef1bb304f62f35ced1bd49a8a810",
Vout: 0,
}, },
{ {
AddrDesc: addressToAddrDesc("2Mt9v216YiNBAzobeNEzd4FQweHrGyuRHze", parser), AddrDesc: addressToAddrDesc("2Mt9v216YiNBAzobeNEzd4FQweHrGyuRHze", parser),
ValueSat: *big.NewInt(8011000000), ValueSat: *big.NewInt(8011000000),
Txid: "e96672c7fcc8da131427fcea7e841028614813496a56c11e8a6185c16861c495",
Vout: 1,
}, },
{ {
AddrDesc: addressToAddrDesc("2NDyqJpHvHnqNtL1F9xAeCWMAW8WLJmEMyD", parser), AddrDesc: addressToAddrDesc("2NDyqJpHvHnqNtL1F9xAeCWMAW8WLJmEMyD", parser),
ValueSat: *big.NewInt(7011000000), ValueSat: *big.NewInt(7011000000),
Txid: "ed308c72f9804dfeefdbb483ef8fd1e638180ad81d6b33f4b58d36d19162fa6d",
Vout: 134,
}, },
}, },
Outputs: []TxOutput{ Outputs: []TxOutput{
@ -1072,9 +1079,10 @@ func Test_packTxAddresses_unpackTxAddresses(t *testing.T) {
}, },
{ {
name: "extendedIndex empty address", name: "extendedIndex empty address",
hex: "baef9a1501000204d2020002162e010162fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db03e039", hex: "baef9a152d01010204d2020002162e010162fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db03e039",
data: &TxAddresses{ data: &TxAddresses{
Height: 123456789, Height: 123456789,
VSize: 45,
Inputs: []TxInput{ Inputs: []TxInput{
{ {
AddrDesc: []byte(nil), AddrDesc: []byte(nil),

View File

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