From 4dca5d4db7fc2c1fac5a2e24dcc99b15573f0188 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Wed, 2 Nov 2016 13:44:13 +0100 Subject: [PATCH] core/types, params: EIP#155 --- accounts/abi/bind/auth.go | 6 +- accounts/abi/bind/backends/simulated.go | 19 +- accounts/abi/bind/base.go | 4 +- accounts/abi/bind/util_test.go | 2 +- cmd/utils/flags.go | 4 + common/registrar/ethreg/api.go | 28 +- console/console_test.go | 2 +- core/bench_test.go | 4 +- core/blockchain.go | 13 +- core/blockchain_test.go | 128 ++++++++- core/chain_makers_test.go | 7 +- core/state_processor.go | 19 +- core/state_transition.go | 39 +-- core/tx_pool.go | 18 +- core/tx_pool_test.go | 51 ++-- core/types/block_test.go | 7 +- core/types/json_test.go | 5 +- core/types/transaction.go | 260 +++++++++++------- core/types/transaction_signing.go | 340 ++++++++++++++++++++++++ core/types/transaction_signing_test.go | 116 ++++++++ core/types/transaction_test.go | 28 +- core/vm/jit_test.go | 2 +- core/vm/runtime/runtime.go | 2 +- core/vm_env.go | 2 +- eth/api.go | 12 +- eth/api_backend.go | 12 +- eth/downloader/downloader_test.go | 3 +- eth/fetcher/fetcher_test.go | 3 +- eth/handler_test.go | 14 +- eth/helper_test.go | 4 +- ethclient/ethclient.go | 8 +- internal/ethapi/api.go | 86 +++--- internal/ethapi/backend.go | 4 + les/api_backend.go | 11 +- les/helper_test.go | 16 +- les/odr_test.go | 59 +--- light/odr_test.go | 73 +---- light/txpool.go | 16 +- light/txpool_test.go | 2 +- light/vm_env.go | 2 +- miner/worker.go | 19 +- params/config.go | 36 ++- tests/state_test_util.go | 3 +- tests/transaction_test_util.go | 13 +- tests/util.go | 23 -- tests/vm_test_util.go | 7 +- 46 files changed, 1068 insertions(+), 464 deletions(-) create mode 100644 core/types/transaction_signing.go create mode 100644 core/types/transaction_signing_test.go diff --git a/accounts/abi/bind/auth.go b/accounts/abi/bind/auth.go index cd6adc7462..a20852fca0 100644 --- a/accounts/abi/bind/auth.go +++ b/accounts/abi/bind/auth.go @@ -48,15 +48,15 @@ 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) { + Signer: func(signer types.Signer, 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.SignEthereum(tx.SigHash().Bytes(), key) + signature, err := crypto.SignEthereum(signer.Hash(tx).Bytes(), key) if err != nil { return nil, err } - return tx.WithSignature(signature) + return tx.WithSignature(signer, signature) }, } } diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index f750a1fbdb..00a8cd3e92 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -237,7 +237,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa b.mu.Lock() defer b.mu.Unlock() - sender, err := tx.From() + sender, err := types.Sender(types.HomesteadSigner{}, tx) if err != nil { panic(fmt.Errorf("invalid transaction: %v", err)) } @@ -262,12 +262,11 @@ type callmsg struct { ethereum.CallMsg } -func (m callmsg) From() (common.Address, error) { return m.CallMsg.From, nil } -func (m callmsg) FromFrontier() (common.Address, error) { return m.CallMsg.From, nil } -func (m callmsg) Nonce() uint64 { return 0 } -func (m callmsg) CheckNonce() bool { return false } -func (m callmsg) To() *common.Address { return m.CallMsg.To } -func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } -func (m callmsg) Gas() *big.Int { return m.CallMsg.Gas } -func (m callmsg) Value() *big.Int { return m.CallMsg.Value } -func (m callmsg) Data() []byte { return m.CallMsg.Data } +func (m callmsg) From() common.Address { return m.CallMsg.From } +func (m callmsg) Nonce() uint64 { return 0 } +func (m callmsg) CheckNonce() bool { return false } +func (m callmsg) To() *common.Address { return m.CallMsg.To } +func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } +func (m callmsg) Gas() *big.Int { return m.CallMsg.Gas } +func (m callmsg) Value() *big.Int { return m.CallMsg.Value } +func (m callmsg) Data() []byte { return m.CallMsg.Data } diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index b032ef72d9..7df02e83f3 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -31,7 +31,7 @@ import ( // SignerFn is a signer function callback when a contract requires a method to // sign the transaction before submission. -type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error) +type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Transaction, error) // CallOpts is the collection of options to fine tune a contract call request. type CallOpts struct { @@ -214,7 +214,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i if opts.Signer == nil { return nil, errors.New("no signer to authorize the transaction with") } - signedTx, err := opts.Signer(opts.From, rawTx) + signedTx, err := opts.Signer(types.HomesteadSigner{}, opts.From, rawTx) if err != nil { return nil, err } diff --git a/accounts/abi/bind/util_test.go b/accounts/abi/bind/util_test.go index 192fa4f4cf..d3ed02575a 100644 --- a/accounts/abi/bind/util_test.go +++ b/accounts/abi/bind/util_test.go @@ -60,7 +60,7 @@ func TestWaitDeployed(t *testing.T) { // Create the transaction. tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code)) - tx, _ = tx.SignECDSA(testKey) + tx, _ = tx.SignECDSA(types.HomesteadSigner{}, testKey) // Wait for it to get mined in the background. var ( diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 641ff6d404..52b78a5c3a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -825,6 +825,10 @@ func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *params.ChainCon Fatalf("Could not make chain configuration: %v", err) } } + // set chain id in case it's zero. + if config.ChainId == nil { + config.ChainId = new(big.Int) + } // Check whether we are allowed to set default config params or not: // - If no genesis is set, we're running either mainnet or testnet (private nets use `geth init`) // - If a genesis is already set, ensure we have a configuration for it (mainnet or testnet) diff --git a/common/registrar/ethreg/api.go b/common/registrar/ethreg/api.go index bbc34f6ac8..a3c48345ef 100644 --- a/common/registrar/ethreg/api.go +++ b/common/registrar/ethreg/api.go @@ -174,25 +174,20 @@ func (be *registryAPIBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr from.SetBalance(common.MaxBig) - msg := callmsg{ - from: from, - gas: common.Big(gasStr), - gasPrice: common.Big(gasPriceStr), - value: common.Big(valueStr), - data: common.FromHex(dataStr), - } + var to *common.Address if len(toStr) > 0 { addr := common.HexToAddress(toStr) - msg.to = &addr + to = &addr } - - if msg.gas.Cmp(big.NewInt(0)) == 0 { - msg.gas = big.NewInt(50000000) + gas := common.Big(gasStr) + if gas.BitLen() == 0 { + gas = big.NewInt(50000000) } - - if msg.gasPrice.Cmp(big.NewInt(0)) == 0 { - msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) + gasPrice := common.Big(gasPriceStr) + if gasPrice.BitLen() == 0 { + gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) } + msg := types.NewMessage(from.Address(), to, 0, common.Big(valueStr), gas, gasPrice, common.FromHex(dataStr)) header := be.bc.CurrentBlock().Header() vmenv := core.NewEnv(statedb, be.config, be.bc, msg, header, vm.Config{}) @@ -258,11 +253,12 @@ func (be *registryAPIBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasSt tx = types.NewTransaction(nonce, to, value, gas, price, data) } - signature, err := be.am.SignEthereum(from, tx.SigHash().Bytes()) + sigHash := (types.HomesteadSigner{}).Hash(tx) + signature, err := be.am.SignEthereum(from, sigHash.Bytes()) if err != nil { return "", err } - signedTx, err := tx.WithSignature(signature) + signedTx, err := tx.WithSignature(types.HomesteadSigner{}, signature) if err != nil { return "", err } diff --git a/console/console_test.go b/console/console_test.go index 77dcc198cf..d5010b907d 100644 --- a/console/console_test.go +++ b/console/console_test.go @@ -97,7 +97,7 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester { t.Fatalf("failed to create node: %v", err) } ethConf := ð.Config{ - ChainConfig: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, + ChainConfig: ¶ms.ChainConfig{HomesteadBlock: new(big.Int), ChainId: new(big.Int)}, Etherbase: common.HexToAddress(testAddress), PowTest: true, } diff --git a/core/bench_test.go b/core/bench_test.go index 8fe4d41de7..a208ea2504 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -83,7 +83,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { toaddr := common.Address{} data := make([]byte, nbytes) gas := IntrinsicGas(data, false, false) - tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(benchRootKey) + tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(types.HomesteadSigner{}, benchRootKey) gen.AddTx(tx) } } @@ -123,7 +123,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) { nil, nil, ) - tx, _ = tx.SignECDSA(ringKeys[from]) + tx, _ = tx.SignECDSA(types.HomesteadSigner{}, ringKeys[from]) gen.AddTx(tx) from = to } diff --git a/core/blockchain.go b/core/blockchain.go index 8b93da60b6..bbcff3b92d 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -634,17 +634,19 @@ func (self *BlockChain) Rollback(chain []common.Hash) { } // SetReceiptsData computes all the non-consensus fields of the receipts -func SetReceiptsData(block *types.Block, receipts types.Receipts) { +func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) { + signer := types.MakeSigner(config, block.Number()) + transactions, logIndex := block.Transactions(), uint(0) for j := 0; j < len(receipts); j++ { // The transaction hash can be retrieved from the transaction itself receipts[j].TxHash = transactions[j].Hash() + tx, _ := transactions[j].AsMessage(signer) // The contract address can be derived from the transaction itself - if MessageCreatesContract(transactions[j]) { - from, _ := transactions[j].From() - receipts[j].ContractAddress = crypto.CreateAddress(from, transactions[j].Nonce()) + if MessageCreatesContract(tx) { + receipts[j].ContractAddress = crypto.CreateAddress(tx.From(), tx.Nonce()) } // The used gas can be calculated based on previous receipts if j == 0 { @@ -666,6 +668,7 @@ func SetReceiptsData(block *types.Block, receipts types.Receipts) { // InsertReceiptChain attempts to complete an already existing header chain with // transaction and receipt data. +// XXX should this be moved to the test? func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) { self.wg.Add(1) defer self.wg.Done() @@ -705,7 +708,7 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain continue } // Compute all the non-consensus fields of the receipts - SetReceiptsData(block, receipts) + SetReceiptsData(self.config, block, receipts) // Write all the data out into the database if err := WriteBody(self.chainDb, block.Hash(), block.NumberU64(), block.Body()); err != nil { errs[index] = fmt.Errorf("failed to write block body: %v", err) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 968cb25acd..dae857f011 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -711,6 +711,7 @@ func TestFastVsFullChains(t *testing.T) { address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) genesis = GenesisBlockForTesting(gendb, address, funds) + signer = types.NewEIP155Signer(big.NewInt(1)) ) blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, 1024, func(i int, block *BlockGen) { block.SetCoinbase(common.Address{0x00}) @@ -718,7 +719,7 @@ func TestFastVsFullChains(t *testing.T) { // 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) + tx, err := types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key) if err != nil { panic(err) } @@ -872,6 +873,7 @@ func TestChainTxReorgs(t *testing.T) { addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) db, _ = ethdb.NewMemDatabase() + signer = types.NewEIP155Signer(big.NewInt(1)) ) genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(1000000)}, @@ -881,8 +883,8 @@ func TestChainTxReorgs(t *testing.T) { // 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) + postponed, _ := types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1) + swapped, _ := types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1) // Create two transactions that will be dropped by the forked chain: // - pastDrop: transaction dropped retroactively from a past block @@ -898,13 +900,13 @@ func TestChainTxReorgs(t *testing.T) { chain, _ := GenerateChain(params.TestChainConfig, 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) + pastDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, 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) + freshDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, 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 @@ -923,18 +925,18 @@ func TestChainTxReorgs(t *testing.T) { chain, _ = GenerateChain(params.TestChainConfig, 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) + pastAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, 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) + freshAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, 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) + futureAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3) gen.AddTx(futureAdd) // This transaction will be added after a full reorg } }) @@ -980,7 +982,8 @@ func TestLogReorgs(t *testing.T) { addr1 = crypto.PubkeyToAddress(key1.PublicKey) db, _ = ethdb.NewMemDatabase() // this code generates a log - code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") + code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") + signer = types.NewEIP155Signer(big.NewInt(1)) ) genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)}, @@ -992,7 +995,7 @@ func TestLogReorgs(t *testing.T) { subs := evmux.Subscribe(RemovedLogsEvent{}) chain, _ := GenerateChain(params.TestChainConfig, 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) + tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(signer, key1) if err != nil { t.Fatalf("failed to create tx: %v", err) } @@ -1020,6 +1023,7 @@ func TestReorgSideEvent(t *testing.T) { key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) genesis = WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)}) + signer = types.NewEIP155Signer(big.NewInt(1)) ) evmux := &event.TypeMux{} @@ -1031,7 +1035,7 @@ func TestReorgSideEvent(t *testing.T) { } replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) { - tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(key1) + tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(signer, key1) if i == 2 { gen.OffsetTime(-1) } @@ -1128,3 +1132,105 @@ func TestCanonicalBlockRetrieval(t *testing.T) { blockchain.InsertChain(types.Blocks{chain[i]}) } } + +func TestEIP155Transition(t *testing.T) { + // Configure and generate a sample block chain + var ( + db, _ = ethdb.NewMemDatabase() + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000) + genesis = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds}) + config = ¶ms.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)} + mux event.TypeMux + ) + + blockchain, _ := NewBlockChain(db, config, FakePow{}, &mux) + blocks, _ := GenerateChain(config, genesis, db, 4, func(i int, block *BlockGen) { + var ( + tx *types.Transaction + err error + basicTx = func(signer types.Signer) (*types.Transaction, error) { + return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key) + } + ) + switch i { + case 0: + tx, err = basicTx(types.HomesteadSigner{}) + if err != nil { + t.Fatal(err) + } + block.AddTx(tx) + case 2: + tx, err = basicTx(types.HomesteadSigner{}) + if err != nil { + t.Fatal(err) + } + block.AddTx(tx) + + tx, err = basicTx(types.NewEIP155Signer(config.ChainId)) + if err != nil { + t.Fatal(err) + } + block.AddTx(tx) + case 3: + tx, err = basicTx(types.HomesteadSigner{}) + if err != nil { + t.Fatal(err) + } + block.AddTx(tx) + + tx, err = basicTx(types.NewEIP155Signer(config.ChainId)) + if err != nil { + t.Fatal(err) + } + block.AddTx(tx) + } + }) + + if _, err := blockchain.InsertChain(blocks); err != nil { + t.Fatal(err) + } + block := blockchain.GetBlockByNumber(1) + if block.Transactions()[0].Protected() { + t.Error("Expected block[0].txs[0] to not be replay protected") + } + + block = blockchain.GetBlockByNumber(3) + if block.Transactions()[0].Protected() { + t.Error("Expected block[3].txs[0] to not be replay protected") + } + if !block.Transactions()[1].Protected() { + t.Error("Expected block[3].txs[1] to be replay protected") + } + if _, err := blockchain.InsertChain(blocks[4:]); err != nil { + t.Fatal(err) + } + + // generate an invalid chain id transaction + config = ¶ms.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)} + blocks, _ = GenerateChain(config, blocks[len(blocks)-1], db, 4, func(i int, block *BlockGen) { + var ( + tx *types.Transaction + err error + basicTx = func(signer types.Signer) (*types.Transaction, error) { + return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key) + } + ) + switch i { + case 0: + tx, err = basicTx(types.NewEIP155Signer(big.NewInt(2))) + if err != nil { + t.Fatal(err) + } + block.AddTx(tx) + } + }) + errExp := "Invalid transaction chain id. Current chain id: 1 tx chain id: 2" + _, err := blockchain.InsertChain(blocks) + if err == nil { + t.Error("expected transaction chain id error") + } else if err.Error() != errExp { + t.Error("expected:", errExp, "got:", err) + } +} diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index b297e671eb..487cd6e186 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -39,6 +39,7 @@ func ExampleGenerateChain() { addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) db, _ = ethdb.NewMemDatabase() + signer = types.HomesteadSigner{} ) chainConfig := ¶ms.ChainConfig{ @@ -54,13 +55,13 @@ func ExampleGenerateChain() { 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) + tx, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, 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) + tx1, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1) + tx2, _ := types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2) gen.AddTx(tx1) gen.AddTx(tx2) case 2: diff --git a/core/state_processor.go b/core/state_processor.go index 9d78400627..46c5db0ee7 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,6 +17,7 @@ package core import ( + "fmt" "math/big" "github.com/ethereum/go-ethereum/core/state" @@ -72,10 +73,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { + if tx.Protected() && tx.ChainId().Cmp(p.config.ChainId) != 0 { + return nil, nil, nil, fmt.Errorf("Invalid transaction chain id. Current chain id: %v tx chain id: %v", p.config.ChainId, tx.ChainId()) + } + statedb.StartRecord(tx.Hash(), block.Hash(), i) receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg) if err != nil { - return nil, nil, totalUsedGas, err + return nil, nil, nil, err } receipts = append(receipts, receipt) allLogs = append(allLogs, logs...) @@ -91,7 +96,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // ApplyTransactions returns the generated receipts and vm logs during the // execution of the state transition phase. func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) { - _, gas, err := ApplyMessage(NewEnv(statedb, config, bc, tx, header, cfg), tx, gp) + msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) + if err != nil { + return nil, nil, nil, err + } + + _, gas, err := ApplyMessage(NewEnv(statedb, config, bc, msg, header, cfg), msg, gp) if err != nil { return nil, nil, nil, err } @@ -101,9 +111,8 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, s receipt := types.NewReceipt(statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes(), usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(gas) - if MessageCreatesContract(tx) { - from, _ := tx.From() - receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce()) + if MessageCreatesContract(msg) { + receipt.ContractAddress = crypto.CreateAddress(msg.From(), tx.Nonce()) } logs := statedb.GetLogs(tx.Hash()) diff --git a/core/state_transition.go b/core/state_transition.go index 2b9d1c6d1d..8abe17b0a2 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -62,8 +62,8 @@ type StateTransition struct { // Message represents a message sent to a contract. type Message interface { - From() (common.Address, error) - FromFrontier() (common.Address, error) + From() common.Address + //FromFrontier() (common.Address, error) To() *common.Address GasPrice() *big.Int @@ -134,23 +134,12 @@ func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.In return ret, gasUsed, err } -func (self *StateTransition) from() (vm.Account, error) { - var ( - f common.Address - err error - ) - if self.env.ChainConfig().IsHomestead(self.env.BlockNumber()) { - f, err = self.msg.From() - } else { - f, err = self.msg.FromFrontier() - } - if err != nil { - return nil, err - } +func (self *StateTransition) from() vm.Account { + f := self.msg.From() if !self.state.Exist(f) { - return self.state.CreateAccount(f), nil + return self.state.CreateAccount(f) } - return self.state.GetAccount(f), nil + return self.state.GetAccount(f) } func (self *StateTransition) to() vm.Account { @@ -185,14 +174,11 @@ func (self *StateTransition) buyGas() error { mgas := self.msg.Gas() mgval := new(big.Int).Mul(mgas, self.gasPrice) - sender, err := self.from() - if err != nil { - return err - } + sender := self.from() if sender.Balance().Cmp(mgval) < 0 { return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], mgval, sender.Balance()) } - if err = self.gp.SubGas(mgas); err != nil { + if err := self.gp.SubGas(mgas); err != nil { return err } self.addGas(mgas) @@ -203,10 +189,7 @@ func (self *StateTransition) buyGas() error { func (self *StateTransition) preCheck() (err error) { msg := self.msg - sender, err := self.from() - if err != nil { - return err - } + sender := self.from() // Make sure this transaction's nonce is correct if msg.CheckNonce() { @@ -232,7 +215,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b return } msg := self.msg - sender, _ := self.from() // err checked in preCheck + sender := self.from() // err checked in preCheck homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber()) contractCreation := MessageCreatesContract(msg) @@ -282,7 +265,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b func (self *StateTransition) refundGas() { // Return eth for remaining gas to the sender account, // exchanged at the original rate. - sender, _ := self.from() // err already checked + sender := self.from() // err already checked remaining := new(big.Int).Mul(self.gas, self.gasPrice) sender.AddBalance(remaining) diff --git a/core/tx_pool.go b/core/tx_pool.go index f1e5f0bddf..edcbc21ebf 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -92,6 +92,7 @@ type TxPool struct { eventMux *event.TypeMux events event.Subscription localTx *txSet + signer types.Signer mu sync.RWMutex pending map[common.Address]*txList // All currently processable transactions @@ -108,6 +109,7 @@ type TxPool struct { func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool { pool := &TxPool{ config: config, + signer: types.NewEIP155Signer(config.ChainId), pending: make(map[common.Address]*txList), queue: make(map[common.Address]*txList), all: make(map[common.Hash]*types.Transaction), @@ -139,8 +141,10 @@ func (pool *TxPool) eventLoop() { switch ev := ev.Data.(type) { case ChainHeadEvent: pool.mu.Lock() - if ev.Block != nil && pool.config.IsHomestead(ev.Block.Number()) { - pool.homestead = true + if ev.Block != nil { + if pool.config.IsHomestead(ev.Block.Number()) { + pool.homestead = true + } } pool.resetState() @@ -272,7 +276,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { return err } - from, err := tx.From() + from, err := types.Sender(pool.signer, tx) if err != nil { return ErrInvalidSender } @@ -307,7 +311,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { return ErrInsufficientFunds } - intrGas := IntrinsicGas(tx.Data(), MessageCreatesContract(tx), pool.homestead) + intrGas := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) if tx.Gas().Cmp(intrGas) < 0 { return ErrIntrinsicGas } @@ -336,7 +340,7 @@ func (pool *TxPool) add(tx *types.Transaction) error { if to := tx.To(); to != nil { rcpt = common.Bytes2Hex(to[:4]) } - from, _ := tx.From() // from already verified during tx validation + from, _ := types.Sender(pool.signer, tx) // from already verified during tx validation glog.Infof("(t) 0x%x => %s (%v) %x\n", from[:4], rcpt, tx.Value, hash) } return nil @@ -347,7 +351,7 @@ func (pool *TxPool) add(tx *types.Transaction) error { // Note, this method assumes the pool lock is held! func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) { // Try to insert the transaction into the future queue - from, _ := tx.From() // already validated + from, _ := types.Sender(pool.signer, tx) // already validated if pool.queue[from] == nil { pool.queue[from] = newTxList(false) } @@ -459,7 +463,7 @@ func (pool *TxPool) removeTx(hash common.Hash) { if !ok { return } - addr, _ := tx.From() // already validated during insertion + addr, _ := types.Sender(pool.signer, tx) // already validated during insertion // Remove it from the list of known transactions delete(pool.all, hash) diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index dbe6fa6350..009d198869 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -32,7 +32,7 @@ import ( ) 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) + tx, _ := types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key) return tx } @@ -47,6 +47,10 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { return newPool, key } +func deriveSender(tx *types.Transaction) (common.Address, error) { + return types.Sender(types.HomesteadSigner{}, tx) +} + func TestInvalidTransactions(t *testing.T) { pool, key := setupTxPool() @@ -55,7 +59,7 @@ func TestInvalidTransactions(t *testing.T) { t.Error("expected", ErrNonExistentAccount) } - from, _ := tx.From() + from, _ := deriveSender(tx) currentState, _ := pool.currentState() currentState.AddBalance(from, big.NewInt(1)) if err := pool.Add(tx); err != ErrInsufficientFunds { @@ -90,7 +94,7 @@ func TestInvalidTransactions(t *testing.T) { func TestTransactionQueue(t *testing.T) { pool, key := setupTxPool() tx := transaction(0, big.NewInt(100), key) - from, _ := tx.From() + from, _ := deriveSender(tx) currentState, _ := pool.currentState() currentState.AddBalance(from, big.NewInt(1000)) pool.enqueueTx(tx.Hash(), tx) @@ -101,7 +105,7 @@ func TestTransactionQueue(t *testing.T) { } tx = transaction(1, big.NewInt(100), key) - from, _ = tx.From() + from, _ = deriveSender(tx) currentState.SetNonce(from, 2) pool.enqueueTx(tx.Hash(), tx) pool.promoteExecutables() @@ -117,7 +121,7 @@ func TestTransactionQueue(t *testing.T) { tx1 := transaction(0, big.NewInt(100), key) tx2 := transaction(10, big.NewInt(100), key) tx3 := transaction(11, big.NewInt(100), key) - from, _ = tx1.From() + from, _ = deriveSender(tx1) currentState, _ = pool.currentState() currentState.AddBalance(from, big.NewInt(1000)) pool.enqueueTx(tx1.Hash(), tx1) @@ -137,7 +141,7 @@ func TestTransactionQueue(t *testing.T) { func TestRemoveTx(t *testing.T) { pool, key := setupTxPool() tx := transaction(0, big.NewInt(100), key) - from, _ := tx.From() + from, _ := deriveSender(tx) currentState, _ := pool.currentState() currentState.AddBalance(from, big.NewInt(1)) @@ -161,8 +165,8 @@ func TestRemoveTx(t *testing.T) { 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() + tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key) + from, _ := deriveSender(tx) currentState, _ := pool.currentState() currentState.AddBalance(from, big.NewInt(1)) if err := pool.Add(tx); err != ErrNegativeValue { @@ -209,9 +213,10 @@ func TestTransactionDoubleNonce(t *testing.T) { } resetState() - tx1, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil).SignECDSA(key) - tx2, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil).SignECDSA(key) - tx3, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil).SignECDSA(key) + signer := types.HomesteadSigner{} + tx1, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil).SignECDSA(signer, key) + tx2, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil).SignECDSA(signer, key) + tx3, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil).SignECDSA(signer, key) // Add the first two transaction, ensure higher priced stays only if err := pool.add(tx1); err != nil { @@ -287,7 +292,7 @@ func TestNonceRecovery(t *testing.T) { func TestRemovedTxEvent(t *testing.T) { pool, key := setupTxPool() tx := transaction(0, big.NewInt(1000000), key) - from, _ := tx.From() + from, _ := deriveSender(tx) currentState, _ := pool.currentState() currentState.AddBalance(from, big.NewInt(1000000000000)) pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}}) @@ -305,7 +310,7 @@ func TestRemovedTxEvent(t *testing.T) { func TestTransactionDropping(t *testing.T) { // Create a test account and fund it pool, key := setupTxPool() - account, _ := transaction(0, big.NewInt(0), key).From() + account, _ := deriveSender(transaction(0, big.NewInt(0), key)) state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000)) @@ -369,7 +374,7 @@ func TestTransactionDropping(t *testing.T) { func TestTransactionPostponing(t *testing.T) { // Create a test account and fund it pool, key := setupTxPool() - account, _ := transaction(0, big.NewInt(0), key).From() + account, _ := deriveSender(transaction(0, big.NewInt(0), key)) state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000)) @@ -443,7 +448,7 @@ func TestTransactionPostponing(t *testing.T) { func TestTransactionQueueAccountLimiting(t *testing.T) { // Create a test account and fund it pool, key := setupTxPool() - account, _ := transaction(0, big.NewInt(0), key).From() + account, _ := deriveSender(transaction(0, big.NewInt(0), key)) state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000000)) @@ -531,7 +536,7 @@ func TestTransactionQueueTimeLimiting(t *testing.T) { // Create a test account and fund it pool, key := setupTxPool() - account, _ := transaction(0, big.NewInt(0), key).From() + account, _ := deriveSender(transaction(0, big.NewInt(0), key)) state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000000)) @@ -555,7 +560,7 @@ func TestTransactionQueueTimeLimiting(t *testing.T) { func TestTransactionPendingLimiting(t *testing.T) { // Create a test account and fund it pool, key := setupTxPool() - account, _ := transaction(0, big.NewInt(0), key).From() + account, _ := deriveSender(transaction(0, big.NewInt(0), key)) state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000000)) @@ -585,7 +590,7 @@ func TestTransactionPendingLimitingEquivalency(t *testing.T) { testTransactionLi func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { // Add a batch of transactions to a pool one by one pool1, key1 := setupTxPool() - account1, _ := transaction(0, big.NewInt(0), key1).From() + account1, _ := deriveSender(transaction(0, big.NewInt(0), key1)) state1, _ := pool1.currentState() state1.AddBalance(account1, big.NewInt(1000000)) @@ -596,7 +601,7 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { } // Add a batch of transactions to a pool in one big batch pool2, key2 := setupTxPool() - account2, _ := transaction(0, big.NewInt(0), key2).From() + account2, _ := deriveSender(transaction(0, big.NewInt(0), key2)) state2, _ := pool2.currentState() state2.AddBalance(account2, big.NewInt(1000000)) @@ -717,7 +722,7 @@ func BenchmarkPendingDemotion10000(b *testing.B) { benchmarkPendingDemotion(b, 1 func benchmarkPendingDemotion(b *testing.B, size int) { // Add a batch of transactions to a pool one by one pool, key := setupTxPool() - account, _ := transaction(0, big.NewInt(0), key).From() + account, _ := deriveSender(transaction(0, big.NewInt(0), key)) state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000000)) @@ -741,7 +746,7 @@ func BenchmarkFuturePromotion10000(b *testing.B) { benchmarkFuturePromotion(b, 1 func benchmarkFuturePromotion(b *testing.B, size int) { // Add a batch of transactions to a pool one by one pool, key := setupTxPool() - account, _ := transaction(0, big.NewInt(0), key).From() + account, _ := deriveSender(transaction(0, big.NewInt(0), key)) state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000000)) @@ -760,7 +765,7 @@ func benchmarkFuturePromotion(b *testing.B, size int) { func BenchmarkPoolInsert(b *testing.B) { // Generate a batch of transactions to enqueue into the pool pool, key := setupTxPool() - account, _ := transaction(0, big.NewInt(0), key).From() + account, _ := deriveSender(transaction(0, big.NewInt(0), key)) state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000000)) @@ -783,7 +788,7 @@ func BenchmarkPoolBatchInsert10000(b *testing.B) { benchmarkPoolBatchInsert(b, 1 func benchmarkPoolBatchInsert(b *testing.B, size int) { // Generate a batch of transactions to enqueue into the pool pool, key := setupTxPool() - account, _ := transaction(0, big.NewInt(0), key).From() + account, _ := deriveSender(transaction(0, big.NewInt(0), key)) state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000000)) diff --git a/core/types/block_test.go b/core/types/block_test.go index ac7f17c0d8..b95bddcfce 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -18,6 +18,7 @@ package types import ( "bytes" + "fmt" "math/big" "reflect" "testing" @@ -51,7 +52,11 @@ func TestBlockEncoding(t *testing.T) { check("Size", block.Size(), common.StorageSize(len(blockEnc))) tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil) - tx1, _ = tx1.WithSignature(common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b11b")) + + tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b11b")) + fmt.Println(block.Transactions()[0].Hash()) + fmt.Println(tx1.data) + fmt.Println(tx1.Hash()) check("len(Transactions)", len(block.Transactions()), 1) check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash()) diff --git a/core/types/json_test.go b/core/types/json_test.go index a028b5d08c..d80cda68b2 100644 --- a/core/types/json_test.go +++ b/core/types/json_test.go @@ -97,10 +97,12 @@ var unmarshalTransactionTests = map[string]struct { wantHash: common.HexToHash("0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9"), wantFrom: common.HexToAddress("0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689"), }, + /* TODO skipping this test as this type can not be tested with the current signing approach "bad signature fields": { input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","v":"0x58","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`, wantError: ErrInvalidSig, }, + */ "missing signature v": { input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`, wantError: errMissingTxSignatureFields, @@ -122,11 +124,12 @@ func TestUnmarshalTransaction(t *testing.T) { if !checkError(t, name, err, test.wantError) { continue } + if tx.Hash() != test.wantHash { t.Errorf("test %q: got hash %x, want %x", name, tx.Hash(), test.wantHash) continue } - from, err := tx.From() + from, err := Sender(HomesteadSigner{}, tx) if err != nil { t.Errorf("test %q: From error %v", name, err) } diff --git a/core/types/transaction.go b/core/types/transaction.go index ceea4f9592..972a36706f 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" ) @@ -36,8 +37,18 @@ var ErrInvalidSig = errors.New("invalid transaction v, r, s values") var ( errMissingTxSignatureFields = errors.New("missing required JSON transaction signature fields") errMissingTxFields = errors.New("missing required JSON transaction fields") + errNoSigner = errors.New("missing signing methods") ) +// deriveSigner makes a *best* guess about which signer to use. +func deriveSigner(V *big.Int) Signer { + if V.BitLen() > 0 && isProtectedV(V) { + return EIP155Signer{chainId: deriveChainId(V)} + } else { + return HomesteadSigner{} + } +} + type Transaction struct { data txdata // caches @@ -52,7 +63,7 @@ type txdata struct { Recipient *common.Address `rlp:"nil"` // nil means contract creation Amount *big.Int Payload []byte - V byte // signature + V *big.Int // signature R, S *big.Int // signature } @@ -64,40 +75,31 @@ type jsonTransaction struct { Recipient *common.Address `json:"to"` Amount *hexBig `json:"value"` Payload *hexBytes `json:"input"` - V *hexUint64 `json:"v"` + V *hexBig `json:"v"` R *hexBig `json:"r"` S *hexBig `json:"s"` } -// NewContractCreation creates a new transaction with no recipient. +func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction { + return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data) +} + func NewContractCreation(nonce uint64, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction { - if len(data) > 0 { - data = common.CopyBytes(data) - } - return &Transaction{data: txdata{ - AccountNonce: nonce, - Recipient: nil, - Amount: new(big.Int).Set(amount), - GasLimit: new(big.Int).Set(gasLimit), - Price: new(big.Int).Set(gasPrice), - Payload: data, - R: new(big.Int), - S: new(big.Int), - }} + return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data) } -// NewTransaction creates a new transaction with the given fields. -func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction { +func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction { if len(data) > 0 { data = common.CopyBytes(data) } d := txdata{ AccountNonce: nonce, - Recipient: &to, + Recipient: to, Payload: data, Amount: new(big.Int), GasLimit: new(big.Int), Price: new(big.Int), + V: new(big.Int), R: new(big.Int), S: new(big.Int), } @@ -110,9 +112,42 @@ func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice if gasPrice != nil { d.Price.Set(gasPrice) } + return &Transaction{data: d} } +func pickSigner(rules params.Rules) Signer { + var signer Signer + switch { + case rules.IsEIP155: + signer = NewEIP155Signer(rules.ChainId) + case rules.IsHomestead: + signer = HomesteadSigner{} + default: + signer = FrontierSigner{} + } + return signer +} + +// ChainId returns which chain id this transaction was signed for (if at all) +func (tx *Transaction) ChainId() *big.Int { + return deriveChainId(tx.data.V) +} + +// Protected returns whether the transaction is pretected from replay protection +func (tx *Transaction) Protected() bool { + return isProtectedV(tx.data.V) +} + +func isProtectedV(V *big.Int) bool { + if V.BitLen() <= 8 { + v := V.Uint64() + return v != 27 && v != 28 + } + // anything not 27 or 28 are considered unprotected + return true +} + // DecodeRLP implements rlp.Encoder func (tx *Transaction) EncodeRLP(w io.Writer) error { return rlp.Encode(w, &tx.data) @@ -125,12 +160,13 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error { if err == nil { tx.size.Store(common.StorageSize(rlp.ListSize(size))) } + return err } // MarshalJSON encodes transactions into the web3 RPC response block format. func (tx *Transaction) MarshalJSON() ([]byte, error) { - hash, v := tx.Hash(), uint64(tx.data.V) + hash := tx.Hash() return json.Marshal(&jsonTransaction{ Hash: &hash, @@ -140,7 +176,7 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { Recipient: tx.data.Recipient, Amount: (*hexBig)(tx.data.Amount), Payload: (*hexBytes)(&tx.data.Payload), - V: (*hexUint64)(&v), + V: (*hexBig)(tx.data.V), R: (*hexBig)(tx.data.R), S: (*hexBig)(tx.data.S), }) @@ -159,9 +195,17 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { if dec.V == nil || dec.R == nil || dec.S == nil { return errMissingTxSignatureFields } - if !crypto.ValidateSignatureValues(byte(*dec.V), (*big.Int)(dec.R), (*big.Int)(dec.S), false) { + + var V byte + if isProtectedV((*big.Int)(dec.V)) { + V = normaliseV(NewEIP155Signer(deriveChainId((*big.Int)(dec.V))), (*big.Int)(dec.V)) + } else { + V = byte(((*big.Int)(dec.V)).Uint64()) + } + if !crypto.ValidateSignatureValues(V, (*big.Int)(dec.R), (*big.Int)(dec.S), false) { return ErrInvalidSig } + if dec.AccountNonce == nil || dec.Price == nil || dec.GasLimit == nil || dec.Amount == nil || dec.Payload == nil { return errMissingTxFields } @@ -175,7 +219,7 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { GasLimit: (*big.Int)(dec.GasLimit), Price: (*big.Int)(dec.Price), Payload: *dec.Payload, - V: byte(*dec.V), + V: (*big.Int)(dec.V), R: (*big.Int)(dec.R), S: (*big.Int)(dec.S), } @@ -211,15 +255,8 @@ func (tx *Transaction) Hash() common.Hash { // SigHash returns the hash to be signed by the sender. // It does not uniquely identify the transaction. -func (tx *Transaction) SigHash() common.Hash { - return rlpHash([]interface{}{ - tx.data.AccountNonce, - tx.data.Price, - tx.data.GasLimit, - tx.data.Recipient, - tx.data.Amount, - tx.data.Payload, - }) +func (tx *Transaction) SigHash(signer Signer) common.Hash { + return signer.Hash(tx) } func (tx *Transaction) Size() common.StorageSize { @@ -232,6 +269,7 @@ func (tx *Transaction) Size() common.StorageSize { return common.StorageSize(c) } +/* // From returns the address derived from the signature (V, R, S) using secp256k1 // elliptic curve and an error if it failed deriving or upon an incorrect // signature. @@ -247,32 +285,15 @@ func (tx *Transaction) Size() common.StorageSize { // both txs before and after the first homestead block. Signatures // valid in homestead are a subset of valid ones in Frontier) func (tx *Transaction) From() (common.Address, error) { - return doFrom(tx, true) -} - -// FromFrontier returns the address derived from the signature (V, R, S) using -// secp256k1 elliptic curve and an error if it failed deriving or upon an -// incorrect signature. -// -// FromFrantier uses the frontier consensus rules to determine whether the -// signature is valid. -// -// FromFrontier caches the address, allowing it to be used regardless of -// Frontier / Homestead. however, the first time called it runs -// signature validations, so we need two versions. This makes it -// easier to ensure backwards compatibility of things like package rpc -// where eth_getblockbynumber uses tx.From() and needs to work for -// both txs before and after the first homestead block. Signatures -// valid in homestead are a subset of valid ones in Frontier) -func (tx *Transaction) FromFrontier() (common.Address, error) { - return doFrom(tx, false) -} + if tx.signer == nil { + return common.Address{}, errNoSigner + } -func doFrom(tx *Transaction, homestead bool) (common.Address, error) { if from := tx.from.Load(); from != nil { return from.(common.Address), nil } - pubkey, err := tx.publicKey(homestead) + + pubkey, err := tx.signer.PublicKey(tx) if err != nil { return common.Address{}, err } @@ -282,68 +303,70 @@ func doFrom(tx *Transaction, homestead bool) (common.Address, error) { return addr, nil } -// Cost returns amount + gasprice * gaslimit. -func (tx *Transaction) Cost() *big.Int { - total := new(big.Int).Mul(tx.data.Price, tx.data.GasLimit) - total.Add(total, tx.data.Amount) - return total -} - // SignatureValues returns the ECDSA signature values contained in the transaction. -func (tx *Transaction) SignatureValues() (v byte, r *big.Int, s *big.Int) { - return tx.data.V, new(big.Int).Set(tx.data.R), new(big.Int).Set(tx.data.S) +func (tx *Transaction) SignatureValues() (v byte, r *big.Int, s *big.Int, err error) { + if tx.signer == nil { + return 0, nil, nil,errNoSigner + } + + return normaliseV(tx.signer, tx.data.V), new(big.Int).Set(tx.data.R),new(big.Int).Set(tx.data.S), nil } -func (tx *Transaction) publicKey(homestead bool) ([]byte, error) { - if !crypto.ValidateSignatureValues(tx.data.V, tx.data.R, tx.data.S, homestead) { - return nil, ErrInvalidSig +*/ + +// AsMessage returns the transaction as a core.Message. +// +// AsMessage requires a signer to derive the sender. +// +// XXX Rename message to something less arbitrary? +func (tx *Transaction) AsMessage(s Signer) (Message, error) { + msg := Message{ + nonce: tx.data.AccountNonce, + price: new(big.Int).Set(tx.data.Price), + gasLimit: new(big.Int).Set(tx.data.GasLimit), + to: tx.data.Recipient, + amount: tx.data.Amount, + data: tx.data.Payload, } - // encode the signature in uncompressed format - r, s := tx.data.R.Bytes(), tx.data.S.Bytes() - sig := make([]byte, 65) - copy(sig[32-len(r):32], r) - copy(sig[64-len(s):64], s) - sig[64] = tx.data.V - 27 + var err error + msg.from, err = Sender(s, tx) + return msg, err +} - // recover the public key from the signature - hash := tx.SigHash() - pub, err := crypto.Ecrecover(hash[:], sig) - if err != nil { - return nil, err - } - if len(pub) == 0 || pub[0] != 4 { - return nil, errors.New("invalid public key") - } - return pub, nil +// SignECDSA signs the transaction using the given signer and private key +// +// XXX This only makes for a nice API: NewTx(...).SignECDSA(signer, prv). Should +// we keep this? +func (tx *Transaction) SignECDSA(signer Signer, prv *ecdsa.PrivateKey) (*Transaction, error) { + return signer.SignECDSA(tx, prv) } // WithSignature returns a new transaction with the given signature. // This signature needs to be formatted as described in the yellow paper (v+27). -func (tx *Transaction) WithSignature(sig []byte) (*Transaction, error) { - if len(sig) != 65 { - panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig))) - } - cpy := &Transaction{data: tx.data} - cpy.data.R = new(big.Int).SetBytes(sig[:32]) - cpy.data.S = new(big.Int).SetBytes(sig[32:64]) - cpy.data.V = sig[64] - return cpy, nil +func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) { + return signer.WithSignature(tx, sig) } -func (tx *Transaction) SignECDSA(prv *ecdsa.PrivateKey) (*Transaction, error) { - h := tx.SigHash() - sig, err := crypto.SignEthereum(h[:], prv) - if err != nil { - return nil, err - } - return tx.WithSignature(sig) +// Cost returns amount + gasprice * gaslimit. +func (tx *Transaction) Cost() *big.Int { + total := new(big.Int).Mul(tx.data.Price, tx.data.GasLimit) + total.Add(total, tx.data.Amount) + return total +} + +func (tx *Transaction) RawSignatureValues() (*big.Int, *big.Int, *big.Int) { + return tx.data.V, tx.data.R, tx.data.S } func (tx *Transaction) String() string { + // make a best guess about the signer and use that to derive + // the sender. + signer := deriveSigner(tx.data.V) + var from, to string - if f, err := tx.From(); err != nil { - from = "[invalid sender]" + if f, err := Sender(signer, tx); err != nil { // derive but don't cache + from = "[invalid sender: invalid sig]" } else { from = fmt.Sprintf("%x", f[:]) } @@ -485,8 +508,9 @@ func (t *TransactionsByPriceAndNonce) Peek() *Transaction { // Shift replaces the current best head with the next one from the same account. func (t *TransactionsByPriceAndNonce) Shift() { - acc, _ := t.heads[0].From() // we only sort valid txs so this cannot fail - + signer := deriveSigner(t.heads[0].data.V) + // derive signer but don't cache. + acc, _ := Sender(signer, t.heads[0]) // we only sort valid txs so this cannot fail if txs, ok := t.txs[acc]; ok && len(txs) > 0 { t.heads[0], t.txs[acc] = txs[0], txs[1:] heap.Fix(&t.heads, 0) @@ -501,3 +525,35 @@ func (t *TransactionsByPriceAndNonce) Shift() { func (t *TransactionsByPriceAndNonce) Pop() { heap.Pop(&t.heads) } + +// Message is a fully derived transaction and implements core.Message +// +// NOTE: In a future PR this will be removed. +type Message struct { + to *common.Address + from common.Address + nonce uint64 + amount, price, gasLimit *big.Int + data []byte +} + +func NewMessage(from common.Address, to *common.Address, nonce uint64, amount, gasLimit, price *big.Int, data []byte) Message { + return Message{ + from: from, + to: to, + nonce: nonce, + amount: amount, + price: price, + gasLimit: gasLimit, + data: data, + } +} + +func (m Message) From() common.Address { return m.from } +func (m Message) To() *common.Address { return m.to } +func (m Message) GasPrice() *big.Int { return m.price } +func (m Message) Value() *big.Int { return m.amount } +func (m Message) Gas() *big.Int { return m.gasLimit } +func (m Message) Nonce() uint64 { return m.nonce } +func (m Message) Data() []byte { return m.data } +func (m Message) CheckNonce() bool { return true } diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go new file mode 100644 index 0000000000..48209e2d8e --- /dev/null +++ b/core/types/transaction_signing.go @@ -0,0 +1,340 @@ +// Copyright 2016 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 . + +package types + +import ( + "crypto/ecdsa" + "errors" + "fmt" + "math/big" + "reflect" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" +) + +// sigCache is used to cache the derived sender and contains +// the signer used to derive it. +type sigCache struct { + signer Signer + from common.Address +} + +// MakeSigner returns a Signer based on the given chain config and block number. +func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { + var signer Signer + switch { + case config.IsEIP155(blockNumber): + signer = NewEIP155Signer(config.ChainId) + case config.IsHomestead(blockNumber): + signer = HomesteadSigner{} + default: + signer = FrontierSigner{} + } + return signer +} + +// SignECDSA signs the transaction using the given signer and private key +func SignECDSA(s Signer, tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) { + h := s.Hash(tx) + sig, err := crypto.SignEthereum(h[:], prv) + if err != nil { + return nil, err + } + return s.WithSignature(tx, sig) +} + +// Sender derives the sender from the tx using the signer derivation +// functions. + +// Sender returns the address derived from the signature (V, R, S) using secp256k1 +// elliptic curve and an error if it failed deriving or upon an incorrect +// signature. +// +// Sender may cache the address, allowing it to be used regardless of +// signing method. The cache is invalidated if the cached signer does +// not match the signer used in the current call. +func Sender(signer Signer, tx *Transaction) (common.Address, error) { + if sc := tx.from.Load(); sc != nil { + sigCache := sc.(sigCache) + // If the signer used to derive from in a previous + // call is not the same as used current, invalidate + // the cache. + if reflect.TypeOf(sigCache.signer) == reflect.TypeOf(signer) { + return sigCache.from, nil + } + } + + pubkey, err := signer.PublicKey(tx) + if err != nil { + return common.Address{}, err + } + var addr common.Address + copy(addr[:], crypto.Keccak256(pubkey[1:])[12:]) + tx.from.Store(sigCache{signer: signer, from: addr}) + return addr, nil +} + +// SignatureValues returns the ECDSA signature values contained in the transaction. +func SignatureValues(signer Signer, tx *Transaction) (v byte, r *big.Int, s *big.Int) { + return normaliseV(signer, tx.data.V), new(big.Int).Set(tx.data.R), new(big.Int).Set(tx.data.S) +} + +type Signer interface { + // Hash returns the rlp encoded hash for signatures + Hash(tx *Transaction) common.Hash + // PubilcKey returns the public key derived from the signature + PublicKey(tx *Transaction) ([]byte, error) + // SignECDSA signs the transaction with the given and returns a copy of the tx + SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) + // WithSignature returns a copy of the transaction with the given signature + WithSignature(tx *Transaction, sig []byte) (*Transaction, error) +} + +// EIP155Transaction implements TransactionInterface using the +// EIP155 rules +type EIP155Signer struct { + HomesteadSigner + + chainId, chainIdMul *big.Int +} + +func NewEIP155Signer(chainId *big.Int) EIP155Signer { + return EIP155Signer{ + chainId: chainId, + chainIdMul: new(big.Int).Mul(chainId, big.NewInt(2)), + } +} + +func (s EIP155Signer) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) { + return SignECDSA(s, tx, prv) +} + +func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) { + // if the transaction is not protected fall back to homestead signer + if !tx.Protected() { + return (HomesteadSigner{}).PublicKey(tx) + } + + V := normaliseV(s, tx.data.V) + if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) { + return nil, ErrInvalidSig + } + + // encode the signature in uncompressed format + R, S := tx.data.R.Bytes(), tx.data.S.Bytes() + sig := make([]byte, 65) + copy(sig[32-len(R):32], R) + copy(sig[64-len(S):64], S) + sig[64] = V - 27 + + // recover the public key from the signature + hash := s.Hash(tx) + pub, err := crypto.Ecrecover(hash[:], sig) + if err != nil { + return nil, err + } + if len(pub) == 0 || pub[0] != 4 { + return nil, errors.New("invalid public key") + } + return pub, nil +} + +// WithSignature returns a new transaction with the given signature. +// This signature needs to be formatted as described in the yellow paper (v+27). +func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) { + if len(sig) != 65 { + panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig))) + } + + cpy := &Transaction{data: tx.data} + cpy.data.R = new(big.Int).SetBytes(sig[:32]) + cpy.data.S = new(big.Int).SetBytes(sig[32:64]) + cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]}) + if s.chainId.BitLen() > 0 { + cpy.data.V = big.NewInt(int64(sig[64] - 27 + 35)) + cpy.data.V.Add(cpy.data.V, s.chainIdMul) + } + return cpy, nil +} + +// Hash returns the hash to be signed by the sender. +// It does not uniquely identify the transaction. +func (s EIP155Signer) Hash(tx *Transaction) common.Hash { + return rlpHash([]interface{}{ + tx.data.AccountNonce, + tx.data.Price, + tx.data.GasLimit, + tx.data.Recipient, + tx.data.Amount, + tx.data.Payload, + s.chainId, uint(0), uint(0), + }) +} + +func (s EIP155Signer) SigECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) { + h := s.Hash(tx) + sig, err := crypto.SignEthereum(h[:], prv) + if err != nil { + return nil, err + } + return s.WithSignature(tx, sig) +} + +// HomesteadTransaction implements TransactionInterface using the +// homestead rules. +type HomesteadSigner struct{ FrontierSigner } + +// WithSignature returns a new transaction with the given snature. +// This snature needs to be formatted as described in the yellow paper (v+27). +func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) { + if len(sig) != 65 { + panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig))) + } + cpy := &Transaction{data: tx.data} + cpy.data.R = new(big.Int).SetBytes(sig[:32]) + cpy.data.S = new(big.Int).SetBytes(sig[32:64]) + cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]}) + return cpy, nil +} + +func (hs HomesteadSigner) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) { + h := hs.Hash(tx) + sig, err := crypto.SignEthereum(h[:], prv) + if err != nil { + return nil, err + } + return hs.WithSignature(tx, sig) +} + +func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) { + if tx.data.V.BitLen() > 8 { + return nil, ErrInvalidSig + } + V := byte(tx.data.V.Uint64()) + if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) { + return nil, ErrInvalidSig + } + // encode the snature in uncompressed format + r, s := tx.data.R.Bytes(), tx.data.S.Bytes() + sig := make([]byte, 65) + copy(sig[32-len(r):32], r) + copy(sig[64-len(s):64], s) + sig[64] = V - 27 + + // recover the public key from the snature + hash := hs.Hash(tx) + pub, err := crypto.Ecrecover(hash[:], sig) + if err != nil { + return nil, err + } + if len(pub) == 0 || pub[0] != 4 { + return nil, errors.New("invalid public key") + } + return pub, nil +} + +type FrontierSigner struct{} + +// WithSignature returns a new transaction with the given snature. +// This snature needs to be formatted as described in the yellow paper (v+27). +func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) { + if len(sig) != 65 { + panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig))) + } + cpy := &Transaction{data: tx.data} + cpy.data.R = new(big.Int).SetBytes(sig[:32]) + cpy.data.S = new(big.Int).SetBytes(sig[32:64]) + cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]}) + return cpy, nil +} + +func (fs FrontierSigner) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) { + h := fs.Hash(tx) + sig, err := crypto.SignEthereum(h[:], prv) + if err != nil { + return nil, err + } + return fs.WithSignature(tx, sig) +} + +// Hash returns the hash to be sned by the sender. +// It does not uniquely identify the transaction. +func (fs FrontierSigner) Hash(tx *Transaction) common.Hash { + return rlpHash([]interface{}{ + tx.data.AccountNonce, + tx.data.Price, + tx.data.GasLimit, + tx.data.Recipient, + tx.data.Amount, + tx.data.Payload, + }) +} + +func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) { + if tx.data.V.BitLen() > 8 { + return nil, ErrInvalidSig + } + + V := byte(tx.data.V.Uint64()) + if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, false) { + return nil, ErrInvalidSig + } + // encode the snature in uncompressed format + r, s := tx.data.R.Bytes(), tx.data.S.Bytes() + sig := make([]byte, 65) + copy(sig[32-len(r):32], r) + copy(sig[64-len(s):64], s) + sig[64] = V - 27 + + // recover the public key from the snature + hash := fs.Hash(tx) + pub, err := crypto.Ecrecover(hash[:], sig) + if err != nil { + return nil, err + } + if len(pub) == 0 || pub[0] != 4 { + return nil, errors.New("invalid public key") + } + return pub, nil +} + +// normaliseV returns the Ethereum version of the V parameter +func normaliseV(s Signer, v *big.Int) byte { + if s, ok := s.(EIP155Signer); ok { + stdV := v.BitLen() <= 8 && (v.Uint64() == 27 || v.Uint64() == 28) + if s.chainId.BitLen() > 0 && !stdV { + nv := byte((new(big.Int).Sub(v, s.chainIdMul).Uint64()) - 35 + 27) + return nv + } + } + return byte(v.Uint64()) +} + +// deriveChainId derives the chain id from the given v parameter +func deriveChainId(v *big.Int) *big.Int { + if v.BitLen() <= 64 { + v := v.Uint64() + if v == 27 || v == 28 { + return new(big.Int) + } + return new(big.Int).SetUint64((v - 35) / 2) + } + v = new(big.Int).Sub(v, big.NewInt(35)) + return v.Div(v, big.NewInt(2)) +} diff --git a/core/types/transaction_signing_test.go b/core/types/transaction_signing_test.go new file mode 100644 index 0000000000..89c5902629 --- /dev/null +++ b/core/types/transaction_signing_test.go @@ -0,0 +1,116 @@ +// Copyright 2016 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 . + +package types + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" +) + +func TestEIP155Signing(t *testing.T) { + key, _ := crypto.GenerateKey() + addr := crypto.PubkeyToAddress(key.PublicKey) + + signer := NewEIP155Signer(big.NewInt(18)) + tx, err := NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil).SignECDSA(signer, key) + if err != nil { + t.Fatal(err) + } + + from, err := Sender(signer, tx) + if err != nil { + t.Fatal(err) + } + if from != addr { + t.Errorf("exected from and address to be equal. Got %x want %x", from, addr) + } +} + +func TestEIP155ChainId(t *testing.T) { + key, _ := crypto.GenerateKey() + addr := crypto.PubkeyToAddress(key.PublicKey) + + signer := NewEIP155Signer(big.NewInt(18)) + tx, err := NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil).SignECDSA(signer, key) + if err != nil { + t.Fatal(err) + } + if !tx.Protected() { + t.Fatal("expected tx to be protected") + } + + if tx.ChainId().Cmp(signer.chainId) != 0 { + t.Error("expected chainId to be", signer.chainId, "got", tx.ChainId()) + } + + tx = NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil) + tx, err = tx.SignECDSA(HomesteadSigner{}, key) + if err != nil { + t.Fatal(err) + } + + if tx.Protected() { + t.Error("didn't expect tx to be protected") + } + + if tx.ChainId().BitLen() > 0 { + t.Error("expected chain id to be 0 got", tx.ChainId()) + } +} + +func TestEIP155SigningVitalik(t *testing.T) { + // Test vectors come from http://vitalik.ca/files/eip155_testvec.txt + for i, test := range []struct { + txRlp, addr string + }{ + {"f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce"}, + {"f864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0x23ef145a395ea3fa3deb533b8a9e1b4c6c25d112"}, + {"f864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2e485e0c23b4c3c542628a5f672eeab0ad4888be"}, + {"f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0x82a88539669a3fd524d669e858935de5e5410cf0"}, + {"f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf9358f2538fd5ccfeb848b64a96b743fcc930554"}, + {"f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xa8f7aba377317440bc5b26198a363ad22af1f3a4"}, + {"f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xf1f571dc362a0e5b2696b8e775f8491d3e50de35"}, + {"f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xd37922162ab7cea97c97a87551ed02c9a38b7332"}, + {"f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029"}, + {"f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f"}, + } { + signer := NewEIP155Signer(big.NewInt(1)) + + var tx *Transaction + err := rlp.DecodeBytes(common.Hex2Bytes(test.txRlp), &tx) + if err != nil { + t.Errorf("%d: %v", i, err) + continue + } + + from, err := Sender(signer, tx) + if err != nil { + t.Errorf("%d: %v", i, err) + continue + } + + addr := common.HexToAddress(test.addr) + if from != addr { + t.Errorf("%d: expected %x got %x", i, addr, from) + } + + } +} diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 98a78d221e..ca105566ad 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -46,15 +46,16 @@ var ( big.NewInt(1), common.FromHex("5544"), ).WithSignature( + HomesteadSigner{}, common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a31c"), ) ) func TestTransactionSigHash(t *testing.T) { - if emptyTx.SigHash() != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") { + if emptyTx.SigHash(HomesteadSigner{}) != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") { t.Errorf("empty transaction hash mismatch, got %x", emptyTx.Hash()) } - if rightvrsTx.SigHash() != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") { + if rightvrsTx.SigHash(HomesteadSigner{}) != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") { t.Errorf("RightVRS transaction hash mismatch, got %x", rightvrsTx.Hash()) } } @@ -72,7 +73,9 @@ func TestTransactionEncode(t *testing.T) { func decodeTx(data []byte) (*Transaction, error) { var tx Transaction - return &tx, rlp.Decode(bytes.NewReader(data), &tx) + t, err := &tx, rlp.Decode(bytes.NewReader(data), &tx) + + return t, err } func defaultTestKey() (*ecdsa.PrivateKey, common.Address) { @@ -88,7 +91,8 @@ func TestRecipientEmpty(t *testing.T) { t.Error(err) t.FailNow() } - from, err := tx.From() + + from, err := Sender(HomesteadSigner{}, tx) if err != nil { t.Error(err) t.FailNow() @@ -107,7 +111,7 @@ func TestRecipientNormal(t *testing.T) { t.FailNow() } - from, err := tx.From() + from, err := Sender(HomesteadSigner{}, tx) if err != nil { t.Error(err) t.FailNow() @@ -127,12 +131,14 @@ func TestTransactionPriceNonceSort(t *testing.T) { for i := 0; i < len(keys); i++ { keys[i], _ = crypto.GenerateKey() } + + signer := HomesteadSigner{} // Generate a batch of transactions with overlapping values, but shifted nonces groups := map[common.Address]Transactions{} for start, key := range keys { addr := crypto.PubkeyToAddress(key.PublicKey) for i := 0; i < 25; i++ { - tx, _ := NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(int64(start+i)), nil).SignECDSA(key) + tx, _ := NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(int64(start+i)), nil).SignECDSA(signer, key) groups[addr] = append(groups[addr], tx) } } @@ -148,11 +154,11 @@ func TestTransactionPriceNonceSort(t *testing.T) { break } for i, txi := range txs { - fromi, _ := txi.From() + fromi, _ := Sender(signer, txi) // Make sure the nonce order is valid for j, txj := range txs[i+1:] { - fromj, _ := txj.From() + fromj, _ := Sender(signer, txj) if fromi == fromj && txi.Nonce() > txj.Nonce() { t.Errorf("invalid nonce ordering: tx #%d (A=%x N=%v) < tx #%d (A=%x N=%v)", i, fromi[:4], txi.Nonce(), i+j, fromj[:4], txj.Nonce()) @@ -161,20 +167,20 @@ func TestTransactionPriceNonceSort(t *testing.T) { // Find the previous and next nonce of this account prev, next := i-1, i+1 for j := i - 1; j >= 0; j-- { - if fromj, _ := txs[j].From(); fromi == fromj { + if fromj, _ := Sender(signer, txs[j]); fromi == fromj { prev = j break } } for j := i + 1; j < len(txs); j++ { - if fromj, _ := txs[j].From(); fromi == fromj { + if fromj, _ := Sender(signer, txs[j]); fromi == fromj { next = j break } } // Make sure that in between the neighbor nonces, the transaction is correctly positioned price wise for j := prev + 1; j < next; j++ { - fromj, _ := txs[j].From() + fromj, _ := Sender(signer, txs[j]) if j < i && txs[j].GasPrice().Cmp(txi.GasPrice()) < 0 { t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", j, fromj[:4], txs[j].GasPrice(), i, fromi[:4], txi.GasPrice()) } diff --git a/core/vm/jit_test.go b/core/vm/jit_test.go index f9c0e8fa2e..6f7ba9250a 100644 --- a/core/vm/jit_test.go +++ b/core/vm/jit_test.go @@ -174,7 +174,7 @@ func NewEnv(config *Config) *Env { } func (self *Env) ChainConfig() *params.ChainConfig { - return ¶ms.ChainConfig{new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int)} + return params.TestChainConfig } func (self *Env) Vm() Vm { return self.evm } func (self *Env) Origin() common.Address { return common.Address{} } diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index f2d86a3247..c57747edcd 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -57,7 +57,7 @@ type Config struct { // sets defaults on the config func setDefaults(cfg *Config) { if cfg.ChainConfig == nil { - cfg.ChainConfig = ¶ms.ChainConfig{new(big.Int), new(big.Int), false, new(big.Int), common.Hash{}, new(big.Int)} + cfg.ChainConfig = ¶ms.ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), false, new(big.Int), common.Hash{}, new(big.Int), new(big.Int), new(big.Int)} } if cfg.Difficulty == nil { diff --git a/core/vm_env.go b/core/vm_env.go index 43e4d2fd6f..43637bd132 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -69,7 +69,7 @@ func NewEnv(state *state.StateDB, chainConfig *params.ChainConfig, chain *BlockC func (self *VMEnv) ChainConfig() *params.ChainConfig { return self.chainConfig } func (self *VMEnv) Vm() vm.Vm { return self.evm } -func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f } +func (self *VMEnv) Origin() common.Address { return self.msg.From() } func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number } func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase } func (self *VMEnv) Time() *big.Int { return self.header.Time } diff --git a/eth/api.go b/eth/api.go index 7932bbcb6d..b3185c3926 100644 --- a/eth/api.go +++ b/eth/api.go @@ -506,21 +506,15 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common. if err != nil { return nil, err } + + signer := types.MakeSigner(api.config, block.Number()) // Mutate the state and trace the selected transaction for idx, tx := range block.Transactions() { // Assemble the transaction call message - from, err := tx.FromFrontier() + msg, err := tx.AsMessage(signer) if err != nil { return nil, fmt.Errorf("sender retrieval failed: %v", err) } - msg := callmsg{ - addr: from, - to: tx.To(), - gas: tx.Gas(), - gasPrice: tx.GasPrice(), - value: tx.Value(), - data: tx.Data(), - } // Mutate the state if we haven't reached the tracing transaction yet if uint64(idx) < txIndex { vmenv := core.NewEnv(stateDb, api.config, api.eth.BlockChain(), msg, block.Header(), vm.Config{}) diff --git a/eth/api_backend.go b/eth/api_backend.go index f17ad6a15f..0925132ef0 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/params" rpc "github.com/ethereum/go-ethereum/rpc" "golang.org/x/net/context" ) @@ -40,6 +41,14 @@ type EthApiBackend struct { gpo *gasprice.GasPriceOracle } +func (b *EthApiBackend) ChainConfig() *params.ChainConfig { + return b.eth.chainConfig +} + +func (b *EthApiBackend) CurrentBlock() *types.Block { + return b.eth.blockchain.CurrentBlock() +} + func (b *EthApiBackend) SetHead(number uint64) { b.eth.blockchain.SetHead(number) } @@ -99,8 +108,7 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int { func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) { statedb := state.(EthApiState).state - addr, _ := msg.From() - from := statedb.GetOrNewStateObject(addr) + from := statedb.GetOrNewStateObject(msg.From()) from.SetBalance(common.MaxBig) vmError := func() error { return nil } return core.NewEnv(statedb, b.eth.chainConfig, b.eth.blockchain, msg, header, vm.Config{}), vmError, nil diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index f5f2437fa8..86638ae2d0 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -118,7 +118,8 @@ func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, paren } // If the block number is multiple of 3, send a bonus transaction to the miner if parent == dl.genesis && i%3 == 0 { - tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testKey) + signer := types.MakeSigner(params.TestChainConfig, block.Number()) + tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testKey) if err != nil { panic(err) } diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go index 5d46c62fd9..426bfd5428 100644 --- a/eth/fetcher/fetcher_test.go +++ b/eth/fetcher/fetcher_test.go @@ -50,7 +50,8 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common // 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) + signer := types.MakeSigner(params.TestChainConfig, block.Number()) + tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testKey) if err != nil { panic(err) } diff --git a/eth/handler_test.go b/eth/handler_test.go index 045bad0d4a..f599e9e869 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -305,18 +305,19 @@ func testGetNodeData(t *testing.T, protocol int) { acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) + signer := types.HomesteadSigner{} // Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_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(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey) + tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, 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(testBank.Address), 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) + tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey) + tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: @@ -396,18 +397,19 @@ func testGetReceipt(t *testing.T, protocol int) { acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) + signer := types.HomesteadSigner{} // Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_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(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey) + tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, 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(testBank.Address), 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) + tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey) + tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: diff --git a/eth/helper_test.go b/eth/helper_test.go index 73af04fcf6..f239767850 100644 --- a/eth/helper_test.go +++ b/eth/helper_test.go @@ -110,7 +110,7 @@ func (p *testTxPool) Pending() map[common.Address]types.Transactions { batches := make(map[common.Address]types.Transactions) for _, tx := range p.pool { - from, _ := tx.From() + from, _ := types.Sender(types.HomesteadSigner{}, tx) batches[from] = append(batches[from], tx) } for _, batch := range batches { @@ -122,7 +122,7 @@ func (p *testTxPool) Pending() map[common.Address]types.Transactions { // newTestTransaction create a new dummy transaction. func newTestTransaction(from *ecdsa.PrivateKey, 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) + tx, _ = tx.SignECDSA(types.HomesteadSigner{}, from) return tx } diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 6e2b1378a7..a095aa0767 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -147,7 +147,7 @@ func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (*typ var tx *types.Transaction err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByHash", hash) if err == nil { - if _, r, _ := tx.SignatureValues(); r == nil { + if _, r, _ := tx.RawSignatureValues(); r == nil { return nil, fmt.Errorf("server returned transaction without signature") } } @@ -166,7 +166,11 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, var tx *types.Transaction err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, index) if err == nil { - if _, r, _ := tx.SignatureValues(); r == nil { + var signer types.Signer = types.HomesteadSigner{} + if tx.Protected() { + signer = types.NewEIP155Signer(tx.ChainId()) + } + if _, r, _ := types.SignatureValues(signer, tx); r == nil { return nil, fmt.Errorf("server returned transaction without signature") } } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 36bb8c077c..0e4dd45240 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -279,7 +279,8 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) } - signature, err := s.am.SignWithPassphrase(args.From, passwd, tx.SigHash().Bytes()) + signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number()) + signature, err := s.am.SignWithPassphrase(args.From, passwd, signer.Hash(tx).Bytes()) if err != nil { return common.Hash{}, err } @@ -537,22 +538,14 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr } // Assemble the CALL invocation - msg := callmsg{ - addr: addr, - to: args.To, - gas: args.Gas.BigInt(), - gasPrice: args.GasPrice.BigInt(), - value: args.Value.BigInt(), - data: common.FromHex(args.Data), + gas, gasPrice := args.Gas.BigInt(), args.GasPrice.BigInt() + if gas.Cmp(common.Big0) == 0 { + gas = big.NewInt(50000000) } - - if msg.gas.Cmp(common.Big0) == 0 { - msg.gas = big.NewInt(50000000) - } - - if msg.gasPrice.Cmp(common.Big0) == 0 { - msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) + if gasPrice.Cmp(common.Big0) == 0 { + gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) } + msg := types.NewMessage(addr, args.To, 0, args.Value.BigInt(), gas, gasPrice, common.FromHex(args.Data)) // Execute the call and return vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header) @@ -714,8 +707,12 @@ type RPCTransaction struct { // newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction { - from, _ := tx.FromFrontier() - v, r, s := tx.SignatureValues() + var signer types.Signer = types.FrontierSigner{} + if tx.Protected() { + signer = types.NewEIP155Signer(tx.ChainId()) + } + from, _ := types.Sender(signer, tx) + v, r, s := types.SignatureValues(signer, tx) return &RPCTransaction{ From: from, Gas: rpc.NewHexNumber(tx.Gas()), @@ -735,11 +732,12 @@ func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction { func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransaction, error) { if txIndex >= 0 && txIndex < len(b.Transactions()) { tx := b.Transactions()[txIndex] - from, err := tx.FromFrontier() - if err != nil { - return nil, err + var signer types.Signer = types.FrontierSigner{} + if tx.Protected() { + signer = types.NewEIP155Signer(tx.ChainId()) } - v, r, s := tx.SignatureValues() + from, _ := types.Sender(signer, tx) + v, r, s := tx.RawSignatureValues() return &RPCTransaction{ BlockHash: b.Hash(), BlockNumber: rpc.NewHexNumber(b.Number()), @@ -958,11 +956,11 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma return nil, nil } - from, err := tx.FromFrontier() - if err != nil { - glog.V(logger.Debug).Infof("%v\n", err) - return nil, nil + var signer types.Signer = types.FrontierSigner{} + if tx.Protected() { + signer = types.NewEIP155Signer(tx.ChainId()) } + from, _ := types.Sender(signer, tx) fields := map[string]interface{}{ "root": rpc.HexBytes(receipt.PostState), @@ -990,11 +988,13 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma // sign is a helper function that signs a transaction with the private key of the given address. func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { - signature, err := s.b.AccountManager().SignEthereum(addr, tx.SigHash().Bytes()) + signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number()) + + signature, err := s.b.AccountManager().SignEthereum(addr, signer.Hash(tx).Bytes()) if err != nil { return nil, err } - return tx.WithSignature(signature) + return tx.WithSignature(signer, signature) } // SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool. @@ -1028,7 +1028,9 @@ func prepareSendTxArgs(ctx context.Context, args SendTxArgs, b Backend) (SendTxA // submitTransaction is a helper function that submits tx to txPool and creates a log entry. func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, signature []byte) (common.Hash, error) { - signedTx, err := tx.WithSignature(signature) + signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number()) + + signedTx, err := tx.WithSignature(signer, signature) if err != nil { return common.Hash{}, err } @@ -1038,7 +1040,7 @@ func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, si } if signedTx.To() == nil { - from, _ := signedTx.From() + from, _ := types.Sender(signer, signedTx) addr := crypto.CreateAddress(from, signedTx.Nonce()) glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex()) } else { @@ -1072,7 +1074,8 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) } - signature, err := s.b.AccountManager().SignEthereum(args.From, tx.SigHash().Bytes()) + signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number()) + signature, err := s.b.AccountManager().SignEthereum(args.From, signer.Hash(tx).Bytes()) if err != nil { return common.Hash{}, err } @@ -1092,8 +1095,9 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod return "", err } + signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number()) if tx.To() == nil { - from, err := tx.FromFrontier() + from, err := types.Sender(signer, tx) if err != nil { return "", err } @@ -1202,7 +1206,12 @@ type SignTransactionResult struct { } func newTx(t *types.Transaction) *Tx { - from, _ := t.FromFrontier() + var signer types.Signer = types.HomesteadSigner{} + if t.Protected() { + signer = types.NewEIP155Signer(t.ChainId()) + } + + from, _ := types.Sender(signer, t) return &Tx{ tx: t, To: t.To(), @@ -1268,7 +1277,11 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction { pending := s.b.GetPoolTransactions() transactions := make([]*RPCTransaction, 0, len(pending)) for _, tx := range pending { - from, _ := tx.FromFrontier() + var signer types.Signer = types.HomesteadSigner{} + if tx.Protected() { + signer = types.NewEIP155Signer(tx.ChainId()) + } + from, _ := types.Sender(signer, tx) if s.b.AccountManager().HasAddress(from) { transactions = append(transactions, newRPCPendingTransaction(tx)) } @@ -1281,7 +1294,12 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction { func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) { pending := s.b.GetPoolTransactions() for _, p := range pending { - if pFrom, err := p.FromFrontier(); err == nil && pFrom == tx.From && p.SigHash() == tx.tx.SigHash() { + var signer types.Signer = types.HomesteadSigner{} + if p.Protected() { + signer = types.NewEIP155Signer(p.ChainId()) + } + + if pFrom, err := types.Sender(signer, p); err == nil && pFrom == tx.From && signer.Hash(p) == signer.Hash(tx.tx) { if gasPrice == nil { gasPrice = rpc.NewHexNumber(tx.tx.GasPrice()) } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index f9358b6cfd..fdc4a39dc8 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" "golang.org/x/net/context" ) @@ -59,6 +60,9 @@ type Backend interface { GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) Stats() (pending int, queued int) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) + + ChainConfig() *params.ChainConfig + CurrentBlock() *types.Block } type State interface { diff --git a/les/api_backend.go b/les/api_backend.go index 42d6cc4733..b77767ed70 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/light" + "github.com/ethereum/go-ethereum/params" rpc "github.com/ethereum/go-ethereum/rpc" "golang.org/x/net/context" ) @@ -39,6 +40,14 @@ type LesApiBackend struct { gpo *gasprice.LightPriceOracle } +func (b *LesApiBackend) ChainConfig() *params.ChainConfig { + return b.eth.chainConfig +} + +func (b *LesApiBackend) CurrentBlock() *types.Block { + return types.NewBlockWithHeader(b.eth.BlockChain().CurrentHeader()) +} + func (b *LesApiBackend) SetHead(number uint64) { b.eth.blockchain.SetHead(number) } @@ -81,7 +90,7 @@ func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int { func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) { stateDb := state.(*light.LightState).Copy() - addr, _ := msg.From() + addr := msg.From() from, err := stateDb.GetOrNewStateObject(ctx, addr) if err != nil { return nil, nil, err diff --git a/les/helper_test.go b/les/helper_test.go index 9569f2f755..a5428e954f 100644 --- a/les/helper_test.go +++ b/les/helper_test.go @@ -73,20 +73,22 @@ contract test { */ func testChainGen(i int, block *core.BlockGen) { + signer := types.HomesteadSigner{} + 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) + tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, 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. // acc1Addr creates a test contract. - tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey) + tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey) nonce := block.TxNonce(acc1Addr) - tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key) + tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key) nonce++ - tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode).SignECDSA(acc1Key) + tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode).SignECDSA(signer, acc1Key) testContractAddr = crypto.CreateAddress(acc1Addr, nonce) block.AddTx(tx1) block.AddTx(tx2) @@ -96,7 +98,7 @@ func testChainGen(i int, block *core.BlockGen) { block.SetCoinbase(acc2Addr) block.SetExtra([]byte("yeehaw")) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") - tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey) + tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey) block.AddTx(tx) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). @@ -107,7 +109,7 @@ func testChainGen(i int, block *core.BlockGen) { b3.Extra = []byte("foo") block.AddUncle(b3) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") - tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey) + tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey) block.AddTx(tx) } } @@ -214,7 +216,7 @@ func (p *testTxPool) GetTransactions() types.Transactions { // newTestTransaction create a new dummy transaction. func newTestTransaction(from *ecdsa.PrivateKey, 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) + tx, _ = tx.SignECDSA(types.HomesteadSigner{}, from) return tx } diff --git a/les/odr_test.go b/les/odr_test.go index e7084bc20a..f1fa59ad83 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -100,45 +100,11 @@ func odrAccounts(ctx context.Context, db ethdb.Database, config *params.ChainCon func TestOdrContractCallLes1(t *testing.T) { testOdr(t, 1, 2, odrContractCall) } -// fullcallmsg is the message type used for call transations. -type fullcallmsg struct { - from *state.StateObject - to *common.Address - gas, gasPrice *big.Int - value *big.Int - data []byte +type callmsg struct { + types.Message } -// accessor boilerplate to implement core.Message -func (m fullcallmsg) From() (common.Address, error) { return m.from.Address(), nil } -func (m fullcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil } -func (m fullcallmsg) Nonce() uint64 { return 0 } -func (m fullcallmsg) CheckNonce() bool { return false } -func (m fullcallmsg) To() *common.Address { return m.to } -func (m fullcallmsg) GasPrice() *big.Int { return m.gasPrice } -func (m fullcallmsg) Gas() *big.Int { return m.gas } -func (m fullcallmsg) Value() *big.Int { return m.value } -func (m fullcallmsg) Data() []byte { return m.data } - -// callmsg is the message type used for call transations. -type lightcallmsg struct { - from *light.StateObject - to *common.Address - gas, gasPrice *big.Int - value *big.Int - data []byte -} - -// accessor boilerplate to implement core.Message -func (m lightcallmsg) From() (common.Address, error) { return m.from.Address(), nil } -func (m lightcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil } -func (m lightcallmsg) Nonce() uint64 { return 0 } -func (m lightcallmsg) CheckNonce() bool { return false } -func (m lightcallmsg) To() *common.Address { return m.to } -func (m lightcallmsg) GasPrice() *big.Int { return m.gasPrice } -func (m lightcallmsg) Gas() *big.Int { return m.gas } -func (m lightcallmsg) Value() *big.Int { return m.value } -func (m lightcallmsg) Data() []byte { return m.data } +func (callmsg) CheckNonce() bool { return false } func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") @@ -153,15 +119,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai from := statedb.GetOrNewStateObject(testBankAddress) from.SetBalance(common.MaxBig) - msg := fullcallmsg{ - from: from, - gas: big.NewInt(100000), - gasPrice: big.NewInt(0), - value: big.NewInt(0), - data: data, - to: &testContractAddr, - } - + msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data)} vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{}) gp := new(core.GasPool).AddGas(common.MaxBig) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) @@ -174,14 +132,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai if err == nil { from.SetBalance(common.MaxBig) - msg := lightcallmsg{ - from: from, - gas: big.NewInt(100000), - gasPrice: big.NewInt(0), - value: big.NewInt(0), - data: data, - to: &testContractAddr, - } + msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data)} vmenv := light.NewEnv(ctx, state, config, lc, msg, header, vm.Config{}) gp := new(core.GasPool).AddGas(common.MaxBig) diff --git a/light/odr_test.go b/light/odr_test.go index 1ae600e283..1f6bcaeb14 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -148,45 +148,11 @@ func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc func TestOdrContractCallLes1(t *testing.T) { testChainOdr(t, 1, 2, odrContractCall) } -// fullcallmsg is the message type used for call transations. -type fullcallmsg struct { - from *state.StateObject - to *common.Address - gas, gasPrice *big.Int - value *big.Int - data []byte +type callmsg struct { + types.Message } -// accessor boilerplate to implement core.Message -func (m fullcallmsg) From() (common.Address, error) { return m.from.Address(), nil } -func (m fullcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil } -func (m fullcallmsg) Nonce() uint64 { return 0 } -func (m fullcallmsg) CheckNonce() bool { return false } -func (m fullcallmsg) To() *common.Address { return m.to } -func (m fullcallmsg) GasPrice() *big.Int { return m.gasPrice } -func (m fullcallmsg) Gas() *big.Int { return m.gas } -func (m fullcallmsg) Value() *big.Int { return m.value } -func (m fullcallmsg) Data() []byte { return m.data } - -// callmsg is the message type used for call transations. -type lightcallmsg struct { - from *StateObject - to *common.Address - gas, gasPrice *big.Int - value *big.Int - data []byte -} - -// accessor boilerplate to implement core.Message -func (m lightcallmsg) From() (common.Address, error) { return m.from.Address(), nil } -func (m lightcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil } -func (m lightcallmsg) Nonce() uint64 { return 0 } -func (m lightcallmsg) CheckNonce() bool { return false } -func (m lightcallmsg) To() *common.Address { return m.to } -func (m lightcallmsg) GasPrice() *big.Int { return m.gasPrice } -func (m lightcallmsg) Gas() *big.Int { return m.gas } -func (m lightcallmsg) Value() *big.Int { return m.value } -func (m lightcallmsg) Data() []byte { return m.data } +func (callmsg) CheckNonce() bool { return false } func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) []byte { data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") @@ -201,15 +167,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain from := statedb.GetOrNewStateObject(testBankAddress) from.SetBalance(common.MaxBig) - msg := fullcallmsg{ - from: from, - gas: big.NewInt(100000), - gasPrice: big.NewInt(0), - value: big.NewInt(0), - data: data, - to: &testContractAddr, - } - + msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data)} vmenv := core.NewEnv(statedb, testChainConfig(), bc, msg, header, vm.Config{}) gp := new(core.GasPool).AddGas(common.MaxBig) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) @@ -222,15 +180,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain if err == nil { from.SetBalance(common.MaxBig) - msg := lightcallmsg{ - from: from, - gas: big.NewInt(100000), - gasPrice: big.NewInt(0), - value: big.NewInt(0), - data: data, - to: &testContractAddr, - } - + msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data)} vmenv := NewEnv(ctx, state, testChainConfig(), lc, msg, header, vm.Config{}) gp := new(core.GasPool).AddGas(common.MaxBig) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) @@ -244,20 +194,21 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain } func testChainGen(i int, block *core.BlockGen) { + signer := types.HomesteadSigner{} 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) + tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, 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. // acc1Addr creates a test contract. - tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey) + tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey) nonce := block.TxNonce(acc1Addr) - tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key) + tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key) nonce++ - tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode).SignECDSA(acc1Key) + tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode).SignECDSA(signer, acc1Key) testContractAddr = crypto.CreateAddress(acc1Addr, nonce) block.AddTx(tx1) block.AddTx(tx2) @@ -267,7 +218,7 @@ func testChainGen(i int, block *core.BlockGen) { block.SetCoinbase(acc2Addr) block.SetExtra([]byte("yeehaw")) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") - tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey) + tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey) block.AddTx(tx) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). @@ -278,7 +229,7 @@ func testChainGen(i int, block *core.BlockGen) { b3.Extra = []byte("foo") block.AddUncle(b3) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") - tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey) + tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey) block.AddTx(tx) } } diff --git a/light/txpool.go b/light/txpool.go index c046cac253..309bc3a322 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -44,6 +44,7 @@ var txPermanent = uint64(500) // created. type TxPool struct { config *params.ChainConfig + signer types.Signer quit chan bool eventMux *event.TypeMux events event.Subscription @@ -80,6 +81,7 @@ type TxRelayBackend interface { func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, chain *LightChain, relay TxRelayBackend) *TxPool { pool := &TxPool{ config: config, + signer: types.HomesteadSigner{}, nonce: make(map[common.Address]uint64), pending: make(map[common.Hash]*types.Transaction), mined: make(map[common.Hash][]*types.Transaction), @@ -198,7 +200,7 @@ func (pool *TxPool) checkMinedTxs(ctx context.Context, hash common.Hash, idx uin if len(receipts) != len(block.Transactions()) { panic(nil) // should never happen if hashes did match } - core.SetReceiptsData(block, receipts) + core.SetReceiptsData(pool.config, block, receipts) } //fmt.Println("WriteReceipt", receipts[i].TxHash) core.WriteReceipt(pool.chainDb, receipts[i]) @@ -309,6 +311,7 @@ func (pool *TxPool) eventLoop() { m, r := txc.getLists() pool.relay.NewHead(pool.head, m, r) pool.homestead = pool.config.IsHomestead(head.Number) + pool.signer = types.MakeSigner(pool.config, head.Number) pool.mu.Unlock() } } @@ -340,7 +343,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error // Validate the transaction sender and it's sig. Throw // if the from fields is invalid. - if from, err = tx.From(); err != nil { + if from, err = types.Sender(pool.signer, tx); err != nil { return core.ErrInvalidSender } @@ -389,7 +392,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error } // Should supply enough intrinsic gas - if tx.Gas().Cmp(core.IntrinsicGas(tx.Data(), core.MessageCreatesContract(tx), pool.homestead)) < 0 { + if tx.Gas().Cmp(core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)) < 0 { return core.ErrIntrinsicGas } @@ -413,7 +416,8 @@ func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error { self.pending[hash] = tx nonce := tx.Nonce() + 1 - addr, _ := tx.From() + + addr, _ := types.Sender(self.signer, tx) if nonce > self.nonce[addr] { self.nonce[addr] = nonce } @@ -433,7 +437,7 @@ func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error { } // we can ignore the error here because From is // verified in ValidateTransaction. - f, _ := tx.From() + f, _ := types.Sender(self.signer, tx) from := common.Bytes2Hex(f[:4]) glog.Infof("(t) %x => %s (%v) %x\n", from, toname, tx.Value, hash) } @@ -518,7 +522,7 @@ func (self *TxPool) Content() (map[common.Address]types.Transactions, map[common // Retrieve all the pending transactions and sort by account and by nonce pending := make(map[common.Address]types.Transactions) for _, tx := range self.pending { - account, _ := tx.From() + account, _ := types.Sender(self.signer, tx) pending[account] = append(pending[account], tx) } // There are no queued transactions in a light pool, just return an empty map diff --git a/light/txpool_test.go b/light/txpool_test.go index 0f797a9e81..759b6b8ab7 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -74,7 +74,7 @@ func txPoolTestChainGen(i int, block *core.BlockGen) { func TestTxPool(t *testing.T) { for i, _ := range testTx { - testTx[i], _ = types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey) + testTx[i], _ = types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(types.HomesteadSigner{}, testBankKey) } var ( diff --git a/light/vm_env.go b/light/vm_env.go index 82008a929e..5d330b072a 100644 --- a/light/vm_env.go +++ b/light/vm_env.go @@ -61,7 +61,7 @@ func NewEnv(ctx context.Context, state *LightState, chainConfig *params.ChainCon func (self *VMEnv) ChainConfig() *params.ChainConfig { return self.chainConfig } func (self *VMEnv) Vm() vm.Vm { return self.evm } -func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f } +func (self *VMEnv) Origin() common.Address { return self.msg.From() } func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number } func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase } func (self *VMEnv) Time() *big.Int { return self.header.Time } diff --git a/miner/worker.go b/miner/worker.go index f98145e8ff..2933b6bd3b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -63,7 +63,9 @@ type uint64RingBuffer struct { // Work is the workers current environment and holds // all of the current state information type Work struct { - config *params.ChainConfig + config *params.ChainConfig + signer types.Signer + state *state.StateDB // apply state changes here ancestors *set.Set // ancestor set (used for checking uncle parent validity) family *set.Set // family set (used for checking uncle invalidity) @@ -235,7 +237,7 @@ func (self *worker) update() { if atomic.LoadInt32(&self.mining) == 0 { self.currentMu.Lock() - acc, _ := ev.Tx.From() + acc, _ := types.Sender(self.current.signer, ev.Tx) txs := map[common.Address]types.Transactions{acc: types.Transactions{ev.Tx}} txset := types.NewTransactionsByPriceAndNonce(txs) @@ -367,6 +369,7 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error } work := &Work{ config: self.config, + signer: types.NewEIP155Signer(self.config.ChainId), state: state, ancestors: set.New(), family: set.New(), @@ -570,7 +573,17 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB } // Error may be ignored here. The error has already been checked // during transaction acceptance is the transaction pool. - from, _ := tx.From() + // + // We use the eip155 signer regardless of the current hf. + from, _ := types.Sender(env.signer, tx) + // Check whether the tx is replay protected. If we're not in the EIP155 hf + // phase, start ignoring the sender until we do. + if tx.Protected() && !env.config.IsEIP155(env.header.Number) { + glog.V(logger.Detail).Infof("Transaction (%x) is replay protected, but we haven't yet hardforked. Transaction will be ignored until we hardfork.\n", tx.Hash()) + + txs.Pop() + continue + } // Ignore any transactions (and accounts subsequently) with low gas limits if tx.GasPrice().Cmp(gasPrice) < 0 && !env.ownedAccounts.Has(from) { diff --git a/params/config.go b/params/config.go index 684e4dc421..d63236ef83 100644 --- a/params/config.go +++ b/params/config.go @@ -28,18 +28,24 @@ import ( // that any network, identified by its genesis block, can have its own // set of configuration options. type ChainConfig struct { + ChainId *big.Int `json:"chainId"` // Chain id identifies the current chain and is used for replay protection + HomesteadBlock *big.Int `json:"homesteadBlock"` // Homestead switch block (nil = no fork, 0 = already homestead) DAOForkBlock *big.Int `json:"daoForkBlock"` // TheDAO hard-fork switch block (nil = no fork) DAOForkSupport bool `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) - EIP150Block *big.Int `json:"EIP150Block"` // EIP150 HF block (nil = no fork) - EIP150Hash common.Hash `json:"EIP150Hash"` // EIP150 HF hash (fast sync aid) + EIP150Block *big.Int `json:"eip150Block"` // EIP150 HF block (nil = no fork) + EIP150Hash common.Hash `json:"eip150Hash"` // EIP150 HF hash (fast sync aid) - EIP158Block *big.Int `json:"EIP158Block"` // EIP158 HF block + EIP155Block *big.Int `json:"eip155Block"` // EIP155 HF block + EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block } -var TestChainConfig = &ChainConfig{new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int)} +var ( + TestChainConfig = &ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int), new(big.Int)} + TestRules = TestChainConfig.Rules(new(big.Int)) +) // IsHomestead returns whether num is either equal to the homestead block or greater. func (c *ChainConfig) IsHomestead(num *big.Int) bool { @@ -75,6 +81,14 @@ func (c *ChainConfig) IsEIP150(num *big.Int) bool { } +func (c *ChainConfig) IsEIP155(num *big.Int) bool { + if c.EIP155Block == nil || num == nil { + return false + } + return num.Cmp(c.EIP155Block) >= 0 + +} + func (c *ChainConfig) IsEIP158(num *big.Int) bool { if c.EIP158Block == nil || num == nil { return false @@ -82,3 +96,17 @@ func (c *ChainConfig) IsEIP158(num *big.Int) bool { return num.Cmp(c.EIP158Block) >= 0 } + +// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions +// that do not have or require information about the block. +// +// Rules is a one time interface meaning that it shouldn't be used in between transition +// phases. +type Rules struct { + ChainId *big.Int + IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool +} + +func (c *ChainConfig) Rules(num *big.Int) Rules { + return Rules{ChainId: new(big.Int).Set(c.ChainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num)} +} diff --git a/tests/state_test_util.go b/tests/state_test_util.go index c8899392ad..c08398321c 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" @@ -225,7 +226,7 @@ func RunState(chainConfig *params.ChainConfig, statedb *state.StateDB, env, tx m key, _ := hex.DecodeString(tx["secretKey"]) addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey) - message := NewMessage(addr, to, data, value, gas, price, nonce) + message := types.NewMessage(addr, to, nonce, value, gas, price, data) vmenv := NewEnvFromMap(chainConfig, statedb, env, tx) vmenv.origin = addr diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index be35147373..184bdee2a8 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -159,16 +159,11 @@ func verifyTxFields(txTest TransactionTest, decodedTx *types.Transaction) (err e } }() - var ( - decodedSender common.Address - ) + var decodedSender common.Address chainConfig := ¶ms.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock} - if chainConfig.IsHomestead(common.String2Big(txTest.Blocknumber)) { - decodedSender, err = decodedTx.From() - } else { - decodedSender, err = decodedTx.FromFrontier() - } + signer := types.MakeSigner(chainConfig, common.String2Big(txTest.Blocknumber)) + decodedSender, err = types.Sender(signer, decodedTx) if err != nil { return err } @@ -198,7 +193,7 @@ func verifyTxFields(txTest TransactionTest, decodedTx *types.Transaction) (err e return fmt.Errorf("Nonce mismatch: %v %v", expectedNonce, decodedTx.Nonce()) } - v, r, s := decodedTx.SignatureValues() + v, r, s := types.SignatureValues(signer, decodedTx) expectedR := mustConvertBigInt(txTest.Transaction.R, 16) if r.Cmp(expectedR) != 0 { return fmt.Errorf("R mismatch: %v %v", expectedR, r) diff --git a/tests/util.go b/tests/util.go index 5296bb54bc..53955a47fa 100644 --- a/tests/util.go +++ b/tests/util.go @@ -282,26 +282,3 @@ func (self *Env) Create(caller vm.ContractRef, data []byte, gas, price, value *b return core.Create(self, caller, data, gas, price, value) } } - -type Message struct { - from common.Address - to *common.Address - value, gas, price *big.Int - data []byte - nonce uint64 -} - -func NewMessage(from common.Address, to *common.Address, data []byte, value, gas, price *big.Int, nonce uint64) Message { - return Message{from, to, value, gas, price, data, nonce} -} - -func (self Message) Hash() []byte { return nil } -func (self Message) From() (common.Address, error) { return self.from, nil } -func (self Message) FromFrontier() (common.Address, error) { return self.from, nil } -func (self Message) To() *common.Address { return self.to } -func (self Message) GasPrice() *big.Int { return self.price } -func (self Message) Gas() *big.Int { return self.gas } -func (self Message) Value() *big.Int { return self.value } -func (self Message) Nonce() uint64 { return self.nonce } -func (self Message) CheckNonce() bool { return true } -func (self Message) Data() []byte { return self.data } diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index f00af87b9e..50660134b7 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -225,7 +225,12 @@ func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, vm.Logs, caller := state.GetOrNewStateObject(from) - vmenv := NewEnvFromMap(¶ms.ChainConfig{params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, true, nil, common.Hash{}, nil}, state, env, exec) + chainConfig := ¶ms.ChainConfig{ + HomesteadBlock: params.MainNetHomesteadBlock, + DAOForkBlock: params.MainNetDAOForkBlock, + DAOForkSupport: true, + } + vmenv := NewEnvFromMap(chainConfig, state, env, exec) vmenv.vmTest = true vmenv.skipTransfer = true vmenv.initial = true