github.com/grupokindynos/coins-explorer@v0.0.0-20210507172551-fa8983d19250/db/rocksdb_ethereumtype_test.go (about) 1 // +build unittest 2 3 package db 4 5 import ( 6 "encoding/hex" 7 "github.com/grupokindynos/coins-explorer/bchain/coins/eth" 8 "github.com/grupokindynos/coins-explorer/tests/dbtestdata" 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 }