database_util_test.go 20.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package core

import (
20
	"bytes"
21
	"io/ioutil"
22 23 24 25 26
	"math/big"
	"os"
	"testing"

	"github.com/ethereum/go-ethereum/common"
27
	"github.com/ethereum/go-ethereum/core/types"
28
	"github.com/ethereum/go-ethereum/crypto"
29 30
	"github.com/ethereum/go-ethereum/crypto/sha3"
	"github.com/ethereum/go-ethereum/ethdb"
31
	"github.com/ethereum/go-ethereum/params"
32
	"github.com/ethereum/go-ethereum/rlp"
33 34
)

35 36 37 38 39
// Tests block header storage and retrieval operations.
func TestHeaderStorage(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()

	// Create a test header to move around the database and make sure it's really new
40 41
	header := &types.Header{Number: big.NewInt(42), Extra: []byte("test header")}
	if entry := GetHeader(db, header.Hash(), header.Number.Uint64()); entry != nil {
42 43 44 45 46 47
		t.Fatalf("Non existent header returned: %v", entry)
	}
	// Write and verify the header in the database
	if err := WriteHeader(db, header); err != nil {
		t.Fatalf("Failed to write header into database: %v", err)
	}
48
	if entry := GetHeader(db, header.Hash(), header.Number.Uint64()); entry == nil {
49 50 51 52
		t.Fatalf("Stored header not found")
	} else if entry.Hash() != header.Hash() {
		t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, header)
	}
53
	if entry := GetHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil {
54 55 56 57 58 59 60 61 62 63
		t.Fatalf("Stored header RLP not found")
	} else {
		hasher := sha3.NewKeccak256()
		hasher.Write(entry)

		if hash := common.BytesToHash(hasher.Sum(nil)); hash != header.Hash() {
			t.Fatalf("Retrieved RLP header mismatch: have %v, want %v", entry, header)
		}
	}
	// Delete the header and verify the execution
64 65
	DeleteHeader(db, header.Hash(), header.Number.Uint64())
	if entry := GetHeader(db, header.Hash(), header.Number.Uint64()); entry != nil {
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
		t.Fatalf("Deleted header returned: %v", entry)
	}
}

// Tests block body storage and retrieval operations.
func TestBodyStorage(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()

	// Create a test body to move around the database and make sure it's really new
	body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}}

	hasher := sha3.NewKeccak256()
	rlp.Encode(hasher, body)
	hash := common.BytesToHash(hasher.Sum(nil))

81
	if entry := GetBody(db, hash, 0); entry != nil {
82 83 84
		t.Fatalf("Non existent body returned: %v", entry)
	}
	// Write and verify the body in the database
85
	if err := WriteBody(db, hash, 0, body); err != nil {
86 87
		t.Fatalf("Failed to write body into database: %v", err)
	}
88
	if entry := GetBody(db, hash, 0); entry == nil {
89 90 91 92
		t.Fatalf("Stored body not found")
	} else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(types.Transactions(body.Transactions)) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(body.Uncles) {
		t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, body)
	}
93
	if entry := GetBodyRLP(db, hash, 0); entry == nil {
94 95 96 97 98 99 100 101 102 103
		t.Fatalf("Stored body RLP not found")
	} else {
		hasher := sha3.NewKeccak256()
		hasher.Write(entry)

		if calc := common.BytesToHash(hasher.Sum(nil)); calc != hash {
			t.Fatalf("Retrieved RLP body mismatch: have %v, want %v", entry, body)
		}
	}
	// Delete the body and verify the execution
104 105
	DeleteBody(db, hash, 0)
	if entry := GetBody(db, hash, 0); entry != nil {
106 107 108 109 110 111 112 113 114
		t.Fatalf("Deleted body returned: %v", entry)
	}
}

// Tests block storage and retrieval operations.
func TestBlockStorage(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()

	// Create a test block to move around the database and make sure it's really new
115 116 117 118 119 120
	block := types.NewBlockWithHeader(&types.Header{
		Extra:       []byte("test block"),
		UncleHash:   types.EmptyUncleHash,
		TxHash:      types.EmptyRootHash,
		ReceiptHash: types.EmptyRootHash,
	})
121
	if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil {
122 123
		t.Fatalf("Non existent block returned: %v", entry)
	}
124
	if entry := GetHeader(db, block.Hash(), block.NumberU64()); entry != nil {
125 126
		t.Fatalf("Non existent header returned: %v", entry)
	}
127
	if entry := GetBody(db, block.Hash(), block.NumberU64()); entry != nil {
128 129 130 131 132 133
		t.Fatalf("Non existent body returned: %v", entry)
	}
	// Write and verify the block in the database
	if err := WriteBlock(db, block); err != nil {
		t.Fatalf("Failed to write block into database: %v", err)
	}
134
	if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry == nil {
135 136 137 138
		t.Fatalf("Stored block not found")
	} else if entry.Hash() != block.Hash() {
		t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block)
	}
139
	if entry := GetHeader(db, block.Hash(), block.NumberU64()); entry == nil {
140 141 142 143
		t.Fatalf("Stored header not found")
	} else if entry.Hash() != block.Header().Hash() {
		t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, block.Header())
	}
144
	if entry := GetBody(db, block.Hash(), block.NumberU64()); entry == nil {
145 146
		t.Fatalf("Stored body not found")
	} else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(block.Transactions()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) {
147
		t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, block.Body())
148 149
	}
	// Delete the block and verify the execution
150 151
	DeleteBlock(db, block.Hash(), block.NumberU64())
	if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil {
152 153
		t.Fatalf("Deleted block returned: %v", entry)
	}
154
	if entry := GetHeader(db, block.Hash(), block.NumberU64()); entry != nil {
155 156
		t.Fatalf("Deleted header returned: %v", entry)
	}
157
	if entry := GetBody(db, block.Hash(), block.NumberU64()); entry != nil {
158 159 160 161 162 163 164
		t.Fatalf("Deleted body returned: %v", entry)
	}
}

// Tests that partial block contents don't get reassembled into full blocks.
func TestPartialBlockStorage(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()
165 166 167 168 169 170
	block := types.NewBlockWithHeader(&types.Header{
		Extra:       []byte("test block"),
		UncleHash:   types.EmptyUncleHash,
		TxHash:      types.EmptyRootHash,
		ReceiptHash: types.EmptyRootHash,
	})
171 172 173 174
	// Store a header and check that it's not recognized as a block
	if err := WriteHeader(db, block.Header()); err != nil {
		t.Fatalf("Failed to write header into database: %v", err)
	}
175
	if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil {
176 177
		t.Fatalf("Non existent block returned: %v", entry)
	}
178
	DeleteHeader(db, block.Hash(), block.NumberU64())
179 180

	// Store a body and check that it's not recognized as a block
181
	if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil {
182 183
		t.Fatalf("Failed to write body into database: %v", err)
	}
184
	if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil {
185 186
		t.Fatalf("Non existent block returned: %v", entry)
	}
187
	DeleteBody(db, block.Hash(), block.NumberU64())
188 189 190 191 192

	// Store a header and a body separately and check reassembly
	if err := WriteHeader(db, block.Header()); err != nil {
		t.Fatalf("Failed to write header into database: %v", err)
	}
193
	if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil {
194 195
		t.Fatalf("Failed to write body into database: %v", err)
	}
196
	if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry == nil {
197 198 199 200 201 202 203 204 205 206 207 208
		t.Fatalf("Stored block not found")
	} else if entry.Hash() != block.Hash() {
		t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block)
	}
}

// Tests block total difficulty storage and retrieval operations.
func TestTdStorage(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()

	// Create a test TD to move around the database and make sure it's really new
	hash, td := common.Hash{}, big.NewInt(314)
209
	if entry := GetTd(db, hash, 0); entry != nil {
210 211 212
		t.Fatalf("Non existent TD returned: %v", entry)
	}
	// Write and verify the TD in the database
213
	if err := WriteTd(db, hash, 0, td); err != nil {
214 215
		t.Fatalf("Failed to write TD into database: %v", err)
	}
216
	if entry := GetTd(db, hash, 0); entry == nil {
217 218 219 220 221
		t.Fatalf("Stored TD not found")
	} else if entry.Cmp(td) != 0 {
		t.Fatalf("Retrieved TD mismatch: have %v, want %v", entry, td)
	}
	// Delete the TD and verify the execution
222 223
	DeleteTd(db, hash, 0)
	if entry := GetTd(db, hash, 0); entry != nil {
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
		t.Fatalf("Deleted TD returned: %v", entry)
	}
}

// Tests that canonical numbers can be mapped to hashes and retrieved.
func TestCanonicalMappingStorage(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()

	// Create a test canonical number and assinged hash to move around
	hash, number := common.Hash{0: 0xff}, uint64(314)
	if entry := GetCanonicalHash(db, number); entry != (common.Hash{}) {
		t.Fatalf("Non existent canonical mapping returned: %v", entry)
	}
	// Write and verify the TD in the database
	if err := WriteCanonicalHash(db, hash, number); err != nil {
		t.Fatalf("Failed to write canonical mapping into database: %v", err)
	}
	if entry := GetCanonicalHash(db, number); entry == (common.Hash{}) {
		t.Fatalf("Stored canonical mapping not found")
	} else if entry != hash {
		t.Fatalf("Retrieved canonical mapping mismatch: have %v, want %v", entry, hash)
	}
	// Delete the TD and verify the execution
	DeleteCanonicalHash(db, number)
	if entry := GetCanonicalHash(db, number); entry != (common.Hash{}) {
		t.Fatalf("Deleted canonical mapping returned: %v", entry)
	}
}

// Tests that head headers and head blocks can be assigned, individually.
func TestHeadStorage(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()

	blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")})
	blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")})
259
	blockFast := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block fast")})
260 261 262 263 264 265 266 267

	// Check that no head entries are in a pristine database
	if entry := GetHeadHeaderHash(db); entry != (common.Hash{}) {
		t.Fatalf("Non head header entry returned: %v", entry)
	}
	if entry := GetHeadBlockHash(db); entry != (common.Hash{}) {
		t.Fatalf("Non head block entry returned: %v", entry)
	}
268 269 270
	if entry := GetHeadFastBlockHash(db); entry != (common.Hash{}) {
		t.Fatalf("Non fast head block entry returned: %v", entry)
	}
271 272 273 274 275 276 277
	// Assign separate entries for the head header and block
	if err := WriteHeadHeaderHash(db, blockHead.Hash()); err != nil {
		t.Fatalf("Failed to write head header hash: %v", err)
	}
	if err := WriteHeadBlockHash(db, blockFull.Hash()); err != nil {
		t.Fatalf("Failed to write head block hash: %v", err)
	}
278 279 280
	if err := WriteHeadFastBlockHash(db, blockFast.Hash()); err != nil {
		t.Fatalf("Failed to write fast head block hash: %v", err)
	}
281 282 283 284 285 286 287
	// Check that both heads are present, and different (i.e. two heads maintained)
	if entry := GetHeadHeaderHash(db); entry != blockHead.Hash() {
		t.Fatalf("Head header hash mismatch: have %v, want %v", entry, blockHead.Hash())
	}
	if entry := GetHeadBlockHash(db); entry != blockFull.Hash() {
		t.Fatalf("Head block hash mismatch: have %v, want %v", entry, blockFull.Hash())
	}
288 289 290
	if entry := GetHeadFastBlockHash(db); entry != blockFast.Hash() {
		t.Fatalf("Fast head block hash mismatch: have %v, want %v", entry, blockFast.Hash())
	}
291
}
292

293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
// Tests that transactions and associated metadata can be stored and retrieved.
func TestTransactionStorage(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()

	tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), big.NewInt(1111), big.NewInt(11111), []byte{0x11, 0x11, 0x11})
	tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), big.NewInt(2222), big.NewInt(22222), []byte{0x22, 0x22, 0x22})
	tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), big.NewInt(3333), big.NewInt(33333), []byte{0x33, 0x33, 0x33})
	txs := []*types.Transaction{tx1, tx2, tx3}

	block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil)

	// Check that no transactions entries are in a pristine database
	for i, tx := range txs {
		if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil {
			t.Fatalf("tx #%d [%x]: non existent transaction returned: %v", i, tx.Hash(), txn)
		}
	}
	// Insert all the transactions into the database, and verify contents
	if err := WriteTransactions(db, block); err != nil {
		t.Fatalf("failed to write transactions: %v", err)
	}
	for i, tx := range txs {
		if txn, hash, number, index := GetTransaction(db, tx.Hash()); txn == nil {
			t.Fatalf("tx #%d [%x]: transaction not found", i, tx.Hash())
		} else {
			if hash != block.Hash() || number != block.NumberU64() || index != uint64(i) {
				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)
			}
			if tx.String() != txn.String() {
				t.Fatalf("tx #%d [%x]: transaction mismatch: have %v, want %v", i, tx.Hash(), txn, tx)
			}
		}
	}
	// Delete the transactions and check purge
	for i, tx := range txs {
		DeleteTransaction(db, tx.Hash())
		if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil {
			t.Fatalf("tx #%d [%x]: deleted transaction returned: %v", i, tx.Hash(), txn)
		}
	}
}

// Tests that receipts can be stored and retrieved.
func TestReceiptStorage(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()

	receipt1 := &types.Receipt{
		PostState:         []byte{0x01},
		CumulativeGasUsed: big.NewInt(1),
342 343 344
		Logs: []*types.Log{
			{Address: common.BytesToAddress([]byte{0x11})},
			{Address: common.BytesToAddress([]byte{0x01, 0x11})},
345 346 347 348 349 350 351 352
		},
		TxHash:          common.BytesToHash([]byte{0x11, 0x11}),
		ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
		GasUsed:         big.NewInt(111111),
	}
	receipt2 := &types.Receipt{
		PostState:         []byte{0x02},
		CumulativeGasUsed: big.NewInt(2),
353 354 355
		Logs: []*types.Log{
			{Address: common.BytesToAddress([]byte{0x22})},
			{Address: common.BytesToAddress([]byte{0x02, 0x22})},
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
		},
		TxHash:          common.BytesToHash([]byte{0x22, 0x22}),
		ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
		GasUsed:         big.NewInt(222222),
	}
	receipts := []*types.Receipt{receipt1, receipt2}

	// Check that no receipt entries are in a pristine database
	for i, receipt := range receipts {
		if r := GetReceipt(db, receipt.TxHash); r != nil {
			t.Fatalf("receipt #%d [%x]: non existent receipt returned: %v", i, receipt.TxHash, r)
		}
	}
	// Insert all the receipts into the database, and verify contents
	if err := WriteReceipts(db, receipts); err != nil {
		t.Fatalf("failed to write receipts: %v", err)
	}
	for i, receipt := range receipts {
		if r := GetReceipt(db, receipt.TxHash); r == nil {
			t.Fatalf("receipt #%d [%x]: receipt not found", i, receipt.TxHash)
		} else {
			rlpHave, _ := rlp.EncodeToBytes(r)
			rlpWant, _ := rlp.EncodeToBytes(receipt)

380
			if !bytes.Equal(rlpHave, rlpWant) {
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
				t.Fatalf("receipt #%d [%x]: receipt mismatch: have %v, want %v", i, receipt.TxHash, r, receipt)
			}
		}
	}
	// Delete the receipts and check purge
	for i, receipt := range receipts {
		DeleteReceipt(db, receipt.TxHash)
		if r := GetReceipt(db, receipt.TxHash); r != nil {
			t.Fatalf("receipt #%d [%x]: deleted receipt returned: %v", i, receipt.TxHash, r)
		}
	}
}

// Tests that receipts associated with a single block can be stored and retrieved.
func TestBlockReceiptStorage(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()

	receipt1 := &types.Receipt{
		PostState:         []byte{0x01},
		CumulativeGasUsed: big.NewInt(1),
401 402 403
		Logs: []*types.Log{
			{Address: common.BytesToAddress([]byte{0x11})},
			{Address: common.BytesToAddress([]byte{0x01, 0x11})},
404 405 406 407 408 409 410 411
		},
		TxHash:          common.BytesToHash([]byte{0x11, 0x11}),
		ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
		GasUsed:         big.NewInt(111111),
	}
	receipt2 := &types.Receipt{
		PostState:         []byte{0x02},
		CumulativeGasUsed: big.NewInt(2),
412 413 414
		Logs: []*types.Log{
			{Address: common.BytesToAddress([]byte{0x22})},
			{Address: common.BytesToAddress([]byte{0x02, 0x22})},
415 416 417 418 419 420 421 422 423
		},
		TxHash:          common.BytesToHash([]byte{0x22, 0x22}),
		ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
		GasUsed:         big.NewInt(222222),
	}
	receipts := []*types.Receipt{receipt1, receipt2}

	// Check that no receipt entries are in a pristine database
	hash := common.BytesToHash([]byte{0x03, 0x14})
424
	if rs := GetBlockReceipts(db, hash, 0); len(rs) != 0 {
425 426 427
		t.Fatalf("non existent receipts returned: %v", rs)
	}
	// Insert the receipt slice into the database and check presence
428
	if err := WriteBlockReceipts(db, hash, 0, receipts); err != nil {
429 430
		t.Fatalf("failed to write block receipts: %v", err)
	}
431
	if rs := GetBlockReceipts(db, hash, 0); len(rs) == 0 {
432 433 434 435 436 437
		t.Fatalf("no receipts returned")
	} else {
		for i := 0; i < len(receipts); i++ {
			rlpHave, _ := rlp.EncodeToBytes(rs[i])
			rlpWant, _ := rlp.EncodeToBytes(receipts[i])

438
			if !bytes.Equal(rlpHave, rlpWant) {
439 440 441 442 443
				t.Fatalf("receipt #%d: receipt mismatch: have %v, want %v", i, rs[i], receipts[i])
			}
		}
	}
	// Delete the receipt slice and check purge
444 445
	DeleteBlockReceipts(db, hash, 0)
	if rs := GetBlockReceipts(db, hash, 0); len(rs) != 0 {
446 447 448 449
		t.Fatalf("deleted receipts returned: %v", rs)
	}
}

450 451 452 453
func TestMipmapBloom(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()

	receipt1 := new(types.Receipt)
454 455 456
	receipt1.Logs = []*types.Log{
		{Address: common.BytesToAddress([]byte("test"))},
		{Address: common.BytesToAddress([]byte("address"))},
457
	}
458
	receipt2 := new(types.Receipt)
459 460 461
	receipt2.Logs = []*types.Log{
		{Address: common.BytesToAddress([]byte("test"))},
		{Address: common.BytesToAddress([]byte("address1"))},
462
	}
463 464 465 466 467 468 469 470 471 472 473 474 475 476

	WriteMipmapBloom(db, 1, types.Receipts{receipt1})
	WriteMipmapBloom(db, 2, types.Receipts{receipt2})

	for _, level := range MIPMapLevels {
		bloom := GetMipmapBloom(db, 2, level)
		if !bloom.Test(new(big.Int).SetBytes([]byte("address1"))) {
			t.Error("expected test to be included on level:", level)
		}
	}

	// reset
	db, _ = ethdb.NewMemDatabase()
	receipt := new(types.Receipt)
477 478
	receipt.Logs = []*types.Log{
		{Address: common.BytesToAddress([]byte("test"))},
479
	}
480 481 482
	WriteMipmapBloom(db, 999, types.Receipts{receipt1})

	receipt = new(types.Receipt)
483 484
	receipt.Logs = []*types.Log{
		{Address: common.BytesToAddress([]byte("test 1"))},
485
	}
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
	WriteMipmapBloom(db, 1000, types.Receipts{receipt})

	bloom := GetMipmapBloom(db, 1000, 1000)
	if bloom.TestBytes([]byte("test")) {
		t.Error("test should not have been included")
	}
}

func TestMipmapChain(t *testing.T) {
	dir, err := ioutil.TempDir("", "mipmap")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	var (
502
		db, _   = ethdb.NewLDBDatabase(dir, 0, 0)
503 504 505 506 507 508 509 510
		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
		addr    = crypto.PubkeyToAddress(key1.PublicKey)
		addr2   = common.BytesToAddress([]byte("jeff"))

		hash1 = common.BytesToHash([]byte("topic1"))
	)
	defer db.Close()

511 512 513 514 515
	gspec := &Genesis{
		Config: params.TestChainConfig,
		Alloc:  GenesisAlloc{addr: {Balance: big.NewInt(1000000)}},
	}
	genesis := gspec.MustCommit(db)
516
	chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) {
517 518 519 520
		var receipts types.Receipts
		switch i {
		case 1:
			receipt := types.NewReceipt(nil, new(big.Int))
521
			receipt.Logs = []*types.Log{{Address: addr, Topics: []common.Hash{hash1}}}
522 523 524 525
			gen.AddUncheckedReceipt(receipt)
			receipts = types.Receipts{receipt}
		case 1000:
			receipt := types.NewReceipt(nil, new(big.Int))
526
			receipt.Logs = []*types.Log{{Address: addr2}}
527 528 529 530 531 532
			gen.AddUncheckedReceipt(receipt)
			receipts = types.Receipts{receipt}

		}

		// store the receipts
533
		err := WriteReceipts(db, receipts)
534 535 536 537 538
		if err != nil {
			t.Fatal(err)
		}
		WriteMipmapBloom(db, uint64(i+1), receipts)
	})
539
	for i, block := range chain {
540 541 542 543 544 545 546
		WriteBlock(db, block)
		if err := WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil {
			t.Fatalf("failed to insert block number: %v", err)
		}
		if err := WriteHeadBlockHash(db, block.Hash()); err != nil {
			t.Fatalf("failed to insert block number: %v", err)
		}
547
		if err := WriteBlockReceipts(db, block.Hash(), block.NumberU64(), receipts[i]); err != nil {
548 549 550 551 552 553 554 555 556
			t.Fatal("error writing block receipts:", err)
		}
	}

	bloom := GetMipmapBloom(db, 0, 1000)
	if bloom.TestBytes(addr2[:]) {
		t.Error("address was included in bloom and should not have")
	}
}