github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/core/database_util_test.go (about) 1 // Copyright 2015 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 core 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "fmt" 23 "io/ioutil" 24 "math/big" 25 "os" 26 "strconv" 27 "testing" 28 29 "crypto/ecdsa" 30 "encoding/binary" 31 "github.com/ethereumproject/go-ethereum/common" 32 "github.com/ethereumproject/go-ethereum/core/types" 33 "github.com/ethereumproject/go-ethereum/core/vm" 34 "github.com/ethereumproject/go-ethereum/crypto" 35 "github.com/ethereumproject/go-ethereum/crypto/sha3" 36 "github.com/ethereumproject/go-ethereum/ethdb" 37 "github.com/ethereumproject/go-ethereum/rlp" 38 "strings" 39 ) 40 41 type diffTest struct { 42 ParentTimestamp uint64 43 ParentDifficulty *big.Int 44 CurrentTimestamp uint64 45 CurrentBlocknumber *big.Int 46 CurrentDifficulty *big.Int 47 } 48 49 func (d *diffTest) UnmarshalJSON(b []byte) (err error) { 50 var ext struct { 51 ParentTimestamp string 52 ParentDifficulty string 53 CurrentTimestamp string 54 CurrentBlocknumber string 55 CurrentDifficulty string 56 } 57 if err := json.Unmarshal(b, &ext); err != nil { 58 return err 59 } 60 61 d.ParentTimestamp, err = strconv.ParseUint(ext.ParentTimestamp, 0, 64) 62 if err != nil { 63 return fmt.Errorf("malformed parent timestamp: %s", err) 64 } 65 66 d.ParentDifficulty = new(big.Int) 67 if _, ok := d.ParentDifficulty.SetString(ext.ParentDifficulty, 0); !ok { 68 return fmt.Errorf("malformed parent difficulty %q", ext.ParentDifficulty) 69 } 70 71 d.CurrentTimestamp, err = strconv.ParseUint(ext.CurrentTimestamp, 0, 64) 72 if err != nil { 73 return fmt.Errorf("malformed current timestamp: %s", err) 74 } 75 76 d.CurrentBlocknumber = new(big.Int) 77 if _, ok := d.CurrentBlocknumber.SetString(ext.CurrentBlocknumber, 0); !ok { 78 return fmt.Errorf("malformed current blocknumber %q", ext.CurrentBlocknumber) 79 } 80 81 d.CurrentDifficulty = new(big.Int) 82 if _, ok := d.CurrentDifficulty.SetString(ext.CurrentDifficulty, 0); !ok { 83 return fmt.Errorf("malformed current difficulty %q", ext.CurrentDifficulty) 84 } 85 86 return nil 87 } 88 89 func TestDifficultyFrontier(t *testing.T) { 90 file, err := os.Open("../tests/files/BasicTests/difficulty.json") 91 if err != nil { 92 t.Fatal(err) 93 } 94 defer file.Close() 95 96 tests := make(map[string]diffTest) 97 err = json.NewDecoder(file).Decode(&tests) 98 if err != nil { 99 t.Fatal(err) 100 } 101 102 for name, test := range tests { 103 number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1)) 104 diff := calcDifficultyFrontier(test.CurrentTimestamp, test.ParentTimestamp, number, test.ParentDifficulty) 105 if diff.Cmp(test.CurrentDifficulty) != 0 { 106 t.Error(name, "failed. Expected", test.CurrentDifficulty, "and calculated", diff) 107 } 108 } 109 } 110 111 // Tests block header storage and retrieval operations. 112 func TestHeaderStorage(t *testing.T) { 113 db, _ := ethdb.NewMemDatabase() 114 115 // Create a test header to move around the database and make sure it's really new 116 header := &types.Header{Extra: []byte("test header")} 117 if entry := GetHeader(db, header.Hash()); entry != nil { 118 t.Fatalf("Non existent header returned: %v", entry) 119 } 120 // Write and verify the header in the database 121 if err := WriteHeader(db, header); err != nil { 122 t.Fatalf("Failed to write header into database: %v", err) 123 } 124 if entry := GetHeader(db, header.Hash()); entry == nil { 125 t.Fatalf("Stored header not found") 126 } else if entry.Hash() != header.Hash() { 127 t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, header) 128 } 129 if entry := GetHeaderRLP(db, header.Hash()); entry == nil { 130 t.Fatalf("Stored header RLP not found") 131 } else { 132 hasher := sha3.NewKeccak256() 133 hasher.Write(entry) 134 135 if hash := common.BytesToHash(hasher.Sum(nil)); hash != header.Hash() { 136 t.Fatalf("Retrieved RLP header mismatch: have %v, want %v", entry, header) 137 } 138 } 139 // Delete the header and verify the execution 140 DeleteHeader(db, header.Hash()) 141 if entry := GetHeader(db, header.Hash()); entry != nil { 142 t.Fatalf("Deleted header returned: %v", entry) 143 } 144 } 145 146 // Tests block body storage and retrieval operations. 147 func TestBodyStorage(t *testing.T) { 148 db, _ := ethdb.NewMemDatabase() 149 150 // Create a test body to move around the database and make sure it's really new 151 body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}} 152 153 hasher := sha3.NewKeccak256() 154 rlp.Encode(hasher, body) 155 hash := common.BytesToHash(hasher.Sum(nil)) 156 157 if entry := GetBody(db, hash); entry != nil { 158 t.Fatalf("Non existent body returned: %v", entry) 159 } 160 // Write and verify the body in the database 161 if err := WriteBody(db, hash, body); err != nil { 162 t.Fatalf("Failed to write body into database: %v", err) 163 } 164 if entry := GetBody(db, hash); entry == nil { 165 t.Fatalf("Stored body not found") 166 } else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(types.Transactions(body.Transactions)) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(body.Uncles) { 167 t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, body) 168 } 169 if entry := GetBodyRLP(db, hash); entry == nil { 170 t.Fatalf("Stored body RLP not found") 171 } else { 172 hasher := sha3.NewKeccak256() 173 hasher.Write(entry) 174 175 if calc := common.BytesToHash(hasher.Sum(nil)); calc != hash { 176 t.Fatalf("Retrieved RLP body mismatch: have %v, want %v", entry, body) 177 } 178 } 179 // Delete the body and verify the execution 180 DeleteBody(db, hash) 181 if entry := GetBody(db, hash); entry != nil { 182 t.Fatalf("Deleted body returned: %v", entry) 183 } 184 } 185 186 // Tests block storage and retrieval operations. 187 func TestBlockStorage(t *testing.T) { 188 db, _ := ethdb.NewMemDatabase() 189 190 // Create a test block to move around the database and make sure it's really new 191 block := types.NewBlockWithHeader(&types.Header{ 192 Extra: []byte("test block"), 193 UncleHash: types.EmptyUncleHash, 194 TxHash: types.EmptyRootHash, 195 ReceiptHash: types.EmptyRootHash, 196 }) 197 if entry := GetBlock(db, block.Hash()); entry != nil { 198 t.Fatalf("Non existent block returned: %v", entry) 199 } 200 if entry := GetHeader(db, block.Hash()); entry != nil { 201 t.Fatalf("Non existent header returned: %v", entry) 202 } 203 if entry := GetBody(db, block.Hash()); entry != nil { 204 t.Fatalf("Non existent body returned: %v", entry) 205 } 206 // Write and verify the block in the database 207 if err := WriteBlock(db, block); err != nil { 208 t.Fatalf("Failed to write block into database: %v", err) 209 } 210 if entry := GetBlock(db, block.Hash()); entry == nil { 211 t.Fatalf("Stored block not found") 212 } else if entry.Hash() != block.Hash() { 213 t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block) 214 } 215 if entry := GetHeader(db, block.Hash()); entry == nil { 216 t.Fatalf("Stored header not found") 217 } else if entry.Hash() != block.Header().Hash() { 218 t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, block.Header()) 219 } 220 if entry := GetBody(db, block.Hash()); entry == nil { 221 t.Fatalf("Stored body not found") 222 } else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(block.Transactions()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) { 223 t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, block.Body()) 224 } 225 // Delete the block and verify the execution 226 DeleteBlock(db, block.Hash()) 227 if entry := GetBlock(db, block.Hash()); entry != nil { 228 t.Fatalf("Deleted block returned: %v", entry) 229 } 230 if entry := GetHeader(db, block.Hash()); entry != nil { 231 t.Fatalf("Deleted header returned: %v", entry) 232 } 233 if entry := GetBody(db, block.Hash()); entry != nil { 234 t.Fatalf("Deleted body returned: %v", entry) 235 } 236 } 237 238 // Tests that partial block contents don't get reassembled into full blocks. 239 func TestPartialBlockStorage(t *testing.T) { 240 db, _ := ethdb.NewMemDatabase() 241 block := types.NewBlockWithHeader(&types.Header{ 242 Extra: []byte("test block"), 243 UncleHash: types.EmptyUncleHash, 244 TxHash: types.EmptyRootHash, 245 ReceiptHash: types.EmptyRootHash, 246 }) 247 // Store a header and check that it's not recognized as a block 248 if err := WriteHeader(db, block.Header()); err != nil { 249 t.Fatalf("Failed to write header into database: %v", err) 250 } 251 if entry := GetBlock(db, block.Hash()); entry != nil { 252 t.Fatalf("Non existent block returned: %v", entry) 253 } 254 DeleteHeader(db, block.Hash()) 255 256 // Store a body and check that it's not recognized as a block 257 if err := WriteBody(db, block.Hash(), block.Body()); err != nil { 258 t.Fatalf("Failed to write body into database: %v", err) 259 } 260 if entry := GetBlock(db, block.Hash()); entry != nil { 261 t.Fatalf("Non existent block returned: %v", entry) 262 } 263 DeleteBody(db, block.Hash()) 264 265 // Store a header and a body separately and check reassembly 266 if err := WriteHeader(db, block.Header()); err != nil { 267 t.Fatalf("Failed to write header into database: %v", err) 268 } 269 if err := WriteBody(db, block.Hash(), block.Body()); err != nil { 270 t.Fatalf("Failed to write body into database: %v", err) 271 } 272 if entry := GetBlock(db, block.Hash()); entry == nil { 273 t.Fatalf("Stored block not found") 274 } else if entry.Hash() != block.Hash() { 275 t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block) 276 } 277 } 278 279 // Tests block total difficulty storage and retrieval operations. 280 func TestTdStorage(t *testing.T) { 281 db, _ := ethdb.NewMemDatabase() 282 283 // Create a test TD to move around the database and make sure it's really new 284 hash, td := common.Hash{}, big.NewInt(314) 285 if entry := GetTd(db, hash); entry != nil { 286 t.Fatalf("Non existent TD returned: %v", entry) 287 } 288 // Write and verify the TD in the database 289 if err := WriteTd(db, hash, td); err != nil { 290 t.Fatalf("Failed to write TD into database: %v", err) 291 } 292 if entry := GetTd(db, hash); entry == nil { 293 t.Fatalf("Stored TD not found") 294 } else if entry.Cmp(td) != 0 { 295 t.Fatalf("Retrieved TD mismatch: have %v, want %v", entry, td) 296 } 297 // Delete the TD and verify the execution 298 DeleteTd(db, hash) 299 if entry := GetTd(db, hash); entry != nil { 300 t.Fatalf("Deleted TD returned: %v", entry) 301 } 302 } 303 304 func TestAddrTxStorage(t *testing.T) { 305 dbFilepath, err := ioutil.TempDir("", "geth-db-util-test") 306 if err != nil { 307 t.Fatal(err) 308 } 309 defer os.RemoveAll(dbFilepath) 310 db, _ := ethdb.NewLDBDatabase(dbFilepath, 10, 100) 311 312 testKey := func(hex string) (*ecdsa.PrivateKey, common.Address) { 313 key := crypto.ToECDSA(common.Hex2Bytes(hex)) 314 addr := crypto.PubkeyToAddress(key.PublicKey) 315 return key, addr 316 } 317 318 skey1, from1 := testKey("123915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") 319 skey2, from2 := testKey("456915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") 320 321 from2to := common.BytesToAddress([]byte{0x22}) 322 323 // from1 -> 1 324 tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), big.NewInt(1111), big.NewInt(11111), []byte{0x11, 0x11, 0x11}) 325 326 // from2 -> 2,3,txC 327 tx2 := types.NewTransaction(2, from2to, big.NewInt(222), big.NewInt(2222), big.NewInt(22222), []byte{0x22, 0x22, 0x22}) 328 tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), big.NewInt(3333), big.NewInt(33333), []byte{0x33, 0x33, 0x33}) 329 txC := types.NewTransaction(4, common.Address{}, big.NewInt(333), big.NewInt(3333), big.NewInt(33333), []byte{0x33, 0x33, 0x33}) 330 331 txs := []*types.Transaction{tx1, tx2, tx3, txC} 332 txsSigned := []*types.Transaction{} 333 334 for _, x := range txs { 335 // Sign em so we get from 336 key := skey1 337 if x.Nonce() != 1 { 338 key = skey2 339 } 340 x.SetSigner(types.NewChainIdSigner(big.NewInt(1))) 341 xs, err := x.SignECDSA(key) 342 if err != nil { 343 t.Fatal(err) 344 } 345 txsSigned = append(txsSigned, xs) 346 } 347 348 block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txsSigned, nil, nil) 349 350 // Put in the transactions just for fun. 351 // 352 // Check that no transactions entries are in a pristine database 353 for i, tx := range txsSigned { 354 if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil { 355 t.Fatalf("tx #%d [%x]: non existent transaction returned: %v", i, tx.Hash(), txn) 356 } 357 } 358 // Insert all the transactions into the database, and verify contents 359 if err := WriteTransactions(db, block); err != nil { 360 t.Fatalf("failed to write transactions: %v", err) 361 } 362 for i, tx := range txsSigned { 363 if txn, hash, number, index := GetTransaction(db, tx.Hash()); txn == nil { 364 t.Fatalf("tx #%d [%x]: transaction not found", i, tx.Hash()) 365 } else { 366 if hash != block.Hash() || number != block.NumberU64() || index != uint64(i) { 367 t.Fatalf("tx #%d [%x]: positional metadata mismatch: have %x/%d/%d, want %x/%v/%v", i, tx.Hash(), hash, number, index, block.Hash(), block.NumberU64(), i) 368 } 369 if tx.String() != txn.String() { 370 t.Fatalf("tx #%d [%x]: transaction mismatch: have %v, want %v", i, tx.Hash(), txn, tx) 371 } 372 } 373 } 374 375 // Write the atx indexes 376 if err := WriteBlockAddTxIndexes(db, block); err != nil { 377 t.Fatal(err) 378 } 379 380 prefix := ethdb.NewBytesPrefix(txAddressIndexPrefix) 381 it := db.NewIteratorRange(prefix) 382 count := 0 383 for it.Next() { 384 count++ 385 //// Debugger -- it's kinda nice to see what the indexes look like 386 //ad, bn, tf, sc, txh := resolveAddrTxBytes(it.Key()) 387 //addr, blockn, direc, ko, txhash := common.BytesToAddress(ad), binary.LittleEndian.Uint64(bn), string(tf), string(sc), common.BytesToHash(txh) 388 //t.Log(addr.Hex(), blockn, direc, ko, txhash.Hex()) 389 } 390 it.Release() 391 if e := it.Error(); e != nil { 392 t.Fatal(e) 393 } 394 if count != 8 { 395 t.Errorf("want: %v, got: %v", 7, count) 396 } 397 398 out, _ := GetAddrTxs(db, from2, 0, 0, "", "", -1, -1, false) 399 if len(out) != 3 { 400 t.Errorf("want: %v, got: %v", 3, len(out)) 401 } 402 403 // Test pagination and reverse 404 outReverse, _ := GetAddrTxs(db, from2, 0, 0, "", "", -1, -1, true) 405 if len(outReverse) != 3 { 406 t.Errorf("want: %v, got: %v", 3, len(outReverse)) 407 } 408 // reverse 409 if out[0] != outReverse[2] || out[1] != outReverse[1] || out[2] != outReverse[0] { 410 t.Errorf("got: %v, want: %v", outReverse, out) 411 } 412 // pagination 413 outPag, _ := GetAddrTxs(db, from2, 0, 0, "", "", 1, -1, false) 414 if len(outPag) != 2 { 415 t.Errorf("got: %v, want: %v", len(outPag), 2) 416 } 417 418 out, _ = GetAddrTxs(db, from2, 0, 0, "", "c", -1, -1, false) 419 if len(out) != 1 { 420 t.Errorf("got: %v, want: %v", len(out), 1) 421 } 422 out, _ = GetAddrTxs(db, common.Address{}, 0, 0, "", "", -1, -1, false) 423 if len(out) != 1 { 424 t.Errorf("got: %v, want: %v", len(out), 1) 425 } 426 427 out, _ = GetAddrTxs(db, from1, 314, 314, "", "", -1, -1, false) 428 if len(out) != 1 { 429 t.Errorf("want: %v, got: %v", 1, len(out)) 430 } else { 431 h := out[0] 432 if !strings.HasPrefix(h, "0x") { 433 t.Errorf("want: 0x-prefix, got: %v", h) 434 } 435 if !common.IsHex(h) { 436 t.Errorf("want: hex, got: %v", h) 437 } 438 txh := common.HexToHash(h) 439 440 if txh != txsSigned[0].Hash() { 441 t.Errorf("got: %x, want: %x", txh, txsSigned[0].Hash()) 442 } 443 444 gx, _, _, _ := GetTransaction(db, txh) 445 if gx == nil { 446 t.Errorf("missing tx: %x", txh) 447 } 448 } 449 450 out, _ = GetAddrTxs(db, from2to, 314, 314, "to", "", -1, -1, false) 451 if len(out) != 1 { 452 t.Errorf("want: %v, got: %v", 1, len(out)) 453 } else { 454 h := out[0] 455 if !strings.HasPrefix(h, "0x") { 456 t.Errorf("want: 0x-prefix, got: %v", h) 457 } 458 if !common.IsHex(h) { 459 t.Errorf("want: hex, got: %v", h) 460 } 461 txh := common.HexToHash(h) 462 if txh != txsSigned[1].Hash() { 463 t.Errorf("got: %x, want: %x", txh, txsSigned[0].Hash()) 464 } 465 gx, _, _, _ := GetTransaction(db, txh) 466 if gx == nil { 467 t.Errorf("missing tx: %x", txh) 468 } 469 f, e := gx.From() 470 if e != nil { 471 t.Error(e) 472 } 473 if f != from2 { 474 t.Errorf("got: %v, want: %v", f, from2) 475 } 476 } 477 out, _ = GetAddrTxs(db, from2to, 314, 314, "from", "", -1, -1, false) 478 if len(out) != 0 { 479 t.Errorf("want: %v, got: %v", 0, len(out)) 480 } 481 } 482 483 func TestFormatAndResolveAddrTxBytesKey(t *testing.T) { 484 testAddr := common.Address{} 485 testBN := uint64(42) 486 testTorf := "f" 487 testKindOf := "s" 488 testTxH := common.Hash{} 489 490 testBNBytes := make([]byte, 8) 491 binary.LittleEndian.PutUint64(testBNBytes, testBN) 492 493 key := formatAddrTxBytesIndex(testAddr.Bytes(), testBNBytes, []byte(testTorf), []byte(testKindOf), testTxH.Bytes()) 494 495 // Test key/prefix iterator-ability. 496 itPrefix := formatAddrTxIterator(testAddr) 497 if !bytes.HasPrefix(key, itPrefix) { 498 t.Fatalf("key/prefix mismatch: prefix=%s key=%s", itPrefix, key) 499 } 500 501 // Reverse engineer key and ensure expected. 502 outAddr, outBNBytes, outTorf, outKindOf, outTxH := resolveAddrTxBytes(key) 503 504 if gotAddr := common.BytesToAddress(outAddr); gotAddr != testAddr { 505 t.Errorf("got: %v, want: %v", gotAddr.Hex(), testAddr.Hex()) 506 } 507 if gotBN := binary.LittleEndian.Uint64(outBNBytes); gotBN != testBN { 508 t.Errorf("got: %v, want: %v", gotBN, testBN) 509 } 510 if gotTorf := string(outTorf); gotTorf != testTorf { 511 t.Errorf("got: %v, want: %v", gotTorf, testTorf) 512 } 513 if gotKindOf := string(outKindOf); gotKindOf != testKindOf { 514 t.Errorf("got: %v, want: %v", gotKindOf, testKindOf) 515 } 516 if gotTxH := common.BytesToHash(outTxH); gotTxH != testTxH { 517 t.Errorf("got: %v, want: %v", gotTxH, testTxH) 518 } 519 520 // Ensure proper key part sizing. 521 sizes := []struct { 522 b []byte 523 expectedLen int 524 }{ 525 {outAddr, common.AddressLength}, 526 {outBNBytes, 8}, 527 {outTorf, 1}, 528 {outKindOf, 1}, 529 {outTxH, common.HashLength}, 530 } 531 for _, s := range sizes { 532 if l := len(s.b); l != s.expectedLen { 533 t.Errorf("want: %v, got: %v", s.expectedLen, l) 534 } 535 } 536 } 537 538 // Tests that canonical numbers can be mapped to hashes and retrieved. 539 func TestCanonicalMappingStorage(t *testing.T) { 540 db, _ := ethdb.NewMemDatabase() 541 542 // Create a test canonical number and assinged hash to move around 543 hash, number := common.Hash{0: 0xff}, uint64(314) 544 if entry := GetCanonicalHash(db, number); entry != (common.Hash{}) { 545 t.Fatalf("Non existent canonical mapping returned: %v", entry) 546 } 547 // Write and verify the TD in the database 548 if err := WriteCanonicalHash(db, hash, number); err != nil { 549 t.Fatalf("Failed to write canonical mapping into database: %v", err) 550 } 551 if entry := GetCanonicalHash(db, number); entry == (common.Hash{}) { 552 t.Fatalf("Stored canonical mapping not found") 553 } else if entry != hash { 554 t.Fatalf("Retrieved canonical mapping mismatch: have %v, want %v", entry, hash) 555 } 556 // Delete the TD and verify the execution 557 DeleteCanonicalHash(db, number) 558 if entry := GetCanonicalHash(db, number); entry != (common.Hash{}) { 559 t.Fatalf("Deleted canonical mapping returned: %v", entry) 560 } 561 } 562 563 // Tests that head headers and head blocks can be assigned, individually. 564 func TestHeadStorage(t *testing.T) { 565 db, _ := ethdb.NewMemDatabase() 566 567 blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")}) 568 blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")}) 569 blockFast := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block fast")}) 570 571 // Check that no head entries are in a pristine database 572 if entry := GetHeadHeaderHash(db); entry != (common.Hash{}) { 573 t.Fatalf("Non head header entry returned: %v", entry) 574 } 575 if entry := GetHeadBlockHash(db); entry != (common.Hash{}) { 576 t.Fatalf("Non head block entry returned: %v", entry) 577 } 578 if entry := GetHeadFastBlockHash(db); entry != (common.Hash{}) { 579 t.Fatalf("Non fast head block entry returned: %v", entry) 580 } 581 // Assign separate entries for the head header and block 582 if err := WriteHeadHeaderHash(db, blockHead.Hash()); err != nil { 583 t.Fatalf("Failed to write head header hash: %v", err) 584 } 585 if err := WriteHeadBlockHash(db, blockFull.Hash()); err != nil { 586 t.Fatalf("Failed to write head block hash: %v", err) 587 } 588 if err := WriteHeadFastBlockHash(db, blockFast.Hash()); err != nil { 589 t.Fatalf("Failed to write fast head block hash: %v", err) 590 } 591 // Check that both heads are present, and different (i.e. two heads maintained) 592 if entry := GetHeadHeaderHash(db); entry != blockHead.Hash() { 593 t.Fatalf("Head header hash mismatch: have %v, want %v", entry, blockHead.Hash()) 594 } 595 if entry := GetHeadBlockHash(db); entry != blockFull.Hash() { 596 t.Fatalf("Head block hash mismatch: have %v, want %v", entry, blockFull.Hash()) 597 } 598 if entry := GetHeadFastBlockHash(db); entry != blockFast.Hash() { 599 t.Fatalf("Fast head block hash mismatch: have %v, want %v", entry, blockFast.Hash()) 600 } 601 } 602 603 // Tests that transactions and associated metadata can be stored and retrieved. 604 func TestTransactionStorage(t *testing.T) { 605 db, _ := ethdb.NewMemDatabase() 606 607 tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), big.NewInt(1111), big.NewInt(11111), []byte{0x11, 0x11, 0x11}) 608 tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), big.NewInt(2222), big.NewInt(22222), []byte{0x22, 0x22, 0x22}) 609 tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), big.NewInt(3333), big.NewInt(33333), []byte{0x33, 0x33, 0x33}) 610 txs := []*types.Transaction{tx1, tx2, tx3} 611 612 block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil) 613 614 // Check that no transactions entries are in a pristine database 615 for i, tx := range txs { 616 if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil { 617 t.Fatalf("tx #%d [%x]: non existent transaction returned: %v", i, tx.Hash(), txn) 618 } 619 } 620 // Insert all the transactions into the database, and verify contents 621 if err := WriteTransactions(db, block); err != nil { 622 t.Fatalf("failed to write transactions: %v", err) 623 } 624 for i, tx := range txs { 625 if txn, hash, number, index := GetTransaction(db, tx.Hash()); txn == nil { 626 t.Fatalf("tx #%d [%x]: transaction not found", i, tx.Hash()) 627 } else { 628 if hash != block.Hash() || number != block.NumberU64() || index != uint64(i) { 629 t.Fatalf("tx #%d [%x]: positional metadata mismatch: have %x/%d/%d, want %x/%v/%v", i, tx.Hash(), hash, number, index, block.Hash(), block.NumberU64(), i) 630 } 631 if tx.String() != txn.String() { 632 t.Fatalf("tx #%d [%x]: transaction mismatch: have %v, want %v", i, tx.Hash(), txn, tx) 633 } 634 } 635 } 636 // Delete the transactions and check purge 637 for i, tx := range txs { 638 DeleteTransaction(db, tx.Hash()) 639 if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil { 640 t.Fatalf("tx #%d [%x]: deleted transaction returned: %v", i, tx.Hash(), txn) 641 } 642 } 643 } 644 645 // Tests that receipts can be stored and retrieved. 646 func TestReceiptStorage(t *testing.T) { 647 db, _ := ethdb.NewMemDatabase() 648 649 receipt1 := &types.Receipt{ 650 PostState: []byte{0x01}, 651 CumulativeGasUsed: big.NewInt(1), 652 Logs: vm.Logs{ 653 &vm.Log{Address: common.BytesToAddress([]byte{0x11})}, 654 &vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})}, 655 }, 656 TxHash: common.BytesToHash([]byte{0x11, 0x11}), 657 ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), 658 GasUsed: big.NewInt(111111), 659 } 660 receipt2 := &types.Receipt{ 661 PostState: []byte{0x02}, 662 CumulativeGasUsed: big.NewInt(2), 663 Logs: vm.Logs{ 664 &vm.Log{Address: common.BytesToAddress([]byte{0x22})}, 665 &vm.Log{Address: common.BytesToAddress([]byte{0x02, 0x22})}, 666 }, 667 TxHash: common.BytesToHash([]byte{0x22, 0x22}), 668 ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), 669 GasUsed: big.NewInt(222222), 670 } 671 receipts := []*types.Receipt{receipt1, receipt2} 672 673 // Check that no receipt entries are in a pristine database 674 for i, receipt := range receipts { 675 if r := GetReceipt(db, receipt.TxHash); r != nil { 676 t.Fatalf("receipt #%d [%x]: non existent receipt returned: %v", i, receipt.TxHash, r) 677 } 678 } 679 // Insert all the receipts into the database, and verify contents 680 if err := WriteReceipts(db, receipts); err != nil { 681 t.Fatalf("failed to write receipts: %v", err) 682 } 683 for i, receipt := range receipts { 684 if r := GetReceipt(db, receipt.TxHash); r == nil { 685 t.Fatalf("receipt #%d [%x]: receipt not found", i, receipt.TxHash) 686 } else { 687 rlpHave, _ := rlp.EncodeToBytes(r) 688 rlpWant, _ := rlp.EncodeToBytes(receipt) 689 690 if bytes.Compare(rlpHave, rlpWant) != 0 { 691 t.Fatalf("receipt #%d [%x]: receipt mismatch: have %v, want %v", i, receipt.TxHash, r, receipt) 692 } 693 } 694 } 695 // Delete the receipts and check purge 696 for i, receipt := range receipts { 697 DeleteReceipt(db, receipt.TxHash) 698 if r := GetReceipt(db, receipt.TxHash); r != nil { 699 t.Fatalf("receipt #%d [%x]: deleted receipt returned: %v", i, receipt.TxHash, r) 700 } 701 } 702 } 703 704 // Tests that receipts associated with a single block can be stored and retrieved. 705 func TestBlockReceiptStorage(t *testing.T) { 706 db, _ := ethdb.NewMemDatabase() 707 708 receipt1 := &types.Receipt{ 709 PostState: []byte{0x01}, 710 CumulativeGasUsed: big.NewInt(1), 711 Logs: vm.Logs{ 712 &vm.Log{Address: common.BytesToAddress([]byte{0x11})}, 713 &vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})}, 714 }, 715 TxHash: common.BytesToHash([]byte{0x11, 0x11}), 716 ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), 717 GasUsed: big.NewInt(111111), 718 } 719 receipt2 := &types.Receipt{ 720 PostState: []byte{0x02}, 721 CumulativeGasUsed: big.NewInt(2), 722 Logs: vm.Logs{ 723 &vm.Log{Address: common.BytesToAddress([]byte{0x22})}, 724 &vm.Log{Address: common.BytesToAddress([]byte{0x02, 0x22})}, 725 }, 726 TxHash: common.BytesToHash([]byte{0x22, 0x22}), 727 ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), 728 GasUsed: big.NewInt(222222), 729 } 730 receipts := []*types.Receipt{receipt1, receipt2} 731 732 // Check that no receipt entries are in a pristine database 733 hash := common.BytesToHash([]byte{0x03, 0x14}) 734 if rs := GetBlockReceipts(db, hash); len(rs) != 0 { 735 t.Fatalf("non existent receipts returned: %v", rs) 736 } 737 // Insert the receipt slice into the database and check presence 738 if err := WriteBlockReceipts(db, hash, receipts); err != nil { 739 t.Fatalf("failed to write block receipts: %v", err) 740 } 741 if rs := GetBlockReceipts(db, hash); len(rs) == 0 { 742 t.Fatalf("no receipts returned") 743 } else { 744 for i := 0; i < len(receipts); i++ { 745 rlpHave, _ := rlp.EncodeToBytes(rs[i]) 746 rlpWant, _ := rlp.EncodeToBytes(receipts[i]) 747 748 if bytes.Compare(rlpHave, rlpWant) != 0 { 749 t.Fatalf("receipt #%d: receipt mismatch: have %v, want %v", i, rs[i], receipts[i]) 750 } 751 } 752 } 753 // Delete the receipt slice and check purge 754 DeleteBlockReceipts(db, hash) 755 if rs := GetBlockReceipts(db, hash); len(rs) != 0 { 756 t.Fatalf("deleted receipts returned: %v", rs) 757 } 758 } 759 760 func TestMipmapBloom(t *testing.T) { 761 db, _ := ethdb.NewMemDatabase() 762 763 receipt1 := new(types.Receipt) 764 receipt1.Logs = vm.Logs{ 765 &vm.Log{Address: common.BytesToAddress([]byte("test"))}, 766 &vm.Log{Address: common.BytesToAddress([]byte("address"))}, 767 } 768 receipt2 := new(types.Receipt) 769 receipt2.Logs = vm.Logs{ 770 &vm.Log{Address: common.BytesToAddress([]byte("test"))}, 771 &vm.Log{Address: common.BytesToAddress([]byte("address1"))}, 772 } 773 774 WriteMipmapBloom(db, 1, types.Receipts{receipt1}) 775 WriteMipmapBloom(db, 2, types.Receipts{receipt2}) 776 777 for _, level := range MIPMapLevels { 778 bloom := GetMipmapBloom(db, 2, level) 779 if !types.BloomLookup(bloom, []byte("address1")) { 780 t.Error("expected test to be included on level:", level) 781 } 782 } 783 784 // reset 785 db, _ = ethdb.NewMemDatabase() 786 receipt := new(types.Receipt) 787 receipt.Logs = vm.Logs{ 788 &vm.Log{Address: common.BytesToAddress([]byte("test"))}, 789 } 790 WriteMipmapBloom(db, 999, types.Receipts{receipt1}) 791 792 receipt = new(types.Receipt) 793 receipt.Logs = vm.Logs{ 794 &vm.Log{Address: common.BytesToAddress([]byte("test 1"))}, 795 } 796 WriteMipmapBloom(db, 1000, types.Receipts{receipt}) 797 798 bloom := GetMipmapBloom(db, 1000, 1000) 799 if types.BloomLookup(bloom, []byte("test")) { 800 t.Error("test should not have been included") 801 } 802 } 803 804 func TestMipmapChain(t *testing.T) { 805 dir, err := ioutil.TempDir("", "mipmap") 806 if err != nil { 807 t.Fatal(err) 808 } 809 defer os.RemoveAll(dir) 810 811 var ( 812 db, _ = ethdb.NewLDBDatabase(dir, 0, 0) 813 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 814 addr = crypto.PubkeyToAddress(key1.PublicKey) 815 addr2 = common.BytesToAddress([]byte("jeff")) 816 817 hash1 = common.BytesToHash([]byte("topic1")) 818 ) 819 defer db.Close() 820 821 genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr, big.NewInt(1000000)}) 822 chain, receipts := GenerateChain(testChainConfig(), genesis, db, 1010, func(i int, gen *BlockGen) { 823 var receipts types.Receipts 824 switch i { 825 case 1: 826 receipt := types.NewReceipt(nil, new(big.Int)) 827 receipt.Logs = vm.Logs{ 828 &vm.Log{ 829 Address: addr, 830 Topics: []common.Hash{hash1}, 831 }, 832 } 833 gen.AddUncheckedReceipt(receipt) 834 receipts = types.Receipts{receipt} 835 case 1000: 836 receipt := types.NewReceipt(nil, new(big.Int)) 837 receipt.Logs = vm.Logs{&vm.Log{Address: addr2}} 838 gen.AddUncheckedReceipt(receipt) 839 receipts = types.Receipts{receipt} 840 841 } 842 843 // store the receipts 844 err := WriteReceipts(db, receipts) 845 if err != nil { 846 t.Fatal(err) 847 } 848 WriteMipmapBloom(db, uint64(i+1), receipts) 849 }) 850 for i, block := range chain { 851 WriteBlock(db, block) 852 if err := WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil { 853 t.Fatalf("failed to insert block number: %v", err) 854 } 855 if err := WriteHeadBlockHash(db, block.Hash()); err != nil { 856 t.Fatalf("failed to insert block number: %v", err) 857 } 858 if err := WriteBlockReceipts(db, block.Hash(), receipts[i]); err != nil { 859 t.Fatal("error writing block receipts:", err) 860 } 861 } 862 863 bloom := GetMipmapBloom(db, 0, 1000) 864 if types.BloomLookup(bloom, addr2[:]) { 865 t.Error("address was included in bloom and should not have") 866 } 867 }