func testGetReceipt(t *testing.T, protocol int) { // Define three accounts to simulate transactions with acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) // Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_makerts_test) generator := func(i int, block *core.BlockGen) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey) tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: // Block 3 is empty but was mined by account #2. block.SetCoinbase(acc2Addr) block.SetExtra([]byte("yeehaw")) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). b2 := block.PrevBlock(1).Header() b2.Extra = []byte("foo") block.AddUncle(b2) b3 := block.PrevBlock(2).Header() b3.Extra = []byte("foo") block.AddUncle(b3) } } // Assemble the test environment pm := newTestProtocolManager(4, generator, nil) peer, _ := newTestPeer("peer", protocol, pm, true) defer peer.close() // Collect the hashes to request, and the response to expect hashes := []common.Hash{} for i := uint64(0); i <= pm.chainman.CurrentBlock().NumberU64(); i++ { for _, tx := range pm.chainman.GetBlockByNumber(i).Transactions() { hashes = append(hashes, tx.Hash()) } } receipts := make([]*types.Receipt, len(hashes)) for i, hash := range hashes { receipts[i] = core.GetReceipt(pm.chaindb, hash) } // Send the hash request and verify the response p2p.Send(peer.app, 0x0f, hashes) if err := p2p.ExpectMsg(peer.app, 0x10, receipts); err != nil { t.Errorf("receipts mismatch: %v", err) } }
// Tests that subsequent signers can be promoted, each requiring half plus one // votes for it to pass through. func TestSignerPromotion(t *testing.T) { // Prefund a few accounts to authorize with and create the oracle keys := make([]*ecdsa.PrivateKey, 5) for i := 0; i < len(keys); i++ { keys[i], _ = crypto.GenerateKey() } key, oracle, sim := setupReleaseTest(t, keys...) // Gradually promote the keys, until all are authorized keys = append([]*ecdsa.PrivateKey{key}, keys...) for i := 1; i < len(keys); i++ { // Check that no votes are accepted from the not yet authed user if _, err := oracle.Promote(bind.NewKeyedTransactor(keys[i]), common.Address{}); err != nil { t.Fatalf("Iter #%d: failed invalid promotion attempt: %v", i, err) } sim.Commit() pend, err := oracle.AuthProposals(nil) if err != nil { t.Fatalf("Iter #%d: failed to retrieve active proposals: %v", i, err) } if len(pend) != 0 { t.Fatalf("Iter #%d: proposal count mismatch: have %d, want 0", i, len(pend)) } // Promote with half - 1 voters and check that the user's not yet authorized for j := 0; j < i/2; j++ { if _, err = oracle.Promote(bind.NewKeyedTransactor(keys[j]), crypto.PubkeyToAddress(keys[i].PublicKey)); err != nil { t.Fatalf("Iter #%d: failed valid promotion attempt: %v", i, err) } } sim.Commit() signers, err := oracle.Signers(nil) if err != nil { t.Fatalf("Iter #%d: failed to retrieve list of signers: %v", i, err) } if len(signers) != i { t.Fatalf("Iter #%d: signer count mismatch: have %v, want %v", i, len(signers), i) } // Promote with the last one needed to pass the promotion if _, err = oracle.Promote(bind.NewKeyedTransactor(keys[i/2]), crypto.PubkeyToAddress(keys[i].PublicKey)); err != nil { t.Fatalf("Iter #%d: failed valid promotion completion attempt: %v", i, err) } sim.Commit() signers, err = oracle.Signers(nil) if err != nil { t.Fatalf("Iter #%d: failed to retrieve list of signers: %v", i, err) } if len(signers) != i+1 { t.Fatalf("Iter #%d: signer count mismatch: have %v, want %v", i, len(signers), i+1) } } }
func RunState(ruleSet RuleSet, statedb *state.StateDB, env, tx map[string]string) ([]byte, vm.Logs, *big.Int, error) { var ( data = common.FromHex(tx["data"]) gas = common.Big(tx["gasLimit"]) price = common.Big(tx["gasPrice"]) value = common.Big(tx["value"]) nonce = common.Big(tx["nonce"]).Uint64() ) var to *common.Address if len(tx["to"]) > 2 { t := common.HexToAddress(tx["to"]) to = &t } // Set pre compiled contracts vm.Precompiled = vm.PrecompiledContracts() snapshot := statedb.Copy() gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"])) key, _ := hex.DecodeString(tx["secretKey"]) addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey) message := NewMessage(addr, to, data, value, gas, price, nonce) vmenv := NewEnvFromMap(ruleSet, statedb, env, tx) vmenv.origin = addr ret, _, err := core.ApplyMessage(vmenv, message, gaspool) if core.IsNonceErr(err) || core.IsInvalidTxErr(err) || core.IsGasLimitErr(err) { statedb.Set(snapshot) } statedb.Commit() return ret, vmenv.state.Logs(), vmenv.Gas, err }
// DecryptKey decrypts a key from a json blob, returning the private key itself. func DecryptKey(keyjson []byte, auth string) (*Key, error) { // Parse the json into a simple map to fetch the key version m := make(map[string]interface{}) if err := json.Unmarshal(keyjson, &m); err != nil { return nil, err } // Depending on the version try to parse one way or another var ( keyBytes, keyId []byte err error ) if version, ok := m["version"].(string); ok && version == "1" { k := new(encryptedKeyJSONV1) if err := json.Unmarshal(keyjson, k); err != nil { return nil, err } keyBytes, keyId, err = decryptKeyV1(k, auth) } else { k := new(encryptedKeyJSONV3) if err := json.Unmarshal(keyjson, k); err != nil { return nil, err } keyBytes, keyId, err = decryptKeyV3(k, auth) } // Handle any decryption errors and return the key if err != nil { return nil, err } key := crypto.ToECDSA(keyBytes) return &Key{ Id: uuid.UUID(keyId), Address: crypto.PubkeyToAddress(key.PublicKey), PrivateKey: key, }, nil }
func TestTransactionChainFork(t *testing.T) { pool, key := setupTxPool() addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, db) pool.currentState = func() (*state.StateDB, error) { return statedb, nil } currentState, _ := pool.currentState() currentState.AddBalance(addr, big.NewInt(100000000000000)) pool.resetState() } resetState() tx := transaction(0, big.NewInt(100000), key) if err := pool.add(tx); err != nil { t.Error("didn't expect error", err) } pool.RemoveTransactions([]*types.Transaction{tx}) // reset the pool's internal state resetState() if err := pool.add(tx); err != nil { t.Error("didn't expect error", err) } }
func TestTransactionDoubleNonce(t *testing.T) { pool, key := setupTxPool() addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { db, _ := ethdb.NewMemDatabase() statedb := state.New(common.Hash{}, db) pool.currentState = func() *state.StateDB { return statedb } pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) pool.resetState() } resetState() tx := transaction(0, big.NewInt(100000), key) tx2 := transaction(0, big.NewInt(1000000), key) if err := pool.add(tx); err != nil { t.Error("didn't expect error", err) } if err := pool.add(tx2); err != nil { t.Error("didn't expect error", err) } pool.checkQueue() if len(pool.pending) != 2 { t.Error("expected 2 pending txs. Got", len(pool.pending)) } }
// Tests that demoting a signer will auto-nuke the currently pending release. func TestVersionAutoNuke(t *testing.T) { // Prefund a few accounts to authorize with and create the oracle keys := make([]*ecdsa.PrivateKey, 5) for i := 0; i < len(keys); i++ { keys[i], _ = crypto.GenerateKey() } key, oracle, sim := setupReleaseTest(t, keys...) // Authorize all the keys as valid signers keys = append([]*ecdsa.PrivateKey{key}, keys...) for i := 1; i < len(keys); i++ { for j := 0; j <= i/2; j++ { if _, err := oracle.Promote(bind.NewKeyedTransactor(keys[j]), crypto.PubkeyToAddress(keys[i].PublicKey)); err != nil { t.Fatalf("Iter #%d: failed valid promotion attempt: %v", i, err) } } sim.Commit() } // Make a release proposal and check it's existence if _, err := oracle.Release(bind.NewKeyedTransactor(keys[0]), 1, 2, 3, [20]byte{4}); err != nil { t.Fatalf("Failed valid proposal attempt: %v", err) } sim.Commit() prop, err := oracle.ProposedVersion(nil) if err != nil { t.Fatalf("Failed to retrieve active proposal: %v", err) } if len(prop.Pass) != 1 { t.Fatalf("Proposal vote count mismatch: have %d, want 1", len(prop.Pass)) } // Demote a signer and check release proposal deletion for i := 0; i <= len(keys)/2; i++ { if _, err := oracle.Demote(bind.NewKeyedTransactor(keys[i]), crypto.PubkeyToAddress(keys[len(keys)-1].PublicKey)); err != nil { t.Fatalf("Iter #%d: failed valid demotion attempt: %v", i, err) } } sim.Commit() prop, err = oracle.ProposedVersion(nil) if err != nil { t.Fatalf("Failed to retrieve active proposal: %v", err) } if len(prop.Pass) != 0 { t.Fatalf("Proposal vote count mismatch: have %d, want 0", len(prop.Pass)) } }
func init() { ringKeys[0] = benchRootKey ringAddrs[0] = benchRootAddr for i := 1; i < len(ringKeys); i++ { ringKeys[i], _ = crypto.GenerateKey() ringAddrs[i] = crypto.PubkeyToAddress(ringKeys[i].PublicKey) } }
func newKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key { id := uuid.NewRandom() key := &Key{ Id: id, Address: crypto.PubkeyToAddress(privateKeyECDSA.PublicKey), PrivateKey: privateKeyECDSA, } return key }
// Tests that the version contract can be deployed and the creator is assigned // the sole authorized signer. func TestContractCreation(t *testing.T) { key, oracle, _ := setupReleaseTest(t) owner := crypto.PubkeyToAddress(key.PublicKey) signers, err := oracle.Signers(nil) if err != nil { t.Fatalf("Failed to retrieve list of signers: %v", err) } if len(signers) != 1 || signers[0] != owner { t.Fatalf("Initial signer mismatch: have %v, want %v", signers, owner) } }
// Tests that proposed versions can be nuked out of existence. func TestVersionNuking(t *testing.T) { // Prefund a few accounts to authorize with and create the oracle keys := make([]*ecdsa.PrivateKey, 9) for i := 0; i < len(keys); i++ { keys[i], _ = crypto.GenerateKey() } key, oracle, sim := setupReleaseTest(t, keys...) // Authorize all the keys as valid signers keys = append([]*ecdsa.PrivateKey{key}, keys...) for i := 1; i < len(keys); i++ { for j := 0; j <= i/2; j++ { if _, err := oracle.Promote(bind.NewKeyedTransactor(keys[j]), crypto.PubkeyToAddress(keys[i].PublicKey)); err != nil { t.Fatalf("Iter #%d: failed valid promotion attempt: %v", i, err) } } sim.Commit() } // Propose releases with more and more keys, always retaining enough users to nuke the proposals for i := 1; i < (len(keys)+1)/2; i++ { // Propose release with an initial set of signers for j := 0; j < i; j++ { if _, err := oracle.Release(bind.NewKeyedTransactor(keys[j]), uint32(i), uint32(i+1), uint32(i+2), [20]byte{byte(i + 3)}); err != nil { t.Fatalf("Iter #%d: failed valid proposal attempt: %v", i, err) } } sim.Commit() prop, err := oracle.ProposedVersion(nil) if err != nil { t.Fatalf("Iter #%d: failed to retrieve active proposal: %v", i, err) } if len(prop.Pass) != i { t.Fatalf("Iter #%d: proposal vote count mismatch: have %d, want %d", i, len(prop.Pass), i) } // Nuke the release with half+1 voters for j := i; j <= i+(len(keys)+1)/2; j++ { if _, err := oracle.Nuke(bind.NewKeyedTransactor(keys[j])); err != nil { t.Fatalf("Iter #%d: failed valid nuke attempt: %v", i, err) } } sim.Commit() prop, err = oracle.ProposedVersion(nil) if err != nil { t.Fatalf("Iter #%d: failed to retrieve active proposal: %v", i, err) } if len(prop.Pass) != 0 || len(prop.Fail) != 0 { t.Fatalf("Iter #%d: proposal vote count mismatch: have %d/%d pass/fail, want 0/0", i, len(prop.Pass), len(prop.Fail)) } } }
// Start Go API. Not important for this version func (c *Contract) Subscribe(key *ecdsa.PrivateKey, serviceId *big.Int, amount, price *big.Int, cb func(*Subscription)) (*types.Transaction, error) { from := crypto.PubkeyToAddress(key.PublicKey) data, err := c.abi.Pack("subscribe", serviceId) if err != nil { return nil, err } statedb, err := c.blockchain.State() if err != nil { return nil, err } transaction, err := types.NewTransaction(statedb.GetNonce(from), contractAddress, amount, big.NewInt(600000), big.NewInt(50000000000), data).SignECDSA(key) if err != nil { return nil, err } evId := c.abi.Events["NewSubscription"].Id() filter := filters.New(c.db) filter.SetAddresses([]common.Address{contractAddress}) filter.SetTopics([][]common.Hash{ // TODO refactor, helper []common.Hash{evId}, []common.Hash{from.Hash()}, []common.Hash{common.BigToHash(serviceId)}, }) filter.SetBeginBlock(0) filter.SetEndBlock(-1) filter.LogCallback = func(log *vm.Log, removed bool) { // TODO: do to and from validation here /* from := log.Topics[1] to := log.Topics[2] */ subscriptionId := common.BytesToHash(log.Data[0:31]) nonce := common.BytesToBig(log.Data[31:]) c.channelMu.Lock() defer c.channelMu.Unlock() channel, exist := c.subs[subscriptionId] if !exist { channel = NewSubscription(c, subscriptionId, from, serviceId, nonce) c.subs[subscriptionId] = channel } cb(channel) } c.filters.Add(filter, filters.PendingLogFilter) return transaction, nil }
func TestMissingNonce(t *testing.T) { pool, key := setupTxPool() addr := crypto.PubkeyToAddress(key.PublicKey) pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) tx := transaction(1, big.NewInt(100000), key) if err := pool.add(tx); err != nil { t.Error("didn't expect error", err) } if len(pool.pending) != 0 { t.Error("expected 0 pending transactions, got", len(pool.pending)) } if len(pool.queue[addr]) != 1 { t.Error("expected 1 queued transaction, got", len(pool.queue[addr])) } }
// NewKeyedTransactor is a utility method to easily create a transaction signer // from a single private key. func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts { keyAddr := crypto.PubkeyToAddress(key.PublicKey) return &TransactOpts{ From: keyAddr, Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { if address != keyAddr { return nil, errors.New("not authorized to sign this account") } signature, err := crypto.Sign(tx.SigHash().Bytes(), key) if err != nil { return nil, err } return tx.WithSignature(signature) }, } }
func TestNonceRecovery(t *testing.T) { const n = 10 pool, key := setupTxPool() addr := crypto.PubkeyToAddress(key.PublicKey) pool.currentState().SetNonce(addr, n) pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) pool.resetState() tx := transaction(n, big.NewInt(100000), key) if err := pool.Add(tx); err != nil { t.Error(err) } // simulate some weird re-order of transactions and missing nonce(s) pool.currentState().SetNonce(addr, n-1) pool.resetState() if fn := pool.pendingState.GetNonce(addr); fn != n+1 { t.Errorf("expected nonce to be %d, got %d", n+1, fn) } }
func TestLogReorgs(t *testing.T) { params.MinGasLimit = big.NewInt(125000) // Minimum the gas limit may ever be. params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block. var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) db, _ = ethdb.NewMemDatabase() // this code generates a log code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") ) genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)}, ) evmux := &event.TypeMux{} blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux) subs := evmux.Subscribe(RemovedLogsEvent{}) chain, _ := GenerateChain(nil, genesis, db, 2, func(i int, gen *BlockGen) { if i == 1 { tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(key1) if err != nil { t.Fatalf("failed to create tx: %v", err) } gen.AddTx(tx) } }) if _, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert chain: %v", err) } chain, _ = GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) {}) if _, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert forked chain: %v", err) } ev := <-subs.Chan() if len(ev.Data.(RemovedLogsEvent).Logs) == 0 { t.Error("expected logs") } }
// setupReleaseTest creates a blockchain simulator and deploys a version oracle // contract for testing. func setupReleaseTest(t *testing.T, prefund ...*ecdsa.PrivateKey) (*ecdsa.PrivateKey, *ReleaseOracle, *backends.SimulatedBackend) { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) accounts := []core.GenesisAccount{{Address: auth.From, Balance: big.NewInt(10000000000)}} for _, key := range prefund { accounts = append(accounts, core.GenesisAccount{Address: crypto.PubkeyToAddress(key.PublicKey), Balance: big.NewInt(10000000000)}) } sim := backends.NewSimulatedBackend(accounts...) // Deploy a version oracle contract, commit and return _, _, oracle, err := DeployReleaseOracle(auth, sim, []common.Address{auth.From}) if err != nil { t.Fatalf("Failed to deploy version contract: %v", err) } sim.Commit() return key, oracle, sim }
func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) { preSaleKeyStruct := struct { EncSeed string EthAddr string Email string BtcAddr string }{} err = json.Unmarshal(fileContent, &preSaleKeyStruct) if err != nil { return nil, err } encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed) iv := encSeedBytes[:16] cipherText := encSeedBytes[16:] /* See https://github.com/ethereum/pyethsaletool pyethsaletool generates the encryption key from password by 2000 rounds of PBKDF2 with HMAC-SHA-256 using password as salt (:(). 16 byte key length within PBKDF2 and resulting key is used as AES key */ passBytes := []byte(password) derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New) plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv) if err != nil { return nil, err } ethPriv := crypto.Keccak256(plainText) ecKey := crypto.ToECDSA(ethPriv) key = &Key{ Id: nil, Address: crypto.PubkeyToAddress(ecKey.PublicKey), PrivateKey: ecKey, } derivedAddr := hex.EncodeToString(key.Address.Bytes()) // needed because .Hex() gives leading "0x" expectedAddr := preSaleKeyStruct.EthAddr if derivedAddr != expectedAddr { err = fmt.Errorf("decrypted addr '%s' not equal to expected addr '%s'", derivedAddr, expectedAddr) } return key, err }
"sync/atomic" "testing" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" ) var ( testdb, _ = ethdb.NewMemDatabase() testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testAddress = crypto.PubkeyToAddress(testKey.PublicKey) genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000)) unknownBlock = types.NewBlock(&types.Header{GasLimit: params.GenesisGasLimit}, nil, nil, nil) ) // makeChain creates a chain of n blocks starting at and including parent. // the returned hash chain is ordered head->parent. In addition, every 3rd block // contains a transaction and every 5th an uncle to allow testing correct block // reassembly. func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { blocks, _ := core.GenerateChain(nil, parent, testdb, n, func(i int, block *core.BlockGen) { block.SetCoinbase(common.Address{seed}) // If the block number is multiple of 3, send a bonus transaction to the miner if parent == genesis && i%3 == 0 { tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testKey)
func ExampleGenerateChain() { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") key3, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) db, _ = ethdb.NewMemDatabase() ) // Ensure that key1 has some funds in the genesis block. genesis := GenesisBlockForTesting(db, addr1, big.NewInt(1000000)) // This call generates a chain of 5 blocks. The function runs for // each block and adds different features to gen based on the // block index. chain := GenerateChain(genesis, db, 5, func(i int, gen *BlockGen) { switch i { case 0: // In block 1, addr1 sends addr2 some ether. tx, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(key1) gen.AddTx(tx) case 1: // In block 2, addr1 sends some more ether to addr2. // addr2 passes it on to addr3. tx1, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key1) tx2, _ := types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2) gen.AddTx(tx1) gen.AddTx(tx2) case 2: // Block 3 is empty but was mined by addr3. gen.SetCoinbase(addr3) gen.SetExtra([]byte("yeehaw")) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). b2 := gen.PrevBlock(1).Header() b2.Extra = []byte("foo") gen.AddUncle(b2) b3 := gen.PrevBlock(2).Header() b3.Extra = []byte("foo") gen.AddUncle(b3) } }) // Import the chain. This runs all block validation rules. evmux := &event.TypeMux{} chainman, _ := NewChainManager(genesis, db, db, FakePow{}, evmux) chainman.SetProcessor(NewBlockProcessor(db, db, FakePow{}, chainman, evmux)) if i, err := chainman.InsertChain(chain); err != nil { fmt.Printf("insert error (block %d): %v\n", i, err) return } state := chainman.State() fmt.Printf("last block: #%d\n", chainman.CurrentBlock().Number()) fmt.Println("balance of addr1:", state.GetBalance(addr1)) fmt.Println("balance of addr2:", state.GetBalance(addr2)) fmt.Println("balance of addr3:", state.GetBalance(addr3)) // Output: // last block: #5 // balance of addr1: 989000 // balance of addr2: 10000 // balance of addr3: 5906250000000001000 }
func defaultTestKey() (*ecdsa.PrivateKey, common.Address) { key := crypto.ToECDSA(common.Hex2Bytes("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")) addr := crypto.PubkeyToAddress(key.PublicKey) return key, addr }
benchInsertChain(b, false, genTxRing(200)) } func BenchmarkInsertChain_ring200_diskdb(b *testing.B) { benchInsertChain(b, true, genTxRing(200)) } func BenchmarkInsertChain_ring1000_memdb(b *testing.B) { benchInsertChain(b, false, genTxRing(1000)) } func BenchmarkInsertChain_ring1000_diskdb(b *testing.B) { benchInsertChain(b, true, genTxRing(1000)) } var ( // This is the content of the genesis block used by the benchmarks. benchRootKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") benchRootAddr = crypto.PubkeyToAddress(benchRootKey.PublicKey) benchRootFunds = common.BigPow(2, 100) ) // genValueTx returns a block generator that includes a single // value-transfer transaction with n bytes of extra data in each // block. func genValueTx(nbytes int) func(int, *BlockGen) { return func(i int, gen *BlockGen) { toaddr := common.Address{} data := make([]byte, nbytes) gas := IntrinsicGas(data) tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(benchRootKey) gen.AddTx(tx) } }
"sync" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/discover" ) var ( testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) testBankFunds = big.NewInt(1000000) ) // newTestProtocolManager creates a new protocol manager for testing purposes, // with the given number of blocks already known, and potential notification // channels for different events. func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, error) { var ( evmux = new(event.TypeMux) pow = new(core.FakePow) db, _ = ethdb.NewMemDatabase() genesis = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{testBankAddress, testBankFunds}) blockchain, _ = core.NewBlockChain(db, pow, evmux) ) chain, _ := core.GenerateChain(genesis, db, blocks, generator)
// Tests that chain reorganizations handle transaction removals and reinsertions. func TestChainTxReorgs(t *testing.T) { params.MinGasLimit = big.NewInt(125000) // Minimum the gas limit may ever be. params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block. var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") key3, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) db, _ = ethdb.NewMemDatabase() ) genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(1000000)}, GenesisAccount{addr2, big.NewInt(1000000)}, GenesisAccount{addr3, big.NewInt(1000000)}, ) // Create two transactions shared between the chains: // - postponed: transaction included at a later block in the forked chain // - swapped: transaction included at the same block number in the forked chain postponed, _ := types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key1) swapped, _ := types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key1) // Create two transactions that will be dropped by the forked chain: // - pastDrop: transaction dropped retroactively from a past block // - freshDrop: transaction dropped exactly at the block where the reorg is detected var pastDrop, freshDrop *types.Transaction // Create three transactions that will be added in the forked chain: // - pastAdd: transaction added before the reorganiztion is detected // - freshAdd: transaction added at the exact block the reorg is detected // - futureAdd: transaction added after the reorg has already finished var pastAdd, freshAdd, futureAdd *types.Transaction chain, _ := GenerateChain(genesis, db, 3, func(i int, gen *BlockGen) { switch i { case 0: pastDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2) gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork case 2: freshDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2) gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point gen.AddTx(swapped) // This transaction will be swapped out at the exact height gen.OffsetTime(9) // Lower the block difficulty to simulate a weaker chain } }) // Import the chain. This runs all block validation rules. evmux := &event.TypeMux{} blockchain, _ := NewBlockChain(db, FakePow{}, evmux) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } // overwrite the old chain chain, _ = GenerateChain(genesis, db, 5, func(i int, gen *BlockGen) { switch i { case 0: pastAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key3) gen.AddTx(pastAdd) // This transaction needs to be injected during reorg case 2: gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain freshAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key3) gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time case 3: futureAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key3) gen.AddTx(futureAdd) // This transaction will be added after a full reorg } }) if _, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert forked chain: %v", err) } // removed tx for i, tx := range (types.Transactions{pastDrop, freshDrop}) { if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil { t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn) } if GetReceipt(db, tx.Hash()) != nil { t.Errorf("drop %d: receipt found while shouldn't have been", i) } } // added tx for i, tx := range (types.Transactions{pastAdd, freshAdd, futureAdd}) { if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil { t.Errorf("add %d: expected tx to be found", i) } if GetReceipt(db, tx.Hash()) == nil { t.Errorf("add %d: expected receipt to be found", i) } } // shared tx for i, tx := range (types.Transactions{postponed, swapped}) { if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil { t.Errorf("share %d: expected tx to be found", i) } if GetReceipt(db, tx.Hash()) == nil { t.Errorf("share %d: expected receipt to be found", i) } } }
// Tests that various import methods move the chain head pointers to the correct // positions. func TestLightVsFastVsFullChainHeads(t *testing.T) { // Configure and generate a sample block chain var ( gendb, _ = ethdb.NewMemDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) genesis = GenesisBlockForTesting(gendb, address, funds) ) height := uint64(1024) blocks, receipts := GenerateChain(genesis, gendb, int(height), nil) // Configure a subchain to roll back remove := []common.Hash{} for _, block := range blocks[height/2:] { remove = append(remove, block.Hash()) } // Create a small assertion method to check the three heads assert := func(t *testing.T, kind string, chain *BlockChain, header uint64, fast uint64, block uint64) { if num := chain.CurrentBlock().NumberU64(); num != block { t.Errorf("%s head block mismatch: have #%v, want #%v", kind, num, block) } if num := chain.CurrentFastBlock().NumberU64(); num != fast { t.Errorf("%s head fast-block mismatch: have #%v, want #%v", kind, num, fast) } if num := chain.CurrentHeader().Number.Uint64(); num != header { t.Errorf("%s head header mismatch: have #%v, want #%v", kind, num, header) } } // Import the chain as an archive node and ensure all pointers are updated archiveDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds}) archive, _ := NewBlockChain(archiveDb, FakePow{}, new(event.TypeMux)) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } assert(t, "archive", archive, height, height, height) archive.Rollback(remove) assert(t, "archive", archive, height/2, height/2, height/2) // Import the chain as a non-archive node and ensure all pointers are updated fastDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds}) fast, _ := NewBlockChain(fastDb, FakePow{}, new(event.TypeMux)) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { headers[i] = block.Header() } if n, err := fast.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } if n, err := fast.InsertReceiptChain(blocks, receipts); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) } assert(t, "fast", fast, height, height, 0) fast.Rollback(remove) assert(t, "fast", fast, height/2, height/2, 0) // Import the chain as a light node and ensure all pointers are updated lightDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(lightDb, GenesisAccount{address, funds}) light, _ := NewBlockChain(lightDb, FakePow{}, new(event.TypeMux)) if n, err := light.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } assert(t, "light", light, height, 0, 0) light.Rollback(remove) assert(t, "light", light, height/2, 0, 0) }
// Tests that fast importing a block chain produces the same chain data as the // classical full block processing. func TestFastVsFullChains(t *testing.T) { // Configure and generate a sample block chain var ( gendb, _ = ethdb.NewMemDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) genesis = GenesisBlockForTesting(gendb, address, funds) ) blocks, receipts := GenerateChain(genesis, gendb, 1024, func(i int, block *BlockGen) { block.SetCoinbase(common.Address{0x00}) // If the block number is multiple of 3, send a few bonus transactions to the miner if i%3 == 2 { for j := 0; j < i%4+1; j++ { tx, err := types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key) if err != nil { panic(err) } block.AddTx(tx) } } // If the block number is a multiple of 5, add a few bonus uncles to the block if i%5 == 5 { block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 1).Hash(), Number: big.NewInt(int64(i - 1))}) } }) // Import the chain as an archive node for the comparison baseline archiveDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds}) archive, _ := NewBlockChain(archiveDb, FakePow{}, new(event.TypeMux)) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } // Fast import the chain as a non-archive node to test fastDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds}) fast, _ := NewBlockChain(fastDb, FakePow{}, new(event.TypeMux)) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { headers[i] = block.Header() } if n, err := fast.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } if n, err := fast.InsertReceiptChain(blocks, receipts); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) } // Iterate over all chain data components, and cross reference for i := 0; i < len(blocks); i++ { num, hash := blocks[i].NumberU64(), blocks[i].Hash() if ftd, atd := fast.GetTd(hash), archive.GetTd(hash); ftd.Cmp(atd) != 0 { t.Errorf("block #%d [%x]: td mismatch: have %v, want %v", num, hash, ftd, atd) } if fheader, aheader := fast.GetHeader(hash), archive.GetHeader(hash); fheader.Hash() != aheader.Hash() { t.Errorf("block #%d [%x]: header mismatch: have %v, want %v", num, hash, fheader, aheader) } if fblock, ablock := fast.GetBlock(hash), archive.GetBlock(hash); fblock.Hash() != ablock.Hash() { t.Errorf("block #%d [%x]: block mismatch: have %v, want %v", num, hash, fblock, ablock) } else if types.DeriveSha(fblock.Transactions()) != types.DeriveSha(ablock.Transactions()) { t.Errorf("block #%d [%x]: transactions mismatch: have %v, want %v", num, hash, fblock.Transactions(), ablock.Transactions()) } else if types.CalcUncleHash(fblock.Uncles()) != types.CalcUncleHash(ablock.Uncles()) { t.Errorf("block #%d [%x]: uncles mismatch: have %v, want %v", num, hash, fblock.Uncles(), ablock.Uncles()) } if freceipts, areceipts := GetBlockReceipts(fastDb, hash), GetBlockReceipts(archiveDb, hash); types.DeriveSha(freceipts) != types.DeriveSha(areceipts) { t.Errorf("block #%d [%x]: receipts mismatch: have %v, want %v", num, hash, freceipts, areceipts) } } // Check that the canonical chains are the same between the databases for i := 0; i < len(blocks)+1; i++ { if fhash, ahash := GetCanonicalHash(fastDb, uint64(i)), GetCanonicalHash(archiveDb, uint64(i)); fhash != ahash { t.Errorf("block #%d: canonical hash mismatch: have %v, want %v", i, fhash, ahash) } } }
func BenchmarkMipmaps(b *testing.B) { dir, err := ioutil.TempDir("", "mipmap") if err != nil { b.Fatal(err) } defer os.RemoveAll(dir) var ( db, _ = ethdb.NewLDBDatabase(dir, 0, 0) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = common.BytesToAddress([]byte("jeff")) addr3 = common.BytesToAddress([]byte("ethereum")) addr4 = common.BytesToAddress([]byte("random addresses please")) ) defer db.Close() genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)}) chain, receipts := core.GenerateChain(nil, genesis, db, 100010, func(i int, gen *core.BlockGen) { var receipts types.Receipts switch i { case 2403: receipt := makeReceipt(addr1) receipts = types.Receipts{receipt} gen.AddUncheckedReceipt(receipt) case 1034: receipt := makeReceipt(addr2) receipts = types.Receipts{receipt} gen.AddUncheckedReceipt(receipt) case 34: receipt := makeReceipt(addr3) receipts = types.Receipts{receipt} gen.AddUncheckedReceipt(receipt) case 99999: receipt := makeReceipt(addr4) receipts = types.Receipts{receipt} gen.AddUncheckedReceipt(receipt) } // store the receipts err := core.WriteReceipts(db, receipts) if err != nil { b.Fatal(err) } core.WriteMipmapBloom(db, uint64(i+1), receipts) }) for i, block := range chain { core.WriteBlock(db, block) if err := core.WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil { b.Fatalf("failed to insert block number: %v", err) } if err := core.WriteHeadBlockHash(db, block.Hash()); err != nil { b.Fatalf("failed to insert block number: %v", err) } if err := core.WriteBlockReceipts(db, block.Hash(), receipts[i]); err != nil { b.Fatal("error writing block receipts:", err) } } b.ResetTimer() filter := New(db) filter.SetAddresses([]common.Address{addr1, addr2, addr3, addr4}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) for i := 0; i < b.N; i++ { logs := filter.Find() if len(logs) != 4 { b.Fatal("expected 4 log, got", len(logs)) } } }
// "main" method, generates a public key, address // func addrGen(toMatch string) { key, _ := crypto.GenerateKey() addr := crypto.PubkeyToAddress(key.PublicKey) addrStr := hex.EncodeToString(addr[:]) addrMatch(addrStr, toMatch, key) }
func testGetNodeData(t *testing.T, protocol int) { // Define three accounts to simulate transactions with acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) // Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_makerts_test) generator := func(i int, block *core.BlockGen) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey) tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: // Block 3 is empty but was mined by account #2. block.SetCoinbase(acc2Addr) block.SetExtra([]byte("yeehaw")) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). b2 := block.PrevBlock(1).Header() b2.Extra = []byte("foo") block.AddUncle(b2) b3 := block.PrevBlock(2).Header() b3.Extra = []byte("foo") block.AddUncle(b3) } } // Assemble the test environment pm := newTestProtocolManagerMust(t, false, 4, generator, nil) peer, _ := newTestPeer("peer", protocol, pm, true) defer peer.close() // Fetch for now the entire chain db hashes := []common.Hash{} for _, key := range pm.chaindb.(*ethdb.MemDatabase).Keys() { if len(key) == len(common.Hash{}) { hashes = append(hashes, common.BytesToHash(key)) } } p2p.Send(peer.app, 0x0d, hashes) msg, err := peer.app.ReadMsg() if err != nil { t.Fatalf("failed to read node data response: %v", err) } if msg.Code != 0x0e { t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, 0x0c) } var data [][]byte if err := msg.Decode(&data); err != nil { t.Fatalf("failed to decode response node data: %v", err) } // Verify that all hashes correspond to the requested data, and reconstruct a state tree for i, want := range hashes { if hash := crypto.Sha3Hash(data[i]); hash != want { fmt.Errorf("data hash mismatch: have %x, want %x", hash, want) } } statedb, _ := ethdb.NewMemDatabase() for i := 0; i < len(data); i++ { statedb.Put(hashes[i].Bytes(), data[i]) } accounts := []common.Address{testBankAddress, acc1Addr, acc2Addr} for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), statedb) for j, acc := range accounts { state, _ := pm.blockchain.State() bw := state.GetBalance(acc) bh := trie.GetBalance(acc) if (bw != nil && bh == nil) || (bw == nil && bh != nil) { t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw) } if bw != nil && bh != nil && bw.Cmp(bw) != 0 { t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw) } } } }
func TestFilters(t *testing.T) { dir, err := ioutil.TempDir("", "mipmap") if err != nil { t.Fatal(err) } defer os.RemoveAll(dir) var ( db, _ = ethdb.NewLDBDatabase(dir, 0, 0) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr = crypto.PubkeyToAddress(key1.PublicKey) hash1 = common.BytesToHash([]byte("topic1")) hash2 = common.BytesToHash([]byte("topic2")) hash3 = common.BytesToHash([]byte("topic3")) hash4 = common.BytesToHash([]byte("topic4")) ) defer db.Close() genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)}) chain, receipts := core.GenerateChain(nil, genesis, db, 1000, func(i int, gen *core.BlockGen) { var receipts types.Receipts switch i { case 1: receipt := types.NewReceipt(nil, new(big.Int)) receipt.Logs = vm.Logs{ &vm.Log{ Address: addr, Topics: []common.Hash{hash1}, }, } gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 2: receipt := types.NewReceipt(nil, new(big.Int)) receipt.Logs = vm.Logs{ &vm.Log{ Address: addr, Topics: []common.Hash{hash2}, }, } gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 998: receipt := types.NewReceipt(nil, new(big.Int)) receipt.Logs = vm.Logs{ &vm.Log{ Address: addr, Topics: []common.Hash{hash3}, }, } gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 999: receipt := types.NewReceipt(nil, new(big.Int)) receipt.Logs = vm.Logs{ &vm.Log{ Address: addr, Topics: []common.Hash{hash4}, }, } gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} } // store the receipts err := core.WriteReceipts(db, receipts) if err != nil { t.Fatal(err) } // i is used as block number for the writes but since the i // starts at 0 and block 0 (genesis) is already present increment // by one core.WriteMipmapBloom(db, uint64(i+1), receipts) }) for i, block := range chain { core.WriteBlock(db, block) if err := core.WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil { t.Fatalf("failed to insert block number: %v", err) } if err := core.WriteHeadBlockHash(db, block.Hash()); err != nil { t.Fatalf("failed to insert block number: %v", err) } if err := core.WriteBlockReceipts(db, block.Hash(), receipts[i]); err != nil { t.Fatal("error writing block receipts:", err) } } filter := New(db) filter.SetAddresses([]common.Address{addr}) filter.SetTopics([][]common.Hash{[]common.Hash{hash1, hash2, hash3, hash4}}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) logs := filter.Find() if len(logs) != 4 { t.Error("expected 4 log, got", len(logs)) } filter = New(db) filter.SetAddresses([]common.Address{addr}) filter.SetTopics([][]common.Hash{[]common.Hash{hash3}}) filter.SetBeginBlock(900) filter.SetEndBlock(999) logs = filter.Find() if len(logs) != 1 { t.Error("expected 1 log, got", len(logs)) } if len(logs) > 0 && logs[0].Topics[0] != hash3 { t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) } filter = New(db) filter.SetAddresses([]common.Address{addr}) filter.SetTopics([][]common.Hash{[]common.Hash{hash3}}) filter.SetBeginBlock(990) filter.SetEndBlock(-1) logs = filter.Find() if len(logs) != 1 { t.Error("expected 1 log, got", len(logs)) } if len(logs) > 0 && logs[0].Topics[0] != hash3 { t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) } filter = New(db) filter.SetTopics([][]common.Hash{[]common.Hash{hash1, hash2}}) filter.SetBeginBlock(1) filter.SetEndBlock(10) logs = filter.Find() if len(logs) != 2 { t.Error("expected 2 log, got", len(logs)) } failHash := common.BytesToHash([]byte("fail")) filter = New(db) filter.SetTopics([][]common.Hash{[]common.Hash{failHash}}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) logs = filter.Find() if len(logs) != 0 { t.Error("expected 0 log, got", len(logs)) } failAddr := common.BytesToAddress([]byte("failmenow")) filter = New(db) filter.SetAddresses([]common.Address{failAddr}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) logs = filter.Find() if len(logs) != 0 { t.Error("expected 0 log, got", len(logs)) } filter = New(db) filter.SetTopics([][]common.Hash{[]common.Hash{failHash}, []common.Hash{hash1}}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) logs = filter.Find() if len(logs) != 0 { t.Error("expected 0 log, got", len(logs)) } }