github.com/bchainhub/blockbook@v0.3.2/db/rocksdb_ethereumtype_test.go (about)

     1  // +build unittest
     2  
     3  package db
     4  
     5  import (
     6  	"blockbook/bchain/coins/eth"
     7  	"blockbook/tests/dbtestdata"
     8  	"encoding/hex"
     9  	"reflect"
    10  	"testing"
    11  
    12  	"github.com/juju/errors"
    13  )
    14  
    15  type testEthereumParser struct {
    16  	*eth.EthereumParser
    17  }
    18  
    19  func ethereumTestnetParser() *eth.EthereumParser {
    20  	return eth.NewEthereumParser(1)
    21  }
    22  
    23  func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect bool) {
    24  	if err := checkColumn(d, cfHeight, []keyPair{
    25  		{
    26  			"0041eee8",
    27  			"c7b98df95acfd11c51ba25611a39e004fe56c8fdfc1582af99354fcd09c17b11" + uintToHex(1534858022) + varuintToHex(2) + varuintToHex(31839),
    28  			nil,
    29  		},
    30  	}); err != nil {
    31  		{
    32  			t.Fatal(err)
    33  		}
    34  	}
    35  	if err := checkColumn(d, cfAddresses, []keyPair{
    36  		{addressKeyHex(dbtestdata.EthAddr3e, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T1, []int32{^0}), nil},
    37  		{addressKeyHex(dbtestdata.EthAddr55, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{1}) + txIndexesHex(dbtestdata.EthTxidB1T1, []int32{0}), nil},
    38  		{addressKeyHex(dbtestdata.EthAddr20, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^0, ^1}), nil},
    39  		{addressKeyHex(dbtestdata.EthAddrContract4a, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{0}), nil},
    40  	}); err != nil {
    41  		{
    42  			t.Fatal(err)
    43  		}
    44  	}
    45  
    46  	if err := checkColumn(d, cfAddressContracts, []keyPair{
    47  		{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "0101", nil},
    48  		{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser), "0201" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil},
    49  		{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser), "0101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil},
    50  		{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "0101", nil},
    51  	}); err != nil {
    52  		{
    53  			t.Fatal(err)
    54  		}
    55  	}
    56  
    57  	var blockTxsKp []keyPair
    58  	if afterDisconnect {
    59  		blockTxsKp = []keyPair{}
    60  	} else {
    61  		blockTxsKp = []keyPair{
    62  			{
    63  				"0041eee8",
    64  				dbtestdata.EthTxidB1T1 +
    65  					dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + "00" +
    66  					dbtestdata.EthTxidB1T2 +
    67  					dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) +
    68  					"02" +
    69  					dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) +
    70  					dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser),
    71  				nil,
    72  			},
    73  		}
    74  	}
    75  	if err := checkColumn(d, cfBlockTxs, blockTxsKp); err != nil {
    76  		{
    77  			t.Fatal(err)
    78  		}
    79  	}
    80  }
    81  
    82  func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB) {
    83  	if err := checkColumn(d, cfHeight, []keyPair{
    84  		{
    85  			"0041eee8",
    86  			"c7b98df95acfd11c51ba25611a39e004fe56c8fdfc1582af99354fcd09c17b11" + uintToHex(1534858022) + varuintToHex(2) + varuintToHex(31839),
    87  			nil,
    88  		},
    89  		{
    90  			"0041eee9",
    91  			"2b57e15e93a0ed197417a34c2498b7187df79099572c04a6b6e6ff418f74e6ee" + uintToHex(1534859988) + varuintToHex(2) + varuintToHex(2345678),
    92  			nil,
    93  		},
    94  	}); err != nil {
    95  		{
    96  			t.Fatal(err)
    97  		}
    98  	}
    99  	if err := checkColumn(d, cfAddresses, []keyPair{
   100  		{addressKeyHex(dbtestdata.EthAddr3e, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T1, []int32{^0}), nil},
   101  		{addressKeyHex(dbtestdata.EthAddr55, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{1}) + txIndexesHex(dbtestdata.EthTxidB1T1, []int32{0}), nil},
   102  		{addressKeyHex(dbtestdata.EthAddr20, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^0, ^1}), nil},
   103  		{addressKeyHex(dbtestdata.EthAddrContract4a, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{0}), nil},
   104  		{addressKeyHex(dbtestdata.EthAddr55, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^2, 1}) + txIndexesHex(dbtestdata.EthTxidB2T1, []int32{^0}), nil},
   105  		{addressKeyHex(dbtestdata.EthAddr9f, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T1, []int32{0}), nil},
   106  		{addressKeyHex(dbtestdata.EthAddr4b, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^0, 1, ^2, 2, ^1}), nil},
   107  		{addressKeyHex(dbtestdata.EthAddr7b, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^1, 2}), nil},
   108  		{addressKeyHex(dbtestdata.EthAddrContract47, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{0}), nil},
   109  	}); err != nil {
   110  		{
   111  			t.Fatal(err)
   112  		}
   113  	}
   114  
   115  	if err := checkColumn(d, cfAddressContracts, []keyPair{
   116  		{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "0101", nil},
   117  		{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser), "0402" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "01", nil},
   118  		{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser), "0101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil},
   119  		{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "0101", nil},
   120  		{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "0101", nil},
   121  		{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser), "0101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02", nil},
   122  		{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser), "0100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "01", nil},
   123  		{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract47, d.chainParser), "0101", nil},
   124  	}); err != nil {
   125  		{
   126  			t.Fatal(err)
   127  		}
   128  	}
   129  
   130  	if err := checkColumn(d, cfBlockTxs, []keyPair{
   131  		{
   132  			"0041eee9",
   133  			dbtestdata.EthTxidB2T1 +
   134  				dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser) + "00" +
   135  				dbtestdata.EthTxidB2T2 +
   136  				dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract47, d.chainParser) +
   137  				"08" +
   138  				dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) +
   139  				dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) +
   140  				dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) +
   141  				dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) +
   142  				dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) +
   143  				dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) +
   144  				dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) +
   145  				dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser),
   146  			nil,
   147  		},
   148  	}); err != nil {
   149  		{
   150  			t.Fatal(err)
   151  		}
   152  	}
   153  }
   154  
   155  // TestRocksDB_Index_EthereumType is an integration test probing the whole indexing functionality for EthereumType chains
   156  // It does the following:
   157  // 1) Connect two blocks (inputs from 2nd block are spending some outputs from the 1st block)
   158  // 2) GetTransactions for various addresses / low-high ranges
   159  // 3) GetBestBlock, GetBlockHash
   160  // 4) Test tx caching functionality
   161  // 5) Disconnect the block 2 using BlockTxs column
   162  // 6) Reconnect block 2 and check
   163  // After each step, the content of DB is examined and any difference against expected state is regarded as failure
   164  func TestRocksDB_Index_EthereumType(t *testing.T) {
   165  	d := setupRocksDB(t, &testEthereumParser{
   166  		EthereumParser: ethereumTestnetParser(),
   167  	})
   168  	defer closeAndDestroyRocksDB(t, d)
   169  
   170  	if len(d.is.BlockTimes) != 0 {
   171  		t.Fatal("Expecting is.BlockTimes 0, got ", len(d.is.BlockTimes))
   172  	}
   173  
   174  	// connect 1st block
   175  	block1 := dbtestdata.GetTestEthereumTypeBlock1(d.chainParser)
   176  	if err := d.ConnectBlock(block1); err != nil {
   177  		t.Fatal(err)
   178  	}
   179  	verifyAfterEthereumTypeBlock1(t, d, false)
   180  
   181  	if len(d.is.BlockTimes) != 1 {
   182  		t.Fatal("Expecting is.BlockTimes 1, got ", len(d.is.BlockTimes))
   183  	}
   184  
   185  	// connect 2nd block
   186  	block2 := dbtestdata.GetTestEthereumTypeBlock2(d.chainParser)
   187  	if err := d.ConnectBlock(block2); err != nil {
   188  		t.Fatal(err)
   189  	}
   190  	verifyAfterEthereumTypeBlock2(t, d)
   191  
   192  	if len(d.is.BlockTimes) != 2 {
   193  		t.Fatal("Expecting is.BlockTimes 2, got ", len(d.is.BlockTimes))
   194  	}
   195  
   196  	// get transactions for various addresses / low-high ranges
   197  	verifyGetTransactions(t, d, "0x"+dbtestdata.EthAddr55, 0, 10000000, []txidIndex{
   198  		{"0x" + dbtestdata.EthTxidB2T2, ^2},
   199  		{"0x" + dbtestdata.EthTxidB2T2, 1},
   200  		{"0x" + dbtestdata.EthTxidB2T1, ^0},
   201  		{"0x" + dbtestdata.EthTxidB1T2, 1},
   202  		{"0x" + dbtestdata.EthTxidB1T1, 0},
   203  	}, nil)
   204  	verifyGetTransactions(t, d, "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eBad", 500000, 1000000, []txidIndex{}, errors.New("Address missing"))
   205  
   206  	// GetBestBlock
   207  	height, hash, err := d.GetBestBlock()
   208  	if err != nil {
   209  		t.Fatal(err)
   210  	}
   211  	if height != 4321001 {
   212  		t.Fatalf("GetBestBlock: got height %v, expected %v", height, 4321001)
   213  	}
   214  	if hash != "0x2b57e15e93a0ed197417a34c2498b7187df79099572c04a6b6e6ff418f74e6ee" {
   215  		t.Fatalf("GetBestBlock: got hash %v, expected %v", hash, "0x2b57e15e93a0ed197417a34c2498b7187df79099572c04a6b6e6ff418f74e6ee")
   216  	}
   217  
   218  	// GetBlockHash
   219  	hash, err = d.GetBlockHash(4321000)
   220  	if err != nil {
   221  		t.Fatal(err)
   222  	}
   223  	if hash != "0xc7b98df95acfd11c51ba25611a39e004fe56c8fdfc1582af99354fcd09c17b11" {
   224  		t.Fatalf("GetBlockHash: got hash %v, expected %v", hash, "0xc7b98df95acfd11c51ba25611a39e004fe56c8fdfc1582af99354fcd09c17b11")
   225  	}
   226  
   227  	// Not connected block
   228  	hash, err = d.GetBlockHash(4321002)
   229  	if err != nil {
   230  		t.Fatal(err)
   231  	}
   232  	if hash != "" {
   233  		t.Fatalf("GetBlockHash: got hash '%v', expected ''", hash)
   234  	}
   235  
   236  	// GetBlockHash
   237  	info, err := d.GetBlockInfo(4321001)
   238  	if err != nil {
   239  		t.Fatal(err)
   240  	}
   241  	iw := &BlockInfo{
   242  		Hash:   "0x2b57e15e93a0ed197417a34c2498b7187df79099572c04a6b6e6ff418f74e6ee",
   243  		Txs:    2,
   244  		Size:   2345678,
   245  		Time:   1534859988,
   246  		Height: 4321001,
   247  	}
   248  	if !reflect.DeepEqual(info, iw) {
   249  		t.Errorf("GetBlockInfo() = %+v, want %+v", info, iw)
   250  	}
   251  
   252  	// Test tx caching functionality, leave one tx in db to test cleanup in DisconnectBlock
   253  	testTxCache(t, d, block1, &block1.Txs[0])
   254  	testTxCache(t, d, block2, &block2.Txs[0])
   255  	if err = d.PutTx(&block2.Txs[1], block2.Height, block2.Txs[1].Blocktime); err != nil {
   256  		t.Fatal(err)
   257  	}
   258  	if err = d.PutTx(&block2.Txs[1], block2.Height, block2.Txs[1].Blocktime); err != nil {
   259  		t.Fatal(err)
   260  	}
   261  	// check that there is only the last tx in the cache
   262  	packedTx, err := d.chainParser.PackTx(&block2.Txs[1], block2.Height, block2.Txs[1].Blocktime)
   263  	if err := checkColumn(d, cfTransactions, []keyPair{
   264  		{dbtestdata.EthTxidB2T2, hex.EncodeToString(packedTx), nil},
   265  	}); err != nil {
   266  		{
   267  			t.Fatal(err)
   268  		}
   269  	}
   270  	// try to disconnect both blocks, however only the last one is kept, it is not possible
   271  	err = d.DisconnectBlockRangeEthereumType(4321000, 4321001)
   272  	if err == nil || err.Error() != "Cannot disconnect blocks with height 4321000 and lower. It is necessary to rebuild index." {
   273  		t.Fatal(err)
   274  	}
   275  	verifyAfterEthereumTypeBlock2(t, d)
   276  
   277  	// disconnect the 2nd block, verify that the db contains only data from the 1st block with restored unspentTxs
   278  	// and that the cached tx is removed
   279  	err = d.DisconnectBlockRangeEthereumType(4321001, 4321001)
   280  	if err != nil {
   281  		t.Fatal(err)
   282  	}
   283  	verifyAfterEthereumTypeBlock1(t, d, true)
   284  	if err := checkColumn(d, cfTransactions, []keyPair{}); err != nil {
   285  		{
   286  			t.Fatal(err)
   287  		}
   288  	}
   289  
   290  	if len(d.is.BlockTimes) != 1 {
   291  		t.Fatal("Expecting is.BlockTimes 1, got ", len(d.is.BlockTimes))
   292  	}
   293  
   294  	// connect block again and verify the state of db
   295  	if err := d.ConnectBlock(block2); err != nil {
   296  		t.Fatal(err)
   297  	}
   298  	verifyAfterEthereumTypeBlock2(t, d)
   299  
   300  	if len(d.is.BlockTimes) != 2 {
   301  		t.Fatal("Expecting is.BlockTimes 2, got ", len(d.is.BlockTimes))
   302  	}
   303  
   304  }