From fb93c9ff7a825ece512ac6ebcaac8247becd0970 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Thu, 2 Aug 2018 16:10:28 +0200 Subject: [PATCH] Add unit test for pack/unpack txAddress --- db/rocksdb.go | 59 ++++++++++-------- db/rocksdb_test.go | 148 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 178 insertions(+), 29 deletions(-) diff --git a/db/rocksdb.go b/db/rocksdb.go index 89c920e5..dc33debb 100644 --- a/db/rocksdb.go +++ b/db/rocksdb.go @@ -478,17 +478,7 @@ func (d *RocksDB) storeTxAddresses(wb *gorocksdb.WriteBatch, am map[string]*txAd 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]) - } + buf = packTxAddresses(ta, buf, varBuf) wb.PutCF(d.cfh[cfTxAddresses], []byte(txID), buf) } return nil @@ -508,19 +498,6 @@ func (d *RocksDB) storeBalances(wb *gorocksdb.WriteBatch, abm map[string]*addrBa 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)) @@ -582,6 +559,38 @@ func (d *RocksDB) getTxAddresses(btxID []byte) (*txAddresses, error) { if len(buf) < 2 { return nil, nil } + return unpackTxAddresses(buf) +} + +func packTxAddresses(ta *txAddresses, buf []byte, varBuf []byte) []byte { + buf = buf[:0] + l := packVaruint(uint(len(ta.inputs)), varBuf) + buf = append(buf, varBuf[:l]...) + for i := range ta.inputs { + buf = appendTxAddress(&ta.inputs[i], buf, varBuf) + } + l = packVaruint(uint(len(ta.outputs)), varBuf) + buf = append(buf, varBuf[:l]...) + for i := range ta.outputs { + buf = appendTxAddress(&ta.outputs[i], buf, varBuf) + } + return buf +} + +func appendTxAddress(txa *txAddress, buf []byte, varBuf []byte) []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 unpackTxAddresses(buf []byte) (*txAddresses, error) { ta := txAddresses{} inputs, l := unpackVaruint(buf) ta.inputs = make([]txAddress, inputs) @@ -601,7 +610,7 @@ func unpackTxAddress(ta *txAddress, buf []byte) int { al, l := unpackVarint(buf) if al < 0 { ta.spent = true - al ^= al + al = ^al } ta.addrID = make([]byte, al) copy(ta.addrID, buf[l:l+al]) diff --git a/db/rocksdb_test.go b/db/rocksdb_test.go index 75608bcc..52aa3b29 100644 --- a/db/rocksdb_test.go +++ b/db/rocksdb_test.go @@ -23,6 +23,13 @@ import ( // for number n, the packing is: 2*n if n>=0 else 2*(-n)-1 // takes only 1 byte if abs(n)<127 +func bitcoinTestnetParser() *btc.BitcoinParser { + return &btc.BitcoinParser{ + BaseParser: &bchain.BaseParser{BlockAddressesToKeep: 1}, + Params: btc.GetChainParams("test"), + } +} + func setupRocksDB(t *testing.T, p bchain.BlockChainParser) *RocksDB { tmp, err := ioutil.TempDir("", "testdb") if err != nil { @@ -546,10 +553,7 @@ func testTxCache(t *testing.T, d *RocksDB, b *bchain.Block, tx *bchain.Tx) { // After each step, the content of DB is examined and any difference against expected state is regarded as failure func TestRocksDB_Index_UTXO(t *testing.T) { d := setupRocksDB(t, &testBitcoinParser{ - BitcoinParser: &btc.BitcoinParser{ - BaseParser: &bchain.BaseParser{BlockAddressesToKeep: 1}, - Params: btc.GetChainParams("test"), - }, + BitcoinParser: bitcoinTestnetParser(), }) defer closeAndDestroyRocksDB(t, d) @@ -880,3 +884,139 @@ func Test_packBigint_unpackBigint(t *testing.T) { }) } } + +func addressToOutput(addr string, parser *btc.BitcoinParser) []byte { + b, err := parser.AddressToOutputScript(addr) + if err != nil { + panic(err) + } + return b +} + +func Test_packTxAddresses_unpackTxAddresses(t *testing.T) { + parser := bitcoinTestnetParser() + tests := []struct { + name string + hex string + data *txAddresses + }{ + { + name: "1", + hex: "022c001443aac20a116e09ea4f7914be1c55e4c17aa600b7002c001454633aa8bd2e552bd4e89c01e73c1b7905eb58460811207cb68a199872012d001443aac20a116e09ea4f7914be1c55e4c17aa600b70101", + data: &txAddresses{ + inputs: []txAddress{ + { + addrID: addressToOutput("tb1qgw4vyzs3dcy75nmezjlpc40yc9a2vq9hghdyt2", parser), + valueSat: *big.NewInt(0), + }, + { + addrID: addressToOutput("tb1q233n429a9e2jh48gnsq7w0qm0yz7kkzx0qczw8", parser), + valueSat: *big.NewInt(1234123421342341234), + }, + }, + outputs: []txAddress{ + { + addrID: addressToOutput("tb1qgw4vyzs3dcy75nmezjlpc40yc9a2vq9hghdyt2", parser), + valueSat: *big.NewInt(1), + spent: true, + }, + }, + }, + }, + { + name: "2", + hex: "032ea9149eb21980dc9d413d8eac27314938b9da920ee53e8705021918f2c02ea91409f70b896169c37981d2b54b371df0d81a136a2c870501dd7e28c02ea914e371782582a4addb541362c55565d2cdf56f6498870501a1e35ec0052fa9141d9ca71efa36d814424ea6ca1437e67287aebe348705012aadcac02ea91424fbc77cdc62702ade74dcf989c15e5d3f9240bc870501664894c02fa914afbfb74ee994c7d45f6698738bc4226d065266f7870501a1e35ec03276a914d2a37ce20ac9ec4f15dd05a7c6e8e9fbdb99850e88ac043b9943603376a9146b2044146a4438e6e5bfbc65f147afeb64d14fbb88ac05012a05f200", + data: &txAddresses{ + inputs: []txAddress{ + { + addrID: addressToOutput("2N7iL7AvS4LViugwsdjTB13uN4T7XhV1bCP", parser), + valueSat: *big.NewInt(9011000000), + }, + { + addrID: addressToOutput("2Mt9v216YiNBAzobeNEzd4FQweHrGyuRHze", parser), + valueSat: *big.NewInt(8011000000), + }, + { + addrID: addressToOutput("2NDyqJpHvHnqNtL1F9xAeCWMAW8WLJmEMyD", parser), + valueSat: *big.NewInt(7011000000), + }, + }, + outputs: []txAddress{ + { + addrID: addressToOutput("2MuwoFGwABMakU7DCpdGDAKzyj2nTyRagDP", parser), + valueSat: *big.NewInt(5011000000), + spent: true, + }, + { + addrID: addressToOutput("2Mvcmw7qkGXNWzkfH1EjvxDcNRGL1Kf2tEM", parser), + valueSat: *big.NewInt(6011000000), + }, + { + addrID: addressToOutput("2N9GVuX3XJGHS5MCdgn97gVezc6EgvzikTB", parser), + valueSat: *big.NewInt(7011000000), + spent: true, + }, + { + addrID: addressToOutput("mzii3fuRSpExMLJEHdHveW8NmiX8MPgavk", parser), + valueSat: *big.NewInt(999900000), + }, + { + addrID: addressToOutput("mqHPFTRk23JZm9W1ANuEFtwTYwxjESSgKs", parser), + valueSat: *big.NewInt(5000000000), + spent: true, + }, + }, + }, + }, + { + name: "empty address", + hex: "01000204d2020002162e010162", + data: &txAddresses{ + inputs: []txAddress{ + { + addrID: []byte{}, + valueSat: *big.NewInt(1234), + }, + }, + outputs: []txAddress{ + { + addrID: []byte{}, + valueSat: *big.NewInt(5678), + }, + { + addrID: []byte{}, + valueSat: *big.NewInt(98), + spent: true, + }, + }, + }, + }, + { + name: "empty", + hex: "0000", + data: &txAddresses{ + inputs: []txAddress{}, + outputs: []txAddress{}, + }, + }, + } + varBuf := make([]byte, maxPackedBigintBytes) + buf := make([]byte, 1024) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := packTxAddresses(tt.data, buf, varBuf) + hex := hex.EncodeToString(b) + if !reflect.DeepEqual(hex, tt.hex) { + t.Errorf("packTxAddresses() = %v, want %v", hex, tt.hex) + } + got1, err := unpackTxAddresses(b) + if err != nil { + t.Errorf("unpackTxAddresses() error = %v", err) + return + } + if !reflect.DeepEqual(got1, tt.data) { + t.Errorf("unpackTxAddresses() = %+v, want %+v", got1, tt.data) + } + }) + } +}