Implement and test connectBlock for index v3

indexv3
Martin Boehm 2018-08-02 14:30:45 +02:00
parent 95f831eefa
commit a2bbf3f9de
2 changed files with 603 additions and 179 deletions

View File

@ -22,7 +22,8 @@ import (
// when doing huge scan, it is better to close it and reopen from time to time to free the resources
const refreshIterator = 5000000
const packedHeightBytes = 4
const dbVersion = 0
const dbVersion = 3
const maxAddrIDLen = 1024
// RepairRocksDB calls RocksDb db repair function
func RepairRocksDB(name string) error {
@ -203,11 +204,11 @@ func (d *RocksDB) GetTransactions(address string, lower uint32, higher uint32, f
for _, o := range outpoints {
var vout uint32
var isOutput bool
if o.vout < 0 {
vout = uint32(^o.vout)
if o.index < 0 {
vout = uint32(^o.index)
isOutput = false
} else {
vout = uint32(o.vout)
vout = uint32(o.index)
isOutput = true
}
tx, err := d.chainParser.UnpackTxid(o.btxID)
@ -272,18 +273,381 @@ func (d *RocksDB) writeBlock(block *bchain.Block, op int) error {
type outpoint struct {
btxID []byte
vout int32
index int32
}
type txAddress struct {
addrID []byte
spent bool
valueSat big.Int
}
type txAddresses struct {
inputs []txAddress
outputs []txAddress
}
type addrBalance struct {
txs uint32
sentSat big.Int
balanceSat big.Int
}
func (d *RocksDB) writeAddressesUTXO(wb *gorocksdb.WriteBatch, block *bchain.Block, op int) error {
if op == opDelete {
// block does not contain mapping tx-> input address, which is necessary to recreate
// unspentTxs; therefore it is not possible to DisconnectBlocks this way
return errors.New("DisconnectBlock is not supported for UTXO chains")
}
addresses := make(map[string][]outpoint)
blockTxids := make([][]byte, len(block.Txs))
txAddressesMap := make(map[string]*txAddresses)
balances := make(map[string]*addrBalance)
// first process all outputs so that inputs can point to txs in this block
for txi, tx := range block.Txs {
btxID, err := d.chainParser.PackTxid(tx.Txid)
if err != nil {
return err
}
blockTxids[txi] = btxID
ta := txAddresses{}
ta.outputs = make([]txAddress, len(tx.Vout))
txAddressesMap[string(btxID)] = &ta
for i, output := range tx.Vout {
tao := &ta.outputs[i]
tao.valueSat = output.ValueSat
addrID, err := d.chainParser.GetAddrIDFromVout(&output)
if err != nil || len(addrID) == 0 || len(addrID) > maxAddrIDLen {
if err != nil {
// do not log ErrAddressMissing, transactions can be without to address (for example eth contracts)
if err != bchain.ErrAddressMissing {
glog.Warningf("rocksdb: addrID: %v - height %d, tx %v, output %v", err, block.Height, tx.Txid, output)
}
} else {
glog.Infof("rocksdb: block %d, skipping addrID of length %d", block.Height, len(addrID))
}
continue
}
tao.addrID = addrID
strAddrID := string(addrID)
// check that the address was used already in this block
o, processed := addresses[strAddrID]
if processed {
// check that the address was already used in this tx
processed = processedInTx(o, btxID)
}
addresses[strAddrID] = append(o, outpoint{
btxID: btxID,
index: int32(i),
})
ab, e := balances[strAddrID]
if !e {
ab, err = d.getAddressBalance(addrID)
if err != nil {
return err
}
if ab == nil {
ab = &addrBalance{}
}
balances[strAddrID] = ab
}
// add number of trx in balance only once, address can be multiple times in tx
if !processed {
ab.txs++
}
ab.balanceSat.Add(&ab.balanceSat, &output.ValueSat)
}
}
// process inputs
for txi, tx := range block.Txs {
spendingTxid := blockTxids[txi]
ta := txAddressesMap[string(spendingTxid)]
ta.inputs = make([]txAddress, len(tx.Vin))
for i, input := range tx.Vin {
tai := &ta.inputs[i]
btxID, err := d.chainParser.PackTxid(input.Txid)
if err != nil {
// do not process inputs without input txid
if err == bchain.ErrTxidMissing {
continue
}
return err
}
stxID := string(btxID)
ita, e := txAddressesMap[stxID]
if !e {
ita, err = d.getTxAddresses(btxID)
if err != nil {
return err
}
if ita == nil {
glog.Warningf("rocksdb: height %d, tx %v, input tx %v not found in txAddresses", block.Height, tx.Txid, input.Txid)
continue
}
txAddressesMap[stxID] = ita
}
if len(ita.outputs) <= int(input.Vout) {
glog.Warningf("rocksdb: height %d, tx %v, input tx %v vout %v is out of bounds of stored tx", block.Height, tx.Txid, input.Txid, input.Vout)
continue
}
ot := &ita.outputs[int(input.Vout)]
if ot.spent {
glog.Warningf("rocksdb: height %d, tx %v, input tx %v vout %v is double spend", block.Height, tx.Txid, input.Txid, input.Vout)
continue
}
tai.addrID = ot.addrID
tai.valueSat = ot.valueSat
// mark the output tx as spent
ot.spent = true
strAddrID := string(ot.addrID)
// check that the address was used already in this block
o, processed := addresses[strAddrID]
if processed {
// check that the address was already used in this tx
processed = processedInTx(o, spendingTxid)
}
addresses[strAddrID] = append(o, outpoint{
btxID: spendingTxid,
index: ^int32(i),
})
ab, e := balances[strAddrID]
if !e {
ab, err = d.getAddressBalance(ot.addrID)
if err != nil {
return err
}
if ab == nil {
ab = &addrBalance{}
}
balances[strAddrID] = ab
}
// add number of trx in balance only once, address can be multiple times in tx
if !processed {
ab.txs++
}
ab.balanceSat.Sub(&ab.balanceSat, &ot.valueSat)
if ab.balanceSat.Sign() < 0 {
ad, err := d.chainParser.OutputScriptToAddresses(ot.addrID)
if err != nil {
glog.Warningf("rocksdb: unparsable address reached negative balance %v, resetting to 0. Parser error %v", ab.balanceSat.String(), err)
} else {
glog.Warningf("rocksdb: address %v reached negative balance %v, resetting to 0", ab.balanceSat.String(), ad)
}
ab.balanceSat.SetInt64(0)
}
ab.sentSat.Add(&ab.sentSat, &ot.valueSat)
}
}
if op == opInsert {
if err := d.storeAddresses(wb, block, addresses); err != nil {
return err
}
if err := d.storeTxAddresses(wb, txAddressesMap); err != nil {
return err
}
if err := d.storeBalances(wb, balances); err != nil {
return err
}
if err := d.storeAndCleanupBlockTxids(wb, block, blockTxids); err != nil {
return err
}
}
return nil
}
func processedInTx(o []outpoint, btxID []byte) bool {
for _, op := range o {
if bytes.Equal(btxID, op.btxID) {
return true
}
}
return false
}
func (d *RocksDB) storeAddresses(wb *gorocksdb.WriteBatch, block *bchain.Block, addresses map[string][]outpoint) error {
for addrID, outpoints := range addresses {
ba := []byte(addrID)
key := packAddressKey(ba, block.Height)
val := d.packOutpoints(outpoints)
wb.PutCF(d.cfh[cfAddresses], key, val)
}
return nil
}
func (d *RocksDB) storeTxAddresses(wb *gorocksdb.WriteBatch, am map[string]*txAddresses) error {
varBuf := make([]byte, maxPackedBigintBytes)
buf := make([]byte, 1024)
for txID, ta := range am {
buf = buf[:0]
l := packVaruint(uint(len(ta.inputs)), varBuf)
buf = append(buf, varBuf[:l]...)
for i := range ta.inputs {
buf = appendTxAddress(buf, varBuf, &ta.inputs[i])
}
l = packVaruint(uint(len(ta.outputs)), varBuf)
buf = append(buf, varBuf[:l]...)
for i := range ta.outputs {
buf = appendTxAddress(buf, varBuf, &ta.outputs[i])
}
wb.PutCF(d.cfh[cfTxAddresses], []byte(txID), buf)
}
return nil
}
func (d *RocksDB) storeBalances(wb *gorocksdb.WriteBatch, abm map[string]*addrBalance) error {
// allocate buffer big enough for number of txs + 2 bigints
buf := make([]byte, vlq.MaxLen32+2*maxPackedBigintBytes)
for addrID, ab := range abm {
l := packVaruint(uint(ab.txs), buf)
ll := packBigint(&ab.sentSat, buf[l:])
l += ll
ll = packBigint(&ab.balanceSat, buf[l:])
l += ll
wb.PutCF(d.cfh[cfAddressBalance], []byte(addrID), buf[:l])
}
return nil
}
func appendTxAddress(buf []byte, varBuf []byte, txa *txAddress) []byte {
la := len(txa.addrID)
if txa.spent {
la = ^la
}
l := packVarint(la, varBuf)
buf = append(buf, varBuf[:l]...)
buf = append(buf, txa.addrID...)
l = packBigint(&txa.valueSat, varBuf)
buf = append(buf, varBuf[:l]...)
return buf
}
func (d *RocksDB) storeAndCleanupBlockTxids(wb *gorocksdb.WriteBatch, block *bchain.Block, txids [][]byte) error {
pl := d.chainParser.PackedTxidLen()
buf := make([]byte, pl*len(txids))
i := 0
for _, txid := range txids {
copy(buf[i:], txid)
i += pl
}
key := packUint(block.Height)
wb.PutCF(d.cfh[cfBlockTxids], key, buf)
keep := d.chainParser.KeepBlockAddresses()
// cleanup old block address
if block.Height > uint32(keep) {
for rh := block.Height - uint32(keep); rh < block.Height; rh-- {
key = packUint(rh)
val, err := d.db.GetCF(d.ro, d.cfh[cfBlockTxids], key)
if err != nil {
return err
}
if val.Size() == 0 {
break
}
val.Free()
d.db.DeleteCF(d.wo, d.cfh[cfBlockTxids], key)
}
}
return nil
}
func (d *RocksDB) getAddressBalance(addrID []byte) (*addrBalance, error) {
val, err := d.db.GetCF(d.ro, d.cfh[cfAddressBalance], addrID)
if err != nil {
return nil, err
}
defer val.Free()
buf := val.Data()
// 3 is minimum length of addrBalance - 1 byte txs, 1 byte sent, 1 byte balance
if len(buf) < 3 {
return nil, nil
}
txs, l := unpackVaruint(buf)
sentSat, sl := unpackBigint(buf[l:])
balanceSat, _ := unpackBigint(buf[l+sl:])
return &addrBalance{
txs: uint32(txs),
sentSat: sentSat,
balanceSat: balanceSat,
}, nil
}
func (d *RocksDB) getTxAddresses(btxID []byte) (*txAddresses, error) {
val, err := d.db.GetCF(d.ro, d.cfh[cfTxAddresses], btxID)
if err != nil {
return nil, err
}
defer val.Free()
buf := val.Data()
// 2 is minimum length of addrBalance - 1 byte inputs len, 1 byte outputs len
if len(buf) < 2 {
return nil, nil
}
ta := txAddresses{}
inputs, l := unpackVaruint(buf)
ta.inputs = make([]txAddress, inputs)
for i := uint(0); i < inputs; i++ {
l += unpackTxAddress(&ta.inputs[i], buf[l:])
}
outputs, ll := unpackVaruint(buf[l:])
l += ll
ta.outputs = make([]txAddress, outputs)
for i := uint(0); i < outputs; i++ {
l += unpackTxAddress(&ta.outputs[i], buf[l:])
}
return &ta, nil
}
func unpackTxAddress(ta *txAddress, buf []byte) int {
al, l := unpackVarint(buf)
if al < 0 {
ta.spent = true
al ^= al
}
ta.addrID = make([]byte, al)
copy(ta.addrID, buf[l:l+al])
al += l
ta.valueSat, l = unpackBigint(buf[al:])
return l + al
}
func (d *RocksDB) packOutpoints(outpoints []outpoint) []byte {
buf := make([]byte, 0)
bvout := make([]byte, vlq.MaxLen32)
for _, o := range outpoints {
l := packVarint32(o.index, bvout)
buf = append(buf, []byte(o.btxID)...)
buf = append(buf, bvout[:l]...)
}
return buf
}
func (d *RocksDB) unpackOutpoints(buf []byte) ([]outpoint, error) {
txidUnpackedLen := d.chainParser.PackedTxidLen()
outpoints := make([]outpoint, 0)
for i := 0; i < len(buf); {
btxID := append([]byte(nil), buf[i:i+txidUnpackedLen]...)
i += txidUnpackedLen
vout, voutLen := unpackVarint32(buf[i:])
i += voutLen
outpoints = append(outpoints, outpoint{
btxID: btxID,
index: vout,
})
}
return outpoints, nil
}
////////////////////////
func (d *RocksDB) packBlockAddress(addrID []byte, spentTxs map[string][]outpoint) []byte {
vBuf := make([]byte, vlq.MaxLen32)
vl := packVarint(int32(len(addrID)), vBuf)
vl := packVarint(len(addrID), vBuf)
blockAddress := append([]byte(nil), vBuf[:vl]...)
blockAddress = append(blockAddress, addrID...)
if spentTxs == nil {
} else {
addrUnspentTxs := spentTxs[string(addrID)]
vl = packVarint(int32(len(addrUnspentTxs)), vBuf)
vl = packVarint(len(addrUnspentTxs), vBuf)
blockAddress = append(blockAddress, vBuf[:vl]...)
buf := d.packOutpoints(addrUnspentTxs)
blockAddress = append(blockAddress, buf...)
@ -342,7 +706,7 @@ func (d *RocksDB) addAddrIDToRecords(op int, wb *gorocksdb.WriteBatch, records m
strAddrID := string(addrID)
records[strAddrID] = append(records[strAddrID], outpoint{
btxID: btxid,
vout: vout,
index: vout,
})
if op == opDelete {
// remove transactions from cache
@ -370,10 +734,10 @@ func appendPackedAddrID(txAddrs []byte, addrID []byte, n uint32, remaining int)
txAddrs = append(txAddrs, make([]byte, vlq.MaxLen32+len(addrID)+remaining*32)...)[:len(txAddrs)]
}
// addrID is packed as number of bytes of the addrID + bytes of addrID + vout
lv := packVarint(int32(len(addrID)), txAddrs[len(txAddrs):len(txAddrs)+vlq.MaxLen32])
lv := packVarint(len(addrID), txAddrs[len(txAddrs):len(txAddrs)+vlq.MaxLen32])
txAddrs = txAddrs[:len(txAddrs)+lv]
txAddrs = append(txAddrs, addrID...)
lv = packVarint(int32(n), txAddrs[len(txAddrs):len(txAddrs)+vlq.MaxLen32])
lv = packVarint(int(n), txAddrs[len(txAddrs):len(txAddrs)+vlq.MaxLen32])
txAddrs = txAddrs[:len(txAddrs)+lv]
return txAddrs
}
@ -399,7 +763,7 @@ func findAndRemoveUnspentAddr(unspentAddrs []byte, vout uint32) ([]byte, []byte)
return nil, unspentAddrs
}
func (d *RocksDB) writeAddressesUTXO(wb *gorocksdb.WriteBatch, block *bchain.Block, op int) error {
func (d *RocksDB) writeAddressesUTXO_old(wb *gorocksdb.WriteBatch, block *bchain.Block, op int) error {
if op == opDelete {
// block does not contain mapping tx-> input address, which is necessary to recreate
// unspentTxs; therefore it is not possible to DisconnectBlocks this way
@ -563,36 +927,9 @@ func (d *RocksDB) unpackBlockAddresses(buf []byte) ([][]byte, [][]outpoint, erro
return addresses, outpointsArray, nil
}
func (d *RocksDB) packOutpoints(outpoints []outpoint) []byte {
buf := make([]byte, 0)
bvout := make([]byte, vlq.MaxLen32)
for _, o := range outpoints {
l := packVarint(o.vout, bvout)
buf = append(buf, []byte(o.btxID)...)
buf = append(buf, bvout[:l]...)
}
return buf
}
func (d *RocksDB) unpackOutpoints(buf []byte) ([]outpoint, error) {
txidUnpackedLen := d.chainParser.PackedTxidLen()
outpoints := make([]outpoint, 0)
for i := 0; i < len(buf); {
btxID := append([]byte(nil), buf[i:i+txidUnpackedLen]...)
i += txidUnpackedLen
vout, voutLen := unpackVarint(buf[i:])
i += voutLen
outpoints = append(outpoints, outpoint{
btxID: btxID,
vout: vout,
})
}
return outpoints, nil
}
func (d *RocksDB) unpackNOutpoints(buf []byte) ([]outpoint, int, error) {
txidUnpackedLen := d.chainParser.PackedTxidLen()
n, p := unpackVarint(buf)
n, p := unpackVarint32(buf)
outpoints := make([]outpoint, n)
for i := int32(0); i < n; i++ {
if p+txidUnpackedLen >= len(buf) {
@ -600,11 +937,11 @@ func (d *RocksDB) unpackNOutpoints(buf []byte) ([]outpoint, int, error) {
}
btxID := append([]byte(nil), buf[p:p+txidUnpackedLen]...)
p += txidUnpackedLen
vout, voutLen := unpackVarint(buf[p:])
vout, voutLen := unpackVarint32(buf[p:])
p += voutLen
outpoints[i] = outpoint{
btxID: btxID,
vout: vout,
index: vout,
}
}
return outpoints, p, nil
@ -616,7 +953,7 @@ func (d *RocksDB) packOutpoint(txid string, vout int32) ([]byte, error) {
return nil, err
}
bv := make([]byte, vlq.MaxLen32)
l := packVarint(vout, bv)
l := packVarint32(vout, bv)
buf := make([]byte, 0, l+len(btxid))
buf = append(buf, btxid...)
buf = append(buf, bv[:l]...)
@ -626,10 +963,12 @@ func (d *RocksDB) packOutpoint(txid string, vout int32) ([]byte, error) {
func (d *RocksDB) unpackOutpoint(buf []byte) (string, int32, int) {
txidUnpackedLen := d.chainParser.PackedTxidLen()
txid, _ := d.chainParser.UnpackTxid(buf[:txidUnpackedLen])
vout, o := unpackVarint(buf[txidUnpackedLen:])
vout, o := unpackVarint32(buf[txidUnpackedLen:])
return txid, vout, txidUnpackedLen + o
}
//////////////////////////////////
// Block index
// GetBestBlock returns the block hash of the block with highest height in the db
@ -799,7 +1138,7 @@ func (d *RocksDB) DisconnectBlockRange(lower uint32, higher uint32) error {
return err
}
}
txAddrs = appendPackedAddrID(txAddrs, addrID, uint32(o.vout), 1)
txAddrs = appendPackedAddrID(txAddrs, addrID, uint32(o.index), 1)
unspentTxs[stxID] = txAddrs
}
// delete unspentTxs from this block
@ -1065,15 +1404,33 @@ func unpackUint(buf []byte) uint32 {
return binary.BigEndian.Uint32(buf)
}
func packVarint(i int32, buf []byte) int {
func packVarint32(i int32, buf []byte) int {
return vlq.PutInt(buf, int64(i))
}
func unpackVarint(buf []byte) (int32, int) {
func packVarint(i int, buf []byte) int {
return vlq.PutInt(buf, int64(i))
}
func packVaruint(i uint, buf []byte) int {
return vlq.PutUint(buf, uint64(i))
}
func unpackVarint32(buf []byte) (int32, int) {
i, ofs := vlq.Int(buf)
return int32(i), ofs
}
func unpackVarint(buf []byte) (int, int) {
i, ofs := vlq.Int(buf)
return int(i), ofs
}
func unpackVaruint(buf []byte) (uint, int) {
i, ofs := vlq.Uint(buf)
return uint(i), ofs
}
const (
// number of bits in a big.Word
wordBits = 32 << (uint64(^big.Word(0)) >> 63)
@ -1081,6 +1438,7 @@ const (
wordBytes = wordBits / 8
// max packed bigint words
maxPackedBigintWords = (256 - wordBytes) / wordBytes
maxPackedBigintBytes = 249
)
// big int is packed in BigEndian order without memory allocation as 1 byte length followed by bytes of big int

View File

@ -60,6 +60,17 @@ func addressToPubKeyHexWithLength(addr string, t *testing.T, d *RocksDB) string
return strconv.FormatInt(int64(len(h)), 16) + h
}
func spentAddressToPubKeyHexWithLength(addr string, t *testing.T, d *RocksDB) string {
h := addressToPubKeyHex(addr, t, d)
return strconv.FormatInt(int64(len(h)+1), 16) + h
}
func bigintToHex(i *big.Int) string {
b := make([]byte, maxPackedBigintBytes)
l := packBigint(i, b)
return hex.EncodeToString(b[:l])
}
// keyPair is used to compare given key value in DB with expected
// for more complicated compares it is possible to specify CompareFunc
type keyPair struct {
@ -105,7 +116,7 @@ func checkColumn(d *RocksDB, col int, kp []keyPair) error {
valOK = kp[i].CompareFunc(val)
}
if !valOK {
return errors.Errorf("Incorrect value %v found in column %v row %v, expecting %v", val, cfNames[col], i, kp[i].Value)
return errors.Errorf("Incorrect value %v found in column %v row %v key %v, expecting %v", val, cfNames[col], i, key, kp[i].Value)
}
i++
}
@ -115,6 +126,38 @@ func checkColumn(d *RocksDB, col int, kp []keyPair) error {
return nil
}
const (
txidB1T1 = "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840"
txidB1T2 = "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75"
txidB2T1 = "7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25"
txidB2T2 = "3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71"
txidB2T3 = "05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07"
addr1 = "mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti" // 76a914010d39800f86122416e28f485029acf77507169288ac
addr2 = "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz" // 76a9148bdf0aa3c567aa5975c2e61321b8bebbe7293df688ac
addr3 = "mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw" // 76a914a08eae93007f22668ab5e4a9c83c8cd1c325e3e088ac
addr4 = "2Mz1CYoppGGsLNUGF2YDhTif6J661JitALS" // a9144a21db08fb6882cb152e1ff06780a430740f770487
addr5 = "2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1" // a914e921fc4912a315078f370d959f2c4f7b6d2a683c87
addr6 = "mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX" // 76a914ccaaaf374e1b06cb83118453d102587b4273d09588ac
addr7 = "mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL" // 76a9148d802c045445df49613f6a70ddd2e48526f3701f88ac
addr8 = "mwwoKQE5Lb1G4picHSHDQKg8jw424PF9SC" // 76a914b434eb0c1a3b7a02e8a29cc616e791ef1e0bf51f88ac
addr9 = "mmJx9Y8ayz9h14yd9fgCW1bUKoEpkBAquP" // 76a9143f8ba3fda3ba7b69f5818086e12223c6dd25e3c888ac
)
var (
satZero = big.NewInt(0)
satB1T1A1 = big.NewInt(100000000)
satB1T1A2 = big.NewInt(12345)
satB1T2A3 = big.NewInt(1234567890123)
satB1T2A4 = big.NewInt(1)
satB1T2A5 = big.NewInt(9876)
satB2T1A6 = big.NewInt(317283951061)
satB2T1A7 = big.NewInt(917283951061)
satB2T2A8 = big.NewInt(118641975500)
satB2T2A9 = big.NewInt(198641975500)
satB2T3A5 = big.NewInt(9000)
)
func getTestUTXOBlock1(t *testing.T, d *RocksDB) *bchain.Block {
return &bchain.Block{
BlockHeader: bchain.BlockHeader{
@ -123,44 +166,49 @@ func getTestUTXOBlock1(t *testing.T, d *RocksDB) *bchain.Block {
},
Txs: []bchain.Tx{
bchain.Tx{
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
Txid: txidB1T1,
Vout: []bchain.Vout{
bchain.Vout{
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: addressToPubKeyHex("mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti", t, d),
Hex: addressToPubKeyHex(addr1, t, d),
},
ValueSat: *satB1T1A1,
},
bchain.Vout{
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: addressToPubKeyHex("mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", t, d),
Hex: addressToPubKeyHex(addr2, t, d),
},
ValueSat: *satB1T1A2,
},
},
Blocktime: 22549300000,
Time: 22549300000,
},
bchain.Tx{
Txid: "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75",
Txid: txidB1T2,
Vout: []bchain.Vout{
bchain.Vout{
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: addressToPubKeyHex("mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw", t, d),
Hex: addressToPubKeyHex(addr3, t, d),
},
ValueSat: *satB1T2A3,
},
bchain.Vout{
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: addressToPubKeyHex("2Mz1CYoppGGsLNUGF2YDhTif6J661JitALS", t, d),
Hex: addressToPubKeyHex(addr4, t, d),
},
ValueSat: *satB1T2A4,
},
bchain.Vout{
N: 2,
ScriptPubKey: bchain.ScriptPubKey{
Hex: addressToPubKeyHex("2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1", t, d),
Hex: addressToPubKeyHex(addr5, t, d),
},
ValueSat: *satB1T2A5,
},
},
Blocktime: 22549300001,
@ -178,14 +226,16 @@ func getTestUTXOBlock2(t *testing.T, d *RocksDB) *bchain.Block {
},
Txs: []bchain.Tx{
bchain.Tx{
Txid: "7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25",
Txid: txidB2T1,
Vin: []bchain.Vin{
// addr3
bchain.Vin{
Txid: "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75",
Txid: txidB1T2,
Vout: 0,
},
// addr2
bchain.Vin{
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
Txid: txidB1T1,
Vout: 1,
},
},
@ -193,30 +243,32 @@ func getTestUTXOBlock2(t *testing.T, d *RocksDB) *bchain.Block {
bchain.Vout{
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: addressToPubKeyHex("mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX", t, d),
Hex: addressToPubKeyHex(addr6, t, d),
},
ValueSat: *satB2T1A6,
},
bchain.Vout{
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: addressToPubKeyHex("mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL", t, d),
Hex: addressToPubKeyHex(addr7, t, d),
},
ValueSat: *satB2T1A7,
},
},
Blocktime: 22549400000,
Time: 22549400000,
},
bchain.Tx{
Txid: "3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71",
Txid: txidB2T2,
Vin: []bchain.Vin{
// spending an output in the same block
// spending an output in the same block - addr6
bchain.Vin{
Txid: "7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25",
Txid: txidB2T1,
Vout: 0,
},
// spending an output in the previous block
// spending an output in the previous block - addr4
bchain.Vin{
Txid: "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75",
Txid: txidB1T2,
Vout: 1,
},
},
@ -224,14 +276,16 @@ func getTestUTXOBlock2(t *testing.T, d *RocksDB) *bchain.Block {
bchain.Vout{
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: addressToPubKeyHex("mwwoKQE5Lb1G4picHSHDQKg8jw424PF9SC", t, d),
Hex: addressToPubKeyHex(addr8, t, d),
},
ValueSat: *satB2T2A8,
},
bchain.Vout{
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: addressToPubKeyHex("mmJx9Y8ayz9h14yd9fgCW1bUKoEpkBAquP", t, d),
Hex: addressToPubKeyHex(addr9, t, d),
},
ValueSat: *satB2T2A9,
},
},
Blocktime: 22549400001,
@ -239,10 +293,11 @@ func getTestUTXOBlock2(t *testing.T, d *RocksDB) *bchain.Block {
},
// transaction from the same address in the previous block
bchain.Tx{
Txid: "05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07",
Txid: txidB2T3,
Vin: []bchain.Vin{
// addr5
bchain.Vin{
Txid: "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75",
Txid: txidB1T2,
Vout: 2,
},
},
@ -250,8 +305,9 @@ func getTestUTXOBlock2(t *testing.T, d *RocksDB) *bchain.Block {
bchain.Vout{
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: addressToPubKeyHex("2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1", t, d),
Hex: addressToPubKeyHex(addr5, t, d),
},
ValueSat: *satB2T3A5,
},
},
Blocktime: 22549400002,
@ -261,7 +317,7 @@ func getTestUTXOBlock2(t *testing.T, d *RocksDB) *bchain.Block {
}
}
func verifyAfterUTXOBlock1(t *testing.T, d *RocksDB, noBlockAddresses bool) {
func verifyAfterUTXOBlock1(t *testing.T, d *RocksDB) {
if err := checkColumn(d, cfHeight, []keyPair{
keyPair{"000370d5", "0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997", nil},
}); err != nil {
@ -271,62 +327,51 @@ func verifyAfterUTXOBlock1(t *testing.T, d *RocksDB, noBlockAddresses bool) {
}
// the vout is encoded as signed varint, i.e. value * 2 for non negative values
if err := checkColumn(d, cfAddresses, []keyPair{
keyPair{addressToPubKeyHex("mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti", t, d) + "000370d5", "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840" + "00", nil},
keyPair{addressToPubKeyHex("mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", t, d) + "000370d5", "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840" + "02", nil},
keyPair{addressToPubKeyHex("mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw", t, d) + "000370d5", "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75" + "00", nil},
keyPair{addressToPubKeyHex("2Mz1CYoppGGsLNUGF2YDhTif6J661JitALS", t, d) + "000370d5", "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75" + "02", nil},
keyPair{addressToPubKeyHex("2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1", t, d) + "000370d5", "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75" + "04", nil},
keyPair{addressToPubKeyHex(addr1, t, d) + "000370d5", txidB1T1 + "00", nil},
keyPair{addressToPubKeyHex(addr2, t, d) + "000370d5", txidB1T1 + "02", nil},
keyPair{addressToPubKeyHex(addr3, t, d) + "000370d5", txidB1T2 + "00", nil},
keyPair{addressToPubKeyHex(addr4, t, d) + "000370d5", txidB1T2 + "02", nil},
keyPair{addressToPubKeyHex(addr5, t, d) + "000370d5", txidB1T2 + "04", nil},
}); err != nil {
{
t.Fatal(err)
}
}
if err := checkColumn(d, cfUnspentTxs, []keyPair{
if err := checkColumn(d, cfTxAddresses, []keyPair{
keyPair{
"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840", "",
func(v string) bool {
return compareFuncBlockAddresses(t, v, []string{
addressToPubKeyHexWithLength("mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti", t, d) + "00",
addressToPubKeyHexWithLength("mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", t, d) + "02",
})
},
txidB1T1,
"00" + "02" +
addressToPubKeyHexWithLength(addr1, t, d) + bigintToHex(satB1T1A1) +
addressToPubKeyHexWithLength(addr2, t, d) + bigintToHex(satB1T1A2),
nil,
},
keyPair{
"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75", "",
func(v string) bool {
return compareFuncBlockAddresses(t, v, []string{
addressToPubKeyHexWithLength("mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw", t, d) + "00",
addressToPubKeyHexWithLength("2Mz1CYoppGGsLNUGF2YDhTif6J661JitALS", t, d) + "02",
addressToPubKeyHexWithLength("2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1", t, d) + "04",
})
},
txidB1T2,
"00" + "03" +
addressToPubKeyHexWithLength(addr3, t, d) + bigintToHex(satB1T2A3) +
addressToPubKeyHexWithLength(addr4, t, d) + bigintToHex(satB1T2A4) +
addressToPubKeyHexWithLength(addr5, t, d) + bigintToHex(satB1T2A5),
nil,
},
}); err != nil {
{
t.Fatal(err)
}
}
// after disconnect there are no blockaddresses for the previous block
var blockAddressesKp []keyPair
if noBlockAddresses {
blockAddressesKp = []keyPair{}
} else {
// the values in cfBlockAddresses are in random order, must use CompareFunc
blockAddressesKp = []keyPair{
keyPair{"000370d5", "",
func(v string) bool {
return compareFuncBlockAddresses(t, v, []string{
addressToPubKeyHexWithLength("mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti", t, d) + "00",
addressToPubKeyHexWithLength("mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", t, d) + "00",
addressToPubKeyHexWithLength("mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw", t, d) + "00",
addressToPubKeyHexWithLength("2Mz1CYoppGGsLNUGF2YDhTif6J661JitALS", t, d) + "00",
addressToPubKeyHexWithLength("2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1", t, d) + "00",
})
},
},
if err := checkColumn(d, cfAddressBalance, []keyPair{
keyPair{addressToPubKeyHex(addr1, t, d), "01" + bigintToHex(satZero) + bigintToHex(satB1T1A1), nil},
keyPair{addressToPubKeyHex(addr2, t, d), "01" + bigintToHex(satZero) + bigintToHex(satB1T1A2), nil},
keyPair{addressToPubKeyHex(addr3, t, d), "01" + bigintToHex(satZero) + bigintToHex(satB1T2A3), nil},
keyPair{addressToPubKeyHex(addr4, t, d), "01" + bigintToHex(satZero) + bigintToHex(satB1T2A4), nil},
keyPair{addressToPubKeyHex(addr5, t, d), "01" + bigintToHex(satZero) + bigintToHex(satB1T2A5), nil},
}); err != nil {
{
t.Fatal(err)
}
}
if err := checkColumn(d, cfBlockAddresses, blockAddressesKp); err != nil {
if err := checkColumn(d, cfBlockTxids, []keyPair{
keyPair{"000370d5", txidB1T1 + txidB1T2, nil},
}); err != nil {
{
t.Fatal(err)
}
@ -343,47 +388,66 @@ func verifyAfterUTXOBlock2(t *testing.T, d *RocksDB) {
}
}
if err := checkColumn(d, cfAddresses, []keyPair{
keyPair{addressToPubKeyHex("mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti", t, d) + "000370d5", "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840" + "00", nil},
keyPair{addressToPubKeyHex("mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", t, d) + "000370d5", "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840" + "02", nil},
keyPair{addressToPubKeyHex("mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw", t, d) + "000370d5", "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75" + "00", nil},
keyPair{addressToPubKeyHex("2Mz1CYoppGGsLNUGF2YDhTif6J661JitALS", t, d) + "000370d5", "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75" + "02", nil},
keyPair{addressToPubKeyHex("2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1", t, d) + "000370d5", "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75" + "04", nil},
keyPair{addressToPubKeyHex("mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX", t, d) + "000370d6", "7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25" + "00" + "3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71" + "01", nil},
keyPair{addressToPubKeyHex("mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL", t, d) + "000370d6", "7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25" + "02", nil},
keyPair{addressToPubKeyHex("mwwoKQE5Lb1G4picHSHDQKg8jw424PF9SC", t, d) + "000370d6", "3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71" + "00", nil},
keyPair{addressToPubKeyHex("mmJx9Y8ayz9h14yd9fgCW1bUKoEpkBAquP", t, d) + "000370d6", "3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71" + "02", nil},
keyPair{addressToPubKeyHex("mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw", t, d) + "000370d6", "7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25" + "01", nil},
keyPair{addressToPubKeyHex("mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", t, d) + "000370d6", "7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25" + "03", nil},
keyPair{addressToPubKeyHex("2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1", t, d) + "000370d6", "05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07" + "00" + "05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07" + "01", nil},
keyPair{addressToPubKeyHex("2Mz1CYoppGGsLNUGF2YDhTif6J661JitALS", t, d) + "000370d6", "3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71" + "03", nil},
keyPair{addressToPubKeyHex(addr1, t, d) + "000370d5", txidB1T1 + "00", nil},
keyPair{addressToPubKeyHex(addr2, t, d) + "000370d5", txidB1T1 + "02", nil},
keyPair{addressToPubKeyHex(addr3, t, d) + "000370d5", txidB1T2 + "00", nil},
keyPair{addressToPubKeyHex(addr4, t, d) + "000370d5", txidB1T2 + "02", nil},
keyPair{addressToPubKeyHex(addr5, t, d) + "000370d5", txidB1T2 + "04", nil},
keyPair{addressToPubKeyHex(addr6, t, d) + "000370d6", txidB2T1 + "00" + txidB2T2 + "01", nil},
keyPair{addressToPubKeyHex(addr7, t, d) + "000370d6", txidB2T1 + "02", nil},
keyPair{addressToPubKeyHex(addr8, t, d) + "000370d6", txidB2T2 + "00", nil},
keyPair{addressToPubKeyHex(addr9, t, d) + "000370d6", txidB2T2 + "02", nil},
keyPair{addressToPubKeyHex(addr3, t, d) + "000370d6", txidB2T1 + "01", nil},
keyPair{addressToPubKeyHex(addr2, t, d) + "000370d6", txidB2T1 + "03", nil},
keyPair{addressToPubKeyHex(addr5, t, d) + "000370d6", txidB2T3 + "00" + txidB2T3 + "01", nil},
keyPair{addressToPubKeyHex(addr4, t, d) + "000370d6", txidB2T2 + "03", nil},
}); err != nil {
{
t.Fatal(err)
}
}
if err := checkColumn(d, cfUnspentTxs, []keyPair{
if err := checkColumn(d, cfTxAddresses, []keyPair{
keyPair{
"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
addressToPubKeyHexWithLength("mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti", t, d) + "00",
txidB1T1,
"00" + "02" +
addressToPubKeyHexWithLength(addr1, t, d) + bigintToHex(satB1T1A1) +
spentAddressToPubKeyHexWithLength(addr2, t, d) + bigintToHex(satB1T1A2),
nil,
},
keyPair{
"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25",
addressToPubKeyHexWithLength("mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL", t, d) + "02",
txidB1T2,
"00" + "03" +
spentAddressToPubKeyHexWithLength(addr3, t, d) + bigintToHex(satB1T2A3) +
spentAddressToPubKeyHexWithLength(addr4, t, d) + bigintToHex(satB1T2A4) +
spentAddressToPubKeyHexWithLength(addr5, t, d) + bigintToHex(satB1T2A5),
nil,
},
keyPair{
"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71", "",
func(v string) bool {
return compareFuncBlockAddresses(t, v, []string{
addressToPubKeyHexWithLength("mwwoKQE5Lb1G4picHSHDQKg8jw424PF9SC", t, d) + "00",
addressToPubKeyHexWithLength("mmJx9Y8ayz9h14yd9fgCW1bUKoEpkBAquP", t, d) + "02",
})
},
txidB2T1,
"02" +
addressToPubKeyHexWithLength(addr3, t, d) + bigintToHex(satB1T2A3) +
addressToPubKeyHexWithLength(addr2, t, d) + bigintToHex(satB1T1A2) +
"02" +
spentAddressToPubKeyHexWithLength(addr6, t, d) + bigintToHex(satB2T1A6) +
addressToPubKeyHexWithLength(addr7, t, d) + bigintToHex(satB2T1A7),
nil,
},
keyPair{
"05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07",
addressToPubKeyHexWithLength("2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1", t, d) + "00",
txidB2T2,
"02" +
addressToPubKeyHexWithLength(addr6, t, d) + bigintToHex(satB2T1A6) +
addressToPubKeyHexWithLength(addr4, t, d) + bigintToHex(satB1T2A4) +
"02" +
addressToPubKeyHexWithLength(addr8, t, d) + bigintToHex(satB2T2A8) +
addressToPubKeyHexWithLength(addr9, t, d) + bigintToHex(satB2T2A9),
nil,
},
keyPair{
txidB2T3,
"01" +
addressToPubKeyHexWithLength(addr5, t, d) + bigintToHex(satB1T2A5) +
"01" +
addressToPubKeyHexWithLength(addr5, t, d) + bigintToHex(satB2T3A5),
nil,
},
}); err != nil {
@ -391,21 +455,23 @@ func verifyAfterUTXOBlock2(t *testing.T, d *RocksDB) {
t.Fatal(err)
}
}
if err := checkColumn(d, cfBlockAddresses, []keyPair{
keyPair{"000370d6", "",
func(v string) bool {
return compareFuncBlockAddresses(t, v, []string{
addressToPubKeyHexWithLength("mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX", t, d) + "00",
addressToPubKeyHexWithLength("mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL", t, d) + "00",
addressToPubKeyHexWithLength("mwwoKQE5Lb1G4picHSHDQKg8jw424PF9SC", t, d) + "00",
addressToPubKeyHexWithLength("mmJx9Y8ayz9h14yd9fgCW1bUKoEpkBAquP", t, d) + "00",
addressToPubKeyHexWithLength("mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw", t, d) + "02" + "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75" + "00",
addressToPubKeyHexWithLength("mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", t, d) + "02" + "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840" + "02",
addressToPubKeyHexWithLength("2Mz1CYoppGGsLNUGF2YDhTif6J661JitALS", t, d) + "02" + "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75" + "02",
addressToPubKeyHexWithLength("2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1", t, d) + "02" + "effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75" + "04",
})
},
},
if err := checkColumn(d, cfAddressBalance, []keyPair{
keyPair{addressToPubKeyHex(addr1, t, d), "01" + bigintToHex(satZero) + bigintToHex(satB1T1A1), nil},
keyPair{addressToPubKeyHex(addr2, t, d), "02" + bigintToHex(satB1T1A2) + bigintToHex(satZero), nil},
keyPair{addressToPubKeyHex(addr3, t, d), "02" + bigintToHex(satB1T2A3) + bigintToHex(satZero), nil},
keyPair{addressToPubKeyHex(addr4, t, d), "02" + bigintToHex(satB1T2A4) + bigintToHex(satZero), nil},
keyPair{addressToPubKeyHex(addr5, t, d), "02" + bigintToHex(satB1T2A5) + bigintToHex(satB2T3A5), nil},
keyPair{addressToPubKeyHex(addr6, t, d), "02" + bigintToHex(satB2T1A6) + bigintToHex(satZero), nil},
keyPair{addressToPubKeyHex(addr7, t, d), "01" + bigintToHex(satZero) + bigintToHex(satB2T1A7), nil},
keyPair{addressToPubKeyHex(addr8, t, d), "01" + bigintToHex(satZero) + bigintToHex(satB2T2A8), nil},
keyPair{addressToPubKeyHex(addr9, t, d), "01" + bigintToHex(satZero) + bigintToHex(satB2T2A9), nil},
}); err != nil {
{
t.Fatal(err)
}
}
if err := checkColumn(d, cfBlockTxids, []keyPair{
keyPair{"000370d6", txidB2T1 + txidB2T2 + txidB2T3, nil},
}); err != nil {
{
t.Fatal(err)
@ -487,12 +553,12 @@ func TestRocksDB_Index_UTXO(t *testing.T) {
})
defer closeAndDestroyRocksDB(t, d)
// connect 1st block - will log warnings about missing UTXO transactions in cfUnspentTxs column
// connect 1st block - will log warnings about missing UTXO transactions in txAddresses column
block1 := getTestUTXOBlock1(t, d)
if err := d.ConnectBlock(block1); err != nil {
t.Fatal(err)
}
verifyAfterUTXOBlock1(t, d, false)
verifyAfterUTXOBlock1(t, d)
// connect 2nd block - use some outputs from the 1st block as the inputs and 1 input uses tx from the same block
block2 := getTestUTXOBlock2(t, d)
@ -502,19 +568,19 @@ func TestRocksDB_Index_UTXO(t *testing.T) {
verifyAfterUTXOBlock2(t, d)
// get transactions for various addresses / low-high ranges
verifyGetTransactions(t, d, "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", 0, 1000000, []txidVoutOutput{
txidVoutOutput{"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840", 1, true},
txidVoutOutput{"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25", 1, false},
verifyGetTransactions(t, d, addr2, 0, 1000000, []txidVoutOutput{
txidVoutOutput{txidB1T1, 1, true},
txidVoutOutput{txidB2T1, 1, false},
}, nil)
verifyGetTransactions(t, d, "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", 225493, 225493, []txidVoutOutput{
txidVoutOutput{"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840", 1, true},
verifyGetTransactions(t, d, addr2, 225493, 225493, []txidVoutOutput{
txidVoutOutput{txidB1T1, 1, true},
}, nil)
verifyGetTransactions(t, d, "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", 225494, 1000000, []txidVoutOutput{
txidVoutOutput{"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25", 1, false},
verifyGetTransactions(t, d, addr2, 225494, 1000000, []txidVoutOutput{
txidVoutOutput{txidB2T1, 1, false},
}, nil)
verifyGetTransactions(t, d, "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", 500000, 1000000, []txidVoutOutput{}, nil)
verifyGetTransactions(t, d, "mwwoKQE5Lb1G4picHSHDQKg8jw424PF9SC", 0, 1000000, []txidVoutOutput{
txidVoutOutput{"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71", 0, true},
verifyGetTransactions(t, d, addr2, 500000, 1000000, []txidVoutOutput{}, nil)
verifyGetTransactions(t, d, addr8, 0, 1000000, []txidVoutOutput{
txidVoutOutput{txidB2T2, 0, true},
}, nil)
verifyGetTransactions(t, d, "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eBad", 500000, 1000000, []txidVoutOutput{}, errors.New("checksum mismatch"))
@ -569,7 +635,7 @@ func TestRocksDB_Index_UTXO(t *testing.T) {
t.Fatal(err)
}
verifyAfterUTXOBlock1(t, d, true)
verifyAfterUTXOBlock1(t, d)
if err := checkColumn(d, cfTransactions, []keyPair{}); err != nil {
{
t.Fatal(err)
@ -661,13 +727,13 @@ func Test_unpackBlockAddresses(t *testing.T) {
want2: [][]hexoutpoint{
[]hexoutpoint{},
[]hexoutpoint{
hexoutpoint{"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25", 0},
hexoutpoint{"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840", 3},
hexoutpoint{txidB2T1, 0},
hexoutpoint{txidB1T1, 3},
},
[]hexoutpoint{},
[]hexoutpoint{},
[]hexoutpoint{
hexoutpoint{"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75", 1},
hexoutpoint{txidB1T2, 1},
},
},
},
@ -679,13 +745,13 @@ func Test_unpackBlockAddresses(t *testing.T) {
[]hexoutpoint{},
[]hexoutpoint{},
[]hexoutpoint{
hexoutpoint{"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75", 0},
hexoutpoint{txidB1T2, 0},
},
[]hexoutpoint{
hexoutpoint{"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840", 1},
hexoutpoint{txidB1T1, 1},
},
[]hexoutpoint{
hexoutpoint{"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75", 1},
hexoutpoint{txidB1T2, 1},
},
[]hexoutpoint{},
[]hexoutpoint{},
@ -714,7 +780,7 @@ func Test_unpackBlockAddresses(t *testing.T) {
for i, g := range got2 {
ho := make([]hexoutpoint, len(g))
for j, o := range g {
ho[j] = hexoutpoint{hex.EncodeToString(o.btxID), o.vout}
ho[j] = hexoutpoint{hex.EncodeToString(o.btxID), o.index}
}
h2[i] = ho
}
@ -741,12 +807,12 @@ func Test_packBigint_unpackBigint(t *testing.T) {
{
name: "0",
bi: big.NewInt(0),
buf: make([]byte, 249),
buf: make([]byte, maxPackedBigintBytes),
},
{
name: "1",
bi: big.NewInt(1),
buf: make([]byte, 249),
buf: make([]byte, maxPackedBigintBytes),
},
{
name: "54321",
@ -756,27 +822,27 @@ func Test_packBigint_unpackBigint(t *testing.T) {
{
name: "12345678",
bi: big.NewInt(12345678),
buf: make([]byte, 249),
buf: make([]byte, maxPackedBigintBytes),
},
{
name: "123456789123456789",
bi: big.NewInt(123456789123456789),
buf: make([]byte, 249),
buf: make([]byte, maxPackedBigintBytes),
},
{
name: "bigbig1",
bi: bigbig1,
buf: make([]byte, 249),
buf: make([]byte, maxPackedBigintBytes),
},
{
name: "bigbig2",
bi: bigbig2,
buf: make([]byte, 249),
buf: make([]byte, maxPackedBigintBytes),
},
{
name: "bigbigbig",
bi: bigbigbig,
buf: make([]byte, 249),
buf: make([]byte, maxPackedBigintBytes),
toobiglen: 242,
},
}