github.com/ethereum/go-ethereum@v1.16.1/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 "math/big" 24 "math/rand" 25 "os" 26 "reflect" 27 "testing" 28 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/crypto" 32 "github.com/ethereum/go-ethereum/params" 33 "github.com/ethereum/go-ethereum/rlp" 34 "golang.org/x/crypto/sha3" 35 ) 36 37 // Tests block header storage and retrieval operations. 38 func TestHeaderStorage(t *testing.T) { 39 db := NewMemoryDatabase() 40 41 // Create a test header to move around the database and make sure it's really new 42 header := &types.Header{Number: big.NewInt(42), Extra: []byte("test header")} 43 if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry != nil { 44 t.Fatalf("Non existent header returned: %v", entry) 45 } 46 // Write and verify the header in the database 47 WriteHeader(db, header) 48 if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry == nil { 49 t.Fatalf("Stored header not found") 50 } else if entry.Hash() != header.Hash() { 51 t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, header) 52 } 53 if entry := ReadHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil { 54 t.Fatalf("Stored header RLP not found") 55 } else { 56 hasher := sha3.NewLegacyKeccak256() 57 hasher.Write(entry) 58 59 if hash := common.BytesToHash(hasher.Sum(nil)); hash != header.Hash() { 60 t.Fatalf("Retrieved RLP header mismatch: have %v, want %v", entry, header) 61 } 62 } 63 // Delete the header and verify the execution 64 DeleteHeader(db, header.Hash(), header.Number.Uint64()) 65 if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry != nil { 66 t.Fatalf("Deleted header returned: %v", entry) 67 } 68 } 69 70 // Tests block body storage and retrieval operations. 71 func TestBodyStorage(t *testing.T) { 72 db := NewMemoryDatabase() 73 74 // Create a test body to move around the database and make sure it's really new 75 body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}} 76 77 hasher := sha3.NewLegacyKeccak256() 78 rlp.Encode(hasher, body) 79 hash := common.BytesToHash(hasher.Sum(nil)) 80 81 if entry := ReadBody(db, hash, 0); entry != nil { 82 t.Fatalf("Non existent body returned: %v", entry) 83 } 84 // Write and verify the body in the database 85 WriteBody(db, hash, 0, body) 86 if entry := ReadBody(db, hash, 0); entry == nil { 87 t.Fatalf("Stored body not found") 88 } else if types.DeriveSha(types.Transactions(entry.Transactions), newTestHasher()) != types.DeriveSha(types.Transactions(body.Transactions), newTestHasher()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(body.Uncles) { 89 t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, body) 90 } 91 if entry := ReadBodyRLP(db, hash, 0); entry == nil { 92 t.Fatalf("Stored body RLP not found") 93 } else { 94 hasher := sha3.NewLegacyKeccak256() 95 hasher.Write(entry) 96 97 if calc := common.BytesToHash(hasher.Sum(nil)); calc != hash { 98 t.Fatalf("Retrieved RLP body mismatch: have %v, want %v", entry, body) 99 } 100 } 101 // Delete the body and verify the execution 102 DeleteBody(db, hash, 0) 103 if entry := ReadBody(db, hash, 0); entry != nil { 104 t.Fatalf("Deleted body returned: %v", entry) 105 } 106 } 107 108 // Tests block storage and retrieval operations. 109 func TestBlockStorage(t *testing.T) { 110 db := NewMemoryDatabase() 111 112 // Create a test block to move around the database and make sure it's really new 113 block := types.NewBlockWithHeader(&types.Header{ 114 Extra: []byte("test block"), 115 UncleHash: types.EmptyUncleHash, 116 TxHash: types.EmptyTxsHash, 117 ReceiptHash: types.EmptyReceiptsHash, 118 }) 119 if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { 120 t.Fatalf("Non existent block returned: %v", entry) 121 } 122 if entry := ReadHeader(db, block.Hash(), block.NumberU64()); entry != nil { 123 t.Fatalf("Non existent header returned: %v", entry) 124 } 125 if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry != nil { 126 t.Fatalf("Non existent body returned: %v", entry) 127 } 128 // Write and verify the block in the database 129 WriteBlock(db, block) 130 if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry == nil { 131 t.Fatalf("Stored block not found") 132 } else if entry.Hash() != block.Hash() { 133 t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block) 134 } 135 if entry := ReadHeader(db, block.Hash(), block.NumberU64()); entry == nil { 136 t.Fatalf("Stored header not found") 137 } else if entry.Hash() != block.Header().Hash() { 138 t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, block.Header()) 139 } 140 if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry == nil { 141 t.Fatalf("Stored body not found") 142 } else if types.DeriveSha(types.Transactions(entry.Transactions), newTestHasher()) != types.DeriveSha(block.Transactions(), newTestHasher()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) { 143 t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, block.Body()) 144 } 145 // Delete the block and verify the execution 146 DeleteBlock(db, block.Hash(), block.NumberU64()) 147 if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { 148 t.Fatalf("Deleted block returned: %v", entry) 149 } 150 if entry := ReadHeader(db, block.Hash(), block.NumberU64()); entry != nil { 151 t.Fatalf("Deleted header returned: %v", entry) 152 } 153 if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry != nil { 154 t.Fatalf("Deleted body returned: %v", entry) 155 } 156 } 157 158 // Tests that partial block contents don't get reassembled into full blocks. 159 func TestPartialBlockStorage(t *testing.T) { 160 db := NewMemoryDatabase() 161 block := types.NewBlockWithHeader(&types.Header{ 162 Extra: []byte("test block"), 163 UncleHash: types.EmptyUncleHash, 164 TxHash: types.EmptyTxsHash, 165 ReceiptHash: types.EmptyReceiptsHash, 166 }) 167 // Store a header and check that it's not recognized as a block 168 WriteHeader(db, block.Header()) 169 if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { 170 t.Fatalf("Non existent block returned: %v", entry) 171 } 172 DeleteHeader(db, block.Hash(), block.NumberU64()) 173 174 // Store a body and check that it's not recognized as a block 175 WriteBody(db, block.Hash(), block.NumberU64(), block.Body()) 176 if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { 177 t.Fatalf("Non existent block returned: %v", entry) 178 } 179 DeleteBody(db, block.Hash(), block.NumberU64()) 180 181 // Store a header and a body separately and check reassembly 182 WriteHeader(db, block.Header()) 183 WriteBody(db, block.Hash(), block.NumberU64(), block.Body()) 184 185 if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry == nil { 186 t.Fatalf("Stored block not found") 187 } else if entry.Hash() != block.Hash() { 188 t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block) 189 } 190 } 191 192 // Tests block storage and retrieval operations. 193 func TestBadBlockStorage(t *testing.T) { 194 db := NewMemoryDatabase() 195 196 // Create a test block to move around the database and make sure it's really new 197 block := types.NewBlockWithHeader(&types.Header{ 198 Number: big.NewInt(1), 199 Extra: []byte("bad block"), 200 UncleHash: types.EmptyUncleHash, 201 TxHash: types.EmptyTxsHash, 202 ReceiptHash: types.EmptyReceiptsHash, 203 }) 204 if entry := ReadBadBlock(db, block.Hash()); entry != nil { 205 t.Fatalf("Non existent block returned: %v", entry) 206 } 207 // Write and verify the block in the database 208 WriteBadBlock(db, block) 209 if entry := ReadBadBlock(db, block.Hash()); entry == nil { 210 t.Fatalf("Stored block not found") 211 } else if entry.Hash() != block.Hash() { 212 t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block) 213 } 214 // Write one more bad block 215 blockTwo := types.NewBlockWithHeader(&types.Header{ 216 Number: big.NewInt(2), 217 Extra: []byte("bad block two"), 218 UncleHash: types.EmptyUncleHash, 219 TxHash: types.EmptyTxsHash, 220 ReceiptHash: types.EmptyReceiptsHash, 221 }) 222 WriteBadBlock(db, blockTwo) 223 224 // Write the block one again, should be filtered out. 225 WriteBadBlock(db, block) 226 badBlocks := ReadAllBadBlocks(db) 227 if len(badBlocks) != 2 { 228 t.Fatalf("Failed to load all bad blocks") 229 } 230 231 // Write a bunch of bad blocks, all the blocks are should sorted 232 // in reverse order. The extra blocks should be truncated. 233 for _, n := range rand.Perm(100) { 234 block := types.NewBlockWithHeader(&types.Header{ 235 Number: big.NewInt(int64(n)), 236 Extra: []byte("bad block"), 237 UncleHash: types.EmptyUncleHash, 238 TxHash: types.EmptyTxsHash, 239 ReceiptHash: types.EmptyReceiptsHash, 240 }) 241 WriteBadBlock(db, block) 242 } 243 badBlocks = ReadAllBadBlocks(db) 244 if len(badBlocks) != badBlockToKeep { 245 t.Fatalf("The number of persised bad blocks in incorrect %d", len(badBlocks)) 246 } 247 for i := 0; i < len(badBlocks)-1; i++ { 248 if badBlocks[i].NumberU64() < badBlocks[i+1].NumberU64() { 249 t.Fatalf("The bad blocks are not sorted #[%d](%d) < #[%d](%d)", i, i+1, badBlocks[i].NumberU64(), badBlocks[i+1].NumberU64()) 250 } 251 } 252 253 // Delete all bad blocks 254 DeleteBadBlocks(db) 255 badBlocks = ReadAllBadBlocks(db) 256 if len(badBlocks) != 0 { 257 t.Fatalf("Failed to delete bad blocks") 258 } 259 } 260 261 // Tests that canonical numbers can be mapped to hashes and retrieved. 262 func TestCanonicalMappingStorage(t *testing.T) { 263 db := NewMemoryDatabase() 264 265 // Create a test canonical number and assigned hash to move around 266 hash, number := common.Hash{0: 0xff}, uint64(314) 267 if entry := ReadCanonicalHash(db, number); entry != (common.Hash{}) { 268 t.Fatalf("Non existent canonical mapping returned: %v", entry) 269 } 270 // Write and verify the TD in the database 271 WriteCanonicalHash(db, hash, number) 272 if entry := ReadCanonicalHash(db, number); entry == (common.Hash{}) { 273 t.Fatalf("Stored canonical mapping not found") 274 } else if entry != hash { 275 t.Fatalf("Retrieved canonical mapping mismatch: have %v, want %v", entry, hash) 276 } 277 // Delete the TD and verify the execution 278 DeleteCanonicalHash(db, number) 279 if entry := ReadCanonicalHash(db, number); entry != (common.Hash{}) { 280 t.Fatalf("Deleted canonical mapping returned: %v", entry) 281 } 282 } 283 284 // Tests that head headers and head blocks can be assigned, individually. 285 func TestHeadStorage(t *testing.T) { 286 db := NewMemoryDatabase() 287 288 blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")}) 289 blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")}) 290 blockFast := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block fast")}) 291 292 // Check that no head entries are in a pristine database 293 if entry := ReadHeadHeaderHash(db); entry != (common.Hash{}) { 294 t.Fatalf("Non head header entry returned: %v", entry) 295 } 296 if entry := ReadHeadBlockHash(db); entry != (common.Hash{}) { 297 t.Fatalf("Non head block entry returned: %v", entry) 298 } 299 if entry := ReadHeadFastBlockHash(db); entry != (common.Hash{}) { 300 t.Fatalf("Non fast head block entry returned: %v", entry) 301 } 302 // Assign separate entries for the head header and block 303 WriteHeadHeaderHash(db, blockHead.Hash()) 304 WriteHeadBlockHash(db, blockFull.Hash()) 305 WriteHeadFastBlockHash(db, blockFast.Hash()) 306 307 // Check that both heads are present, and different (i.e. two heads maintained) 308 if entry := ReadHeadHeaderHash(db); entry != blockHead.Hash() { 309 t.Fatalf("Head header hash mismatch: have %v, want %v", entry, blockHead.Hash()) 310 } 311 if entry := ReadHeadBlockHash(db); entry != blockFull.Hash() { 312 t.Fatalf("Head block hash mismatch: have %v, want %v", entry, blockFull.Hash()) 313 } 314 if entry := ReadHeadFastBlockHash(db); entry != blockFast.Hash() { 315 t.Fatalf("Fast head block hash mismatch: have %v, want %v", entry, blockFast.Hash()) 316 } 317 } 318 319 // Tests that receipts associated with a single block can be stored and retrieved. 320 func TestBlockReceiptStorage(t *testing.T) { 321 db := NewMemoryDatabase() 322 323 // Create a live block since we need metadata to reconstruct the receipt 324 tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil) 325 tx2 := types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil) 326 327 body := &types.Body{Transactions: types.Transactions{tx1, tx2}} 328 329 // Create the two receipts to manage afterwards 330 receipt1 := &types.Receipt{ 331 Status: types.ReceiptStatusFailed, 332 CumulativeGasUsed: 1, 333 Logs: []*types.Log{ 334 {Address: common.BytesToAddress([]byte{0x11})}, 335 {Address: common.BytesToAddress([]byte{0x01, 0x11})}, 336 }, 337 TxHash: tx1.Hash(), 338 ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), 339 GasUsed: 111111, 340 } 341 receipt1.Bloom = types.CreateBloom(receipt1) 342 343 receipt2 := &types.Receipt{ 344 PostState: common.Hash{2}.Bytes(), 345 CumulativeGasUsed: 2, 346 Logs: []*types.Log{ 347 {Address: common.BytesToAddress([]byte{0x22})}, 348 {Address: common.BytesToAddress([]byte{0x02, 0x22})}, 349 }, 350 TxHash: tx2.Hash(), 351 ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), 352 GasUsed: 222222, 353 } 354 receipt2.Bloom = types.CreateBloom(receipt2) 355 receipts := []*types.Receipt{receipt1, receipt2} 356 357 // Check that no receipt entries are in a pristine database 358 hash := common.BytesToHash([]byte{0x03, 0x14}) 359 if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 { 360 t.Fatalf("non existent receipts returned: %v", rs) 361 } 362 // Insert the body that corresponds to the receipts 363 WriteBody(db, hash, 0, body) 364 365 // Insert the receipt slice into the database and check presence 366 WriteReceipts(db, hash, 0, receipts) 367 if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) == 0 { 368 t.Fatal("no receipts returned") 369 } else { 370 if err := checkReceiptsRLP(rs, receipts); err != nil { 371 t.Fatal(err) 372 } 373 } 374 // Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed) 375 DeleteBody(db, hash, 0) 376 if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); rs != nil { 377 t.Fatalf("receipts returned when body was deleted: %v", rs) 378 } 379 // Ensure that receipts without metadata can be returned without the block body too 380 raw := ReadRawReceipts(db, hash, 0) 381 for _, r := range raw { 382 r.Bloom = types.CreateBloom(r) 383 } 384 if err := checkReceiptsRLP(raw, receipts); err != nil { 385 t.Fatal(err) 386 } 387 // Sanity check that body alone without the receipt is a full purge 388 WriteBody(db, hash, 0, body) 389 390 DeleteReceipts(db, hash, 0) 391 if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 { 392 t.Fatalf("deleted receipts returned: %v", rs) 393 } 394 } 395 396 func checkReceiptsRLP(have, want types.Receipts) error { 397 if len(have) != len(want) { 398 return fmt.Errorf("receipts sizes mismatch: have %d, want %d", len(have), len(want)) 399 } 400 for i := 0; i < len(want); i++ { 401 rlpHave, err := rlp.EncodeToBytes(have[i]) 402 if err != nil { 403 return err 404 } 405 rlpWant, err := rlp.EncodeToBytes(want[i]) 406 if err != nil { 407 return err 408 } 409 if !bytes.Equal(rlpHave, rlpWant) { 410 return fmt.Errorf("receipt #%d: receipt mismatch: have %s, want %s", i, hex.EncodeToString(rlpHave), hex.EncodeToString(rlpWant)) 411 } 412 } 413 return nil 414 } 415 416 func TestAncientStorage(t *testing.T) { 417 // Freezer style fast import the chain. 418 frdir := t.TempDir() 419 db, err := Open(NewMemoryDatabase(), OpenOptions{Ancient: frdir}) 420 if err != nil { 421 t.Fatalf("failed to create database with ancient backend") 422 } 423 defer db.Close() 424 425 // Create a test block 426 block := types.NewBlockWithHeader(&types.Header{ 427 Number: big.NewInt(0), 428 Extra: []byte("test block"), 429 UncleHash: types.EmptyUncleHash, 430 TxHash: types.EmptyTxsHash, 431 ReceiptHash: types.EmptyReceiptsHash, 432 }) 433 // Ensure nothing non-existent will be read 434 hash, number := block.Hash(), block.NumberU64() 435 if blob := ReadHeaderRLP(db, hash, number); len(blob) > 0 { 436 t.Fatalf("non existent header returned") 437 } 438 if blob := ReadBodyRLP(db, hash, number); len(blob) > 0 { 439 t.Fatalf("non existent body returned") 440 } 441 if blob := ReadReceiptsRLP(db, hash, number); len(blob) > 0 { 442 t.Fatalf("non existent receipts returned") 443 } 444 if blob := ReadCanonicalReceiptsRLP(db, number, &hash); len(blob) > 0 { 445 t.Fatalf("non existent receipts returned") 446 } 447 448 // Write and verify the header in the database 449 WriteAncientBlocks(db, []*types.Block{block}, types.EncodeBlockReceiptLists([]types.Receipts{nil})) 450 451 if blob := ReadHeaderRLP(db, hash, number); len(blob) == 0 { 452 t.Fatalf("no header returned") 453 } 454 if blob := ReadBodyRLP(db, hash, number); len(blob) == 0 { 455 t.Fatalf("no body returned") 456 } 457 if blob := ReadReceiptsRLP(db, hash, number); len(blob) == 0 { 458 t.Fatalf("no receipts returned") 459 } 460 if blob := ReadCanonicalReceiptsRLP(db, number, &hash); len(blob) == 0 { 461 t.Fatalf("no receipts returned") 462 } 463 464 // Use a fake hash for data retrieval, nothing should be returned. 465 fakeHash := common.BytesToHash([]byte{0x01, 0x02, 0x03}) 466 if blob := ReadHeaderRLP(db, fakeHash, number); len(blob) != 0 { 467 t.Fatalf("invalid header returned") 468 } 469 if blob := ReadBodyRLP(db, fakeHash, number); len(blob) != 0 { 470 t.Fatalf("invalid body returned") 471 } 472 if blob := ReadReceiptsRLP(db, fakeHash, number); len(blob) != 0 { 473 t.Fatalf("invalid receipts returned") 474 } 475 } 476 477 func TestWriteAncientHeaderChain(t *testing.T) { 478 db, err := Open(NewMemoryDatabase(), OpenOptions{Ancient: t.TempDir()}) 479 if err != nil { 480 t.Fatalf("failed to create database with ancient backend") 481 } 482 defer db.Close() 483 484 // Create a test block 485 var headers []*types.Header 486 headers = append(headers, &types.Header{ 487 Number: big.NewInt(0), 488 Extra: []byte("test block"), 489 UncleHash: types.EmptyUncleHash, 490 TxHash: types.EmptyTxsHash, 491 ReceiptHash: types.EmptyReceiptsHash, 492 }) 493 headers = append(headers, &types.Header{ 494 Number: big.NewInt(1), 495 Extra: []byte("test block"), 496 UncleHash: types.EmptyUncleHash, 497 TxHash: types.EmptyTxsHash, 498 ReceiptHash: types.EmptyReceiptsHash, 499 }) 500 // Write and verify the header in the database 501 WriteAncientHeaderChain(db, headers) 502 503 for _, header := range headers { 504 if blob := ReadHeaderRLP(db, header.Hash(), header.Number.Uint64()); len(blob) == 0 { 505 t.Fatalf("no header returned") 506 } 507 if h := ReadCanonicalHash(db, header.Number.Uint64()); h != header.Hash() { 508 t.Fatalf("no canonical hash returned") 509 } 510 if blob := ReadBodyRLP(db, header.Hash(), header.Number.Uint64()); len(blob) != 0 { 511 t.Fatalf("unexpected body returned") 512 } 513 if blob := ReadReceiptsRLP(db, header.Hash(), header.Number.Uint64()); len(blob) != 0 { 514 t.Fatalf("unexpected body returned") 515 } 516 } 517 } 518 519 func TestCanonicalHashIteration(t *testing.T) { 520 var cases = []struct { 521 from, to uint64 522 limit int 523 expect []uint64 524 }{ 525 {1, 8, 0, nil}, 526 {1, 8, 1, []uint64{1}}, 527 {1, 8, 10, []uint64{1, 2, 3, 4, 5, 6, 7}}, 528 {1, 9, 10, []uint64{1, 2, 3, 4, 5, 6, 7, 8}}, 529 {2, 9, 10, []uint64{2, 3, 4, 5, 6, 7, 8}}, 530 {9, 10, 10, nil}, 531 } 532 // Test empty db iteration 533 db := NewMemoryDatabase() 534 numbers, _ := ReadAllCanonicalHashes(db, 0, 10, 10) 535 if len(numbers) != 0 { 536 t.Fatalf("No entry should be returned to iterate an empty db") 537 } 538 // Fill database with testing data. 539 for i := uint64(1); i <= 8; i++ { 540 WriteCanonicalHash(db, common.Hash{}, i) 541 } 542 for i, c := range cases { 543 numbers, _ := ReadAllCanonicalHashes(db, c.from, c.to, c.limit) 544 if !reflect.DeepEqual(numbers, c.expect) { 545 t.Fatalf("Case %d failed, want %v, got %v", i, c.expect, numbers) 546 } 547 } 548 } 549 550 func TestHashesInRange(t *testing.T) { 551 mkHeader := func(number, seq int) *types.Header { 552 h := types.Header{ 553 Difficulty: new(big.Int), 554 Number: big.NewInt(int64(number)), 555 GasLimit: uint64(seq), 556 } 557 return &h 558 } 559 db := NewMemoryDatabase() 560 // For each number, write N versions of that particular number 561 total := 0 562 for i := 0; i < 15; i++ { 563 for ii := 0; ii < i; ii++ { 564 WriteHeader(db, mkHeader(i, ii)) 565 total++ 566 } 567 } 568 if have, want := len(ReadAllHashesInRange(db, 10, 10)), 10; have != want { 569 t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have) 570 } 571 if have, want := len(ReadAllHashesInRange(db, 10, 9)), 0; have != want { 572 t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have) 573 } 574 if have, want := len(ReadAllHashesInRange(db, 0, 100)), total; have != want { 575 t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have) 576 } 577 if have, want := len(ReadAllHashesInRange(db, 9, 10)), 9+10; have != want { 578 t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have) 579 } 580 if have, want := len(ReadAllHashes(db, 10)), 10; have != want { 581 t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have) 582 } 583 if have, want := len(ReadAllHashes(db, 16)), 0; have != want { 584 t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have) 585 } 586 if have, want := len(ReadAllHashes(db, 1)), 1; have != want { 587 t.Fatalf("Wrong number of hashes read, want %d, got %d", want, have) 588 } 589 } 590 591 // This measures the write speed of the WriteAncientBlocks operation. 592 func BenchmarkWriteAncientBlocks(b *testing.B) { 593 // Open freezer database. 594 frdir := b.TempDir() 595 db, err := Open(NewMemoryDatabase(), OpenOptions{Ancient: frdir}) 596 if err != nil { 597 b.Fatalf("failed to create database with ancient backend") 598 } 599 defer db.Close() 600 601 // Create the data to insert. The blocks must have consecutive numbers, so we create 602 // all of them ahead of time. However, there is no need to create receipts 603 // individually for each block, just make one batch here and reuse it for all writes. 604 const batchSize = 128 605 const blockTxs = 20 606 allBlocks := makeTestBlocks(b.N, blockTxs) 607 batchReceipts := makeTestReceipts(batchSize, blockTxs) 608 b.ResetTimer() 609 610 // The benchmark loop writes batches of blocks, but note that the total block count is 611 // b.N. This means the resulting ns/op measurement is the time it takes to write a 612 // single block and its associated data. 613 var totalSize int64 614 for i := 0; i < b.N; i += batchSize { 615 length := batchSize 616 if i+batchSize > b.N { 617 length = b.N - i 618 } 619 620 blocks := allBlocks[i : i+length] 621 receipts := batchReceipts[:length] 622 writeSize, err := WriteAncientBlocks(db, blocks, types.EncodeBlockReceiptLists(receipts)) 623 if err != nil { 624 b.Fatal(err) 625 } 626 totalSize += writeSize 627 } 628 629 // Enable MB/s reporting. 630 b.SetBytes(totalSize / int64(b.N)) 631 } 632 633 // makeTestBlocks creates fake blocks for the ancient write benchmark. 634 func makeTestBlocks(nblock int, txsPerBlock int) []*types.Block { 635 key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 636 signer := types.LatestSignerForChainID(big.NewInt(8)) 637 638 // Create transactions. 639 txs := make([]*types.Transaction, txsPerBlock) 640 for i := 0; i < len(txs); i++ { 641 var err error 642 to := common.Address{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} 643 txs[i], err = types.SignNewTx(key, signer, &types.LegacyTx{ 644 Nonce: 2, 645 GasPrice: big.NewInt(30000), 646 Gas: 0x45454545, 647 To: &to, 648 }) 649 if err != nil { 650 panic(err) 651 } 652 } 653 654 // Create the blocks. 655 blocks := make([]*types.Block, nblock) 656 for i := 0; i < nblock; i++ { 657 header := &types.Header{ 658 Number: big.NewInt(int64(i)), 659 Extra: []byte("test block"), 660 } 661 blocks[i] = types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs}) 662 blocks[i].Hash() // pre-cache the block hash 663 } 664 return blocks 665 } 666 667 // makeTestReceipts creates fake receipts for the ancient write benchmark. 668 func makeTestReceipts(n int, nPerBlock int) []types.Receipts { 669 receipts := make([]*types.Receipt, nPerBlock) 670 var logs []*types.Log 671 for i := 0; i < 5; i++ { 672 logs = append(logs, new(types.Log)) 673 } 674 for i := 0; i < len(receipts); i++ { 675 receipts[i] = &types.Receipt{ 676 Status: types.ReceiptStatusSuccessful, 677 CumulativeGasUsed: 0x888888888, 678 Logs: logs, 679 } 680 } 681 allReceipts := make([]types.Receipts, n) 682 for i := 0; i < n; i++ { 683 allReceipts[i] = receipts 684 } 685 return allReceipts 686 } 687 688 type fullLogRLP struct { 689 Address common.Address 690 Topics []common.Hash 691 Data []byte 692 BlockNumber uint64 693 BlockTimestamp uint64 694 TxHash common.Hash 695 TxIndex uint 696 BlockHash common.Hash 697 Index uint 698 } 699 700 func newFullLogRLP(l *types.Log) *fullLogRLP { 701 return &fullLogRLP{ 702 Address: l.Address, 703 Topics: l.Topics, 704 Data: l.Data, 705 BlockNumber: l.BlockNumber, 706 BlockTimestamp: l.BlockTimestamp, 707 TxHash: l.TxHash, 708 TxIndex: l.TxIndex, 709 BlockHash: l.BlockHash, 710 Index: l.Index, 711 } 712 } 713 714 // Tests that logs associated with a single block can be retrieved. 715 func TestReadLogs(t *testing.T) { 716 db := NewMemoryDatabase() 717 718 // Create a live block since we need metadata to reconstruct the receipt 719 tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil) 720 tx2 := types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil) 721 722 body := &types.Body{Transactions: types.Transactions{tx1, tx2}} 723 724 // Create the two receipts to manage afterwards 725 receipt1 := &types.Receipt{ 726 Status: types.ReceiptStatusFailed, 727 CumulativeGasUsed: 1, 728 Logs: []*types.Log{ 729 {Address: common.BytesToAddress([]byte{0x11})}, 730 {Address: common.BytesToAddress([]byte{0x01, 0x11})}, 731 }, 732 TxHash: tx1.Hash(), 733 ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), 734 GasUsed: 111111, 735 } 736 receipt1.Bloom = types.CreateBloom(receipt1) 737 738 receipt2 := &types.Receipt{ 739 PostState: common.Hash{2}.Bytes(), 740 CumulativeGasUsed: 2, 741 Logs: []*types.Log{ 742 {Address: common.BytesToAddress([]byte{0x22})}, 743 {Address: common.BytesToAddress([]byte{0x02, 0x22})}, 744 }, 745 TxHash: tx2.Hash(), 746 ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), 747 GasUsed: 222222, 748 } 749 receipt2.Bloom = types.CreateBloom(receipt2) 750 receipts := []*types.Receipt{receipt1, receipt2} 751 752 hash := common.BytesToHash([]byte{0x03, 0x14}) 753 // Check that no receipt entries are in a pristine database 754 if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 { 755 t.Fatalf("non existent receipts returned: %v", rs) 756 } 757 // Insert the body that corresponds to the receipts 758 WriteBody(db, hash, 0, body) 759 760 // Insert the receipt slice into the database and check presence 761 WriteReceipts(db, hash, 0, receipts) 762 763 logs := ReadLogs(db, hash, 0) 764 if len(logs) == 0 { 765 t.Fatalf("no logs returned") 766 } 767 if have, want := len(logs), 2; have != want { 768 t.Fatalf("unexpected number of logs returned, have %d want %d", have, want) 769 } 770 if have, want := len(logs[0]), 2; have != want { 771 t.Fatalf("unexpected number of logs[0] returned, have %d want %d", have, want) 772 } 773 if have, want := len(logs[1]), 2; have != want { 774 t.Fatalf("unexpected number of logs[1] returned, have %d want %d", have, want) 775 } 776 777 for i, pr := range receipts { 778 for j, pl := range pr.Logs { 779 rlpHave, err := rlp.EncodeToBytes(newFullLogRLP(logs[i][j])) 780 if err != nil { 781 t.Fatal(err) 782 } 783 rlpWant, err := rlp.EncodeToBytes(newFullLogRLP(pl)) 784 if err != nil { 785 t.Fatal(err) 786 } 787 if !bytes.Equal(rlpHave, rlpWant) { 788 t.Fatalf("receipt #%d: receipt mismatch: have %s, want %s", i, hex.EncodeToString(rlpHave), hex.EncodeToString(rlpWant)) 789 } 790 } 791 } 792 } 793 794 func TestDeriveLogFields(t *testing.T) { 795 // Create a few transactions to have receipts for 796 to2 := common.HexToAddress("0x2") 797 to3 := common.HexToAddress("0x3") 798 txs := types.Transactions{ 799 types.NewTx(&types.LegacyTx{ 800 Nonce: 1, 801 Value: big.NewInt(1), 802 Gas: 1, 803 GasPrice: big.NewInt(1), 804 }), 805 types.NewTx(&types.LegacyTx{ 806 To: &to2, 807 Nonce: 2, 808 Value: big.NewInt(2), 809 Gas: 2, 810 GasPrice: big.NewInt(2), 811 }), 812 types.NewTx(&types.AccessListTx{ 813 To: &to3, 814 Nonce: 3, 815 Value: big.NewInt(3), 816 Gas: 3, 817 GasPrice: big.NewInt(3), 818 }), 819 } 820 // Create the corresponding receipts 821 receipts := []*types.Receipt{ 822 { 823 Logs: []*types.Log{ 824 {Address: common.BytesToAddress([]byte{0x11})}, 825 {Address: common.BytesToAddress([]byte{0x01, 0x11})}, 826 }, 827 }, 828 { 829 Logs: []*types.Log{ 830 {Address: common.BytesToAddress([]byte{0x22})}, 831 {Address: common.BytesToAddress([]byte{0x02, 0x22})}, 832 }, 833 }, 834 { 835 Logs: []*types.Log{ 836 {Address: common.BytesToAddress([]byte{0x33})}, 837 {Address: common.BytesToAddress([]byte{0x03, 0x33})}, 838 }, 839 }, 840 } 841 842 // Derive log metadata fields 843 number := big.NewInt(1) 844 hash := common.BytesToHash([]byte{0x03, 0x14}) 845 types.Receipts(receipts).DeriveFields(params.TestChainConfig, hash, number.Uint64(), 12, big.NewInt(0), big.NewInt(0), txs) 846 847 // Iterate over all the computed fields and check that they're correct 848 logIndex := uint(0) 849 for i := range receipts { 850 for j := range receipts[i].Logs { 851 if receipts[i].Logs[j].BlockNumber != number.Uint64() { 852 t.Errorf("receipts[%d].Logs[%d].BlockNumber = %d, want %d", i, j, receipts[i].Logs[j].BlockNumber, number.Uint64()) 853 } 854 if receipts[i].Logs[j].BlockHash != hash { 855 t.Errorf("receipts[%d].Logs[%d].BlockHash = %s, want %s", i, j, receipts[i].Logs[j].BlockHash.String(), hash.String()) 856 } 857 if receipts[i].Logs[j].BlockTimestamp != 12 { 858 t.Errorf("receipts[%d].Logs[%d].BlockTimestamp = %d, want %d", i, j, receipts[i].Logs[j].BlockTimestamp, 12) 859 } 860 if receipts[i].Logs[j].TxHash != txs[i].Hash() { 861 t.Errorf("receipts[%d].Logs[%d].TxHash = %s, want %s", i, j, receipts[i].Logs[j].TxHash.String(), txs[i].Hash().String()) 862 } 863 if receipts[i].Logs[j].TxIndex != uint(i) { 864 t.Errorf("receipts[%d].Logs[%d].TransactionIndex = %d, want %d", i, j, receipts[i].Logs[j].TxIndex, i) 865 } 866 if receipts[i].Logs[j].Index != logIndex { 867 t.Errorf("receipts[%d].Logs[%d].Index = %d, want %d", i, j, receipts[i].Logs[j].Index, logIndex) 868 } 869 logIndex++ 870 } 871 } 872 } 873 874 func BenchmarkDecodeRLPLogs(b *testing.B) { 875 // Encoded receipts from block 0x14ee094309fbe8f70b65f45ebcc08fb33f126942d97464aad5eb91cfd1e2d269 876 buf, err := os.ReadFile("testdata/stored_receipts.bin") 877 if err != nil { 878 b.Fatal(err) 879 } 880 b.Run("ReceiptForStorage", func(b *testing.B) { 881 b.ReportAllocs() 882 var r []*types.ReceiptForStorage 883 for i := 0; i < b.N; i++ { 884 if err := rlp.DecodeBytes(buf, &r); err != nil { 885 b.Fatal(err) 886 } 887 } 888 }) 889 b.Run("rlpLogs", func(b *testing.B) { 890 b.ReportAllocs() 891 var r []*receiptLogs 892 for i := 0; i < b.N; i++ { 893 if err := rlp.DecodeBytes(buf, &r); err != nil { 894 b.Fatal(err) 895 } 896 } 897 }) 898 } 899 900 func TestHeadersRLPStorage(t *testing.T) { 901 // Have N headers in the freezer 902 frdir := t.TempDir() 903 904 db, err := Open(NewMemoryDatabase(), OpenOptions{Ancient: frdir}) 905 if err != nil { 906 t.Fatalf("failed to create database with ancient backend") 907 } 908 defer db.Close() 909 910 // Create blocks 911 var chain []*types.Block 912 var pHash common.Hash 913 for i := 0; i < 100; i++ { 914 block := types.NewBlockWithHeader(&types.Header{ 915 Number: big.NewInt(int64(i)), 916 Extra: []byte("test block"), 917 UncleHash: types.EmptyUncleHash, 918 TxHash: types.EmptyTxsHash, 919 ReceiptHash: types.EmptyReceiptsHash, 920 ParentHash: pHash, 921 }) 922 chain = append(chain, block) 923 pHash = block.Hash() 924 } 925 receipts := make([]types.Receipts, 100) 926 // Write first half to ancients 927 WriteAncientBlocks(db, chain[:50], types.EncodeBlockReceiptLists(receipts[:50])) 928 // Write second half to db 929 for i := 50; i < 100; i++ { 930 WriteCanonicalHash(db, chain[i].Hash(), chain[i].NumberU64()) 931 WriteBlock(db, chain[i]) 932 } 933 checkSequence := func(from, amount int) { 934 headersRlp := ReadHeaderRange(db, uint64(from), uint64(amount)) 935 if have, want := len(headersRlp), amount; have != want { 936 t.Fatalf("have %d headers, want %d", have, want) 937 } 938 for i, headerRlp := range headersRlp { 939 var header types.Header 940 if err := rlp.DecodeBytes(headerRlp, &header); err != nil { 941 t.Fatal(err) 942 } 943 if have, want := header.Number.Uint64(), uint64(from-i); have != want { 944 t.Fatalf("wrong number, have %d want %d", have, want) 945 } 946 } 947 } 948 checkSequence(99, 20) // Latest block and 19 parents 949 checkSequence(99, 50) // Latest block -> all db blocks 950 checkSequence(99, 51) // Latest block -> one from ancients 951 checkSequence(99, 52) // Latest blocks -> two from ancients 952 checkSequence(50, 2) // One from db, one from ancients 953 checkSequence(49, 1) // One from ancients 954 checkSequence(49, 50) // All ancient ones 955 checkSequence(99, 100) // All blocks 956 checkSequence(0, 1) // Only genesis 957 checkSequence(1, 1) // Only block 1 958 checkSequence(1, 2) // Genesis + block 1 959 }