github.com/aychain/blockbook@v0.1.1-0.20181121092459-6d1fc7e07c5b/db/rocksdb_test.go (about)

     1  // +build unittest
     2  
     3  package db
     4  
     5  import (
     6  	"blockbook/bchain"
     7  	"blockbook/bchain/coins/btc"
     8  	"blockbook/common"
     9  	"blockbook/tests/dbtestdata"
    10  	"encoding/binary"
    11  	"encoding/hex"
    12  	"fmt"
    13  	"io/ioutil"
    14  	"math/big"
    15  	"os"
    16  	"reflect"
    17  	"sort"
    18  	"strings"
    19  	"testing"
    20  
    21  	vlq "github.com/bsm/go-vlq"
    22  	"github.com/jakm/btcutil/chaincfg"
    23  	"github.com/juju/errors"
    24  )
    25  
    26  // simplified explanation of signed varint packing, used in many index data structures
    27  // for number n, the packing is: 2*n if n>=0 else 2*(-n)-1
    28  // takes only 1 byte if abs(n)<127
    29  
    30  func TestMain(m *testing.M) {
    31  	c := m.Run()
    32  	chaincfg.ResetParams()
    33  	os.Exit(c)
    34  }
    35  
    36  func bitcoinTestnetParser() *btc.BitcoinParser {
    37  	return btc.NewBitcoinParser(
    38  		btc.GetChainParams("test"),
    39  		&btc.Configuration{BlockAddressesToKeep: 1})
    40  }
    41  
    42  func setupRocksDB(t *testing.T, p bchain.BlockChainParser) *RocksDB {
    43  	tmp, err := ioutil.TempDir("", "testdb")
    44  	if err != nil {
    45  		t.Fatal(err)
    46  	}
    47  	d, err := NewRocksDB(tmp, 100000, -1, p, nil)
    48  	if err != nil {
    49  		t.Fatal(err)
    50  	}
    51  	is, err := d.LoadInternalState("btc-testnet")
    52  	if err != nil {
    53  		t.Fatal(err)
    54  	}
    55  	d.SetInternalState(is)
    56  	return d
    57  }
    58  
    59  func closeAndDestroyRocksDB(t *testing.T, d *RocksDB) {
    60  	if err := d.Close(); err != nil {
    61  		t.Fatal(err)
    62  	}
    63  	os.RemoveAll(d.path)
    64  }
    65  
    66  func inputAddressToPubKeyHexWithLength(addr string, t *testing.T, d *RocksDB) string {
    67  	h := dbtestdata.AddressToPubKeyHex(addr, d.chainParser)
    68  	return hex.EncodeToString([]byte{byte(len(h) / 2)}) + h
    69  }
    70  
    71  func addressToPubKeyHexWithLength(addr string, t *testing.T, d *RocksDB) string {
    72  	h := dbtestdata.AddressToPubKeyHex(addr, d.chainParser)
    73  	return hex.EncodeToString([]byte{byte(len(h))}) + h
    74  }
    75  
    76  func spentAddressToPubKeyHexWithLength(addr string, t *testing.T, d *RocksDB) string {
    77  	h := dbtestdata.AddressToPubKeyHex(addr, d.chainParser)
    78  	return hex.EncodeToString([]byte{byte(len(h) + 1)}) + h
    79  }
    80  
    81  func bigintToHex(i *big.Int) string {
    82  	b := make([]byte, maxPackedBigintBytes)
    83  	l := packBigint(i, b)
    84  	return hex.EncodeToString(b[:l])
    85  }
    86  
    87  func varuintToHex(i uint) string {
    88  	b := make([]byte, vlq.MaxLen64)
    89  	l := vlq.PutUint(b, uint64(i))
    90  	return hex.EncodeToString(b[:l])
    91  }
    92  
    93  func uintToHex(i uint32) string {
    94  	buf := make([]byte, 4)
    95  	binary.BigEndian.PutUint32(buf, i)
    96  	return hex.EncodeToString(buf)
    97  }
    98  
    99  // keyPair is used to compare given key value in DB with expected
   100  // for more complicated compares it is possible to specify CompareFunc
   101  type keyPair struct {
   102  	Key, Value  string
   103  	CompareFunc func(string) bool
   104  }
   105  
   106  func compareFuncBlockAddresses(t *testing.T, v string, expected []string) bool {
   107  	for _, e := range expected {
   108  		lb := len(v)
   109  		v = strings.Replace(v, e, "", 1)
   110  		if lb == len(v) {
   111  			t.Error(e, " not found in ", v)
   112  			return false
   113  		}
   114  	}
   115  	if len(v) != 0 {
   116  		t.Error("not expected content ", v)
   117  	}
   118  	return len(v) == 0
   119  }
   120  
   121  func checkColumn(d *RocksDB, col int, kp []keyPair) error {
   122  	sort.Slice(kp, func(i, j int) bool {
   123  		return kp[i].Key < kp[j].Key
   124  	})
   125  	it := d.db.NewIteratorCF(d.ro, d.cfh[col])
   126  	defer it.Close()
   127  	i := 0
   128  	for it.SeekToFirst(); it.Valid(); it.Next() {
   129  		if i >= len(kp) {
   130  			return errors.Errorf("Expected less rows in column %v", cfNames[col])
   131  		}
   132  		key := hex.EncodeToString(it.Key().Data())
   133  		if key != kp[i].Key {
   134  			return errors.Errorf("Incorrect key %v found in column %v row %v, expecting %v", key, cfNames[col], i, kp[i].Key)
   135  		}
   136  		val := hex.EncodeToString(it.Value().Data())
   137  		var valOK bool
   138  		if kp[i].CompareFunc == nil {
   139  			valOK = val == kp[i].Value
   140  		} else {
   141  			valOK = kp[i].CompareFunc(val)
   142  		}
   143  		if !valOK {
   144  			return errors.Errorf("Incorrect value %v found in column %v row %v key %v, expecting %v", val, cfNames[col], i, key, kp[i].Value)
   145  		}
   146  		i++
   147  	}
   148  	if i != len(kp) {
   149  		return errors.Errorf("Expected more rows in column %v: got %v, expected %v", cfNames[col], i, len(kp))
   150  	}
   151  	return nil
   152  }
   153  
   154  func verifyAfterUTXOBlock1(t *testing.T, d *RocksDB, afterDisconnect bool) {
   155  	if err := checkColumn(d, cfHeight, []keyPair{
   156  		keyPair{
   157  			"000370d5",
   158  			"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997" + uintToHex(1534858021) + varuintToHex(2) + varuintToHex(1234567),
   159  			nil,
   160  		},
   161  	}); err != nil {
   162  		{
   163  			t.Fatal(err)
   164  		}
   165  	}
   166  	// the vout is encoded as signed varint, i.e. value * 2 for non negative values
   167  	if err := checkColumn(d, cfAddresses, []keyPair{
   168  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr1, d.chainParser) + "000370d5", dbtestdata.TxidB1T1 + "00", nil},
   169  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser) + "000370d5", dbtestdata.TxidB1T1 + "02", nil},
   170  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser) + "000370d5", dbtestdata.TxidB1T2 + "00", nil},
   171  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser) + "000370d5", dbtestdata.TxidB1T2 + "02", nil},
   172  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser) + "000370d5", dbtestdata.TxidB1T2 + "04", nil},
   173  	}); err != nil {
   174  		{
   175  			t.Fatal(err)
   176  		}
   177  	}
   178  	if err := checkColumn(d, cfTxAddresses, []keyPair{
   179  		keyPair{
   180  			dbtestdata.TxidB1T1,
   181  			varuintToHex(225493) +
   182  				"00" +
   183  				"02" +
   184  				addressToPubKeyHexWithLength(dbtestdata.Addr1, t, d) + bigintToHex(dbtestdata.SatB1T1A1) +
   185  				addressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2),
   186  			nil,
   187  		},
   188  		keyPair{
   189  			dbtestdata.TxidB1T2,
   190  			varuintToHex(225493) +
   191  				"00" +
   192  				"03" +
   193  				addressToPubKeyHexWithLength(dbtestdata.Addr3, t, d) + bigintToHex(dbtestdata.SatB1T2A3) +
   194  				addressToPubKeyHexWithLength(dbtestdata.Addr4, t, d) + bigintToHex(dbtestdata.SatB1T2A4) +
   195  				addressToPubKeyHexWithLength(dbtestdata.Addr5, t, d) + bigintToHex(dbtestdata.SatB1T2A5),
   196  			nil,
   197  		},
   198  	}); err != nil {
   199  		{
   200  			t.Fatal(err)
   201  		}
   202  	}
   203  	if err := checkColumn(d, cfAddressBalance, []keyPair{
   204  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr1, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A1), nil},
   205  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A2), nil},
   206  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T2A3), nil},
   207  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T2A4), nil},
   208  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T2A5), nil},
   209  	}); err != nil {
   210  		{
   211  			t.Fatal(err)
   212  		}
   213  	}
   214  
   215  	var blockTxsKp []keyPair
   216  	if afterDisconnect {
   217  		blockTxsKp = []keyPair{}
   218  	} else {
   219  		blockTxsKp = []keyPair{
   220  			keyPair{
   221  				"000370d5",
   222  				dbtestdata.TxidB1T1 + "00" + dbtestdata.TxidB1T2 + "00",
   223  				nil,
   224  			},
   225  		}
   226  	}
   227  
   228  	if err := checkColumn(d, cfBlockTxs, blockTxsKp); err != nil {
   229  		{
   230  			t.Fatal(err)
   231  		}
   232  	}
   233  }
   234  
   235  func verifyAfterUTXOBlock2(t *testing.T, d *RocksDB) {
   236  	if err := checkColumn(d, cfHeight, []keyPair{
   237  		keyPair{
   238  			"000370d5",
   239  			"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997" + uintToHex(1534858021) + varuintToHex(2) + varuintToHex(1234567),
   240  			nil,
   241  		},
   242  		keyPair{
   243  			"000370d6",
   244  			"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6" + uintToHex(1534859123) + varuintToHex(4) + varuintToHex(2345678),
   245  			nil,
   246  		},
   247  	}); err != nil {
   248  		{
   249  			t.Fatal(err)
   250  		}
   251  	}
   252  	if err := checkColumn(d, cfAddresses, []keyPair{
   253  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr1, d.chainParser) + "000370d5", dbtestdata.TxidB1T1 + "00", nil},
   254  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser) + "000370d5", dbtestdata.TxidB1T1 + "02", nil},
   255  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser) + "000370d5", dbtestdata.TxidB1T2 + "00", nil},
   256  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser) + "000370d5", dbtestdata.TxidB1T2 + "02", nil},
   257  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser) + "000370d5", dbtestdata.TxidB1T2 + "04", nil},
   258  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr6, d.chainParser) + "000370d6", dbtestdata.TxidB2T1 + "00" + dbtestdata.TxidB2T2 + "01", nil},
   259  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr7, d.chainParser) + "000370d6", dbtestdata.TxidB2T1 + "02", nil},
   260  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr8, d.chainParser) + "000370d6", dbtestdata.TxidB2T2 + "00", nil},
   261  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr9, d.chainParser) + "000370d6", dbtestdata.TxidB2T2 + "02", nil},
   262  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser) + "000370d6", dbtestdata.TxidB2T1 + "01", nil},
   263  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser) + "000370d6", dbtestdata.TxidB2T1 + "03", nil},
   264  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser) + "000370d6", dbtestdata.TxidB2T3 + "00" + dbtestdata.TxidB2T3 + "01", nil},
   265  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.AddrA, d.chainParser) + "000370d6", dbtestdata.TxidB2T4 + "00", nil},
   266  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser) + "000370d6", dbtestdata.TxidB2T2 + "03", nil},
   267  	}); err != nil {
   268  		{
   269  			t.Fatal(err)
   270  		}
   271  	}
   272  	if err := checkColumn(d, cfTxAddresses, []keyPair{
   273  		keyPair{
   274  			dbtestdata.TxidB1T1,
   275  			varuintToHex(225493) +
   276  				"00" +
   277  				"02" +
   278  				addressToPubKeyHexWithLength(dbtestdata.Addr1, t, d) + bigintToHex(dbtestdata.SatB1T1A1) +
   279  				spentAddressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2),
   280  			nil,
   281  		},
   282  		keyPair{
   283  			dbtestdata.TxidB1T2,
   284  			varuintToHex(225493) +
   285  				"00" +
   286  				"03" +
   287  				spentAddressToPubKeyHexWithLength(dbtestdata.Addr3, t, d) + bigintToHex(dbtestdata.SatB1T2A3) +
   288  				spentAddressToPubKeyHexWithLength(dbtestdata.Addr4, t, d) + bigintToHex(dbtestdata.SatB1T2A4) +
   289  				spentAddressToPubKeyHexWithLength(dbtestdata.Addr5, t, d) + bigintToHex(dbtestdata.SatB1T2A5),
   290  			nil,
   291  		},
   292  		keyPair{
   293  			dbtestdata.TxidB2T1,
   294  			varuintToHex(225494) +
   295  				"02" +
   296  				inputAddressToPubKeyHexWithLength(dbtestdata.Addr3, t, d) + bigintToHex(dbtestdata.SatB1T2A3) +
   297  				inputAddressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2) +
   298  				"02" +
   299  				spentAddressToPubKeyHexWithLength(dbtestdata.Addr6, t, d) + bigintToHex(dbtestdata.SatB2T1A6) +
   300  				addressToPubKeyHexWithLength(dbtestdata.Addr7, t, d) + bigintToHex(dbtestdata.SatB2T1A7),
   301  			nil,
   302  		},
   303  		keyPair{
   304  			dbtestdata.TxidB2T2,
   305  			varuintToHex(225494) +
   306  				"02" +
   307  				inputAddressToPubKeyHexWithLength(dbtestdata.Addr6, t, d) + bigintToHex(dbtestdata.SatB2T1A6) +
   308  				inputAddressToPubKeyHexWithLength(dbtestdata.Addr4, t, d) + bigintToHex(dbtestdata.SatB1T2A4) +
   309  				"02" +
   310  				addressToPubKeyHexWithLength(dbtestdata.Addr8, t, d) + bigintToHex(dbtestdata.SatB2T2A8) +
   311  				addressToPubKeyHexWithLength(dbtestdata.Addr9, t, d) + bigintToHex(dbtestdata.SatB2T2A9),
   312  			nil,
   313  		},
   314  		keyPair{
   315  			dbtestdata.TxidB2T3,
   316  			varuintToHex(225494) +
   317  				"01" +
   318  				inputAddressToPubKeyHexWithLength(dbtestdata.Addr5, t, d) + bigintToHex(dbtestdata.SatB1T2A5) +
   319  				"01" +
   320  				addressToPubKeyHexWithLength(dbtestdata.Addr5, t, d) + bigintToHex(dbtestdata.SatB2T3A5),
   321  			nil,
   322  		},
   323  		keyPair{
   324  			dbtestdata.TxidB2T4,
   325  			varuintToHex(225494) +
   326  				"01" + inputAddressToPubKeyHexWithLength("", t, d) + bigintToHex(dbtestdata.SatZero) +
   327  				"02" +
   328  				addressToPubKeyHexWithLength(dbtestdata.AddrA, t, d) + bigintToHex(dbtestdata.SatB2T4AA) +
   329  				addressToPubKeyHexWithLength("", t, d) + bigintToHex(dbtestdata.SatZero),
   330  			nil,
   331  		},
   332  	}); err != nil {
   333  		{
   334  			t.Fatal(err)
   335  		}
   336  	}
   337  	if err := checkColumn(d, cfAddressBalance, []keyPair{
   338  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr1, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A1), nil},
   339  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T1A2) + bigintToHex(dbtestdata.SatZero), nil},
   340  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T2A3) + bigintToHex(dbtestdata.SatZero), nil},
   341  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T2A4) + bigintToHex(dbtestdata.SatZero), nil},
   342  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T2A5) + bigintToHex(dbtestdata.SatB2T3A5), nil},
   343  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr6, d.chainParser), "02" + bigintToHex(dbtestdata.SatB2T1A6) + bigintToHex(dbtestdata.SatZero), nil},
   344  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr7, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T1A7), nil},
   345  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr8, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T2A8), nil},
   346  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr9, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T2A9), nil},
   347  		keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.AddrA, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T4AA), nil},
   348  	}); err != nil {
   349  		{
   350  			t.Fatal(err)
   351  		}
   352  	}
   353  	if err := checkColumn(d, cfBlockTxs, []keyPair{
   354  		keyPair{
   355  			"000370d6",
   356  			dbtestdata.TxidB2T1 + "02" + dbtestdata.TxidB1T2 + "00" + dbtestdata.TxidB1T1 + "02" +
   357  				dbtestdata.TxidB2T2 + "02" + dbtestdata.TxidB2T1 + "00" + dbtestdata.TxidB1T2 + "02" +
   358  				dbtestdata.TxidB2T3 + "01" + dbtestdata.TxidB1T2 + "04" +
   359  				dbtestdata.TxidB2T4 + "01" + "0000000000000000000000000000000000000000000000000000000000000000" + "00",
   360  			nil,
   361  		},
   362  	}); err != nil {
   363  		{
   364  			t.Fatal(err)
   365  		}
   366  	}
   367  }
   368  
   369  type txidVoutOutput struct {
   370  	txid     string
   371  	vout     uint32
   372  	isOutput bool
   373  }
   374  
   375  func verifyGetTransactions(t *testing.T, d *RocksDB, addr string, low, high uint32, wantTxids []txidVoutOutput, wantErr error) {
   376  	gotTxids := make([]txidVoutOutput, 0)
   377  	addToTxids := func(txid string, vout uint32, isOutput bool) error {
   378  		gotTxids = append(gotTxids, txidVoutOutput{txid, vout, isOutput})
   379  		return nil
   380  	}
   381  	if err := d.GetTransactions(addr, low, high, addToTxids); err != nil {
   382  		if wantErr == nil || wantErr.Error() != err.Error() {
   383  			t.Fatal(err)
   384  		}
   385  	}
   386  	if !reflect.DeepEqual(gotTxids, wantTxids) {
   387  		t.Errorf("GetTransactions() = %v, want %v", gotTxids, wantTxids)
   388  	}
   389  }
   390  
   391  type testBitcoinParser struct {
   392  	*btc.BitcoinParser
   393  }
   394  
   395  // override PackTx and UnpackTx to default BaseParser functionality
   396  // BitcoinParser uses tx hex which is not available for the test transactions
   397  func (p *testBitcoinParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
   398  	return p.BaseParser.PackTx(tx, height, blockTime)
   399  }
   400  
   401  func (p *testBitcoinParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
   402  	return p.BaseParser.UnpackTx(buf)
   403  }
   404  
   405  func testTxCache(t *testing.T, d *RocksDB, b *bchain.Block, tx *bchain.Tx) {
   406  	if err := d.PutTx(tx, b.Height, tx.Blocktime); err != nil {
   407  		t.Fatal(err)
   408  	}
   409  	gtx, height, err := d.GetTx(tx.Txid)
   410  	if err != nil {
   411  		t.Fatal(err)
   412  	}
   413  	if b.Height != height {
   414  		t.Fatalf("GetTx: got height %v, expected %v", height, b.Height)
   415  	}
   416  	// Confirmations are not stored in the DB, set them from input tx
   417  	gtx.Confirmations = tx.Confirmations
   418  	if fmt.Sprint(gtx) != fmt.Sprint(tx) {
   419  		t.Errorf("GetTx: %v, want %v", gtx, tx)
   420  	}
   421  	if err := d.DeleteTx(tx.Txid); err != nil {
   422  		t.Fatal(err)
   423  	}
   424  }
   425  
   426  // TestRocksDB_Index_UTXO is an integration test probing the whole indexing functionality for UTXO chains
   427  // It does the following:
   428  // 1) Connect two blocks (inputs from 2nd block are spending some outputs from the 1st block)
   429  // 2) GetTransactions for various addresses / low-high ranges
   430  // 3) GetBestBlock, GetBlockHash
   431  // 4) Test tx caching functionality
   432  // 5) Disconnect block 2 - expect error
   433  // 6) Disconnect the block 2 using BlockTxs column
   434  // 7) Reconnect block 2 and check
   435  // After each step, the content of DB is examined and any difference against expected state is regarded as failure
   436  func TestRocksDB_Index_UTXO(t *testing.T) {
   437  	d := setupRocksDB(t, &testBitcoinParser{
   438  		BitcoinParser: bitcoinTestnetParser(),
   439  	})
   440  	defer closeAndDestroyRocksDB(t, d)
   441  
   442  	// connect 1st block - will log warnings about missing UTXO transactions in txAddresses column
   443  	block1 := dbtestdata.GetTestUTXOBlock1(d.chainParser)
   444  	if err := d.ConnectBlock(block1); err != nil {
   445  		t.Fatal(err)
   446  	}
   447  	verifyAfterUTXOBlock1(t, d, false)
   448  
   449  	// connect 2nd block - use some outputs from the 1st block as the inputs and 1 input uses tx from the same block
   450  	block2 := dbtestdata.GetTestUTXOBlock2(d.chainParser)
   451  	if err := d.ConnectBlock(block2); err != nil {
   452  		t.Fatal(err)
   453  	}
   454  	verifyAfterUTXOBlock2(t, d)
   455  
   456  	// get transactions for various addresses / low-high ranges
   457  	verifyGetTransactions(t, d, dbtestdata.Addr2, 0, 1000000, []txidVoutOutput{
   458  		txidVoutOutput{dbtestdata.TxidB1T1, 1, true},
   459  		txidVoutOutput{dbtestdata.TxidB2T1, 1, false},
   460  	}, nil)
   461  	verifyGetTransactions(t, d, dbtestdata.Addr2, 225493, 225493, []txidVoutOutput{
   462  		txidVoutOutput{dbtestdata.TxidB1T1, 1, true},
   463  	}, nil)
   464  	verifyGetTransactions(t, d, dbtestdata.Addr2, 225494, 1000000, []txidVoutOutput{
   465  		txidVoutOutput{dbtestdata.TxidB2T1, 1, false},
   466  	}, nil)
   467  	verifyGetTransactions(t, d, dbtestdata.Addr2, 500000, 1000000, []txidVoutOutput{}, nil)
   468  	verifyGetTransactions(t, d, dbtestdata.Addr8, 0, 1000000, []txidVoutOutput{
   469  		txidVoutOutput{dbtestdata.TxidB2T2, 0, true},
   470  	}, nil)
   471  	verifyGetTransactions(t, d, "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eBad", 500000, 1000000, []txidVoutOutput{}, errors.New("checksum mismatch"))
   472  
   473  	// GetBestBlock
   474  	height, hash, err := d.GetBestBlock()
   475  	if err != nil {
   476  		t.Fatal(err)
   477  	}
   478  	if height != 225494 {
   479  		t.Fatalf("GetBestBlock: got height %v, expected %v", height, 225494)
   480  	}
   481  	if hash != "00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6" {
   482  		t.Fatalf("GetBestBlock: got hash %v, expected %v", hash, "00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6")
   483  	}
   484  
   485  	// GetBlockHash
   486  	hash, err = d.GetBlockHash(225493)
   487  	if err != nil {
   488  		t.Fatal(err)
   489  	}
   490  	if hash != "0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997" {
   491  		t.Fatalf("GetBlockHash: got hash %v, expected %v", hash, "0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997")
   492  	}
   493  
   494  	// Not connected block
   495  	hash, err = d.GetBlockHash(225495)
   496  	if err != nil {
   497  		t.Fatal(err)
   498  	}
   499  	if hash != "" {
   500  		t.Fatalf("GetBlockHash: got hash '%v', expected ''", hash)
   501  	}
   502  
   503  	// GetBlockHash
   504  	info, err := d.GetBlockInfo(225494)
   505  	if err != nil {
   506  		t.Fatal(err)
   507  	}
   508  	iw := &BlockInfo{
   509  		Hash:   "00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6",
   510  		Txs:    4,
   511  		Size:   2345678,
   512  		Time:   1534859123,
   513  		Height: 225494,
   514  	}
   515  	if !reflect.DeepEqual(info, iw) {
   516  		t.Errorf("GetAddressBalance() = %+v, want %+v", info, iw)
   517  	}
   518  
   519  	// Test tx caching functionality, leave one tx in db to test cleanup in DisconnectBlock
   520  	testTxCache(t, d, block1, &block1.Txs[0])
   521  	testTxCache(t, d, block2, &block2.Txs[0])
   522  	if err = d.PutTx(&block2.Txs[1], block2.Height, block2.Txs[1].Blocktime); err != nil {
   523  		t.Fatal(err)
   524  	}
   525  	// check that there is only the last tx in the cache
   526  	packedTx, err := d.chainParser.PackTx(&block2.Txs[1], block2.Height, block2.Txs[1].Blocktime)
   527  	if err := checkColumn(d, cfTransactions, []keyPair{
   528  		keyPair{block2.Txs[1].Txid, hex.EncodeToString(packedTx), nil},
   529  	}); err != nil {
   530  		{
   531  			t.Fatal(err)
   532  		}
   533  	}
   534  
   535  	// DisconnectBlock for UTXO chains is not possible
   536  	err = d.DisconnectBlock(block2)
   537  	if err == nil || err.Error() != "DisconnectBlock is not supported for UTXO chains" {
   538  		t.Fatal(err)
   539  	}
   540  	verifyAfterUTXOBlock2(t, d)
   541  
   542  	// try to disconnect both blocks, however only the last one is kept, it is not possible
   543  	err = d.DisconnectBlockRangeUTXO(225493, 225494)
   544  	if err == nil || err.Error() != "Cannot disconnect blocks with height 225493 and lower. It is necessary to rebuild index." {
   545  		t.Fatal(err)
   546  	}
   547  	verifyAfterUTXOBlock2(t, d)
   548  
   549  	// disconnect the 2nd block, verify that the db contains only data from the 1st block with restored unspentTxs
   550  	// and that the cached tx is removed
   551  	err = d.DisconnectBlockRangeUTXO(225494, 225494)
   552  	if err != nil {
   553  		t.Fatal(err)
   554  	}
   555  	verifyAfterUTXOBlock1(t, d, true)
   556  	if err := checkColumn(d, cfTransactions, []keyPair{}); err != nil {
   557  		{
   558  			t.Fatal(err)
   559  		}
   560  	}
   561  
   562  	// connect block again and verify the state of db
   563  	if err := d.ConnectBlock(block2); err != nil {
   564  		t.Fatal(err)
   565  	}
   566  	verifyAfterUTXOBlock2(t, d)
   567  
   568  	// test public methods for address balance and tx addresses
   569  
   570  	ab, err := d.GetAddressBalance(dbtestdata.Addr5)
   571  	if err != nil {
   572  		t.Fatal(err)
   573  	}
   574  	abw := &AddrBalance{
   575  		Txs:        2,
   576  		SentSat:    *dbtestdata.SatB1T2A5,
   577  		BalanceSat: *dbtestdata.SatB2T3A5,
   578  	}
   579  	if !reflect.DeepEqual(ab, abw) {
   580  		t.Errorf("GetAddressBalance() = %+v, want %+v", ab, abw)
   581  	}
   582  	rs := ab.ReceivedSat()
   583  	rsw := dbtestdata.SatB1T2A5.Add(dbtestdata.SatB1T2A5, dbtestdata.SatB2T3A5)
   584  	if rs.Cmp(rsw) != 0 {
   585  		t.Errorf("GetAddressBalance().ReceivedSat() = %v, want %v", rs, rsw)
   586  	}
   587  
   588  	ta, err := d.GetTxAddresses(dbtestdata.TxidB2T1)
   589  	if err != nil {
   590  		t.Fatal(err)
   591  	}
   592  	taw := &TxAddresses{
   593  		Height: 225494,
   594  		Inputs: []TxInput{
   595  			{
   596  				AddrDesc: addressToAddrDesc(dbtestdata.Addr3, d.chainParser),
   597  				ValueSat: *dbtestdata.SatB1T2A3,
   598  			},
   599  			{
   600  				AddrDesc: addressToAddrDesc(dbtestdata.Addr2, d.chainParser),
   601  				ValueSat: *dbtestdata.SatB1T1A2,
   602  			},
   603  		},
   604  		Outputs: []TxOutput{
   605  			{
   606  				AddrDesc: addressToAddrDesc(dbtestdata.Addr6, d.chainParser),
   607  				Spent:    true,
   608  				ValueSat: *dbtestdata.SatB2T1A6,
   609  			},
   610  			{
   611  				AddrDesc: addressToAddrDesc(dbtestdata.Addr7, d.chainParser),
   612  				Spent:    false,
   613  				ValueSat: *dbtestdata.SatB2T1A7,
   614  			},
   615  		},
   616  	}
   617  	if !reflect.DeepEqual(ta, taw) {
   618  		t.Errorf("GetTxAddresses() = %+v, want %+v", ta, taw)
   619  	}
   620  	ia, _, err := ta.Inputs[0].Addresses(d.chainParser)
   621  	if err != nil {
   622  		t.Fatal(err)
   623  	}
   624  	if !reflect.DeepEqual(ia, []string{dbtestdata.Addr3}) {
   625  		t.Errorf("GetTxAddresses().Inputs[0].Addresses() = %v, want %v", ia, []string{dbtestdata.Addr3})
   626  	}
   627  
   628  }
   629  
   630  func Test_BulkConnect_UTXO(t *testing.T) {
   631  	d := setupRocksDB(t, &testBitcoinParser{
   632  		BitcoinParser: bitcoinTestnetParser(),
   633  	})
   634  	defer closeAndDestroyRocksDB(t, d)
   635  
   636  	bc, err := d.InitBulkConnect()
   637  	if err != nil {
   638  		t.Fatal(err)
   639  	}
   640  
   641  	if d.is.DbState != common.DbStateInconsistent {
   642  		t.Fatal("DB not in DbStateInconsistent")
   643  	}
   644  
   645  	if err := bc.ConnectBlock(dbtestdata.GetTestUTXOBlock1(d.chainParser), false); err != nil {
   646  		t.Fatal(err)
   647  	}
   648  	if err := checkColumn(d, cfBlockTxs, []keyPair{}); err != nil {
   649  		{
   650  			t.Fatal(err)
   651  		}
   652  	}
   653  
   654  	if err := bc.ConnectBlock(dbtestdata.GetTestUTXOBlock2(d.chainParser), true); err != nil {
   655  		t.Fatal(err)
   656  	}
   657  
   658  	if err := bc.Close(); err != nil {
   659  		t.Fatal(err)
   660  	}
   661  
   662  	if d.is.DbState != common.DbStateOpen {
   663  		t.Fatal("DB not in DbStateOpen")
   664  	}
   665  
   666  	verifyAfterUTXOBlock2(t, d)
   667  }
   668  
   669  func Test_packBigint_unpackBigint(t *testing.T) {
   670  	bigbig1, _ := big.NewInt(0).SetString("123456789123456789012345", 10)
   671  	bigbig2, _ := big.NewInt(0).SetString("12345678912345678901234512389012345123456789123456789012345123456789123456789012345", 10)
   672  	bigbigbig := big.NewInt(0)
   673  	bigbigbig.Mul(bigbig2, bigbig2)
   674  	bigbigbig.Mul(bigbigbig, bigbigbig)
   675  	bigbigbig.Mul(bigbigbig, bigbigbig)
   676  	tests := []struct {
   677  		name      string
   678  		bi        *big.Int
   679  		buf       []byte
   680  		toobiglen int
   681  	}{
   682  		{
   683  			name: "0",
   684  			bi:   big.NewInt(0),
   685  			buf:  make([]byte, maxPackedBigintBytes),
   686  		},
   687  		{
   688  			name: "1",
   689  			bi:   big.NewInt(1),
   690  			buf:  make([]byte, maxPackedBigintBytes),
   691  		},
   692  		{
   693  			name: "54321",
   694  			bi:   big.NewInt(54321),
   695  			buf:  make([]byte, 249),
   696  		},
   697  		{
   698  			name: "12345678",
   699  			bi:   big.NewInt(12345678),
   700  			buf:  make([]byte, maxPackedBigintBytes),
   701  		},
   702  		{
   703  			name: "123456789123456789",
   704  			bi:   big.NewInt(123456789123456789),
   705  			buf:  make([]byte, maxPackedBigintBytes),
   706  		},
   707  		{
   708  			name: "bigbig1",
   709  			bi:   bigbig1,
   710  			buf:  make([]byte, maxPackedBigintBytes),
   711  		},
   712  		{
   713  			name: "bigbig2",
   714  			bi:   bigbig2,
   715  			buf:  make([]byte, maxPackedBigintBytes),
   716  		},
   717  		{
   718  			name:      "bigbigbig",
   719  			bi:        bigbigbig,
   720  			buf:       make([]byte, maxPackedBigintBytes),
   721  			toobiglen: 242,
   722  		},
   723  	}
   724  	for _, tt := range tests {
   725  		t.Run(tt.name, func(t *testing.T) {
   726  			// packBigint
   727  			got := packBigint(tt.bi, tt.buf)
   728  			if tt.toobiglen == 0 {
   729  				// create buffer that we expect
   730  				bb := tt.bi.Bytes()
   731  				want := append([]byte(nil), byte(len(bb)))
   732  				want = append(want, bb...)
   733  				if got != len(want) {
   734  					t.Errorf("packBigint() = %v, want %v", got, len(want))
   735  				}
   736  				for i := 0; i < got; i++ {
   737  					if tt.buf[i] != want[i] {
   738  						t.Errorf("packBigint() buf = %v, want %v", tt.buf[:got], want)
   739  						break
   740  					}
   741  				}
   742  				// unpackBigint
   743  				got1, got2 := unpackBigint(tt.buf)
   744  				if got2 != len(want) {
   745  					t.Errorf("unpackBigint() = %v, want %v", got2, len(want))
   746  				}
   747  				if tt.bi.Cmp(&got1) != 0 {
   748  					t.Errorf("unpackBigint() = %v, want %v", got1, tt.bi)
   749  				}
   750  			} else {
   751  				if got != tt.toobiglen {
   752  					t.Errorf("packBigint() = %v, want toobiglen %v", got, tt.toobiglen)
   753  				}
   754  			}
   755  		})
   756  	}
   757  }
   758  
   759  func addressToAddrDesc(addr string, parser bchain.BlockChainParser) []byte {
   760  	b, err := parser.GetAddrDescFromAddress(addr)
   761  	if err != nil {
   762  		panic(err)
   763  	}
   764  	return b
   765  }
   766  
   767  func Test_packTxAddresses_unpackTxAddresses(t *testing.T) {
   768  	parser := bitcoinTestnetParser()
   769  	tests := []struct {
   770  		name string
   771  		hex  string
   772  		data *TxAddresses
   773  	}{
   774  		{
   775  			name: "1",
   776  			hex:  "7b0216001443aac20a116e09ea4f7914be1c55e4c17aa600b70016001454633aa8bd2e552bd4e89c01e73c1b7905eb58460811207cb68a199872012d001443aac20a116e09ea4f7914be1c55e4c17aa600b70101",
   777  			data: &TxAddresses{
   778  				Height: 123,
   779  				Inputs: []TxInput{
   780  					{
   781  						AddrDesc: addressToAddrDesc("tb1qgw4vyzs3dcy75nmezjlpc40yc9a2vq9hghdyt2", parser),
   782  						ValueSat: *big.NewInt(0),
   783  					},
   784  					{
   785  						AddrDesc: addressToAddrDesc("tb1q233n429a9e2jh48gnsq7w0qm0yz7kkzx0qczw8", parser),
   786  						ValueSat: *big.NewInt(1234123421342341234),
   787  					},
   788  				},
   789  				Outputs: []TxOutput{
   790  					{
   791  						AddrDesc: addressToAddrDesc("tb1qgw4vyzs3dcy75nmezjlpc40yc9a2vq9hghdyt2", parser),
   792  						ValueSat: *big.NewInt(1),
   793  						Spent:    true,
   794  					},
   795  				},
   796  			},
   797  		},
   798  		{
   799  			name: "2",
   800  			hex:  "e0390317a9149eb21980dc9d413d8eac27314938b9da920ee53e8705021918f2c017a91409f70b896169c37981d2b54b371df0d81a136a2c870501dd7e28c017a914e371782582a4addb541362c55565d2cdf56f6498870501a1e35ec0052fa9141d9ca71efa36d814424ea6ca1437e67287aebe348705012aadcac02ea91424fbc77cdc62702ade74dcf989c15e5d3f9240bc870501664894c02fa914afbfb74ee994c7d45f6698738bc4226d065266f7870501a1e35ec03276a914d2a37ce20ac9ec4f15dd05a7c6e8e9fbdb99850e88ac043b9943603376a9146b2044146a4438e6e5bfbc65f147afeb64d14fbb88ac05012a05f200",
   801  			data: &TxAddresses{
   802  				Height: 12345,
   803  				Inputs: []TxInput{
   804  					{
   805  						AddrDesc: addressToAddrDesc("2N7iL7AvS4LViugwsdjTB13uN4T7XhV1bCP", parser),
   806  						ValueSat: *big.NewInt(9011000000),
   807  					},
   808  					{
   809  						AddrDesc: addressToAddrDesc("2Mt9v216YiNBAzobeNEzd4FQweHrGyuRHze", parser),
   810  						ValueSat: *big.NewInt(8011000000),
   811  					},
   812  					{
   813  						AddrDesc: addressToAddrDesc("2NDyqJpHvHnqNtL1F9xAeCWMAW8WLJmEMyD", parser),
   814  						ValueSat: *big.NewInt(7011000000),
   815  					},
   816  				},
   817  				Outputs: []TxOutput{
   818  					{
   819  						AddrDesc: addressToAddrDesc("2MuwoFGwABMakU7DCpdGDAKzyj2nTyRagDP", parser),
   820  						ValueSat: *big.NewInt(5011000000),
   821  						Spent:    true,
   822  					},
   823  					{
   824  						AddrDesc: addressToAddrDesc("2Mvcmw7qkGXNWzkfH1EjvxDcNRGL1Kf2tEM", parser),
   825  						ValueSat: *big.NewInt(6011000000),
   826  					},
   827  					{
   828  						AddrDesc: addressToAddrDesc("2N9GVuX3XJGHS5MCdgn97gVezc6EgvzikTB", parser),
   829  						ValueSat: *big.NewInt(7011000000),
   830  						Spent:    true,
   831  					},
   832  					{
   833  						AddrDesc: addressToAddrDesc("mzii3fuRSpExMLJEHdHveW8NmiX8MPgavk", parser),
   834  						ValueSat: *big.NewInt(999900000),
   835  					},
   836  					{
   837  						AddrDesc: addressToAddrDesc("mqHPFTRk23JZm9W1ANuEFtwTYwxjESSgKs", parser),
   838  						ValueSat: *big.NewInt(5000000000),
   839  						Spent:    true,
   840  					},
   841  				},
   842  			},
   843  		},
   844  		{
   845  			name: "empty address",
   846  			hex:  "baef9a1501000204d2020002162e010162",
   847  			data: &TxAddresses{
   848  				Height: 123456789,
   849  				Inputs: []TxInput{
   850  					{
   851  						AddrDesc: []byte{},
   852  						ValueSat: *big.NewInt(1234),
   853  					},
   854  				},
   855  				Outputs: []TxOutput{
   856  					{
   857  						AddrDesc: []byte{},
   858  						ValueSat: *big.NewInt(5678),
   859  					},
   860  					{
   861  						AddrDesc: []byte{},
   862  						ValueSat: *big.NewInt(98),
   863  						Spent:    true,
   864  					},
   865  				},
   866  			},
   867  		},
   868  		{
   869  			name: "empty",
   870  			hex:  "000000",
   871  			data: &TxAddresses{
   872  				Inputs:  []TxInput{},
   873  				Outputs: []TxOutput{},
   874  			},
   875  		},
   876  	}
   877  	varBuf := make([]byte, maxPackedBigintBytes)
   878  	buf := make([]byte, 1024)
   879  	for _, tt := range tests {
   880  		t.Run(tt.name, func(t *testing.T) {
   881  			b := packTxAddresses(tt.data, buf, varBuf)
   882  			hex := hex.EncodeToString(b)
   883  			if !reflect.DeepEqual(hex, tt.hex) {
   884  				t.Errorf("packTxAddresses() = %v, want %v", hex, tt.hex)
   885  			}
   886  			got1, err := unpackTxAddresses(b)
   887  			if err != nil {
   888  				t.Errorf("unpackTxAddresses() error = %v", err)
   889  				return
   890  			}
   891  			if !reflect.DeepEqual(got1, tt.data) {
   892  				t.Errorf("unpackTxAddresses() = %+v, want %+v", got1, tt.data)
   893  			}
   894  		})
   895  	}
   896  }