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) } }
// 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) if err != nil { panic(err) } block.AddTx(tx) } // If the block number is a multiple of 5, add a bonus uncle to the block if i%5 == 0 { block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 1).Hash(), Number: big.NewInt(int64(i - 1))}) } }) hashes := make([]common.Hash, n+1) hashes[len(hashes)-1] = parent.Hash() blockm := make(map[common.Hash]*types.Block, n+1) blockm[parent.Hash()] = parent for i, b := range blocks { hashes[len(hashes)-i-2] = b.Hash() blockm[b.Hash()] = b } return hashes, blockm }
// 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) } }
func TestNegativeValue(t *testing.T) { pool, key := setupTxPool() tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(key) from, _ := tx.From() pool.currentState().AddBalance(from, big.NewInt(1)) if err := pool.Add(tx); err != ErrNegativeValue { t.Error("expected", ErrNegativeValue, "got", err) } }
func (self *XEth) SignTransaction(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (*types.Transaction, error) { if len(toStr) > 0 && toStr != "0x" && !isAddress(toStr) { return nil, errors.New("Invalid address") } var ( from = common.HexToAddress(fromStr) to = common.HexToAddress(toStr) value = common.Big(valueStr) gas *big.Int price *big.Int data []byte contractCreation bool ) if len(gasStr) == 0 { gas = DefaultGas() } else { gas = common.Big(gasStr) } if len(gasPriceStr) == 0 { price = self.DefaultGasPrice() } else { price = common.Big(gasPriceStr) } data = common.FromHex(codeStr) if len(toStr) == 0 { contractCreation = true } var nonce uint64 if len(nonceStr) != 0 { nonce = common.Big(nonceStr).Uint64() } else { // XXX: replaced tx pool state with managed state from app // state := self.backend.TxPool().State() state := self.ManagedState() nonce = state.GetNonce(from) } var tx *types.Transaction if contractCreation { tx = types.NewContractCreation(nonce, value, gas, price, data) } else { tx = types.NewTransaction(nonce, to, value, gas, price, data) } signed, err := self.sign(tx, from, false) if err != nil { return nil, err } return signed, nil }
// 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) } } }
// 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 }
// transact executes an actual transaction invocation, first deriving any missing // authorization fields, and then scheduling the transaction for execution. func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { var err error // Ensure a valid value field and resolve the account nonce value := opts.Value if value == nil { value = new(big.Int) } nonce := uint64(0) if opts.Nonce == nil { nonce, err = c.transactor.PendingAccountNonce(opts.From) if err != nil { return nil, fmt.Errorf("failed to retrieve account nonce: %v", err) } } else { nonce = opts.Nonce.Uint64() } // Figure out the gas allowance and gas price values gasPrice := opts.GasPrice if gasPrice == nil { gasPrice, err = c.transactor.SuggestGasPrice() if err != nil { return nil, fmt.Errorf("failed to suggest gas price: %v", err) } } gasLimit := opts.GasLimit if gasLimit == nil { gasLimit, err = c.transactor.EstimateGasLimit(opts.From, contract, value, input) if err != nil { return nil, fmt.Errorf("failed to exstimate gas needed: %v", err) } } // Create the transaction, sign it and schedule it for execution var rawTx *types.Transaction if contract == nil { rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input) } else { rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input) } if opts.Signer == nil { return nil, errors.New("no signer to authorize the transaction with") } signedTx, err := opts.Signer(opts.From, rawTx) if err != nil { return nil, err } if err := c.transactor.SendTransaction(signedTx); err != nil { return nil, err } return signedTx, nil }
// Claim redeems a given signature using the canonical channel. It creates an // Ethereum transaction and submits it to the Ethereum network. // // Chaim returns the unsigned transaction and an error if it failed. func (c *Contract) Claim(signer common.Address, from common.Address, serviceId *big.Int, nonce uint64, amount *big.Int, sig []byte) (*types.Transaction, error) { if len(sig) != 65 { return nil, fmt.Errorf("Invalid signature. Signature requires to be 65 bytes") } subscriptionId := c.SubscriptionId(from, serviceId) signature := bytesToSignature(sig) txData, err := c.abi.Pack("claim", subscriptionId, nonce, amount, signature.v, signature.r, signature.s) if err != nil { return nil, err } statedb, _ := c.blockchain.State() gasPrice := big.NewInt(50000000000) gasLimit := big.NewInt(250000) tx := types.NewTransaction(statedb.GetNonce(signer), contractAddress, new(big.Int), gasLimit, gasPrice, txData) return tx, nil }
// Transfer initiates a value transfer from an origin account to a destination // account. func (eapis *EtherAPIs) Transfer(from, to common.Address, amount *big.Int) (common.Hash, error) { // Make sure we actually own the origin account and have a valid destination accman := eapis.ethereum.AccountManager() if !accman.HasAccount(from) { return common.Hash{}, fmt.Errorf("unknown account: 0x%x", from.Bytes()) } if to == (common.Address{}) { return common.Hash{}, fmt.Errorf("missing destination account") } // Serialize transaction creations to avoid nonce clashes eapis.txlock.Lock() defer eapis.txlock.Unlock() // Assemble and create the new transaction var ( txpool = eapis.ethereum.TxPool() nonce = txpool.State().GetNonce(from) gasLimit = params.TxGas gasPrice = eapis.ethereum.GpoMinGasPrice ) tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, nil) // Sign the transaction and inject into the local pool for propagation signature, err := accman.Sign(accounts.Account{Address: from}, tx.SigHash().Bytes()) if err != nil { return common.Hash{}, err } signed, err := tx.WithSignature(signature) if err != nil { return common.Hash{}, err } txpool.SetLocal(signed) if err := txpool.Add(signed); err != nil { return common.Hash{}, err } return signed.Hash(), nil }
// genTxRing returns a block generator that sends ether in a ring // among n accounts. This is creates n entries in the state database // and fills the blocks with many small transactions. func genTxRing(naccounts int) func(int, *BlockGen) { from := 0 return func(i int, gen *BlockGen) { gas := CalcGasLimit(gen.PrevBlock(i - 1)) for { gas.Sub(gas, params.TxGas) if gas.Cmp(params.TxGas) < 0 { break } to := (from + 1) % naccounts tx := types.NewTransaction( gen.TxNonce(ringAddrs[from]), ringAddrs[to], benchRootFunds, params.TxGas, nil, nil, ) tx, _ = tx.SignECDSA(ringKeys[from]) gen.AddTx(tx) from = to } } }
func (tx *tx) UnmarshalJSON(b []byte) (err error) { var fields map[string]interface{} if err := json.Unmarshal(b, &fields); err != nil { return shared.NewDecodeParamError(err.Error()) } var ( nonce uint64 to common.Address amount = new(big.Int).Set(common.Big0) gasLimit = new(big.Int).Set(common.Big0) gasPrice = new(big.Int).Set(common.Big0) data []byte contractCreation = true ) if val, found := fields["To"]; found { if strVal, ok := val.(string); ok && len(strVal) > 0 { tx.To = strVal to = common.HexToAddress(strVal) contractCreation = false } } if val, found := fields["From"]; found { if strVal, ok := val.(string); ok { tx.From = strVal } } if val, found := fields["Nonce"]; found { if strVal, ok := val.(string); ok { tx.Nonce = strVal if nonce, err = strconv.ParseUint(strVal, 10, 64); err != nil { return shared.NewDecodeParamError(fmt.Sprintf("Unable to decode tx.Nonce - %v", err)) } } } else { return shared.NewDecodeParamError("tx.Nonce not found") } var parseOk bool if val, found := fields["Value"]; found { if strVal, ok := val.(string); ok { tx.Value = strVal if _, parseOk = amount.SetString(strVal, 0); !parseOk { return shared.NewDecodeParamError(fmt.Sprintf("Unable to decode tx.Amount - %v", err)) } } } if val, found := fields["Data"]; found { if strVal, ok := val.(string); ok { tx.Data = strVal if strings.HasPrefix(strVal, "0x") { data = common.Hex2Bytes(strVal[2:]) } else { data = common.Hex2Bytes(strVal) } } } if val, found := fields["GasLimit"]; found { if strVal, ok := val.(string); ok { tx.GasLimit = strVal if _, parseOk = gasLimit.SetString(strVal, 0); !parseOk { return shared.NewDecodeParamError(fmt.Sprintf("Unable to decode tx.GasLimit - %v", err)) } } } if val, found := fields["GasPrice"]; found { if strVal, ok := val.(string); ok { tx.GasPrice = strVal if _, parseOk = gasPrice.SetString(strVal, 0); !parseOk { return shared.NewDecodeParamError(fmt.Sprintf("Unable to decode tx.GasPrice - %v", err)) } } } if contractCreation { tx.tx = types.NewContractCreation(nonce, amount, gasLimit, gasPrice, data) } else { tx.tx = types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data) } return nil }
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 }
// transact executes an actual transaction invocation, first deriving any missing // authorization fields, and then scheduling the transaction for execution. func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { var err error // Ensure a valid value field and resolve the account nonce value := opts.Value if value == nil { value = new(big.Int) } nonce := uint64(0) if opts.Nonce == nil { nonce, err = c.transactor.PendingAccountNonce(opts.From) if err != nil { return nil, fmt.Errorf("failed to retrieve account nonce: %v", err) } } else { nonce = opts.Nonce.Uint64() } // Figure out the gas allowance and gas price values gasPrice := opts.GasPrice if gasPrice == nil { gasPrice, err = c.transactor.SuggestGasPrice() if err != nil { return nil, fmt.Errorf("failed to suggest gas price: %v", err) } } gasLimit := opts.GasLimit if gasLimit == nil { // Gas estimation cannot succeed without code for method invocations if contract != nil && atomic.LoadUint32(&c.pendingHasCode) == 0 { if code, err := c.transactor.HasCode(c.address, true); err != nil { return nil, err } else if !code { return nil, ErrNoCode } atomic.StoreUint32(&c.pendingHasCode, 1) } // If the contract surely has code (or code is not needed), estimate the transaction gasLimit, err = c.transactor.EstimateGasLimit(opts.From, contract, value, input) if err != nil { return nil, fmt.Errorf("failed to exstimate gas needed: %v", err) } } // Create the transaction, sign it and schedule it for execution var rawTx *types.Transaction if contract == nil { rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input) } else { rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input) } if opts.Signer == nil { return nil, errors.New("no signer to authorize the transaction with") } signedTx, err := opts.Signer(opts.From, rawTx) if err != nil { return nil, err } if err := c.transactor.SendTransaction(signedTx); err != nil { return nil, err } return signedTx, nil }
func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { // this minimalistic recoding is enough (works for natspec.js) var jsontx = fmt.Sprintf(`{"params":[{"to":"%s","data": "%s"}]}`, toStr, codeStr) if !self.ConfirmTransaction(jsontx) { err := fmt.Errorf("Transaction not confirmed") return "", err } var ( from = common.HexToAddress(fromStr) to = common.HexToAddress(toStr) value = common.Big(valueStr) gas *big.Int price *big.Int data []byte contractCreation bool ) if len(gasStr) == 0 { gas = DefaultGas() } else { gas = common.Big(gasStr) } if len(gasPriceStr) == 0 { price = self.DefaultGasPrice() } else { price = common.Big(gasPriceStr) } data = common.FromHex(codeStr) if len(toStr) == 0 { contractCreation = true } // 2015-05-18 Is this still needed? // TODO if no_private_key then //if _, exists := p.register[args.From]; exists { // p.register[args.From] = append(p.register[args.From], args) //} else { /* account := accounts.Get(common.FromHex(args.From)) if account != nil { if account.Unlocked() { if !unlockAccount(account) { return } } result, _ := account.Transact(common.FromHex(args.To), common.FromHex(args.Value), common.FromHex(args.Gas), common.FromHex(args.GasPrice), common.FromHex(args.Data)) if len(result) > 0 { *reply = common.ToHex(result) } } else if _, exists := p.register[args.From]; exists { p.register[ags.From] = append(p.register[args.From], args) } */ // TODO: align default values to have the same type, e.g. not depend on // common.Value conversions later on var nonce uint64 if len(nonceStr) != 0 { nonce = common.Big(nonceStr).Uint64() } else { state := self.backend.TxPool().State() nonce = state.GetNonce(from) } var tx *types.Transaction if contractCreation { tx = types.NewContractCreation(nonce, value, gas, price, data) } else { tx = types.NewTransaction(nonce, to, value, gas, price, data) } signed, err := self.sign(tx, from, false) if err != nil { return "", err } if err = self.backend.TxPool().Add(signed); err != nil { return "", err } if contractCreation { addr := crypto.CreateAddress(from, nonce) glog.V(logger.Info).Infof("Tx(%x) created: %x\n", tx.Hash(), addr) } else { glog.V(logger.Info).Infof("Tx(%x) to: %x\n", tx.Hash(), tx.To()) } return signed.Hash().Hex(), nil }
// newTestTransaction create a new dummy transaction. func newTestTransaction(from *crypto.Key, nonce uint64, datasize int) *types.Transaction { tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize)) tx, _ = tx.SignECDSA(from.PrivateKey) return tx }
// 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 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 transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction { tx, _ := types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil).SignECDSA(key) return tx }
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) } } } }
// Transact forms a transaction from the given arguments and submits it to the // transactio pool for execution. func (be *registryAPIBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { if len(toStr) > 0 && toStr != "0x" && !common.IsHexAddress(toStr) { return "", errors.New("invalid address") } var ( from = common.HexToAddress(fromStr) to = common.HexToAddress(toStr) value = common.Big(valueStr) gas *big.Int price *big.Int data []byte contractCreation bool ) if len(gasStr) == 0 { gas = big.NewInt(90000) } else { gas = common.Big(gasStr) } if len(gasPriceStr) == 0 { price = big.NewInt(10000000000000) } else { price = common.Big(gasPriceStr) } data = common.FromHex(codeStr) if len(toStr) == 0 { contractCreation = true } nonce := be.txPool.State().GetNonce(from) if len(nonceStr) != 0 { nonce = common.Big(nonceStr).Uint64() } var tx *types.Transaction if contractCreation { tx = types.NewContractCreation(nonce, value, gas, price, data) } else { tx = types.NewTransaction(nonce, to, value, gas, price, data) } acc := accounts.Account{from} signature, err := be.am.Sign(acc, tx.SigHash().Bytes()) if err != nil { return "", err } signedTx, err := tx.WithSignature(signature) if err != nil { return "", err } be.txPool.SetLocal(signedTx) if err := be.txPool.Add(signedTx); err != nil { return "", nil } if contractCreation { addr := crypto.CreateAddress(from, nonce) glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex()) } else { glog.V(logger.Info).Infof("Tx(%s) to: %s\n", signedTx.Hash().Hex(), tx.To().Hex()) } return signedTx.Hash().Hex(), nil }