2018-08-28 16:25:26 -06:00
|
|
|
// +build unittest
|
2018-06-14 04:41:03 -06:00
|
|
|
|
2018-04-18 15:42:38 -06:00
|
|
|
package db
|
|
|
|
|
|
|
|
import (
|
|
|
|
"blockbook/bchain"
|
|
|
|
"blockbook/bchain/coins/btc"
|
2018-08-18 16:23:26 -06:00
|
|
|
"blockbook/common"
|
2018-10-15 06:27:58 -06:00
|
|
|
"blockbook/tests/dbtestdata"
|
2018-08-21 08:36:14 -06:00
|
|
|
"encoding/binary"
|
2018-04-18 15:42:38 -06:00
|
|
|
"encoding/hex"
|
2018-04-20 08:03:45 -06:00
|
|
|
"fmt"
|
2018-04-18 15:42:38 -06:00
|
|
|
"io/ioutil"
|
2018-07-27 11:46:21 -06:00
|
|
|
"math/big"
|
2018-04-18 15:42:38 -06:00
|
|
|
"os"
|
2018-04-19 07:11:32 -06:00
|
|
|
"reflect"
|
2018-04-19 06:28:05 -06:00
|
|
|
"sort"
|
2018-04-20 05:56:55 -06:00
|
|
|
"strings"
|
2018-04-18 15:42:38 -06:00
|
|
|
"testing"
|
|
|
|
|
2018-08-21 05:16:29 -06:00
|
|
|
vlq "github.com/bsm/go-vlq"
|
2018-10-02 09:02:57 -06:00
|
|
|
"github.com/jakm/btcutil/chaincfg"
|
2018-04-18 15:42:38 -06:00
|
|
|
"github.com/juju/errors"
|
|
|
|
)
|
|
|
|
|
2018-04-24 04:00:24 -06:00
|
|
|
// simplified explanation of signed varint packing, used in many index data structures
|
|
|
|
// for number n, the packing is: 2*n if n>=0 else 2*(-n)-1
|
2018-05-29 03:37:35 -06:00
|
|
|
// takes only 1 byte if abs(n)<127
|
2018-04-24 04:00:24 -06:00
|
|
|
|
2018-10-02 09:02:57 -06:00
|
|
|
func TestMain(m *testing.M) {
|
|
|
|
c := m.Run()
|
|
|
|
chaincfg.ResetParams()
|
|
|
|
os.Exit(c)
|
|
|
|
}
|
|
|
|
|
2018-08-02 08:10:28 -06:00
|
|
|
func bitcoinTestnetParser() *btc.BitcoinParser {
|
2018-08-16 07:31:11 -06:00
|
|
|
return btc.NewBitcoinParser(
|
|
|
|
btc.GetChainParams("test"),
|
|
|
|
&btc.Configuration{BlockAddressesToKeep: 1})
|
2018-08-02 08:10:28 -06:00
|
|
|
}
|
|
|
|
|
2018-04-18 15:42:38 -06:00
|
|
|
func setupRocksDB(t *testing.T, p bchain.BlockChainParser) *RocksDB {
|
|
|
|
tmp, err := ioutil.TempDir("", "testdb")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-09-18 03:49:39 -06:00
|
|
|
d, err := NewRocksDB(tmp, 100000, -1, p, nil)
|
2018-04-18 15:42:38 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-06-04 09:11:10 -06:00
|
|
|
is, err := d.LoadInternalState("btc-testnet")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
d.SetInternalState(is)
|
2018-04-18 15:42:38 -06:00
|
|
|
return d
|
|
|
|
}
|
|
|
|
|
2018-05-23 03:07:16 -06:00
|
|
|
func closeAndDestroyRocksDB(t *testing.T, d *RocksDB) {
|
2018-04-18 15:42:38 -06:00
|
|
|
if err := d.Close(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
os.RemoveAll(d.path)
|
|
|
|
}
|
|
|
|
|
2018-08-16 07:31:11 -06:00
|
|
|
func inputAddressToPubKeyHexWithLength(addr string, t *testing.T, d *RocksDB) string {
|
2018-10-15 10:09:46 -06:00
|
|
|
h := dbtestdata.AddressToPubKeyHex(addr, d.chainParser)
|
2018-08-17 15:48:36 -06:00
|
|
|
return hex.EncodeToString([]byte{byte(len(h) / 2)}) + h
|
2018-08-16 07:31:11 -06:00
|
|
|
}
|
|
|
|
|
2018-04-20 05:56:55 -06:00
|
|
|
func addressToPubKeyHexWithLength(addr string, t *testing.T, d *RocksDB) string {
|
2018-10-15 10:09:46 -06:00
|
|
|
h := dbtestdata.AddressToPubKeyHex(addr, d.chainParser)
|
2018-08-17 15:48:36 -06:00
|
|
|
return hex.EncodeToString([]byte{byte(len(h))}) + h
|
2018-04-18 15:42:38 -06:00
|
|
|
}
|
|
|
|
|
2018-08-02 06:30:45 -06:00
|
|
|
func spentAddressToPubKeyHexWithLength(addr string, t *testing.T, d *RocksDB) string {
|
2018-10-15 10:09:46 -06:00
|
|
|
h := dbtestdata.AddressToPubKeyHex(addr, d.chainParser)
|
2018-08-17 15:48:36 -06:00
|
|
|
return hex.EncodeToString([]byte{byte(len(h) + 1)}) + h
|
2018-08-02 06:30:45 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func bigintToHex(i *big.Int) string {
|
|
|
|
b := make([]byte, maxPackedBigintBytes)
|
|
|
|
l := packBigint(i, b)
|
|
|
|
return hex.EncodeToString(b[:l])
|
|
|
|
}
|
|
|
|
|
2018-08-21 05:16:29 -06:00
|
|
|
func varuintToHex(i uint) string {
|
|
|
|
b := make([]byte, vlq.MaxLen64)
|
|
|
|
l := vlq.PutUint(b, uint64(i))
|
|
|
|
return hex.EncodeToString(b[:l])
|
|
|
|
}
|
|
|
|
|
2018-08-21 08:36:14 -06:00
|
|
|
func uintToHex(i uint32) string {
|
|
|
|
buf := make([]byte, 4)
|
|
|
|
binary.BigEndian.PutUint32(buf, i)
|
|
|
|
return hex.EncodeToString(buf)
|
|
|
|
}
|
|
|
|
|
2018-04-20 05:56:55 -06:00
|
|
|
// keyPair is used to compare given key value in DB with expected
|
|
|
|
// for more complicated compares it is possible to specify CompareFunc
|
2018-04-18 15:42:38 -06:00
|
|
|
type keyPair struct {
|
2018-04-20 05:56:55 -06:00
|
|
|
Key, Value string
|
|
|
|
CompareFunc func(string) bool
|
2018-04-18 15:42:38 -06:00
|
|
|
}
|
|
|
|
|
2018-04-24 04:00:24 -06:00
|
|
|
func compareFuncBlockAddresses(t *testing.T, v string, expected []string) bool {
|
2018-04-20 07:08:08 -06:00
|
|
|
for _, e := range expected {
|
|
|
|
lb := len(v)
|
|
|
|
v = strings.Replace(v, e, "", 1)
|
|
|
|
if lb == len(v) {
|
2018-04-24 04:00:24 -06:00
|
|
|
t.Error(e, " not found in ", v)
|
2018-04-20 07:08:08 -06:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
2018-04-24 04:00:24 -06:00
|
|
|
if len(v) != 0 {
|
|
|
|
t.Error("not expected content ", v)
|
|
|
|
}
|
2018-04-20 07:08:08 -06:00
|
|
|
return len(v) == 0
|
|
|
|
}
|
|
|
|
|
2018-04-18 15:42:38 -06:00
|
|
|
func checkColumn(d *RocksDB, col int, kp []keyPair) error {
|
2018-04-19 06:28:05 -06:00
|
|
|
sort.Slice(kp, func(i, j int) bool {
|
|
|
|
return kp[i].Key < kp[j].Key
|
|
|
|
})
|
2018-04-18 15:42:38 -06:00
|
|
|
it := d.db.NewIteratorCF(d.ro, d.cfh[col])
|
|
|
|
defer it.Close()
|
|
|
|
i := 0
|
|
|
|
for it.SeekToFirst(); it.Valid(); it.Next() {
|
|
|
|
if i >= len(kp) {
|
2018-04-26 11:50:22 -06:00
|
|
|
return errors.Errorf("Expected less rows in column %v", cfNames[col])
|
2018-04-18 15:42:38 -06:00
|
|
|
}
|
|
|
|
key := hex.EncodeToString(it.Key().Data())
|
|
|
|
if key != kp[i].Key {
|
2018-04-26 11:50:22 -06:00
|
|
|
return errors.Errorf("Incorrect key %v found in column %v row %v, expecting %v", key, cfNames[col], i, kp[i].Key)
|
2018-04-18 15:42:38 -06:00
|
|
|
}
|
|
|
|
val := hex.EncodeToString(it.Value().Data())
|
2018-04-20 05:56:55 -06:00
|
|
|
var valOK bool
|
|
|
|
if kp[i].CompareFunc == nil {
|
|
|
|
valOK = val == kp[i].Value
|
|
|
|
} else {
|
|
|
|
valOK = kp[i].CompareFunc(val)
|
|
|
|
}
|
|
|
|
if !valOK {
|
2018-08-02 06:30:45 -06:00
|
|
|
return errors.Errorf("Incorrect value %v found in column %v row %v key %v, expecting %v", val, cfNames[col], i, key, kp[i].Value)
|
2018-04-18 15:42:38 -06:00
|
|
|
}
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
if i != len(kp) {
|
2018-04-26 11:50:22 -06:00
|
|
|
return errors.Errorf("Expected more rows in column %v: got %v, expected %v", cfNames[col], i, len(kp))
|
2018-04-18 15:42:38 -06:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2018-04-19 06:28:05 -06:00
|
|
|
|
2018-08-16 07:31:11 -06:00
|
|
|
func verifyAfterUTXOBlock1(t *testing.T, d *RocksDB, afterDisconnect bool) {
|
2018-04-19 07:11:32 -06:00
|
|
|
if err := checkColumn(d, cfHeight, []keyPair{
|
2018-08-21 08:36:14 -06:00
|
|
|
keyPair{
|
|
|
|
"000370d5",
|
|
|
|
"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997" + uintToHex(1534858021) + varuintToHex(2) + varuintToHex(1234567),
|
|
|
|
nil,
|
|
|
|
},
|
2018-04-19 07:11:32 -06:00
|
|
|
}); err != nil {
|
|
|
|
{
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-04-19 06:28:05 -06:00
|
|
|
}
|
2018-04-19 07:11:32 -06:00
|
|
|
// the vout is encoded as signed varint, i.e. value * 2 for non negative values
|
|
|
|
if err := checkColumn(d, cfAddresses, []keyPair{
|
2018-10-15 10:09:46 -06:00
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr1, d.chainParser) + "000370d5", dbtestdata.TxidB1T1 + "00", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser) + "000370d5", dbtestdata.TxidB1T1 + "02", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser) + "000370d5", dbtestdata.TxidB1T2 + "00", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser) + "000370d5", dbtestdata.TxidB1T2 + "02", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser) + "000370d5", dbtestdata.TxidB1T2 + "04", nil},
|
2018-04-19 07:11:32 -06:00
|
|
|
}); err != nil {
|
|
|
|
{
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2018-08-02 06:30:45 -06:00
|
|
|
if err := checkColumn(d, cfTxAddresses, []keyPair{
|
2018-04-19 07:11:32 -06:00
|
|
|
keyPair{
|
2018-10-15 06:27:58 -06:00
|
|
|
dbtestdata.TxidB1T1,
|
2018-08-21 05:16:29 -06:00
|
|
|
varuintToHex(225493) +
|
|
|
|
"00" +
|
|
|
|
"02" +
|
2018-10-15 06:27:58 -06:00
|
|
|
addressToPubKeyHexWithLength(dbtestdata.Addr1, t, d) + bigintToHex(dbtestdata.SatB1T1A1) +
|
|
|
|
addressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2),
|
2018-08-02 06:30:45 -06:00
|
|
|
nil,
|
2018-04-19 07:11:32 -06:00
|
|
|
},
|
|
|
|
keyPair{
|
2018-10-15 06:27:58 -06:00
|
|
|
dbtestdata.TxidB1T2,
|
2018-08-21 05:16:29 -06:00
|
|
|
varuintToHex(225493) +
|
|
|
|
"00" +
|
|
|
|
"03" +
|
2018-10-15 06:27:58 -06:00
|
|
|
addressToPubKeyHexWithLength(dbtestdata.Addr3, t, d) + bigintToHex(dbtestdata.SatB1T2A3) +
|
|
|
|
addressToPubKeyHexWithLength(dbtestdata.Addr4, t, d) + bigintToHex(dbtestdata.SatB1T2A4) +
|
|
|
|
addressToPubKeyHexWithLength(dbtestdata.Addr5, t, d) + bigintToHex(dbtestdata.SatB1T2A5),
|
2018-08-02 06:30:45 -06:00
|
|
|
nil,
|
2018-04-20 05:56:55 -06:00
|
|
|
},
|
|
|
|
}); err != nil {
|
|
|
|
{
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2018-08-02 06:30:45 -06:00
|
|
|
if err := checkColumn(d, cfAddressBalance, []keyPair{
|
2018-10-15 10:09:46 -06:00
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr1, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A1), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A2), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T2A3), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T2A4), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T2A5), nil},
|
2018-08-02 06:30:45 -06:00
|
|
|
}); err != nil {
|
|
|
|
{
|
|
|
|
t.Fatal(err)
|
2018-04-23 09:05:23 -06:00
|
|
|
}
|
|
|
|
}
|
2018-08-16 07:31:11 -06:00
|
|
|
|
|
|
|
var blockTxsKp []keyPair
|
|
|
|
if afterDisconnect {
|
|
|
|
blockTxsKp = []keyPair{}
|
|
|
|
} else {
|
|
|
|
blockTxsKp = []keyPair{
|
|
|
|
keyPair{
|
|
|
|
"000370d5",
|
2018-10-15 06:27:58 -06:00
|
|
|
dbtestdata.TxidB1T1 + "00" + dbtestdata.TxidB1T2 + "00",
|
2018-08-16 07:31:11 -06:00
|
|
|
nil,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := checkColumn(d, cfBlockTxs, blockTxsKp); err != nil {
|
2018-04-19 07:11:32 -06:00
|
|
|
{
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-20 05:56:55 -06:00
|
|
|
func verifyAfterUTXOBlock2(t *testing.T, d *RocksDB) {
|
2018-04-19 06:28:05 -06:00
|
|
|
if err := checkColumn(d, cfHeight, []keyPair{
|
2018-08-21 08:36:14 -06:00
|
|
|
keyPair{
|
|
|
|
"000370d5",
|
|
|
|
"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997" + uintToHex(1534858021) + varuintToHex(2) + varuintToHex(1234567),
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
keyPair{
|
|
|
|
"000370d6",
|
|
|
|
"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6" + uintToHex(1534859123) + varuintToHex(4) + varuintToHex(2345678),
|
|
|
|
nil,
|
|
|
|
},
|
2018-04-19 06:28:05 -06:00
|
|
|
}); err != nil {
|
|
|
|
{
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := checkColumn(d, cfAddresses, []keyPair{
|
2018-10-15 10:09:46 -06:00
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr1, d.chainParser) + "000370d5", dbtestdata.TxidB1T1 + "00", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser) + "000370d5", dbtestdata.TxidB1T1 + "02", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser) + "000370d5", dbtestdata.TxidB1T2 + "00", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser) + "000370d5", dbtestdata.TxidB1T2 + "02", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser) + "000370d5", dbtestdata.TxidB1T2 + "04", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr6, d.chainParser) + "000370d6", dbtestdata.TxidB2T1 + "00" + dbtestdata.TxidB2T2 + "01", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr7, d.chainParser) + "000370d6", dbtestdata.TxidB2T1 + "02", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr8, d.chainParser) + "000370d6", dbtestdata.TxidB2T2 + "00", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr9, d.chainParser) + "000370d6", dbtestdata.TxidB2T2 + "02", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser) + "000370d6", dbtestdata.TxidB2T1 + "01", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser) + "000370d6", dbtestdata.TxidB2T1 + "03", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser) + "000370d6", dbtestdata.TxidB2T3 + "00" + dbtestdata.TxidB2T3 + "01", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.AddrA, d.chainParser) + "000370d6", dbtestdata.TxidB2T4 + "00", nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser) + "000370d6", dbtestdata.TxidB2T2 + "03", nil},
|
2018-04-19 06:28:05 -06:00
|
|
|
}); err != nil {
|
|
|
|
{
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2018-08-02 06:30:45 -06:00
|
|
|
if err := checkColumn(d, cfTxAddresses, []keyPair{
|
2018-04-19 06:28:05 -06:00
|
|
|
keyPair{
|
2018-10-15 06:27:58 -06:00
|
|
|
dbtestdata.TxidB1T1,
|
2018-08-21 05:16:29 -06:00
|
|
|
varuintToHex(225493) +
|
|
|
|
"00" +
|
|
|
|
"02" +
|
2018-10-15 06:27:58 -06:00
|
|
|
addressToPubKeyHexWithLength(dbtestdata.Addr1, t, d) + bigintToHex(dbtestdata.SatB1T1A1) +
|
|
|
|
spentAddressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2),
|
2018-04-20 05:56:55 -06:00
|
|
|
nil,
|
2018-04-19 06:28:05 -06:00
|
|
|
},
|
|
|
|
keyPair{
|
2018-10-15 06:27:58 -06:00
|
|
|
dbtestdata.TxidB1T2,
|
2018-08-21 05:16:29 -06:00
|
|
|
varuintToHex(225493) +
|
|
|
|
"00" +
|
|
|
|
"03" +
|
2018-10-15 06:27:58 -06:00
|
|
|
spentAddressToPubKeyHexWithLength(dbtestdata.Addr3, t, d) + bigintToHex(dbtestdata.SatB1T2A3) +
|
|
|
|
spentAddressToPubKeyHexWithLength(dbtestdata.Addr4, t, d) + bigintToHex(dbtestdata.SatB1T2A4) +
|
|
|
|
spentAddressToPubKeyHexWithLength(dbtestdata.Addr5, t, d) + bigintToHex(dbtestdata.SatB1T2A5),
|
2018-04-20 05:56:55 -06:00
|
|
|
nil,
|
2018-04-19 06:28:05 -06:00
|
|
|
},
|
|
|
|
keyPair{
|
2018-10-15 06:27:58 -06:00
|
|
|
dbtestdata.TxidB2T1,
|
2018-08-21 05:16:29 -06:00
|
|
|
varuintToHex(225494) +
|
|
|
|
"02" +
|
2018-10-15 06:27:58 -06:00
|
|
|
inputAddressToPubKeyHexWithLength(dbtestdata.Addr3, t, d) + bigintToHex(dbtestdata.SatB1T2A3) +
|
|
|
|
inputAddressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2) +
|
2018-08-02 06:30:45 -06:00
|
|
|
"02" +
|
2018-10-15 06:27:58 -06:00
|
|
|
spentAddressToPubKeyHexWithLength(dbtestdata.Addr6, t, d) + bigintToHex(dbtestdata.SatB2T1A6) +
|
|
|
|
addressToPubKeyHexWithLength(dbtestdata.Addr7, t, d) + bigintToHex(dbtestdata.SatB2T1A7),
|
2018-08-02 06:30:45 -06:00
|
|
|
nil,
|
|
|
|
},
|
|
|
|
keyPair{
|
2018-10-15 06:27:58 -06:00
|
|
|
dbtestdata.TxidB2T2,
|
2018-08-21 05:16:29 -06:00
|
|
|
varuintToHex(225494) +
|
|
|
|
"02" +
|
2018-10-15 06:27:58 -06:00
|
|
|
inputAddressToPubKeyHexWithLength(dbtestdata.Addr6, t, d) + bigintToHex(dbtestdata.SatB2T1A6) +
|
|
|
|
inputAddressToPubKeyHexWithLength(dbtestdata.Addr4, t, d) + bigintToHex(dbtestdata.SatB1T2A4) +
|
2018-08-02 06:30:45 -06:00
|
|
|
"02" +
|
2018-10-15 06:27:58 -06:00
|
|
|
addressToPubKeyHexWithLength(dbtestdata.Addr8, t, d) + bigintToHex(dbtestdata.SatB2T2A8) +
|
|
|
|
addressToPubKeyHexWithLength(dbtestdata.Addr9, t, d) + bigintToHex(dbtestdata.SatB2T2A9),
|
2018-08-02 06:30:45 -06:00
|
|
|
nil,
|
2018-04-20 05:56:55 -06:00
|
|
|
},
|
2018-05-02 17:03:20 -06:00
|
|
|
keyPair{
|
2018-10-15 06:27:58 -06:00
|
|
|
dbtestdata.TxidB2T3,
|
2018-08-21 05:16:29 -06:00
|
|
|
varuintToHex(225494) +
|
|
|
|
"01" +
|
2018-10-15 06:27:58 -06:00
|
|
|
inputAddressToPubKeyHexWithLength(dbtestdata.Addr5, t, d) + bigintToHex(dbtestdata.SatB1T2A5) +
|
2018-08-02 06:30:45 -06:00
|
|
|
"01" +
|
2018-10-15 06:27:58 -06:00
|
|
|
addressToPubKeyHexWithLength(dbtestdata.Addr5, t, d) + bigintToHex(dbtestdata.SatB2T3A5),
|
2018-05-02 17:03:20 -06:00
|
|
|
nil,
|
|
|
|
},
|
2018-08-17 15:48:36 -06:00
|
|
|
keyPair{
|
2018-10-15 06:27:58 -06:00
|
|
|
dbtestdata.TxidB2T4,
|
2018-08-21 05:16:29 -06:00
|
|
|
varuintToHex(225494) +
|
2018-10-15 06:27:58 -06:00
|
|
|
"01" + inputAddressToPubKeyHexWithLength("", t, d) + bigintToHex(dbtestdata.SatZero) +
|
2018-08-17 15:48:36 -06:00
|
|
|
"02" +
|
2018-10-15 06:27:58 -06:00
|
|
|
addressToPubKeyHexWithLength(dbtestdata.AddrA, t, d) + bigintToHex(dbtestdata.SatB2T4AA) +
|
|
|
|
addressToPubKeyHexWithLength("", t, d) + bigintToHex(dbtestdata.SatZero),
|
2018-08-17 15:48:36 -06:00
|
|
|
nil,
|
|
|
|
},
|
2018-04-20 05:56:55 -06:00
|
|
|
}); err != nil {
|
|
|
|
{
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2018-08-02 06:30:45 -06:00
|
|
|
if err := checkColumn(d, cfAddressBalance, []keyPair{
|
2018-10-15 10:09:46 -06:00
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr1, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A1), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T1A2) + bigintToHex(dbtestdata.SatZero), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T2A3) + bigintToHex(dbtestdata.SatZero), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T2A4) + bigintToHex(dbtestdata.SatZero), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T2A5) + bigintToHex(dbtestdata.SatB2T3A5), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr6, d.chainParser), "02" + bigintToHex(dbtestdata.SatB2T1A6) + bigintToHex(dbtestdata.SatZero), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr7, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T1A7), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr8, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T2A8), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr9, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T2A9), nil},
|
|
|
|
keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.AddrA, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T4AA), nil},
|
2018-08-02 06:30:45 -06:00
|
|
|
}); err != nil {
|
|
|
|
{
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2018-08-16 07:31:11 -06:00
|
|
|
if err := checkColumn(d, cfBlockTxs, []keyPair{
|
|
|
|
keyPair{
|
|
|
|
"000370d6",
|
2018-10-15 06:27:58 -06:00
|
|
|
dbtestdata.TxidB2T1 + "02" + dbtestdata.TxidB1T2 + "00" + dbtestdata.TxidB1T1 + "02" +
|
|
|
|
dbtestdata.TxidB2T2 + "02" + dbtestdata.TxidB2T1 + "00" + dbtestdata.TxidB1T2 + "02" +
|
|
|
|
dbtestdata.TxidB2T3 + "01" + dbtestdata.TxidB1T2 + "04" +
|
|
|
|
dbtestdata.TxidB2T4 + "01" + "0000000000000000000000000000000000000000000000000000000000000000" + "00",
|
2018-08-16 07:31:11 -06:00
|
|
|
nil,
|
|
|
|
},
|
2018-04-19 06:28:05 -06:00
|
|
|
}); err != nil {
|
|
|
|
{
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2018-04-18 15:42:38 -06:00
|
|
|
}
|
2018-04-19 07:11:32 -06:00
|
|
|
|
|
|
|
type txidVoutOutput struct {
|
|
|
|
txid string
|
|
|
|
vout uint32
|
|
|
|
isOutput bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func verifyGetTransactions(t *testing.T, d *RocksDB, addr string, low, high uint32, wantTxids []txidVoutOutput, wantErr error) {
|
|
|
|
gotTxids := make([]txidVoutOutput, 0)
|
|
|
|
addToTxids := func(txid string, vout uint32, isOutput bool) error {
|
|
|
|
gotTxids = append(gotTxids, txidVoutOutput{txid, vout, isOutput})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if err := d.GetTransactions(addr, low, high, addToTxids); err != nil {
|
|
|
|
if wantErr == nil || wantErr.Error() != err.Error() {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(gotTxids, wantTxids) {
|
|
|
|
t.Errorf("GetTransactions() = %v, want %v", gotTxids, wantTxids)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-20 05:56:55 -06:00
|
|
|
type testBitcoinParser struct {
|
|
|
|
*btc.BitcoinParser
|
|
|
|
}
|
|
|
|
|
2018-04-20 08:03:45 -06:00
|
|
|
// override PackTx and UnpackTx to default BaseParser functionality
|
|
|
|
// BitcoinParser uses tx hex which is not available for the test transactions
|
|
|
|
func (p *testBitcoinParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
|
|
|
|
return p.BaseParser.PackTx(tx, height, blockTime)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *testBitcoinParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
|
|
|
return p.BaseParser.UnpackTx(buf)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testTxCache(t *testing.T, d *RocksDB, b *bchain.Block, tx *bchain.Tx) {
|
|
|
|
if err := d.PutTx(tx, b.Height, tx.Blocktime); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
gtx, height, err := d.GetTx(tx.Txid)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if b.Height != height {
|
|
|
|
t.Fatalf("GetTx: got height %v, expected %v", height, b.Height)
|
|
|
|
}
|
2018-10-19 08:36:22 -06:00
|
|
|
// Confirmations are not stored in the DB, set them from input tx
|
|
|
|
gtx.Confirmations = tx.Confirmations
|
2018-04-20 08:03:45 -06:00
|
|
|
if fmt.Sprint(gtx) != fmt.Sprint(tx) {
|
|
|
|
t.Errorf("GetTx: %v, want %v", gtx, tx)
|
|
|
|
}
|
|
|
|
if err := d.DeleteTx(tx.Txid); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-23 09:05:23 -06:00
|
|
|
// TestRocksDB_Index_UTXO is an integration test probing the whole indexing functionality for UTXO chains
|
2018-04-19 07:11:32 -06:00
|
|
|
// It does the following:
|
|
|
|
// 1) Connect two blocks (inputs from 2nd block are spending some outputs from the 1st block)
|
|
|
|
// 2) GetTransactions for various addresses / low-high ranges
|
2018-04-20 07:08:08 -06:00
|
|
|
// 3) GetBestBlock, GetBlockHash
|
|
|
|
// 4) Test tx caching functionality
|
|
|
|
// 5) Disconnect block 2 - expect error
|
2018-08-16 07:31:11 -06:00
|
|
|
// 6) Disconnect the block 2 using BlockTxs column
|
|
|
|
// 7) Reconnect block 2 and check
|
2018-04-20 08:03:45 -06:00
|
|
|
// After each step, the content of DB is examined and any difference against expected state is regarded as failure
|
2018-04-19 07:11:32 -06:00
|
|
|
func TestRocksDB_Index_UTXO(t *testing.T) {
|
2018-05-28 06:57:44 -06:00
|
|
|
d := setupRocksDB(t, &testBitcoinParser{
|
2018-08-02 08:10:28 -06:00
|
|
|
BitcoinParser: bitcoinTestnetParser(),
|
2018-05-28 06:57:44 -06:00
|
|
|
})
|
2018-05-23 03:07:16 -06:00
|
|
|
defer closeAndDestroyRocksDB(t, d)
|
2018-04-19 07:11:32 -06:00
|
|
|
|
2018-08-02 06:30:45 -06:00
|
|
|
// connect 1st block - will log warnings about missing UTXO transactions in txAddresses column
|
2018-10-15 10:09:46 -06:00
|
|
|
block1 := dbtestdata.GetTestUTXOBlock1(d.chainParser)
|
2018-04-19 07:11:32 -06:00
|
|
|
if err := d.ConnectBlock(block1); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-08-16 07:31:11 -06:00
|
|
|
verifyAfterUTXOBlock1(t, d, false)
|
2018-04-19 07:11:32 -06:00
|
|
|
|
|
|
|
// connect 2nd block - use some outputs from the 1st block as the inputs and 1 input uses tx from the same block
|
2018-10-15 10:09:46 -06:00
|
|
|
block2 := dbtestdata.GetTestUTXOBlock2(d.chainParser)
|
2018-04-19 07:11:32 -06:00
|
|
|
if err := d.ConnectBlock(block2); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-04-20 05:56:55 -06:00
|
|
|
verifyAfterUTXOBlock2(t, d)
|
2018-04-19 07:11:32 -06:00
|
|
|
|
|
|
|
// get transactions for various addresses / low-high ranges
|
2018-10-15 06:27:58 -06:00
|
|
|
verifyGetTransactions(t, d, dbtestdata.Addr2, 0, 1000000, []txidVoutOutput{
|
|
|
|
txidVoutOutput{dbtestdata.TxidB1T1, 1, true},
|
|
|
|
txidVoutOutput{dbtestdata.TxidB2T1, 1, false},
|
2018-04-19 07:11:32 -06:00
|
|
|
}, nil)
|
2018-10-15 06:27:58 -06:00
|
|
|
verifyGetTransactions(t, d, dbtestdata.Addr2, 225493, 225493, []txidVoutOutput{
|
|
|
|
txidVoutOutput{dbtestdata.TxidB1T1, 1, true},
|
2018-04-19 07:11:32 -06:00
|
|
|
}, nil)
|
2018-10-15 06:27:58 -06:00
|
|
|
verifyGetTransactions(t, d, dbtestdata.Addr2, 225494, 1000000, []txidVoutOutput{
|
|
|
|
txidVoutOutput{dbtestdata.TxidB2T1, 1, false},
|
2018-04-19 07:11:32 -06:00
|
|
|
}, nil)
|
2018-10-15 06:27:58 -06:00
|
|
|
verifyGetTransactions(t, d, dbtestdata.Addr2, 500000, 1000000, []txidVoutOutput{}, nil)
|
|
|
|
verifyGetTransactions(t, d, dbtestdata.Addr8, 0, 1000000, []txidVoutOutput{
|
|
|
|
txidVoutOutput{dbtestdata.TxidB2T2, 0, true},
|
2018-04-19 07:11:32 -06:00
|
|
|
}, nil)
|
|
|
|
verifyGetTransactions(t, d, "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eBad", 500000, 1000000, []txidVoutOutput{}, errors.New("checksum mismatch"))
|
|
|
|
|
2018-04-20 07:08:08 -06:00
|
|
|
// GetBestBlock
|
|
|
|
height, hash, err := d.GetBestBlock()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if height != 225494 {
|
|
|
|
t.Fatalf("GetBestBlock: got height %v, expected %v", height, 225494)
|
|
|
|
}
|
|
|
|
if hash != "00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6" {
|
|
|
|
t.Fatalf("GetBestBlock: got hash %v, expected %v", hash, "00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6")
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetBlockHash
|
|
|
|
hash, err = d.GetBlockHash(225493)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if hash != "0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997" {
|
|
|
|
t.Fatalf("GetBlockHash: got hash %v, expected %v", hash, "0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997")
|
|
|
|
}
|
|
|
|
|
2018-08-21 08:36:14 -06:00
|
|
|
// Not connected block
|
|
|
|
hash, err = d.GetBlockHash(225495)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if hash != "" {
|
|
|
|
t.Fatalf("GetBlockHash: got hash '%v', expected ''", hash)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetBlockHash
|
|
|
|
info, err := d.GetBlockInfo(225494)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
iw := &BlockInfo{
|
2018-09-14 04:10:03 -06:00
|
|
|
Hash: "00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6",
|
|
|
|
Txs: 4,
|
|
|
|
Size: 2345678,
|
|
|
|
Time: 1534859123,
|
|
|
|
Height: 225494,
|
2018-08-21 08:36:14 -06:00
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(info, iw) {
|
|
|
|
t.Errorf("GetAddressBalance() = %+v, want %+v", info, iw)
|
|
|
|
}
|
|
|
|
|
2018-04-20 08:03:45 -06:00
|
|
|
// Test tx caching functionality, leave one tx in db to test cleanup in DisconnectBlock
|
|
|
|
testTxCache(t, d, block1, &block1.Txs[0])
|
|
|
|
testTxCache(t, d, block2, &block2.Txs[0])
|
|
|
|
if err = d.PutTx(&block2.Txs[1], block2.Height, block2.Txs[1].Blocktime); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
// check that there is only the last tx in the cache
|
|
|
|
packedTx, err := d.chainParser.PackTx(&block2.Txs[1], block2.Height, block2.Txs[1].Blocktime)
|
|
|
|
if err := checkColumn(d, cfTransactions, []keyPair{
|
|
|
|
keyPair{block2.Txs[1].Txid, hex.EncodeToString(packedTx), nil},
|
|
|
|
}); err != nil {
|
|
|
|
{
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-20 05:56:55 -06:00
|
|
|
// DisconnectBlock for UTXO chains is not possible
|
2018-04-20 07:08:08 -06:00
|
|
|
err = d.DisconnectBlock(block2)
|
2018-04-20 05:56:55 -06:00
|
|
|
if err == nil || err.Error() != "DisconnectBlock is not supported for UTXO chains" {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
verifyAfterUTXOBlock2(t, d)
|
|
|
|
|
2018-08-03 11:26:16 -06:00
|
|
|
// try to disconnect both blocks, however only the last one is kept, it is not possible
|
|
|
|
err = d.DisconnectBlockRangeUTXO(225493, 225494)
|
|
|
|
if err == nil || err.Error() != "Cannot disconnect blocks with height 225493 and lower. It is necessary to rebuild index." {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
verifyAfterUTXOBlock2(t, d)
|
|
|
|
|
2018-04-23 09:05:23 -06:00
|
|
|
// disconnect the 2nd block, verify that the db contains only data from the 1st block with restored unspentTxs
|
|
|
|
// and that the cached tx is removed
|
2018-08-03 11:26:16 -06:00
|
|
|
err = d.DisconnectBlockRangeUTXO(225494, 225494)
|
2018-04-23 09:05:23 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-08-16 07:31:11 -06:00
|
|
|
verifyAfterUTXOBlock1(t, d, true)
|
2018-04-23 09:05:23 -06:00
|
|
|
if err := checkColumn(d, cfTransactions, []keyPair{}); err != nil {
|
|
|
|
{
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2018-04-20 05:56:55 -06:00
|
|
|
|
2018-08-16 07:31:11 -06:00
|
|
|
// connect block again and verify the state of db
|
|
|
|
if err := d.ConnectBlock(block2); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
verifyAfterUTXOBlock2(t, d)
|
2018-08-20 10:35:46 -06:00
|
|
|
|
|
|
|
// test public methods for address balance and tx addresses
|
|
|
|
|
2018-10-15 06:27:58 -06:00
|
|
|
ab, err := d.GetAddressBalance(dbtestdata.Addr5)
|
2018-08-20 10:35:46 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
abw := &AddrBalance{
|
|
|
|
Txs: 2,
|
2018-10-15 06:27:58 -06:00
|
|
|
SentSat: *dbtestdata.SatB1T2A5,
|
|
|
|
BalanceSat: *dbtestdata.SatB2T3A5,
|
2018-08-20 10:35:46 -06:00
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(ab, abw) {
|
|
|
|
t.Errorf("GetAddressBalance() = %+v, want %+v", ab, abw)
|
|
|
|
}
|
|
|
|
rs := ab.ReceivedSat()
|
2018-10-15 06:27:58 -06:00
|
|
|
rsw := dbtestdata.SatB1T2A5.Add(dbtestdata.SatB1T2A5, dbtestdata.SatB2T3A5)
|
2018-08-20 10:35:46 -06:00
|
|
|
if rs.Cmp(rsw) != 0 {
|
|
|
|
t.Errorf("GetAddressBalance().ReceivedSat() = %v, want %v", rs, rsw)
|
|
|
|
}
|
|
|
|
|
2018-10-15 06:27:58 -06:00
|
|
|
ta, err := d.GetTxAddresses(dbtestdata.TxidB2T1)
|
2018-08-20 10:35:46 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
taw := &TxAddresses{
|
2018-08-21 05:16:29 -06:00
|
|
|
Height: 225494,
|
2018-08-20 10:35:46 -06:00
|
|
|
Inputs: []TxInput{
|
|
|
|
{
|
2018-10-15 06:27:58 -06:00
|
|
|
AddrDesc: addressToAddrDesc(dbtestdata.Addr3, d.chainParser),
|
|
|
|
ValueSat: *dbtestdata.SatB1T2A3,
|
2018-08-20 10:35:46 -06:00
|
|
|
},
|
|
|
|
{
|
2018-10-15 06:27:58 -06:00
|
|
|
AddrDesc: addressToAddrDesc(dbtestdata.Addr2, d.chainParser),
|
|
|
|
ValueSat: *dbtestdata.SatB1T1A2,
|
2018-08-20 10:35:46 -06:00
|
|
|
},
|
|
|
|
},
|
|
|
|
Outputs: []TxOutput{
|
|
|
|
{
|
2018-10-15 06:27:58 -06:00
|
|
|
AddrDesc: addressToAddrDesc(dbtestdata.Addr6, d.chainParser),
|
2018-08-20 10:35:46 -06:00
|
|
|
Spent: true,
|
2018-10-15 06:27:58 -06:00
|
|
|
ValueSat: *dbtestdata.SatB2T1A6,
|
2018-08-20 10:35:46 -06:00
|
|
|
},
|
|
|
|
{
|
2018-10-15 06:27:58 -06:00
|
|
|
AddrDesc: addressToAddrDesc(dbtestdata.Addr7, d.chainParser),
|
2018-08-20 10:35:46 -06:00
|
|
|
Spent: false,
|
2018-10-15 06:27:58 -06:00
|
|
|
ValueSat: *dbtestdata.SatB2T1A7,
|
2018-08-20 10:35:46 -06:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(ta, taw) {
|
|
|
|
t.Errorf("GetTxAddresses() = %+v, want %+v", ta, taw)
|
|
|
|
}
|
2018-08-28 16:25:26 -06:00
|
|
|
ia, _, err := ta.Inputs[0].Addresses(d.chainParser)
|
2018-08-20 10:35:46 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-10-15 06:27:58 -06:00
|
|
|
if !reflect.DeepEqual(ia, []string{dbtestdata.Addr3}) {
|
|
|
|
t.Errorf("GetTxAddresses().Inputs[0].Addresses() = %v, want %v", ia, []string{dbtestdata.Addr3})
|
2018-08-20 10:35:46 -06:00
|
|
|
}
|
|
|
|
|
2018-08-18 16:23:26 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func Test_BulkConnect_UTXO(t *testing.T) {
|
|
|
|
d := setupRocksDB(t, &testBitcoinParser{
|
|
|
|
BitcoinParser: bitcoinTestnetParser(),
|
|
|
|
})
|
|
|
|
defer closeAndDestroyRocksDB(t, d)
|
|
|
|
|
|
|
|
bc, err := d.InitBulkConnect()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if d.is.DbState != common.DbStateInconsistent {
|
|
|
|
t.Fatal("DB not in DbStateInconsistent")
|
|
|
|
}
|
|
|
|
|
2018-10-15 10:09:46 -06:00
|
|
|
if err := bc.ConnectBlock(dbtestdata.GetTestUTXOBlock1(d.chainParser), false); err != nil {
|
2018-08-18 16:23:26 -06:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := checkColumn(d, cfBlockTxs, []keyPair{}); err != nil {
|
|
|
|
{
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-15 10:09:46 -06:00
|
|
|
if err := bc.ConnectBlock(dbtestdata.GetTestUTXOBlock2(d.chainParser), true); err != nil {
|
2018-08-18 16:23:26 -06:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := bc.Close(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-08-16 07:31:11 -06:00
|
|
|
|
2018-08-18 16:23:26 -06:00
|
|
|
if d.is.DbState != common.DbStateOpen {
|
|
|
|
t.Fatal("DB not in DbStateOpen")
|
|
|
|
}
|
|
|
|
|
|
|
|
verifyAfterUTXOBlock2(t, d)
|
2018-04-19 07:11:32 -06:00
|
|
|
}
|
2018-04-20 15:53:17 -06:00
|
|
|
|
2018-07-27 11:46:21 -06:00
|
|
|
func Test_packBigint_unpackBigint(t *testing.T) {
|
|
|
|
bigbig1, _ := big.NewInt(0).SetString("123456789123456789012345", 10)
|
|
|
|
bigbig2, _ := big.NewInt(0).SetString("12345678912345678901234512389012345123456789123456789012345123456789123456789012345", 10)
|
|
|
|
bigbigbig := big.NewInt(0)
|
|
|
|
bigbigbig.Mul(bigbig2, bigbig2)
|
|
|
|
bigbigbig.Mul(bigbigbig, bigbigbig)
|
|
|
|
bigbigbig.Mul(bigbigbig, bigbigbig)
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
bi *big.Int
|
|
|
|
buf []byte
|
|
|
|
toobiglen int
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "0",
|
|
|
|
bi: big.NewInt(0),
|
2018-08-02 06:30:45 -06:00
|
|
|
buf: make([]byte, maxPackedBigintBytes),
|
2018-07-27 11:46:21 -06:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "1",
|
|
|
|
bi: big.NewInt(1),
|
2018-08-02 06:30:45 -06:00
|
|
|
buf: make([]byte, maxPackedBigintBytes),
|
2018-07-27 11:46:21 -06:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "54321",
|
|
|
|
bi: big.NewInt(54321),
|
|
|
|
buf: make([]byte, 249),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "12345678",
|
|
|
|
bi: big.NewInt(12345678),
|
2018-08-02 06:30:45 -06:00
|
|
|
buf: make([]byte, maxPackedBigintBytes),
|
2018-07-27 11:46:21 -06:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "123456789123456789",
|
|
|
|
bi: big.NewInt(123456789123456789),
|
2018-08-02 06:30:45 -06:00
|
|
|
buf: make([]byte, maxPackedBigintBytes),
|
2018-07-27 11:46:21 -06:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "bigbig1",
|
|
|
|
bi: bigbig1,
|
2018-08-02 06:30:45 -06:00
|
|
|
buf: make([]byte, maxPackedBigintBytes),
|
2018-07-27 11:46:21 -06:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "bigbig2",
|
|
|
|
bi: bigbig2,
|
2018-08-02 06:30:45 -06:00
|
|
|
buf: make([]byte, maxPackedBigintBytes),
|
2018-07-27 11:46:21 -06:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "bigbigbig",
|
|
|
|
bi: bigbigbig,
|
2018-08-02 06:30:45 -06:00
|
|
|
buf: make([]byte, maxPackedBigintBytes),
|
2018-07-27 11:46:21 -06:00
|
|
|
toobiglen: 242,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
// packBigint
|
|
|
|
got := packBigint(tt.bi, tt.buf)
|
|
|
|
if tt.toobiglen == 0 {
|
|
|
|
// create buffer that we expect
|
|
|
|
bb := tt.bi.Bytes()
|
|
|
|
want := append([]byte(nil), byte(len(bb)))
|
|
|
|
want = append(want, bb...)
|
|
|
|
if got != len(want) {
|
|
|
|
t.Errorf("packBigint() = %v, want %v", got, len(want))
|
|
|
|
}
|
|
|
|
for i := 0; i < got; i++ {
|
|
|
|
if tt.buf[i] != want[i] {
|
|
|
|
t.Errorf("packBigint() buf = %v, want %v", tt.buf[:got], want)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// unpackBigint
|
|
|
|
got1, got2 := unpackBigint(tt.buf)
|
|
|
|
if got2 != len(want) {
|
|
|
|
t.Errorf("unpackBigint() = %v, want %v", got2, len(want))
|
|
|
|
}
|
|
|
|
if tt.bi.Cmp(&got1) != 0 {
|
|
|
|
t.Errorf("unpackBigint() = %v, want %v", got1, tt.bi)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if got != tt.toobiglen {
|
|
|
|
t.Errorf("packBigint() = %v, want toobiglen %v", got, tt.toobiglen)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2018-08-02 08:10:28 -06:00
|
|
|
|
2018-08-28 16:25:26 -06:00
|
|
|
func addressToAddrDesc(addr string, parser bchain.BlockChainParser) []byte {
|
|
|
|
b, err := parser.GetAddrDescFromAddress(addr)
|
2018-08-02 08:10:28 -06:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_packTxAddresses_unpackTxAddresses(t *testing.T) {
|
|
|
|
parser := bitcoinTestnetParser()
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
hex string
|
2018-08-20 10:35:46 -06:00
|
|
|
data *TxAddresses
|
2018-08-02 08:10:28 -06:00
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "1",
|
2018-08-21 05:16:29 -06:00
|
|
|
hex: "7b0216001443aac20a116e09ea4f7914be1c55e4c17aa600b70016001454633aa8bd2e552bd4e89c01e73c1b7905eb58460811207cb68a199872012d001443aac20a116e09ea4f7914be1c55e4c17aa600b70101",
|
2018-08-20 10:35:46 -06:00
|
|
|
data: &TxAddresses{
|
2018-08-21 05:16:29 -06:00
|
|
|
Height: 123,
|
2018-08-20 10:35:46 -06:00
|
|
|
Inputs: []TxInput{
|
2018-08-02 08:10:28 -06:00
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: addressToAddrDesc("tb1qgw4vyzs3dcy75nmezjlpc40yc9a2vq9hghdyt2", parser),
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(0),
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: addressToAddrDesc("tb1q233n429a9e2jh48gnsq7w0qm0yz7kkzx0qczw8", parser),
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(1234123421342341234),
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
},
|
2018-08-20 10:35:46 -06:00
|
|
|
Outputs: []TxOutput{
|
2018-08-02 08:10:28 -06:00
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: addressToAddrDesc("tb1qgw4vyzs3dcy75nmezjlpc40yc9a2vq9hghdyt2", parser),
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(1),
|
|
|
|
Spent: true,
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "2",
|
2018-08-21 05:16:29 -06:00
|
|
|
hex: "e0390317a9149eb21980dc9d413d8eac27314938b9da920ee53e8705021918f2c017a91409f70b896169c37981d2b54b371df0d81a136a2c870501dd7e28c017a914e371782582a4addb541362c55565d2cdf56f6498870501a1e35ec0052fa9141d9ca71efa36d814424ea6ca1437e67287aebe348705012aadcac02ea91424fbc77cdc62702ade74dcf989c15e5d3f9240bc870501664894c02fa914afbfb74ee994c7d45f6698738bc4226d065266f7870501a1e35ec03276a914d2a37ce20ac9ec4f15dd05a7c6e8e9fbdb99850e88ac043b9943603376a9146b2044146a4438e6e5bfbc65f147afeb64d14fbb88ac05012a05f200",
|
2018-08-20 10:35:46 -06:00
|
|
|
data: &TxAddresses{
|
2018-08-21 05:16:29 -06:00
|
|
|
Height: 12345,
|
2018-08-20 10:35:46 -06:00
|
|
|
Inputs: []TxInput{
|
2018-08-02 08:10:28 -06:00
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: addressToAddrDesc("2N7iL7AvS4LViugwsdjTB13uN4T7XhV1bCP", parser),
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(9011000000),
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: addressToAddrDesc("2Mt9v216YiNBAzobeNEzd4FQweHrGyuRHze", parser),
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(8011000000),
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: addressToAddrDesc("2NDyqJpHvHnqNtL1F9xAeCWMAW8WLJmEMyD", parser),
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(7011000000),
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
},
|
2018-08-20 10:35:46 -06:00
|
|
|
Outputs: []TxOutput{
|
2018-08-02 08:10:28 -06:00
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: addressToAddrDesc("2MuwoFGwABMakU7DCpdGDAKzyj2nTyRagDP", parser),
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(5011000000),
|
|
|
|
Spent: true,
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: addressToAddrDesc("2Mvcmw7qkGXNWzkfH1EjvxDcNRGL1Kf2tEM", parser),
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(6011000000),
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: addressToAddrDesc("2N9GVuX3XJGHS5MCdgn97gVezc6EgvzikTB", parser),
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(7011000000),
|
|
|
|
Spent: true,
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: addressToAddrDesc("mzii3fuRSpExMLJEHdHveW8NmiX8MPgavk", parser),
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(999900000),
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: addressToAddrDesc("mqHPFTRk23JZm9W1ANuEFtwTYwxjESSgKs", parser),
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(5000000000),
|
|
|
|
Spent: true,
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "empty address",
|
2018-08-21 05:16:29 -06:00
|
|
|
hex: "baef9a1501000204d2020002162e010162",
|
2018-08-20 10:35:46 -06:00
|
|
|
data: &TxAddresses{
|
2018-08-21 05:16:29 -06:00
|
|
|
Height: 123456789,
|
2018-08-20 10:35:46 -06:00
|
|
|
Inputs: []TxInput{
|
2018-08-02 08:10:28 -06:00
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: []byte{},
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(1234),
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
},
|
2018-08-20 10:35:46 -06:00
|
|
|
Outputs: []TxOutput{
|
2018-08-02 08:10:28 -06:00
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: []byte{},
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(5678),
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
{
|
2018-08-30 14:39:03 -06:00
|
|
|
AddrDesc: []byte{},
|
2018-08-20 10:35:46 -06:00
|
|
|
ValueSat: *big.NewInt(98),
|
|
|
|
Spent: true,
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "empty",
|
2018-08-21 05:16:29 -06:00
|
|
|
hex: "000000",
|
2018-08-20 10:35:46 -06:00
|
|
|
data: &TxAddresses{
|
|
|
|
Inputs: []TxInput{},
|
|
|
|
Outputs: []TxOutput{},
|
2018-08-02 08:10:28 -06:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|