github.com/baptiste-b-pegasys/quorum/v22@v22.4.2/core/rawdb/accessors_chain_test.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package rawdb 18 19 import ( 20 "bytes" 21 "encoding/hex" 22 "fmt" 23 "io/ioutil" 24 "math/big" 25 "math/rand" 26 "os" 27 "reflect" 28 "testing" 29 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/core/types" 32 "github.com/ethereum/go-ethereum/ethdb" 33 "github.com/ethereum/go-ethereum/log" 34 "github.com/ethereum/go-ethereum/params" 35 "github.com/ethereum/go-ethereum/rlp" 36 "github.com/stretchr/testify/assert" 37 "golang.org/x/crypto/sha3" 38 ) 39 40 // Tests block header storage and retrieval operations. 41 func TestHeaderStorage(t *testing.T) { 42 db := NewMemoryDatabase() 43 44 // Create a test header to move around the database and make sure it's really new 45 header := &types.Header{Number: big.NewInt(42), Extra: []byte("test header")} 46 if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry != nil { 47 t.Fatalf("Non existent header returned: %v", entry) 48 } 49 // Write and verify the header in the database 50 WriteHeader(db, header) 51 if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry == nil { 52 t.Fatalf("Stored header not found") 53 } else if entry.Hash() != header.Hash() { 54 t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, header) 55 } 56 if entry := ReadHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil { 57 t.Fatalf("Stored header RLP not found") 58 } else { 59 hasher := sha3.NewLegacyKeccak256() 60 hasher.Write(entry) 61 62 if hash := common.BytesToHash(hasher.Sum(nil)); hash != header.Hash() { 63 t.Fatalf("Retrieved RLP header mismatch: have %v, want %v", entry, header) 64 } 65 } 66 // Delete the header and verify the execution 67 DeleteHeader(db, header.Hash(), header.Number.Uint64()) 68 if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry != nil { 69 t.Fatalf("Deleted header returned: %v", entry) 70 } 71 } 72 73 // Tests block body storage and retrieval operations. 74 func TestBodyStorage(t *testing.T) { 75 db := NewMemoryDatabase() 76 77 // Create a test body to move around the database and make sure it's really new 78 body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}} 79 80 hasher := sha3.NewLegacyKeccak256() 81 rlp.Encode(hasher, body) 82 hash := common.BytesToHash(hasher.Sum(nil)) 83 84 if entry := ReadBody(db, hash, 0); entry != nil { 85 t.Fatalf("Non existent body returned: %v", entry) 86 } 87 // Write and verify the body in the database 88 WriteBody(db, hash, 0, body) 89 if entry := ReadBody(db, hash, 0); entry == nil { 90 t.Fatalf("Stored body not found") 91 } else if types.DeriveSha(types.Transactions(entry.Transactions), newHasher()) != types.DeriveSha(types.Transactions(body.Transactions), newHasher()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(body.Uncles) { 92 t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, body) 93 } 94 if entry := ReadBodyRLP(db, hash, 0); entry == nil { 95 t.Fatalf("Stored body RLP not found") 96 } else { 97 hasher := sha3.NewLegacyKeccak256() 98 hasher.Write(entry) 99 100 if calc := common.BytesToHash(hasher.Sum(nil)); calc != hash { 101 t.Fatalf("Retrieved RLP body mismatch: have %v, want %v", entry, body) 102 } 103 } 104 // Delete the body and verify the execution 105 DeleteBody(db, hash, 0) 106 if entry := ReadBody(db, hash, 0); entry != nil { 107 t.Fatalf("Deleted body returned: %v", entry) 108 } 109 } 110 111 // Tests block storage and retrieval operations. 112 func TestBlockStorage(t *testing.T) { 113 db := NewMemoryDatabase() 114 115 // Create a test block to move around the database and make sure it's really new 116 block := types.NewBlockWithHeader(&types.Header{ 117 Extra: []byte("test block"), 118 UncleHash: types.EmptyUncleHash, 119 TxHash: types.EmptyRootHash, 120 ReceiptHash: types.EmptyRootHash, 121 }) 122 if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { 123 t.Fatalf("Non existent block returned: %v", entry) 124 } 125 if entry := ReadHeader(db, block.Hash(), block.NumberU64()); entry != nil { 126 t.Fatalf("Non existent header returned: %v", entry) 127 } 128 if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry != nil { 129 t.Fatalf("Non existent body returned: %v", entry) 130 } 131 // Write and verify the block in the database 132 WriteBlock(db, block) 133 if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry == nil { 134 t.Fatalf("Stored block not found") 135 } else if entry.Hash() != block.Hash() { 136 t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block) 137 } 138 if entry := ReadHeader(db, block.Hash(), block.NumberU64()); entry == nil { 139 t.Fatalf("Stored header not found") 140 } else if entry.Hash() != block.Header().Hash() { 141 t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, block.Header()) 142 } 143 if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry == nil { 144 t.Fatalf("Stored body not found") 145 } else if types.DeriveSha(types.Transactions(entry.Transactions), newHasher()) != types.DeriveSha(block.Transactions(), newHasher()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) { 146 t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, block.Body()) 147 } 148 // Delete the block and verify the execution 149 DeleteBlock(db, block.Hash(), block.NumberU64()) 150 if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { 151 t.Fatalf("Deleted block returned: %v", entry) 152 } 153 if entry := ReadHeader(db, block.Hash(), block.NumberU64()); entry != nil { 154 t.Fatalf("Deleted header returned: %v", entry) 155 } 156 if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry != nil { 157 t.Fatalf("Deleted body returned: %v", entry) 158 } 159 } 160 161 // Tests that partial block contents don't get reassembled into full blocks. 162 func TestPartialBlockStorage(t *testing.T) { 163 db := NewMemoryDatabase() 164 block := types.NewBlockWithHeader(&types.Header{ 165 Extra: []byte("test block"), 166 UncleHash: types.EmptyUncleHash, 167 TxHash: types.EmptyRootHash, 168 ReceiptHash: types.EmptyRootHash, 169 }) 170 // Store a header and check that it's not recognized as a block 171 WriteHeader(db, block.Header()) 172 if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { 173 t.Fatalf("Non existent block returned: %v", entry) 174 } 175 DeleteHeader(db, block.Hash(), block.NumberU64()) 176 177 // Store a body and check that it's not recognized as a block 178 WriteBody(db, block.Hash(), block.NumberU64(), block.Body()) 179 if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { 180 t.Fatalf("Non existent block returned: %v", entry) 181 } 182 DeleteBody(db, block.Hash(), block.NumberU64()) 183 184 // Store a header and a body separately and check reassembly 185 WriteHeader(db, block.Header()) 186 WriteBody(db, block.Hash(), block.NumberU64(), block.Body()) 187 188 if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry == nil { 189 t.Fatalf("Stored block not found") 190 } else if entry.Hash() != block.Hash() { 191 t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block) 192 } 193 } 194 195 // Tests block storage and retrieval operations. 196 func TestBadBlockStorage(t *testing.T) { 197 db := NewMemoryDatabase() 198 199 // Create a test block to move around the database and make sure it's really new 200 block := types.NewBlockWithHeader(&types.Header{ 201 Number: big.NewInt(1), 202 Extra: []byte("bad block"), 203 UncleHash: types.EmptyUncleHash, 204 TxHash: types.EmptyRootHash, 205 ReceiptHash: types.EmptyRootHash, 206 }) 207 if entry := ReadBadBlock(db, block.Hash()); entry != nil { 208 t.Fatalf("Non existent block returned: %v", entry) 209 } 210 // Write and verify the block in the database 211 WriteBadBlock(db, block) 212 if entry := ReadBadBlock(db, block.Hash()); entry == nil { 213 t.Fatalf("Stored block not found") 214 } else if entry.Hash() != block.Hash() { 215 t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block) 216 } 217 // Write one more bad block 218 blockTwo := types.NewBlockWithHeader(&types.Header{ 219 Number: big.NewInt(2), 220 Extra: []byte("bad block two"), 221 UncleHash: types.EmptyUncleHash, 222 TxHash: types.EmptyRootHash, 223 ReceiptHash: types.EmptyRootHash, 224 }) 225 WriteBadBlock(db, blockTwo) 226 227 // Write the block one again, should be filtered out. 228 WriteBadBlock(db, block) 229 badBlocks := ReadAllBadBlocks(db) 230 if len(badBlocks) != 2 { 231 t.Fatalf("Failed to load all bad blocks") 232 } 233 234 // Write a bunch of bad blocks, all the blocks are should sorted 235 // in reverse order. The extra blocks should be truncated. 236 for _, n := range rand.Perm(100) { 237 block := types.NewBlockWithHeader(&types.Header{ 238 Number: big.NewInt(int64(n)), 239 Extra: []byte("bad block"), 240 UncleHash: types.EmptyUncleHash, 241 TxHash: types.EmptyRootHash, 242 ReceiptHash: types.EmptyRootHash, 243 }) 244 WriteBadBlock(db, block) 245 } 246 badBlocks = ReadAllBadBlocks(db) 247 if len(badBlocks) != badBlockToKeep { 248 t.Fatalf("The number of persised bad blocks in incorrect %d", len(badBlocks)) 249 } 250 for i := 0; i < len(badBlocks)-1; i++ { 251 if badBlocks[i].NumberU64() < badBlocks[i+1].NumberU64() { 252 t.Fatalf("The bad blocks are not sorted #[%d](%d) < #[%d](%d)", i, i+1, badBlocks[i].NumberU64(), badBlocks[i+1].NumberU64()) 253 } 254 } 255 256 // Delete all bad blocks 257 DeleteBadBlocks(db) 258 badBlocks = ReadAllBadBlocks(db) 259 if len(badBlocks) != 0 { 260 t.Fatalf("Failed to delete bad blocks") 261 } 262 } 263 264 // Tests block total difficulty storage and retrieval operations. 265 func TestTdStorage(t *testing.T) { 266 db := NewMemoryDatabase() 267 268 // Create a test TD to move around the database and make sure it's really new 269 hash, td := common.Hash{}, big.NewInt(314) 270 if entry := ReadTd(db, hash, 0); entry != nil { 271 t.Fatalf("Non existent TD returned: %v", entry) 272 } 273 // Write and verify the TD in the database 274 WriteTd(db, hash, 0, td) 275 if entry := ReadTd(db, hash, 0); entry == nil { 276 t.Fatalf("Stored TD not found") 277 } else if entry.Cmp(td) != 0 { 278 t.Fatalf("Retrieved TD mismatch: have %v, want %v", entry, td) 279 } 280 // Delete the TD and verify the execution 281 DeleteTd(db, hash, 0) 282 if entry := ReadTd(db, hash, 0); entry != nil { 283 t.Fatalf("Deleted TD returned: %v", entry) 284 } 285 } 286 287 // Tests that canonical numbers can be mapped to hashes and retrieved. 288 func TestCanonicalMappingStorage(t *testing.T) { 289 db := NewMemoryDatabase() 290 291 // Create a test canonical number and assinged hash to move around 292 hash, number := common.Hash{0: 0xff}, uint64(314) 293 if entry := ReadCanonicalHash(db, number); entry != (common.Hash{}) { 294 t.Fatalf("Non existent canonical mapping returned: %v", entry) 295 } 296 // Write and verify the TD in the database 297 WriteCanonicalHash(db, hash, number) 298 if entry := ReadCanonicalHash(db, number); entry == (common.Hash{}) { 299 t.Fatalf("Stored canonical mapping not found") 300 } else if entry != hash { 301 t.Fatalf("Retrieved canonical mapping mismatch: have %v, want %v", entry, hash) 302 } 303 // Delete the TD and verify the execution 304 DeleteCanonicalHash(db, number) 305 if entry := ReadCanonicalHash(db, number); entry != (common.Hash{}) { 306 t.Fatalf("Deleted canonical mapping returned: %v", entry) 307 } 308 } 309 310 // Tests that head headers and head blocks can be assigned, individually. 311 func TestHeadStorage(t *testing.T) { 312 db := NewMemoryDatabase() 313 314 blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")}) 315 blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")}) 316 blockFast := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block fast")}) 317 318 // Check that no head entries are in a pristine database 319 if entry := ReadHeadHeaderHash(db); entry != (common.Hash{}) { 320 t.Fatalf("Non head header entry returned: %v", entry) 321 } 322 if entry := ReadHeadBlockHash(db); entry != (common.Hash{}) { 323 t.Fatalf("Non head block entry returned: %v", entry) 324 } 325 if entry := ReadHeadFastBlockHash(db); entry != (common.Hash{}) { 326 t.Fatalf("Non fast head block entry returned: %v", entry) 327 } 328 // Assign separate entries for the head header and block 329 WriteHeadHeaderHash(db, blockHead.Hash()) 330 WriteHeadBlockHash(db, blockFull.Hash()) 331 WriteHeadFastBlockHash(db, blockFast.Hash()) 332 333 // Check that both heads are present, and different (i.e. two heads maintained) 334 if entry := ReadHeadHeaderHash(db); entry != blockHead.Hash() { 335 t.Fatalf("Head header hash mismatch: have %v, want %v", entry, blockHead.Hash()) 336 } 337 if entry := ReadHeadBlockHash(db); entry != blockFull.Hash() { 338 t.Fatalf("Head block hash mismatch: have %v, want %v", entry, blockFull.Hash()) 339 } 340 if entry := ReadHeadFastBlockHash(db); entry != blockFast.Hash() { 341 t.Fatalf("Fast head block hash mismatch: have %v, want %v", entry, blockFast.Hash()) 342 } 343 } 344 345 // Tests that receipts associated with a single block can be stored and retrieved. 346 func TestBlockReceiptStorage(t *testing.T) { 347 db := NewMemoryDatabase() 348 349 // Create a live block since we need metadata to reconstruct the receipt 350 tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil) 351 tx2 := types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil) 352 353 body := &types.Body{Transactions: types.Transactions{tx1, tx2}} 354 355 // Create the two receipts to manage afterwards 356 receipt1 := &types.Receipt{ 357 Status: types.ReceiptStatusFailed, 358 CumulativeGasUsed: 1, 359 Logs: []*types.Log{ 360 {Address: common.BytesToAddress([]byte{0x11})}, 361 {Address: common.BytesToAddress([]byte{0x01, 0x11})}, 362 }, 363 TxHash: tx1.Hash(), 364 ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), 365 GasUsed: 111111, 366 } 367 receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1}) 368 369 receipt2 := &types.Receipt{ 370 PostState: common.Hash{2}.Bytes(), 371 CumulativeGasUsed: 2, 372 Logs: []*types.Log{ 373 {Address: common.BytesToAddress([]byte{0x22})}, 374 {Address: common.BytesToAddress([]byte{0x02, 0x22})}, 375 }, 376 TxHash: tx2.Hash(), 377 ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), 378 GasUsed: 222222, 379 } 380 receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2}) 381 receipts := []*types.Receipt{receipt1, receipt2} 382 383 // Check that no receipt entries are in a pristine database 384 hash := common.BytesToHash([]byte{0x03, 0x14}) 385 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { 386 t.Fatalf("non existent receipts returned: %v", rs) 387 } 388 // Insert the body that corresponds to the receipts 389 WriteBody(db, hash, 0, body) 390 391 // Insert the receipt slice into the database and check presence 392 WriteReceipts(db, hash, 0, receipts) 393 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) == 0 { 394 t.Fatalf("no receipts returned") 395 } else { 396 if err := checkReceiptsRLP(rs, receipts); err != nil { 397 t.Fatalf(err.Error()) 398 } 399 // check that the raw data does not contain the quorumExtraData array (since the prepared receipts do not have any quorumExtraData) 400 receiptData := ReadReceiptsRLP(db, hash, 0) 401 _, extraData, err := rlp.SplitList(receiptData) 402 assert.NoError(t, err) 403 assert.Empty(t, extraData) 404 } 405 // Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed) 406 DeleteBody(db, hash, 0) 407 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); rs != nil { 408 t.Fatalf("receipts returned when body was deleted: %v", rs) 409 } 410 // Ensure that receipts without metadata can be returned without the block body too 411 if err := checkReceiptsRLP(ReadRawReceipts(db, hash, 0), receipts); err != nil { 412 t.Fatalf(err.Error()) 413 } 414 // Sanity check that body alone without the receipt is a full purge 415 WriteBody(db, hash, 0, body) 416 417 DeleteReceipts(db, hash, 0) 418 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { 419 t.Fatalf("deleted receipts returned: %v", rs) 420 } 421 } 422 423 func TestBlockReceiptStorageWithLegacyMPSV1EncodingWithMPSData(t *testing.T) { 424 db := NewMemoryDatabase() 425 426 // Create a live block since we need metadata to reconstruct the receipt 427 tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil) 428 tx2 := types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil) 429 tx2.SetPrivate() 430 431 body := &types.Body{Transactions: types.Transactions{tx1, tx2}} 432 433 // Create the two receipts to manage afterwards 434 receipt1 := &types.Receipt{ 435 Status: types.ReceiptStatusFailed, 436 CumulativeGasUsed: 1, 437 Logs: []*types.Log{ 438 {Address: common.BytesToAddress([]byte{0x11})}, 439 {Address: common.BytesToAddress([]byte{0x01, 0x11})}, 440 }, 441 TxHash: tx1.Hash(), 442 ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), 443 GasUsed: 111111, 444 } 445 receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1}) 446 447 psiReceipt2 := &types.Receipt{ 448 PostState: common.Hash{2}.Bytes(), 449 CumulativeGasUsed: 2, 450 Logs: []*types.Log{ 451 {Address: common.BytesToAddress([]byte{0x22})}, 452 {Address: common.BytesToAddress([]byte{0x02, 0x22})}, 453 }, 454 TxHash: tx2.Hash(), 455 ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), 456 GasUsed: 222222, 457 } 458 459 receipt2 := &types.Receipt{ 460 PostState: common.Hash{2}.Bytes(), 461 CumulativeGasUsed: 2, 462 Logs: []*types.Log{ 463 {Address: common.BytesToAddress([]byte{0x22})}, 464 {Address: common.BytesToAddress([]byte{0x02, 0x22})}, 465 }, 466 TxHash: tx2.Hash(), 467 ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), 468 GasUsed: 222222, 469 QuorumReceiptExtraData: types.QuorumReceiptExtraData{ 470 PSReceipts: map[types.PrivateStateIdentifier]*types.Receipt{types.PrivateStateIdentifier("psi1"): psiReceipt2}, 471 }, 472 } 473 receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2}) 474 receipts := []*types.Receipt{receipt1, receipt2} 475 476 // Check that no receipt entries are in a pristine database 477 hash := common.BytesToHash([]byte{0x03, 0x14}) 478 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { 479 t.Fatalf("non existent receipts returned: %v", rs) 480 } 481 // Insert the body that corresponds to the receipts 482 WriteBody(db, hash, 0, body) 483 484 // Insert the receipt slice into the database and check presence 485 WriteReceiptsMPSV1(db, hash, 0, receipts) 486 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) == 0 { 487 t.Fatalf("no receipts returned") 488 } else { 489 if err := checkReceiptsRLP(rs, receipts); err != nil { 490 t.Fatalf(err.Error()) 491 } 492 rec2 := rs[1] 493 assert.Len(t, rec2.PSReceipts, 1) 494 psRec2 := rec2.PSReceipts[types.PrivateStateIdentifier("psi1")] 495 assert.NotNil(t, psRec2) 496 } 497 // Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed) 498 DeleteBody(db, hash, 0) 499 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); rs != nil { 500 t.Fatalf("receipts returned when body was deleted: %v", rs) 501 } 502 // Ensure that receipts without metadata can be returned without the block body too 503 if err := checkReceiptsRLP(ReadRawReceipts(db, hash, 0), receipts); err != nil { 504 t.Fatalf(err.Error()) 505 } 506 } 507 508 func TestBlockReceiptStorageWithLegacyMPSV1EncodingWithoutMPSData(t *testing.T) { 509 db := NewMemoryDatabase() 510 511 // Create a live block since we need metadata to reconstruct the receipt 512 tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil) 513 tx2 := types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil) 514 tx2.SetPrivate() 515 516 body := &types.Body{Transactions: types.Transactions{tx1, tx2}} 517 518 // Create the two receipts to manage afterwards 519 receipt1 := &types.Receipt{ 520 Status: types.ReceiptStatusFailed, 521 CumulativeGasUsed: 1, 522 Logs: []*types.Log{ 523 {Address: common.BytesToAddress([]byte{0x11})}, 524 {Address: common.BytesToAddress([]byte{0x01, 0x11})}, 525 }, 526 TxHash: tx1.Hash(), 527 ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), 528 GasUsed: 111111, 529 } 530 receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1}) 531 532 receipt2 := &types.Receipt{ 533 PostState: common.Hash{2}.Bytes(), 534 CumulativeGasUsed: 2, 535 Logs: []*types.Log{ 536 {Address: common.BytesToAddress([]byte{0x22})}, 537 {Address: common.BytesToAddress([]byte{0x02, 0x22})}, 538 }, 539 TxHash: tx2.Hash(), 540 ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), 541 GasUsed: 222222, 542 } 543 receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2}) 544 receipts := []*types.Receipt{receipt1, receipt2} 545 546 // Check that no receipt entries are in a pristine database 547 hash := common.BytesToHash([]byte{0x03, 0x14}) 548 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { 549 t.Fatalf("non existent receipts returned: %v", rs) 550 } 551 // Insert the body that corresponds to the receipts 552 WriteBody(db, hash, 0, body) 553 554 // Insert the receipt slice into the database and check presence 555 WriteReceiptsMPSV1(db, hash, 0, receipts) 556 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) == 0 { 557 t.Fatalf("no receipts returned") 558 } else { 559 if err := checkReceiptsRLP(rs, receipts); err != nil { 560 t.Fatalf(err.Error()) 561 } 562 rec2 := rs[1] 563 assert.Len(t, rec2.PSReceipts, 0) 564 } 565 // Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed) 566 DeleteBody(db, hash, 0) 567 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); rs != nil { 568 t.Fatalf("receipts returned when body was deleted: %v", rs) 569 } 570 // Ensure that receipts without metadata can be returned without the block body too 571 if err := checkReceiptsRLP(ReadRawReceipts(db, hash, 0), receipts); err != nil { 572 t.Fatalf(err.Error()) 573 } 574 } 575 576 // Tests that receipts associated with a single block can be stored and retrieved. 577 func TestBlockReceiptStorageWithQuorumExtraData(t *testing.T) { 578 db := NewMemoryDatabase() 579 580 // Create a live block since we need metadata to reconstruct the receipt 581 tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil) 582 tx2 := types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil) 583 tx2.SetPrivate() 584 585 body := &types.Body{Transactions: types.Transactions{tx1, tx2}} 586 587 // Create the two receipts to manage afterwards 588 receipt1 := &types.Receipt{ 589 Status: types.ReceiptStatusFailed, 590 CumulativeGasUsed: 1, 591 Logs: []*types.Log{ 592 {Address: common.BytesToAddress([]byte{0x11})}, 593 {Address: common.BytesToAddress([]byte{0x01, 0x11})}, 594 }, 595 TxHash: tx1.Hash(), 596 ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), 597 GasUsed: 111111, 598 } 599 receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1}) 600 601 psiReceipt2 := &types.Receipt{ 602 PostState: common.Hash{2}.Bytes(), 603 CumulativeGasUsed: 2, 604 Logs: []*types.Log{ 605 {Address: common.BytesToAddress([]byte{0x22})}, 606 {Address: common.BytesToAddress([]byte{0x02, 0x22})}, 607 }, 608 TxHash: tx2.Hash(), 609 ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), 610 GasUsed: 222222, 611 QuorumReceiptExtraData: types.QuorumReceiptExtraData{ 612 RevertReason: []byte("arbitraryvalue"), 613 }, 614 } 615 616 receipt2 := &types.Receipt{ 617 PostState: common.Hash{2}.Bytes(), 618 CumulativeGasUsed: 2, 619 Logs: []*types.Log{ 620 {Address: common.BytesToAddress([]byte{0x22})}, 621 {Address: common.BytesToAddress([]byte{0x02, 0x22})}, 622 }, 623 TxHash: tx2.Hash(), 624 ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), 625 GasUsed: 222222, 626 QuorumReceiptExtraData: types.QuorumReceiptExtraData{ 627 RevertReason: []byte("arbitraryvalue"), 628 PSReceipts: map[types.PrivateStateIdentifier]*types.Receipt{types.PrivateStateIdentifier("psi1"): psiReceipt2}, 629 }, 630 } 631 receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2}) 632 receipts := []*types.Receipt{receipt1, receipt2} 633 634 // Check that no receipt entries are in a pristine database 635 hash := common.BytesToHash([]byte{0x03, 0x14}) 636 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { 637 t.Fatalf("non existent receipts returned: %v", rs) 638 } 639 // Insert the body that corresponds to the receipts 640 WriteBody(db, hash, 0, body) 641 642 // Insert the receipt slice into the database and check presence 643 WriteReceipts(db, hash, 0, receipts) 644 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) == 0 { 645 t.Fatalf("no receipts returned") 646 } else { 647 if err := checkReceiptsRLP(rs, receipts); err != nil { 648 t.Fatalf(err.Error()) 649 } 650 rec2 := rs[1] 651 assert.Len(t, rec2.PSReceipts, 1) 652 assert.Equal(t, rec2.RevertReason, []byte("arbitraryvalue")) 653 psRec2 := rec2.PSReceipts[types.PrivateStateIdentifier("psi1")] 654 assert.Equal(t, psRec2.RevertReason, []byte("arbitraryvalue")) 655 } 656 // Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed) 657 DeleteBody(db, hash, 0) 658 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); rs != nil { 659 t.Fatalf("receipts returned when body was deleted: %v", rs) 660 } 661 // Ensure that receipts without metadata can be returned without the block body too 662 if err := checkReceiptsRLP(ReadRawReceipts(db, hash, 0), receipts); err != nil { 663 t.Fatalf(err.Error()) 664 } 665 // Sanity check that body alone without the receipt is a full purge 666 WriteBody(db, hash, 0, body) 667 668 DeleteReceipts(db, hash, 0) 669 if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { 670 t.Fatalf("deleted receipts returned: %v", rs) 671 } 672 } 673 674 func checkReceiptsRLP(have, want types.Receipts) error { 675 if len(have) != len(want) { 676 return fmt.Errorf("receipts sizes mismatch: have %d, want %d", len(have), len(want)) 677 } 678 for i := 0; i < len(want); i++ { 679 rlpHave, err := rlp.EncodeToBytes(have[i]) 680 if err != nil { 681 return err 682 } 683 rlpWant, err := rlp.EncodeToBytes(want[i]) 684 if err != nil { 685 return err 686 } 687 if !bytes.Equal(rlpHave, rlpWant) { 688 return fmt.Errorf("receipt #%d: receipt mismatch: have %s, want %s", i, hex.EncodeToString(rlpHave), hex.EncodeToString(rlpWant)) 689 } 690 } 691 return nil 692 } 693 694 func TestAncientStorage(t *testing.T) { 695 // Freezer style fast import the chain. 696 frdir, err := ioutil.TempDir("", "") 697 if err != nil { 698 t.Fatalf("failed to create temp freezer dir: %v", err) 699 } 700 defer os.Remove(frdir) 701 702 db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "") 703 if err != nil { 704 t.Fatalf("failed to create database with ancient backend") 705 } 706 // Create a test block 707 block := types.NewBlockWithHeader(&types.Header{ 708 Number: big.NewInt(0), 709 Extra: []byte("test block"), 710 UncleHash: types.EmptyUncleHash, 711 TxHash: types.EmptyRootHash, 712 ReceiptHash: types.EmptyRootHash, 713 }) 714 // Ensure nothing non-existent will be read 715 hash, number := block.Hash(), block.NumberU64() 716 if blob := ReadHeaderRLP(db, hash, number); len(blob) > 0 { 717 t.Fatalf("non existent header returned") 718 } 719 if blob := ReadBodyRLP(db, hash, number); len(blob) > 0 { 720 t.Fatalf("non existent body returned") 721 } 722 if blob := ReadReceiptsRLP(db, hash, number); len(blob) > 0 { 723 t.Fatalf("non existent receipts returned") 724 } 725 if blob := ReadTdRLP(db, hash, number); len(blob) > 0 { 726 t.Fatalf("non existent td returned") 727 } 728 // Write and verify the header in the database 729 WriteAncientBlock(db, block, nil, big.NewInt(100)) 730 if blob := ReadHeaderRLP(db, hash, number); len(blob) == 0 { 731 t.Fatalf("no header returned") 732 } 733 if blob := ReadBodyRLP(db, hash, number); len(blob) == 0 { 734 t.Fatalf("no body returned") 735 } 736 if blob := ReadReceiptsRLP(db, hash, number); len(blob) == 0 { 737 t.Fatalf("no receipts returned") 738 } 739 if blob := ReadTdRLP(db, hash, number); len(blob) == 0 { 740 t.Fatalf("no td returned") 741 } 742 // Use a fake hash for data retrieval, nothing should be returned. 743 fakeHash := common.BytesToHash([]byte{0x01, 0x02, 0x03}) 744 if blob := ReadHeaderRLP(db, fakeHash, number); len(blob) != 0 { 745 t.Fatalf("invalid header returned") 746 } 747 if blob := ReadBodyRLP(db, fakeHash, number); len(blob) != 0 { 748 t.Fatalf("invalid body returned") 749 } 750 if blob := ReadReceiptsRLP(db, fakeHash, number); len(blob) != 0 { 751 t.Fatalf("invalid receipts returned") 752 } 753 if blob := ReadTdRLP(db, fakeHash, number); len(blob) != 0 { 754 t.Fatalf("invalid td returned") 755 } 756 } 757 758 func TestCanonicalHashIteration(t *testing.T) { 759 var cases = []struct { 760 from, to uint64 761 limit int 762 expect []uint64 763 }{ 764 {1, 8, 0, nil}, 765 {1, 8, 1, []uint64{1}}, 766 {1, 8, 10, []uint64{1, 2, 3, 4, 5, 6, 7}}, 767 {1, 9, 10, []uint64{1, 2, 3, 4, 5, 6, 7, 8}}, 768 {2, 9, 10, []uint64{2, 3, 4, 5, 6, 7, 8}}, 769 {9, 10, 10, nil}, 770 } 771 // Test empty db iteration 772 db := NewMemoryDatabase() 773 numbers, _ := ReadAllCanonicalHashes(db, 0, 10, 10) 774 if len(numbers) != 0 { 775 t.Fatalf("No entry should be returned to iterate an empty db") 776 } 777 // Fill database with testing data. 778 for i := uint64(1); i <= 8; i++ { 779 WriteCanonicalHash(db, common.Hash{}, i) 780 WriteTd(db, common.Hash{}, i, big.NewInt(10)) // Write some interferential data 781 } 782 for i, c := range cases { 783 numbers, _ := ReadAllCanonicalHashes(db, c.from, c.to, c.limit) 784 if !reflect.DeepEqual(numbers, c.expect) { 785 t.Fatalf("Case %d failed, want %v, got %v", i, c.expect, numbers) 786 } 787 } 788 } 789 790 func WriteReceiptsMPSV1(db ethdb.KeyValueWriter, hash common.Hash, number uint64, receipts types.Receipts) { 791 // Convert the receipts into their storage form and serialize them 792 storageReceipts := make([]*types.ReceiptForStorageMPSV1, len(receipts)) 793 for i, receipt := range receipts { 794 storageReceipts[i] = (*types.ReceiptForStorageMPSV1)(receipt) 795 } 796 bytes, err := rlp.EncodeToBytes(storageReceipts) 797 if err != nil { 798 log.Crit("Failed to encode block receipts", "err", err) 799 } 800 // Store the flattened receipt slice 801 if err := db.Put(blockReceiptsKey(number, hash), bytes); err != nil { 802 log.Crit("Failed to store block receipts", "err", err) 803 } 804 }