Browse Source

all: add support for EIP-2718, EIP-2930 transactions (#21502)

This adds support for EIP-2718 typed transactions as well as EIP-2930
access list transactions (tx type 1). These EIPs are scheduled for the
Berlin fork.

There very few changes to existing APIs in core/types, and several new APIs
to deal with access list transactions. In particular, there are two new
constructor functions for transactions: types.NewTx and types.SignNewTx.
Since the canonical encoding of typed transactions is not RLP-compatible,
Transaction now has new methods for encoding and decoding: MarshalBinary
and UnmarshalBinary.

The existing EIP-155 signer does not support the new transaction types.
All code dealing with transaction signatures should be updated to use the
newer EIP-2930 signer. To make this easier for future updates, we have
added new constructor functions for types.Signer: types.LatestSigner and
types.LatestSignerForChainID. 

This change also adds support for the YoloV3 testnet.

Co-authored-by: Martin Holst Swende <martin@swende.se>
Co-authored-by: Felix Lange <fjl@twurst.com>
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
lightclient 4 years ago
parent
commit
bbfb1e4008
69 changed files with 2420 additions and 907 deletions
  1. 2 2
      accounts/abi/bind/auth.go
  2. 15 10
      accounts/abi/bind/backends/simulated.go
  3. 6 11
      accounts/keystore/keystore.go
  4. 1 1
      accounts/scwallet/wallet.go
  5. 2 0
      accounts/usbwallet/trezor.go
  6. 1 1
      cmd/clef/main.go
  7. 8 9
      cmd/evm/README.md
  8. 19 18
      cmd/evm/internal/t8ntool/execution.go
  9. 5 0
      cmd/evm/internal/t8ntool/flags.go
  10. 109 26
      cmd/evm/internal/t8ntool/transition.go
  11. 1 0
      cmd/evm/main.go
  12. 11 0
      cmd/evm/testdata/8/alloc.json
  13. 7 0
      cmd/evm/testdata/8/env.json
  14. 63 0
      cmd/evm/testdata/8/readme.md
  15. 58 0
      cmd/evm/testdata/8/txs.json
  16. 4 3
      cmd/geth/main.go
  17. 1 2
      cmd/geth/usage.go
  18. 2 2
      cmd/utils/flags.go
  19. 1 1
      core/bench_test.go
  20. 90 12
      core/blockchain_test.go
  21. 9 1
      core/error.go
  22. 3 3
      core/genesis.go
  23. 0 0
      core/genesis_alloc.go
  24. 26 0
      core/state/statedb.go
  25. 16 17
      core/state_prefetcher.go
  26. 17 22
      core/state_processor.go
  27. 15 3
      core/state_transition.go
  28. 9 3
      core/tx_pool.go
  29. 115 0
      core/types/access_list_tx.go
  30. 1 20
      core/types/block.go
  31. 61 1
      core/types/block_test.go
  32. 0 58
      core/types/derive_sha.go
  33. 43 0
      core/types/gen_access_tuple.go
  34. 6 0
      core/types/gen_receipt_json.go
  35. 0 101
      core/types/gen_tx_json.go
  36. 112 0
      core/types/hashing.go
  37. 212 0
      core/types/hashing_test.go
  38. 111 0
      core/types/legacy_tx.go
  39. 81 20
      core/types/receipt.go
  40. 49 2
      core/types/receipt_test.go
  41. 279 187
      core/types/transaction.go
  42. 187 0
      core/types/transaction_marshalling.go
  43. 226 33
      core/types/transaction_signing.go
  44. 245 31
      core/types/transaction_test.go
  45. 1 0
      core/vm/interface.go
  46. 4 14
      core/vm/runtime/runtime.go
  47. 1 1
      eth/downloader/downloader.go
  48. 1 1
      eth/gasprice/gasprice_test.go
  49. 3 2
      eth/tracers/api.go
  50. 1 1
      eth/tracers/tracer.go
  51. 1 2
      ethclient/ethclient.go
  52. 1 1
      ethclient/ethclient_test.go
  53. 3 0
      ethclient/signer.go
  54. 2 7
      graphql/graphql.go
  55. 2 0
      interfaces.go
  56. 107 62
      internal/ethapi/api.go
  57. 3 1
      internal/guide/guide_test.go
  58. 1 1
      les/benchmark.go
  59. 2 2
      les/odr_test.go
  60. 1 1
      light/odr_test.go
  61. 5 5
      light/txpool.go
  62. 6 1
      miner/worker.go
  63. 17 2
      miner/worker_test.go
  64. 3 3
      params/config.go
  65. 17 14
      params/protocol_params.go
  66. 2 3
      signer/core/api.go
  67. 6 12
      tests/state_test_util.go
  68. 1 1
      tests/transaction_test_util.go
  69. 0 170
      trie/stacktrie_test.go

+ 2 - 2
accounts/abi/bind/auth.go

@@ -120,7 +120,7 @@ func NewKeyStoreTransactorWithChainID(keystore *keystore.KeyStore, account accou
 	if chainID == nil {
 	if chainID == nil {
 		return nil, ErrNoChainID
 		return nil, ErrNoChainID
 	}
 	}
-	signer := types.NewEIP155Signer(chainID)
+	signer := types.LatestSignerForChainID(chainID)
 	return &TransactOpts{
 	return &TransactOpts{
 		From: account.Address,
 		From: account.Address,
 		Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) {
 		Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) {
@@ -143,7 +143,7 @@ func NewKeyedTransactorWithChainID(key *ecdsa.PrivateKey, chainID *big.Int) (*Tr
 	if chainID == nil {
 	if chainID == nil {
 		return nil, ErrNoChainID
 		return nil, ErrNoChainID
 	}
 	}
-	signer := types.NewEIP155Signer(chainID)
+	signer := types.LatestSignerForChainID(chainID)
 	return &TransactOpts{
 	return &TransactOpts{
 		From: keyAddr,
 		From: keyAddr,
 		Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) {
 		Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) {

+ 15 - 10
accounts/abi/bind/backends/simulated.go

@@ -559,7 +559,10 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
 	b.mu.Lock()
 	b.mu.Lock()
 	defer b.mu.Unlock()
 	defer b.mu.Unlock()
 
 
-	sender, err := types.Sender(types.NewEIP155Signer(b.config.ChainID), tx)
+	// Check transaction validity.
+	block := b.blockchain.CurrentBlock()
+	signer := types.MakeSigner(b.blockchain.Config(), block.Number())
+	sender, err := types.Sender(signer, tx)
 	if err != nil {
 	if err != nil {
 		panic(fmt.Errorf("invalid transaction: %v", err))
 		panic(fmt.Errorf("invalid transaction: %v", err))
 	}
 	}
@@ -568,7 +571,8 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
 		panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
 		panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
 	}
 	}
 
 
-	blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
+	// Include tx in chain.
+	blocks, _ := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
 		for _, tx := range b.pendingBlock.Transactions() {
 		for _, tx := range b.pendingBlock.Transactions() {
 			block.AddTxWithChain(b.blockchain, tx)
 			block.AddTxWithChain(b.blockchain, tx)
 		}
 		}
@@ -707,14 +711,15 @@ type callMsg struct {
 	ethereum.CallMsg
 	ethereum.CallMsg
 }
 }
 
 
-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() uint64          { 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() uint64                  { 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) AccessList() types.AccessList { return m.CallMsg.AccessList }
 
 
 // filterBackend implements filters.Backend to support filtering for logs without
 // filterBackend implements filters.Backend to support filtering for logs without
 // taking bloom-bits acceleration structures into account.
 // taking bloom-bits acceleration structures into account.

+ 6 - 11
accounts/keystore/keystore.go

@@ -283,11 +283,9 @@ func (ks *KeyStore) SignTx(a accounts.Account, tx *types.Transaction, chainID *b
 	if !found {
 	if !found {
 		return nil, ErrLocked
 		return nil, ErrLocked
 	}
 	}
-	// Depending on the presence of the chain ID, sign with EIP155 or homestead
-	if chainID != nil {
-		return types.SignTx(tx, types.NewEIP155Signer(chainID), unlockedKey.PrivateKey)
-	}
-	return types.SignTx(tx, types.HomesteadSigner{}, unlockedKey.PrivateKey)
+	// Depending on the presence of the chain ID, sign with 2718 or homestead
+	signer := types.LatestSignerForChainID(chainID)
+	return types.SignTx(tx, signer, unlockedKey.PrivateKey)
 }
 }
 
 
 // SignHashWithPassphrase signs hash if the private key matching the given address
 // SignHashWithPassphrase signs hash if the private key matching the given address
@@ -310,12 +308,9 @@ func (ks *KeyStore) SignTxWithPassphrase(a accounts.Account, passphrase string,
 		return nil, err
 		return nil, err
 	}
 	}
 	defer zeroKey(key.PrivateKey)
 	defer zeroKey(key.PrivateKey)
-
-	// Depending on the presence of the chain ID, sign with EIP155 or homestead
-	if chainID != nil {
-		return types.SignTx(tx, types.NewEIP155Signer(chainID), key.PrivateKey)
-	}
-	return types.SignTx(tx, types.HomesteadSigner{}, key.PrivateKey)
+	// Depending on the presence of the chain ID, sign with or without replay protection.
+	signer := types.LatestSignerForChainID(chainID)
+	return types.SignTx(tx, signer, key.PrivateKey)
 }
 }
 
 
 // Unlock unlocks the given account indefinitely.
 // Unlock unlocks the given account indefinitely.

+ 1 - 1
accounts/scwallet/wallet.go

@@ -699,7 +699,7 @@ func (w *Wallet) signHash(account accounts.Account, hash []byte) ([]byte, error)
 // the needed details via SignTxWithPassphrase, or by other means (e.g. unlock
 // the needed details via SignTxWithPassphrase, or by other means (e.g. unlock
 // the account in a keystore).
 // the account in a keystore).
 func (w *Wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
 func (w *Wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
-	signer := types.NewEIP155Signer(chainID)
+	signer := types.LatestSignerForChainID(chainID)
 	hash := signer.Hash(tx)
 	hash := signer.Hash(tx)
 	sig, err := w.signHash(account, hash[:])
 	sig, err := w.signHash(account, hash[:])
 	if err != nil {
 	if err != nil {

+ 2 - 0
accounts/usbwallet/trezor.go

@@ -255,9 +255,11 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction
 	if chainID == nil {
 	if chainID == nil {
 		signer = new(types.HomesteadSigner)
 		signer = new(types.HomesteadSigner)
 	} else {
 	} else {
+		// Trezor backend does not support typed transactions yet.
 		signer = types.NewEIP155Signer(chainID)
 		signer = types.NewEIP155Signer(chainID)
 		signature[64] -= byte(chainID.Uint64()*2 + 35)
 		signature[64] -= byte(chainID.Uint64()*2 + 35)
 	}
 	}
+
 	// Inject the final signature into the transaction and sanity check the sender
 	// Inject the final signature into the transaction and sanity check the sender
 	signed, err := tx.WithSignature(signer, signature)
 	signed, err := tx.WithSignature(signer, signature)
 	if err != nil {
 	if err != nil {

+ 1 - 1
cmd/clef/main.go

@@ -1106,7 +1106,7 @@ func GenDoc(ctx *cli.Context) {
 
 
 		rlpdata := common.FromHex("0xf85d640101948a8eafb1cf62bfbeb1741769dae1a9dd47996192018026a0716bd90515acb1e68e5ac5867aa11a1e65399c3349d479f5fb698554ebc6f293a04e8a4ebfff434e971e0ef12c5bf3a881b06fd04fc3f8b8a7291fb67a26a1d4ed")
 		rlpdata := common.FromHex("0xf85d640101948a8eafb1cf62bfbeb1741769dae1a9dd47996192018026a0716bd90515acb1e68e5ac5867aa11a1e65399c3349d479f5fb698554ebc6f293a04e8a4ebfff434e971e0ef12c5bf3a881b06fd04fc3f8b8a7291fb67a26a1d4ed")
 		var tx types.Transaction
 		var tx types.Transaction
-		rlp.DecodeBytes(rlpdata, &tx)
+		tx.UnmarshalBinary(rlpdata)
 		add("OnApproved - SignTransactionResult", desc, &ethapi.SignTransactionResult{Raw: rlpdata, Tx: &tx})
 		add("OnApproved - SignTransactionResult", desc, &ethapi.SignTransactionResult{Raw: rlpdata, Tx: &tx})
 
 
 	}
 	}

+ 8 - 9
cmd/evm/README.md

@@ -30,7 +30,7 @@ Command line params that has to be supported are
    --trace.nomemory                   Disable full memory dump in traces
    --trace.nomemory                   Disable full memory dump in traces
    --trace.nostack                    Disable stack output in traces
    --trace.nostack                    Disable stack output in traces
    --trace.noreturndata               Disable return data output in traces
    --trace.noreturndata               Disable return data output in traces
-   --output.basedir value             Specifies where output files are placed. Will be created if it does not exist. (default: ".")
+   --output.basedir value             Specifies where output files are placed. Will be created if it does not exist.
    --output.alloc alloc               Determines where to put the alloc of the post-state.
    --output.alloc alloc               Determines where to put the alloc of the post-state.
                                       `stdout` - into the stdout output
                                       `stdout` - into the stdout output
                                       `stderr` - into the stderr output
                                       `stderr` - into the stderr output
@@ -237,10 +237,10 @@ Example where blockhashes are provided:
 cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2
 cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2
 ```
 ```
 ```
 ```
-{"pc":0,"op":96,"gas":"0x5f58ef8","gasCost":"0x3","memory":"0x","memSize":0,"stack":[],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"PUSH1","error":""}
-{"pc":2,"op":64,"gas":"0x5f58ef5","gasCost":"0x14","memory":"0x","memSize":0,"stack":["0x1"],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"BLOCKHASH","error":""}
-{"pc":3,"op":0,"gas":"0x5f58ee1","gasCost":"0x0","memory":"0x","memSize":0,"stack":["0xdac58aa524e50956d0c0bae7f3f8bb9d35381365d07804dd5b48a5a297c06af4"],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"STOP","error":""}
-{"output":"","gasUsed":"0x17","time":112885}
+{"pc":0,"op":96,"gas":"0x5f58ef8","gasCost":"0x3","memory":"0x","memSize":0,"stack":[],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""}
+{"pc":2,"op":64,"gas":"0x5f58ef5","gasCost":"0x14","memory":"0x","memSize":0,"stack":["0x1"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"BLOCKHASH","error":""}
+{"pc":3,"op":0,"gas":"0x5f58ee1","gasCost":"0x0","memory":"0x","memSize":0,"stack":["0xdac58aa524e50956d0c0bae7f3f8bb9d35381365d07804dd5b48a5a297c06af4"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"STOP","error":""}
+{"output":"","gasUsed":"0x17","time":142709}
 ```
 ```
 
 
 In this example, the caller has not provided the required blockhash:
 In this example, the caller has not provided the required blockhash:
@@ -256,9 +256,9 @@ Error code: 4
 Another thing that can be done, is to chain invocations:
 Another thing that can be done, is to chain invocations:
 ```
 ```
 ./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --output.alloc=stdout | ./evm t8n --input.alloc=stdin --input.env=./testdata/1/env.json --input.txs=./testdata/1/txs.json
 ./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --output.alloc=stdout | ./evm t8n --input.alloc=stdin --input.env=./testdata/1/env.json --input.txs=./testdata/1/txs.json
-INFO [08-03|15:25:15.168] rejected tx                              index=1 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low"
-INFO [08-03|15:25:15.169] rejected tx                              index=0 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low"
-INFO [08-03|15:25:15.169] rejected tx                              index=1 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low"
+INFO [01-21|22:41:22.963] rejected tx                              index=1 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1"
+INFO [01-21|22:41:22.966] rejected tx                              index=0 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1"
+INFO [01-21|22:41:22.967] rejected tx                              index=1 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1"
 
 
 ```
 ```
 What happened here, is that we first applied two identical transactions, so the second one was rejected. 
 What happened here, is that we first applied two identical transactions, so the second one was rejected. 
@@ -267,4 +267,3 @@ the same two transactions: this time, both failed due to too low nonce.
 
 
 In order to meaningfully chain invocations, one would need to provide meaningful new `env`, otherwise the
 In order to meaningfully chain invocations, one would need to provide meaningful new `env`, otherwise the
 actual blocknumber (exposed to the EVM) would not increase.
 actual blocknumber (exposed to the EVM) would not increase.
-

+ 19 - 18
cmd/evm/internal/t8ntool/execution.go

@@ -143,19 +143,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
 		vmConfig.Debug = (tracer != nil)
 		vmConfig.Debug = (tracer != nil)
 		statedb.Prepare(tx.Hash(), blockHash, txIndex)
 		statedb.Prepare(tx.Hash(), blockHash, txIndex)
 		txContext := core.NewEVMTxContext(msg)
 		txContext := core.NewEVMTxContext(msg)
-
-		evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
-		if chainConfig.IsYoloV3(vmContext.BlockNumber) {
-			statedb.AddAddressToAccessList(msg.From())
-			if dst := msg.To(); dst != nil {
-				statedb.AddAddressToAccessList(*dst)
-				// If it's a create-tx, the destination will be added inside evm.create
-			}
-			for _, addr := range evm.ActivePrecompiles() {
-				statedb.AddAddressToAccessList(addr)
-			}
-		}
 		snapshot := statedb.Snapshot()
 		snapshot := statedb.Snapshot()
+		evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
+
 		// (ret []byte, usedGas uint64, failed bool, err error)
 		// (ret []byte, usedGas uint64, failed bool, err error)
 		msgResult, err := core.ApplyMessage(evm, msg, gaspool)
 		msgResult, err := core.ApplyMessage(evm, msg, gaspool)
 		if err != nil {
 		if err != nil {
@@ -169,7 +159,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
 			return nil, nil, NewError(ErrorMissingBlockhash, hashError)
 			return nil, nil, NewError(ErrorMissingBlockhash, hashError)
 		}
 		}
 		gasUsed += msgResult.UsedGas
 		gasUsed += msgResult.UsedGas
-		// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
+
+		// Receipt:
 		{
 		{
 			var root []byte
 			var root []byte
 			if chainConfig.IsByzantium(vmContext.BlockNumber) {
 			if chainConfig.IsByzantium(vmContext.BlockNumber) {
@@ -178,22 +169,32 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
 				root = statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)).Bytes()
 				root = statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)).Bytes()
 			}
 			}
 
 
-			receipt := types.NewReceipt(root, msgResult.Failed(), gasUsed)
+			// Create a new receipt for the transaction, storing the intermediate root and
+			// gas used by the tx.
+			receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: gasUsed}
+			if msgResult.Failed() {
+				receipt.Status = types.ReceiptStatusFailed
+			} else {
+				receipt.Status = types.ReceiptStatusSuccessful
+			}
 			receipt.TxHash = tx.Hash()
 			receipt.TxHash = tx.Hash()
 			receipt.GasUsed = msgResult.UsedGas
 			receipt.GasUsed = msgResult.UsedGas
-			// if the transaction created a contract, store the creation address in the receipt.
+
+			// If the transaction created a contract, store the creation address in the receipt.
 			if msg.To() == nil {
 			if msg.To() == nil {
 				receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
 				receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
 			}
 			}
-			// Set the receipt logs and create a bloom for filtering
+
+			// Set the receipt logs and create the bloom filter.
 			receipt.Logs = statedb.GetLogs(tx.Hash())
 			receipt.Logs = statedb.GetLogs(tx.Hash())
 			receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
 			receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
-			// These three are non-consensus fields
+			// These three are non-consensus fields:
 			//receipt.BlockHash
 			//receipt.BlockHash
-			//receipt.BlockNumber =
+			//receipt.BlockNumber
 			receipt.TransactionIndex = uint(txIndex)
 			receipt.TransactionIndex = uint(txIndex)
 			receipts = append(receipts, receipt)
 			receipts = append(receipts, receipt)
 		}
 		}
+
 		txIndex++
 		txIndex++
 	}
 	}
 	statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber))
 	statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber))

+ 5 - 0
cmd/evm/internal/t8ntool/flags.go

@@ -47,6 +47,11 @@ var (
 		Usage: "Specifies where output files are placed. Will be created if it does not exist.",
 		Usage: "Specifies where output files are placed. Will be created if it does not exist.",
 		Value: "",
 		Value: "",
 	}
 	}
+	OutputBodyFlag = cli.StringFlag{
+		Name:  "output.body",
+		Usage: "If set, the RLP of the transactions (block body) will be written to this file.",
+		Value: "",
+	}
 	OutputAllocFlag = cli.StringFlag{
 	OutputAllocFlag = cli.StringFlag{
 		Name: "output.alloc",
 		Name: "output.alloc",
 		Usage: "Determines where to put the `alloc` of the post-state.\n" +
 		Usage: "Determines where to put the `alloc` of the post-state.\n" +

+ 109 - 26
cmd/evm/internal/t8ntool/transition.go

@@ -17,6 +17,7 @@
 package t8ntool
 package t8ntool
 
 
 import (
 import (
+	"crypto/ecdsa"
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
@@ -25,12 +26,15 @@ import (
 	"path"
 	"path"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
+	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
+	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/tests"
 	"github.com/ethereum/go-ethereum/tests"
 	"gopkg.in/urfave/cli.v1"
 	"gopkg.in/urfave/cli.v1"
 )
 )
@@ -64,9 +68,9 @@ func (n *NumberedError) Code() int {
 }
 }
 
 
 type input struct {
 type input struct {
-	Alloc core.GenesisAlloc  `json:"alloc,omitempty"`
-	Env   *stEnv             `json:"env,omitempty"`
-	Txs   types.Transactions `json:"txs,omitempty"`
+	Alloc core.GenesisAlloc `json:"alloc,omitempty"`
+	Env   *stEnv            `json:"env,omitempty"`
+	Txs   []*txWithKey      `json:"txs,omitempty"`
 }
 }
 
 
 func Main(ctx *cli.Context) error {
 func Main(ctx *cli.Context) error {
@@ -135,7 +139,7 @@ func Main(ctx *cli.Context) error {
 		txStr     = ctx.String(InputTxsFlag.Name)
 		txStr     = ctx.String(InputTxsFlag.Name)
 		inputData = &input{}
 		inputData = &input{}
 	)
 	)
-
+	// Figure out the prestate alloc
 	if allocStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector {
 	if allocStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector {
 		decoder := json.NewDecoder(os.Stdin)
 		decoder := json.NewDecoder(os.Stdin)
 		decoder.Decode(inputData)
 		decoder.Decode(inputData)
@@ -151,7 +155,9 @@ func Main(ctx *cli.Context) error {
 			return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling alloc-file: %v", err))
 			return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling alloc-file: %v", err))
 		}
 		}
 	}
 	}
+	prestate.Pre = inputData.Alloc
 
 
+	// Set the block environment
 	if envStr != stdinSelector {
 	if envStr != stdinSelector {
 		inFile, err := os.Open(envStr)
 		inFile, err := os.Open(envStr)
 		if err != nil {
 		if err != nil {
@@ -165,26 +171,8 @@ func Main(ctx *cli.Context) error {
 		}
 		}
 		inputData.Env = &env
 		inputData.Env = &env
 	}
 	}
-
-	if txStr != stdinSelector {
-		inFile, err := os.Open(txStr)
-		if err != nil {
-			return NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err))
-		}
-		defer inFile.Close()
-		decoder := json.NewDecoder(inFile)
-		var txs types.Transactions
-		if err := decoder.Decode(&txs); err != nil {
-			return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling txs-file: %v", err))
-		}
-		inputData.Txs = txs
-	}
-
-	prestate.Pre = inputData.Alloc
 	prestate.Env = *inputData.Env
 	prestate.Env = *inputData.Env
-	txs = inputData.Txs
 
 
-	// Iterate over all the tests, run them and aggregate the results
 	vmConfig := vm.Config{
 	vmConfig := vm.Config{
 		Tracer: tracer,
 		Tracer: tracer,
 		Debug:  (tracer != nil),
 		Debug:  (tracer != nil),
@@ -200,17 +188,105 @@ func Main(ctx *cli.Context) error {
 	// Set the chain id
 	// Set the chain id
 	chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name))
 	chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name))
 
 
+	var txsWithKeys []*txWithKey
+	if txStr != stdinSelector {
+		inFile, err := os.Open(txStr)
+		if err != nil {
+			return NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err))
+		}
+		defer inFile.Close()
+		decoder := json.NewDecoder(inFile)
+		if err := decoder.Decode(&txsWithKeys); err != nil {
+			return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling txs-file: %v", err))
+		}
+	} else {
+		txsWithKeys = inputData.Txs
+	}
+	// We may have to sign the transactions.
+	signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number)))
+
+	if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil {
+		return NewError(ErrorJson, fmt.Errorf("Failed signing transactions: %v", err))
+	}
+
+	// Iterate over all the tests, run them and aggregate the results
+
 	// Run the test and aggregate the result
 	// Run the test and aggregate the result
 	state, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer)
 	state, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	body, _ := rlp.EncodeToBytes(txs)
 	// Dump the excution result
 	// Dump the excution result
-	//postAlloc := state.DumpGenesisFormat(false, false, false)
 	collector := make(Alloc)
 	collector := make(Alloc)
 	state.DumpToCollector(collector, false, false, false, nil, -1)
 	state.DumpToCollector(collector, false, false, false, nil, -1)
-	return dispatchOutput(ctx, baseDir, result, collector)
+	return dispatchOutput(ctx, baseDir, result, collector, body)
+
+}
 
 
+// txWithKey is a helper-struct, to allow us to use the types.Transaction along with
+// a `secretKey`-field, for input
+type txWithKey struct {
+	key *ecdsa.PrivateKey
+	tx  *types.Transaction
+}
+
+func (t *txWithKey) UnmarshalJSON(input []byte) error {
+	// Read the secretKey, if present
+	type sKey struct {
+		Key *common.Hash `json:"secretKey"`
+	}
+	var key sKey
+	if err := json.Unmarshal(input, &key); err != nil {
+		return err
+	}
+	if key.Key != nil {
+		k := key.Key.Hex()[2:]
+		if ecdsaKey, err := crypto.HexToECDSA(k); err != nil {
+			return err
+		} else {
+			t.key = ecdsaKey
+		}
+	}
+	// Now, read the transaction itself
+	var tx types.Transaction
+	if err := json.Unmarshal(input, &tx); err != nil {
+		return err
+	}
+	t.tx = &tx
+	return nil
+}
+
+// signUnsignedTransactions converts the input txs to canonical transactions.
+//
+// The transactions can have two forms, either
+//   1. unsigned or
+//   2. signed
+// For (1), r, s, v, need so be zero, and the `secretKey` needs to be set.
+// If so, we sign it here and now, with the given `secretKey`
+// If the condition above is not met, then it's considered a signed transaction.
+//
+// To manage this, we read the transactions twice, first trying to read the secretKeys,
+// and secondly to read them with the standard tx json format
+func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Transactions, error) {
+	var signedTxs []*types.Transaction
+	for i, txWithKey := range txs {
+		tx := txWithKey.tx
+		key := txWithKey.key
+		v, r, s := tx.RawSignatureValues()
+		if key != nil && v.BitLen()+r.BitLen()+s.BitLen() == 0 {
+			// This transaction needs to be signed
+			signed, err := types.SignTx(tx, signer, key)
+			if err != nil {
+				return nil, NewError(ErrorJson, fmt.Errorf("Tx %d: failed to sign tx: %v", i, err))
+			}
+			signedTxs = append(signedTxs, signed)
+		} else {
+			// Already signed
+			signedTxs = append(signedTxs, tx)
+		}
+	}
+	return signedTxs, nil
 }
 }
 
 
 type Alloc map[common.Address]core.GenesisAccount
 type Alloc map[common.Address]core.GenesisAccount
@@ -241,15 +317,17 @@ func saveFile(baseDir, filename string, data interface{}) error {
 	if err != nil {
 	if err != nil {
 		return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err))
 		return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err))
 	}
 	}
-	if err = ioutil.WriteFile(path.Join(baseDir, filename), b, 0644); err != nil {
+	location := path.Join(baseDir, filename)
+	if err = ioutil.WriteFile(location, b, 0644); err != nil {
 		return NewError(ErrorIO, fmt.Errorf("failed writing output: %v", err))
 		return NewError(ErrorIO, fmt.Errorf("failed writing output: %v", err))
 	}
 	}
+	log.Info("Wrote file", "file", location)
 	return nil
 	return nil
 }
 }
 
 
 // dispatchOutput writes the output data to either stderr or stdout, or to the specified
 // dispatchOutput writes the output data to either stderr or stdout, or to the specified
 // files
 // files
-func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc) error {
+func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc, body hexutil.Bytes) error {
 	stdOutObject := make(map[string]interface{})
 	stdOutObject := make(map[string]interface{})
 	stdErrObject := make(map[string]interface{})
 	stdErrObject := make(map[string]interface{})
 	dispatch := func(baseDir, fName, name string, obj interface{}) error {
 	dispatch := func(baseDir, fName, name string, obj interface{}) error {
@@ -258,6 +336,8 @@ func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, a
 			stdOutObject[name] = obj
 			stdOutObject[name] = obj
 		case "stderr":
 		case "stderr":
 			stdErrObject[name] = obj
 			stdErrObject[name] = obj
+		case "":
+			// don't save
 		default: // save to file
 		default: // save to file
 			if err := saveFile(baseDir, fName, obj); err != nil {
 			if err := saveFile(baseDir, fName, obj); err != nil {
 				return err
 				return err
@@ -271,6 +351,9 @@ func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, a
 	if err := dispatch(baseDir, ctx.String(OutputResultFlag.Name), "result", result); err != nil {
 	if err := dispatch(baseDir, ctx.String(OutputResultFlag.Name), "result", result); err != nil {
 		return err
 		return err
 	}
 	}
+	if err := dispatch(baseDir, ctx.String(OutputBodyFlag.Name), "body", body); err != nil {
+		return err
+	}
 	if len(stdOutObject) > 0 {
 	if len(stdOutObject) > 0 {
 		b, err := json.MarshalIndent(stdOutObject, "", " ")
 		b, err := json.MarshalIndent(stdOutObject, "", " ")
 		if err != nil {
 		if err != nil {

+ 1 - 0
cmd/evm/main.go

@@ -149,6 +149,7 @@ var stateTransitionCommand = cli.Command{
 		t8ntool.OutputBasedir,
 		t8ntool.OutputBasedir,
 		t8ntool.OutputAllocFlag,
 		t8ntool.OutputAllocFlag,
 		t8ntool.OutputResultFlag,
 		t8ntool.OutputResultFlag,
+		t8ntool.OutputBodyFlag,
 		t8ntool.InputAllocFlag,
 		t8ntool.InputAllocFlag,
 		t8ntool.InputEnvFlag,
 		t8ntool.InputEnvFlag,
 		t8ntool.InputTxsFlag,
 		t8ntool.InputTxsFlag,

+ 11 - 0
cmd/evm/testdata/8/alloc.json

@@ -0,0 +1,11 @@
+{
+  "0x000000000000000000000000000000000000aaaa": {
+    "balance": "0x03",
+    "code": "0x5854505854",
+    "nonce": "0x1"
+  },
+  "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
+    "balance": "0x100000",
+    "nonce": "0x00"
+  }
+}

+ 7 - 0
cmd/evm/testdata/8/env.json

@@ -0,0 +1,7 @@
+{
+  "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+  "currentDifficulty": "0x20000",
+  "currentGasLimit": "0x1000000000",
+  "currentNumber": "0x1000000",
+  "currentTimestamp": "0x04"
+}

+ 63 - 0
cmd/evm/testdata/8/readme.md

@@ -0,0 +1,63 @@
+## EIP-2930 testing
+
+This test contains testcases for EIP-2930, which uses transactions with access lists. 
+
+### Prestate
+
+The alloc portion contains one contract (`0x000000000000000000000000000000000000aaaa`), containing the 
+following code: `0x5854505854`: `PC ;SLOAD; POP; PC; SLOAD`.
+
+Essentialy, this contract does `SLOAD(0)` and `SLOAD(3)`.
+
+The alloc also contains some funds on `0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b`. 
+
+## Transactions
+
+There are three transactions, each invokes the contract above. 
+
+1. ACL-transaction, which contains some non-used slots
+2. Regular transaction
+3. ACL-transaction, which contains the slots `1` and `3` in `0x000000000000000000000000000000000000aaaa`
+
+## Execution 
+
+Running it yields: 
+```
+dir=./testdata/8 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace && cat trace-* | grep SLOAD
+{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
+{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
+{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
+{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
+{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
+{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
+
+```
+
+Simlarly, we can provide the input transactions via `stdin` instead of as file: 
+
+```
+dir=./testdata/8 \
+  && cat $dir/txs.json | jq "{txs: .}" \
+  | ./evm t8n --state.fork=Berlin \
+     --input.alloc=$dir/alloc.json \
+     --input.txs=stdin \
+     --input.env=$dir/env.json \
+     --trace  \
+  && cat trace-* | grep SLOAD
+
+{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
+{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
+{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
+{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
+{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
+{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
+```
+
+If we try to execute it on older rules: 
+```
+dir=./testdata/8 && ./evm t8n --state.fork=Istanbul --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json 
+INFO [01-21|23:21:51.265] rejected tx                              index=0 hash="d2818d…6ab3da" error="tx type not supported"
+INFO [01-21|23:21:51.265] rejected tx                              index=1 hash="26ea00…81c01b" from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="nonce too high: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B, tx: 1 state: 0"
+INFO [01-21|23:21:51.265] rejected tx                              index=2 hash="698d01…369cee" error="tx type not supported"
+```
+Number `1` and `3` are not applicable, and therefore number `2` has wrong nonce. 

+ 58 - 0
cmd/evm/testdata/8/txs.json

@@ -0,0 +1,58 @@
+[
+  {
+    "gas": "0x4ef00",
+    "gasPrice": "0x1",
+    "chainId": "0x1",
+    "input": "0x",
+    "nonce": "0x0",
+    "to": "0x000000000000000000000000000000000000aaaa",
+    "value": "0x1",
+    "type" : "0x1",
+    "accessList": [
+      {"address": "0x0000000000000000000000000000000000000000",
+        "storageKeys": [
+          "0x0000000000000000000000000000000000000000000000000000000000000000",
+          "0x0000000000000000000000000000000000000000000000000000000000000000"
+        ]
+      }
+    ],
+    "v": "0x0",
+    "r": "0x0",
+    "s": "0x0",
+    "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
+  },
+  {
+    "gas": "0x4ef00",
+    "gasPrice": "0x1",
+    "input": "0x",
+    "nonce": "0x1",
+    "to": "0x000000000000000000000000000000000000aaaa",
+    "value": "0x2",
+    "v": "0x0",
+    "r": "0x0",
+    "s": "0x0",
+    "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
+  },
+  {
+    "gas": "0x4ef00",
+    "gasPrice": "0x1",
+    "chainId": "0x1",
+    "input": "0x",
+    "nonce": "0x2",
+    "to": "0x000000000000000000000000000000000000aaaa",
+    "value": "0x1",
+    "type" : "0x1",
+    "accessList": [
+      {"address": "0x000000000000000000000000000000000000aaaa",
+        "storageKeys": [
+          "0x0000000000000000000000000000000000000000000000000000000000000000",
+          "0x0000000000000000000000000000000000000000000000000000000000000003"
+        ]
+      }
+    ],
+    "v": "0x0",
+    "r": "0x0",
+    "s": "0x0",
+    "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
+  }
+]

+ 4 - 3
cmd/geth/main.go

@@ -140,9 +140,7 @@ var (
 		utils.RopstenFlag,
 		utils.RopstenFlag,
 		utils.RinkebyFlag,
 		utils.RinkebyFlag,
 		utils.GoerliFlag,
 		utils.GoerliFlag,
-		// YOLOv3 is not yet complete!
-		// TODO: enable this once 2718/2930 is added
-		//utils.YoloV3Flag,
+		utils.YoloV3Flag,
 		utils.VMEnableDebugFlag,
 		utils.VMEnableDebugFlag,
 		utils.NetworkIdFlag,
 		utils.NetworkIdFlag,
 		utils.EthStatsURLFlag,
 		utils.EthStatsURLFlag,
@@ -286,6 +284,9 @@ func prepare(ctx *cli.Context) {
 	case ctx.GlobalIsSet(utils.GoerliFlag.Name):
 	case ctx.GlobalIsSet(utils.GoerliFlag.Name):
 		log.Info("Starting Geth on Görli testnet...")
 		log.Info("Starting Geth on Görli testnet...")
 
 
+	case ctx.GlobalIsSet(utils.YoloV3Flag.Name):
+		log.Info("Starting Geth on YOLOv3 testnet...")
+
 	case ctx.GlobalIsSet(utils.DeveloperFlag.Name):
 	case ctx.GlobalIsSet(utils.DeveloperFlag.Name):
 		log.Info("Starting Geth in ephemeral dev mode...")
 		log.Info("Starting Geth in ephemeral dev mode...")
 
 

+ 1 - 2
cmd/geth/usage.go

@@ -44,8 +44,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{
 			utils.MainnetFlag,
 			utils.MainnetFlag,
 			utils.GoerliFlag,
 			utils.GoerliFlag,
 			utils.RinkebyFlag,
 			utils.RinkebyFlag,
-			// TODO: Re-enable this when 2718/2930 is added
-			//utils.YoloV3Flag,
+			utils.YoloV3Flag,
 			utils.RopstenFlag,
 			utils.RopstenFlag,
 			utils.SyncModeFlag,
 			utils.SyncModeFlag,
 			utils.ExitWhenSyncedFlag,
 			utils.ExitWhenSyncedFlag,

+ 2 - 2
cmd/utils/flags.go

@@ -1277,7 +1277,7 @@ func setDataDir(ctx *cli.Context, cfg *node.Config) {
 	case ctx.GlobalBool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir():
 	case ctx.GlobalBool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir():
 		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
 		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
 	case ctx.GlobalBool(YoloV3Flag.Name) && cfg.DataDir == node.DefaultDataDir():
 	case ctx.GlobalBool(YoloV3Flag.Name) && cfg.DataDir == node.DefaultDataDir():
-		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "yolo-v2")
+		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "yolo-v3")
 	}
 	}
 }
 }
 
 
@@ -1609,7 +1609,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
 		SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash)
 		SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash)
 	case ctx.GlobalBool(YoloV3Flag.Name):
 	case ctx.GlobalBool(YoloV3Flag.Name):
 		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
 		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
-			cfg.NetworkId = new(big.Int).SetBytes([]byte("yolov3")).Uint64() // "yolov3"
+			cfg.NetworkId = new(big.Int).SetBytes([]byte("yolov3x")).Uint64() // "yolov3x"
 		}
 		}
 		cfg.Genesis = core.DefaultYoloV3GenesisBlock()
 		cfg.Genesis = core.DefaultYoloV3GenesisBlock()
 	case ctx.GlobalBool(DeveloperFlag.Name):
 	case ctx.GlobalBool(DeveloperFlag.Name):

+ 1 - 1
core/bench_test.go

@@ -85,7 +85,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
 	return func(i int, gen *BlockGen) {
 	return func(i int, gen *BlockGen) {
 		toaddr := common.Address{}
 		toaddr := common.Address{}
 		data := make([]byte, nbytes)
 		data := make([]byte, nbytes)
-		gas, _ := IntrinsicGas(data, false, false, false)
+		gas, _ := IntrinsicGas(data, nil, false, false, false)
 		tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey)
 		tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey)
 		gen.AddTx(tx)
 		gen.AddTx(tx)
 	}
 	}

+ 90 - 12
core/blockchain_test.go

@@ -600,7 +600,7 @@ func TestFastVsFullChains(t *testing.T) {
 			Alloc:  GenesisAlloc{address: {Balance: funds}},
 			Alloc:  GenesisAlloc{address: {Balance: funds}},
 		}
 		}
 		genesis = gspec.MustCommit(gendb)
 		genesis = gspec.MustCommit(gendb)
-		signer  = types.NewEIP155Signer(gspec.Config.ChainID)
+		signer  = types.LatestSigner(gspec.Config)
 	)
 	)
 	blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, 1024, func(i int, block *BlockGen) {
 	blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, 1024, func(i int, block *BlockGen) {
 		block.SetCoinbase(common.Address{0x00})
 		block.SetCoinbase(common.Address{0x00})
@@ -839,7 +839,7 @@ func TestChainTxReorgs(t *testing.T) {
 			},
 			},
 		}
 		}
 		genesis = gspec.MustCommit(db)
 		genesis = gspec.MustCommit(db)
-		signer  = types.NewEIP155Signer(gspec.Config.ChainID)
+		signer  = types.LatestSigner(gspec.Config)
 	)
 	)
 
 
 	// Create two transactions shared between the chains:
 	// Create two transactions shared between the chains:
@@ -944,7 +944,7 @@ func TestLogReorgs(t *testing.T) {
 		code    = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
 		code    = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
 		gspec   = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
 		gspec   = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
 		genesis = gspec.MustCommit(db)
 		genesis = gspec.MustCommit(db)
-		signer  = types.NewEIP155Signer(gspec.Config.ChainID)
+		signer  = types.LatestSigner(gspec.Config)
 	)
 	)
 
 
 	blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
 	blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
@@ -998,7 +998,7 @@ func TestLogRebirth(t *testing.T) {
 		db            = rawdb.NewMemoryDatabase()
 		db            = rawdb.NewMemoryDatabase()
 		gspec         = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
 		gspec         = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
 		genesis       = gspec.MustCommit(db)
 		genesis       = gspec.MustCommit(db)
-		signer        = types.NewEIP155Signer(gspec.Config.ChainID)
+		signer        = types.LatestSigner(gspec.Config)
 		engine        = ethash.NewFaker()
 		engine        = ethash.NewFaker()
 		blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil)
 		blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil)
 	)
 	)
@@ -1062,7 +1062,7 @@ func TestSideLogRebirth(t *testing.T) {
 		db            = rawdb.NewMemoryDatabase()
 		db            = rawdb.NewMemoryDatabase()
 		gspec         = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
 		gspec         = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
 		genesis       = gspec.MustCommit(db)
 		genesis       = gspec.MustCommit(db)
-		signer        = types.NewEIP155Signer(gspec.Config.ChainID)
+		signer        = types.LatestSigner(gspec.Config)
 		blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
 		blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
 	)
 	)
 
 
@@ -1135,7 +1135,7 @@ func TestReorgSideEvent(t *testing.T) {
 			Alloc:  GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}},
 			Alloc:  GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}},
 		}
 		}
 		genesis = gspec.MustCommit(db)
 		genesis = gspec.MustCommit(db)
-		signer  = types.NewEIP155Signer(gspec.Config.ChainID)
+		signer  = types.LatestSigner(gspec.Config)
 	)
 	)
 
 
 	blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
 	blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
@@ -1295,7 +1295,7 @@ func TestEIP155Transition(t *testing.T) {
 			}
 			}
 			block.AddTx(tx)
 			block.AddTx(tx)
 
 
-			tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainID))
+			tx, err = basicTx(types.LatestSigner(gspec.Config))
 			if err != nil {
 			if err != nil {
 				t.Fatal(err)
 				t.Fatal(err)
 			}
 			}
@@ -1307,7 +1307,7 @@ func TestEIP155Transition(t *testing.T) {
 			}
 			}
 			block.AddTx(tx)
 			block.AddTx(tx)
 
 
-			tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainID))
+			tx, err = basicTx(types.LatestSigner(gspec.Config))
 			if err != nil {
 			if err != nil {
 				t.Fatal(err)
 				t.Fatal(err)
 			}
 			}
@@ -1345,7 +1345,7 @@ func TestEIP155Transition(t *testing.T) {
 			}
 			}
 		)
 		)
 		if i == 0 {
 		if i == 0 {
-			tx, err = basicTx(types.NewEIP155Signer(big.NewInt(2)))
+			tx, err = basicTx(types.LatestSigner(config))
 			if err != nil {
 			if err != nil {
 				t.Fatal(err)
 				t.Fatal(err)
 			}
 			}
@@ -1385,7 +1385,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
 		var (
 		var (
 			tx     *types.Transaction
 			tx     *types.Transaction
 			err    error
 			err    error
-			signer = types.NewEIP155Signer(gspec.Config.ChainID)
+			signer = types.LatestSigner(gspec.Config)
 		)
 		)
 		switch i {
 		switch i {
 		case 0:
 		case 0:
@@ -2078,7 +2078,7 @@ func TestTransactionIndices(t *testing.T) {
 		funds   = big.NewInt(1000000000)
 		funds   = big.NewInt(1000000000)
 		gspec   = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}}
 		gspec   = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}}
 		genesis = gspec.MustCommit(gendb)
 		genesis = gspec.MustCommit(gendb)
-		signer  = types.NewEIP155Signer(gspec.Config.ChainID)
+		signer  = types.LatestSigner(gspec.Config)
 	)
 	)
 	height := uint64(128)
 	height := uint64(128)
 	blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), func(i int, block *BlockGen) {
 	blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), func(i int, block *BlockGen) {
@@ -2205,7 +2205,7 @@ func TestSkipStaleTxIndicesInFastSync(t *testing.T) {
 		funds   = big.NewInt(1000000000)
 		funds   = big.NewInt(1000000000)
 		gspec   = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}}
 		gspec   = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}}
 		genesis = gspec.MustCommit(gendb)
 		genesis = gspec.MustCommit(gendb)
-		signer  = types.NewEIP155Signer(gspec.Config.ChainID)
+		signer  = types.LatestSigner(gspec.Config)
 	)
 	)
 	height := uint64(128)
 	height := uint64(128)
 	blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), func(i int, block *BlockGen) {
 	blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), func(i int, block *BlockGen) {
@@ -3030,3 +3030,81 @@ func TestInitThenFailCreateContract(t *testing.T) {
 		}
 		}
 	}
 	}
 }
 }
+
+// TestEIP2718Transition tests that an EIP-2718 transaction will be accepted
+// after the fork block has passed. This is verified by sending an EIP-2930
+// access list transaction, which specifies a single slot access, and then
+// checking that the gas usage of a hot SLOAD and a cold SLOAD are calculated
+// correctly.
+func TestEIP2718Transition(t *testing.T) {
+	var (
+		aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
+
+		// Generate a canonical chain to act as the main dataset
+		engine = ethash.NewFaker()
+		db     = rawdb.NewMemoryDatabase()
+
+		// A sender who makes transactions, has some funds
+		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+		address = crypto.PubkeyToAddress(key.PublicKey)
+		funds   = big.NewInt(1000000000)
+		gspec   = &Genesis{
+			Config: params.YoloV3ChainConfig,
+			Alloc: GenesisAlloc{
+				address: {Balance: funds},
+				// The address 0xAAAA sloads 0x00 and 0x01
+				aa: {
+					Code: []byte{
+						byte(vm.PC),
+						byte(vm.PC),
+						byte(vm.SLOAD),
+						byte(vm.SLOAD),
+					},
+					Nonce:   0,
+					Balance: big.NewInt(0),
+				},
+			},
+		}
+		genesis = gspec.MustCommit(db)
+	)
+
+	blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) {
+		b.SetCoinbase(common.Address{1})
+
+		// One transaction to 0xAAAA
+		signer := types.LatestSigner(gspec.Config)
+		tx, _ := types.SignNewTx(key, signer, &types.AccessListTx{
+			ChainID:  gspec.Config.ChainID,
+			Nonce:    0,
+			To:       &aa,
+			Gas:      30000,
+			GasPrice: big.NewInt(1),
+			AccessList: types.AccessList{{
+				Address:     aa,
+				StorageKeys: []common.Hash{{0}},
+			}},
+		})
+		b.AddTx(tx)
+	})
+
+	// Import the canonical chain
+	diskdb := rawdb.NewMemoryDatabase()
+	gspec.MustCommit(diskdb)
+
+	chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
+	if err != nil {
+		t.Fatalf("failed to create tester chain: %v", err)
+	}
+	if n, err := chain.InsertChain(blocks); err != nil {
+		t.Fatalf("block %d: failed to insert into chain: %v", n, err)
+	}
+
+	block := chain.GetBlockByNumber(1)
+
+	// Expected gas is intrinsic + 2 * pc + hot load + cold load, since only one load is in the access list
+	expected := params.TxGas + params.TxAccessListAddressGas + params.TxAccessListStorageKeyGas + vm.GasQuickStep*2 + vm.WarmStorageReadCostEIP2929 + vm.ColdSloadCostEIP2929
+	if block.GasUsed() != expected {
+		t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expected, block.GasUsed())
+
+	}
+}

+ 9 - 1
core/error.go

@@ -16,7 +16,11 @@
 
 
 package core
 package core
 
 
-import "errors"
+import (
+	"errors"
+
+	"github.com/ethereum/go-ethereum/core/types"
+)
 
 
 var (
 var (
 	// ErrKnownBlock is returned when a block to import is already known locally.
 	// ErrKnownBlock is returned when a block to import is already known locally.
@@ -63,4 +67,8 @@ var (
 	// ErrIntrinsicGas is returned if the transaction is specified to use less gas
 	// ErrIntrinsicGas is returned if the transaction is specified to use less gas
 	// than required to start the invocation.
 	// than required to start the invocation.
 	ErrIntrinsicGas = errors.New("intrinsic gas too low")
 	ErrIntrinsicGas = errors.New("intrinsic gas too low")
+
+	// ErrTxTypeNotSupported is returned if a transaction is not supported in the
+	// current network configuration.
+	ErrTxTypeNotSupported = types.ErrTxTypeNotSupported
 )
 )

+ 3 - 3
core/genesis.go

@@ -377,11 +377,11 @@ func DefaultGoerliGenesisBlock() *Genesis {
 }
 }
 
 
 func DefaultYoloV3GenesisBlock() *Genesis {
 func DefaultYoloV3GenesisBlock() *Genesis {
-	// Full genesis: https://gist.github.com/holiman/b2c32a05ff2e2712e11c0787d987d46f
+	// Full genesis: https://gist.github.com/holiman/c6ed9269dce28304ad176314caa75e97
 	return &Genesis{
 	return &Genesis{
 		Config:     params.YoloV3ChainConfig,
 		Config:     params.YoloV3ChainConfig,
-		Timestamp:  0x60117f8b,
-		ExtraData:  hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000008a37866fd3627c9205a37c8685666f32ec07bb1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
+		Timestamp:  0x6027dd2e,
+		ExtraData:  hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000001041afbcb359d5a8dc58c15b2ff51354ff8a217d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
 		GasLimit:   0x47b760,
 		GasLimit:   0x47b760,
 		Difficulty: big.NewInt(1),
 		Difficulty: big.NewInt(1),
 		Alloc:      decodePrealloc(yoloV3AllocData),
 		Alloc:      decodePrealloc(yoloV3AllocData),

File diff suppressed because it is too large
+ 0 - 0
core/genesis_alloc.go


+ 26 - 0
core/state/statedb.go

@@ -983,6 +983,32 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
 	return root, err
 	return root, err
 }
 }
 
 
+// PrepareAccessList handles the preparatory steps for executing a state transition with
+// regards to both EIP-2929 and EIP-2930:
+//
+// - Add sender to access list (2929)
+// - Add destination to access list (2929)
+// - Add precompiles to access list (2929)
+// - Add the contents of the optional tx access list (2930)
+//
+// This method should only be called if Yolov3/Berlin/2929+2930 is applicable at the current number.
+func (s *StateDB) PrepareAccessList(sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
+	s.AddAddressToAccessList(sender)
+	if dst != nil {
+		s.AddAddressToAccessList(*dst)
+		// If it's a create-tx, the destination will be added inside evm.create
+	}
+	for _, addr := range precompiles {
+		s.AddAddressToAccessList(addr)
+	}
+	for _, el := range list {
+		s.AddAddressToAccessList(el.Address)
+		for _, key := range el.StorageKeys {
+			s.AddSlotToAccessList(el.Address, key)
+		}
+	}
+}
+
 // AddAddressToAccessList adds the given address to the access list
 // AddAddressToAccessList adds the given address to the access list
 func (s *StateDB) AddAddressToAccessList(addr common.Address) {
 func (s *StateDB) AddAddressToAccessList(addr common.Address) {
 	if s.accessList.AddAddress(addr) {
 	if s.accessList.AddAddress(addr) {

+ 16 - 17
core/state_prefetcher.go

@@ -19,7 +19,6 @@ package core
 import (
 import (
 	"sync/atomic"
 	"sync/atomic"
 
 
-	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/consensus"
 	"github.com/ethereum/go-ethereum/consensus"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
@@ -50,8 +49,11 @@ func newStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine conse
 // only goal is to pre-cache transaction signatures and state trie nodes.
 // only goal is to pre-cache transaction signatures and state trie nodes.
 func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *uint32) {
 func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *uint32) {
 	var (
 	var (
-		header  = block.Header()
-		gaspool = new(GasPool).AddGas(block.GasLimit())
+		header       = block.Header()
+		gaspool      = new(GasPool).AddGas(block.GasLimit())
+		blockContext = NewEVMBlockContext(header, p.bc, nil)
+		evm          = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
+		signer       = types.MakeSigner(p.config, header.Number)
 	)
 	)
 	// Iterate over and process the individual transactions
 	// Iterate over and process the individual transactions
 	byzantium := p.config.IsByzantium(block.Number())
 	byzantium := p.config.IsByzantium(block.Number())
@@ -60,9 +62,13 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
 		if interrupt != nil && atomic.LoadUint32(interrupt) == 1 {
 		if interrupt != nil && atomic.LoadUint32(interrupt) == 1 {
 			return
 			return
 		}
 		}
-		// Block precaching permitted to continue, execute the transaction
+		// Convert the transaction into an executable message and pre-cache its sender
+		msg, err := tx.AsMessage(signer)
+		if err != nil {
+			return // Also invalid block, bail out
+		}
 		statedb.Prepare(tx.Hash(), block.Hash(), i)
 		statedb.Prepare(tx.Hash(), block.Hash(), i)
-		if err := precacheTransaction(p.config, p.bc, nil, gaspool, statedb, header, tx, cfg); err != nil {
+		if err := precacheTransaction(msg, p.config, gaspool, statedb, header, evm); err != nil {
 			return // Ugh, something went horribly wrong, bail out
 			return // Ugh, something went horribly wrong, bail out
 		}
 		}
 		// If we're pre-byzantium, pre-load trie nodes for the intermediate root
 		// If we're pre-byzantium, pre-load trie nodes for the intermediate root
@@ -79,17 +85,10 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
 // precacheTransaction attempts to apply a transaction to the given state database
 // precacheTransaction attempts to apply a transaction to the given state database
 // and uses the input parameters for its environment. The goal is not to execute
 // and uses the input parameters for its environment. The goal is not to execute
 // the transaction successfully, rather to warm up touched data slots.
 // the transaction successfully, rather to warm up touched data slots.
-func precacheTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gaspool *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, cfg vm.Config) error {
-	// Convert the transaction into an executable message and pre-cache its sender
-	msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
-	if err != nil {
-		return err
-	}
-	// Create the EVM and execute the transaction
-	context := NewEVMBlockContext(header, bc, author)
-	txContext := NewEVMTxContext(msg)
-	vm := vm.NewEVM(context, txContext, statedb, config, cfg)
-
-	_, err = ApplyMessage(vm, msg, gaspool)
+func precacheTransaction(msg types.Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error {
+	// Update the evm with the new transaction context.
+	evm.Reset(NewEVMTxContext(msg), statedb)
+	// Add addresses to access list if applicable
+	_, err := ApplyMessage(evm, msg, gaspool)
 	return err
 	return err
 }
 }

+ 17 - 22
core/state_processor.go

@@ -90,28 +90,17 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
 }
 }
 
 
 func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
 func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
-	// Create a new context to be used in the EVM environment
+	// Create a new context to be used in the EVM environment.
 	txContext := NewEVMTxContext(msg)
 	txContext := NewEVMTxContext(msg)
-	// Add addresses to access list if applicable
-	if config.IsYoloV3(header.Number) {
-		statedb.AddAddressToAccessList(msg.From())
-		if dst := msg.To(); dst != nil {
-			statedb.AddAddressToAccessList(*dst)
-			// If it's a create-tx, the destination will be added inside evm.create
-		}
-		for _, addr := range evm.ActivePrecompiles() {
-			statedb.AddAddressToAccessList(addr)
-		}
-	}
-
-	// Update the evm with the new transaction context.
 	evm.Reset(txContext, statedb)
 	evm.Reset(txContext, statedb)
-	// Apply the transaction to the current state (included in the env)
+
+	// Apply the transaction to the current state (included in the env).
 	result, err := ApplyMessage(evm, msg, gp)
 	result, err := ApplyMessage(evm, msg, gp)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	// Update the state with pending changes
+
+	// Update the state with pending changes.
 	var root []byte
 	var root []byte
 	if config.IsByzantium(header.Number) {
 	if config.IsByzantium(header.Number) {
 		statedb.Finalise(true)
 		statedb.Finalise(true)
@@ -120,22 +109,28 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
 	}
 	}
 	*usedGas += result.UsedGas
 	*usedGas += result.UsedGas
 
 
-	// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
-	// based on the eip phase, we're passing whether the root touch-delete accounts.
-	receipt := types.NewReceipt(root, result.Failed(), *usedGas)
+	// Create a new receipt for the transaction, storing the intermediate root and gas used
+	// by the tx.
+	receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas}
+	if result.Failed() {
+		receipt.Status = types.ReceiptStatusFailed
+	} else {
+		receipt.Status = types.ReceiptStatusSuccessful
+	}
 	receipt.TxHash = tx.Hash()
 	receipt.TxHash = tx.Hash()
 	receipt.GasUsed = result.UsedGas
 	receipt.GasUsed = result.UsedGas
-	// if the transaction created a contract, store the creation address in the receipt.
+
+	// If the transaction created a contract, store the creation address in the receipt.
 	if msg.To() == nil {
 	if msg.To() == nil {
 		receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
 		receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
 	}
 	}
-	// Set the receipt logs and create a bloom for filtering
+
+	// Set the receipt logs and create the bloom filter.
 	receipt.Logs = statedb.GetLogs(tx.Hash())
 	receipt.Logs = statedb.GetLogs(tx.Hash())
 	receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
 	receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
 	receipt.BlockHash = statedb.BlockHash()
 	receipt.BlockHash = statedb.BlockHash()
 	receipt.BlockNumber = header.Number
 	receipt.BlockNumber = header.Number
 	receipt.TransactionIndex = uint(statedb.TxIndex())
 	receipt.TransactionIndex = uint(statedb.TxIndex())
-
 	return receipt, err
 	return receipt, err
 }
 }
 
 

+ 15 - 3
core/state_transition.go

@@ -22,6 +22,7 @@ import (
 	"math/big"
 	"math/big"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
 )
 )
@@ -67,6 +68,7 @@ type Message interface {
 	Nonce() uint64
 	Nonce() uint64
 	CheckNonce() bool
 	CheckNonce() bool
 	Data() []byte
 	Data() []byte
+	AccessList() types.AccessList
 }
 }
 
 
 // ExecutionResult includes all output after executing given evm
 // ExecutionResult includes all output after executing given evm
@@ -105,10 +107,10 @@ func (result *ExecutionResult) Revert() []byte {
 }
 }
 
 
 // IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
 // IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
-func IntrinsicGas(data []byte, contractCreation, isHomestead bool, isEIP2028 bool) (uint64, error) {
+func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool) (uint64, error) {
 	// Set the starting gas for the raw transaction
 	// Set the starting gas for the raw transaction
 	var gas uint64
 	var gas uint64
-	if contractCreation && isHomestead {
+	if isContractCreation && isHomestead {
 		gas = params.TxGasContractCreation
 		gas = params.TxGasContractCreation
 	} else {
 	} else {
 		gas = params.TxGas
 		gas = params.TxGas
@@ -138,6 +140,10 @@ func IntrinsicGas(data []byte, contractCreation, isHomestead bool, isEIP2028 boo
 		}
 		}
 		gas += z * params.TxDataZeroGas
 		gas += z * params.TxDataZeroGas
 	}
 	}
+	if accessList != nil {
+		gas += uint64(len(accessList)) * params.TxAccessListAddressGas
+		gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas
+	}
 	return gas, nil
 	return gas, nil
 }
 }
 
 
@@ -238,7 +244,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
 	contractCreation := msg.To() == nil
 	contractCreation := msg.To() == nil
 
 
 	// Check clauses 4-5, subtract intrinsic gas if everything is correct
 	// Check clauses 4-5, subtract intrinsic gas if everything is correct
-	gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul)
+	gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -251,6 +257,12 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
 	if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) {
 	if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) {
 		return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex())
 		return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex())
 	}
 	}
+
+	// Set up the initial access list.
+	if st.evm.ChainConfig().IsYoloV3(st.evm.Context.BlockNumber) {
+		st.state.PrepareAccessList(msg.From(), msg.To(), st.evm.ActivePrecompiles(), msg.AccessList())
+	}
+
 	var (
 	var (
 		ret   []byte
 		ret   []byte
 		vmerr error // vm errors do not effect consensus and are therefore not assigned to err
 		vmerr error // vm errors do not effect consensus and are therefore not assigned to err

+ 9 - 3
core/tx_pool.go

@@ -229,6 +229,7 @@ type TxPool struct {
 	mu          sync.RWMutex
 	mu          sync.RWMutex
 
 
 	istanbul bool // Fork indicator whether we are in the istanbul stage.
 	istanbul bool // Fork indicator whether we are in the istanbul stage.
+	eip2718  bool // Fork indicator whether we are using EIP-2718 type transactions.
 
 
 	currentState  *state.StateDB // Current state in the blockchain head
 	currentState  *state.StateDB // Current state in the blockchain head
 	pendingNonces *txNoncer      // Pending state tracking virtual nonces
 	pendingNonces *txNoncer      // Pending state tracking virtual nonces
@@ -268,7 +269,7 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block
 		config:          config,
 		config:          config,
 		chainconfig:     chainconfig,
 		chainconfig:     chainconfig,
 		chain:           chain,
 		chain:           chain,
-		signer:          types.NewEIP155Signer(chainconfig.ChainID),
+		signer:          types.LatestSigner(chainconfig),
 		pending:         make(map[common.Address]*txList),
 		pending:         make(map[common.Address]*txList),
 		queue:           make(map[common.Address]*txList),
 		queue:           make(map[common.Address]*txList),
 		beats:           make(map[common.Address]time.Time),
 		beats:           make(map[common.Address]time.Time),
@@ -522,6 +523,10 @@ func (pool *TxPool) local() map[common.Address]types.Transactions {
 // validateTx checks whether a transaction is valid according to the consensus
 // validateTx checks whether a transaction is valid according to the consensus
 // rules and adheres to some heuristic limits of the local node (price and size).
 // rules and adheres to some heuristic limits of the local node (price and size).
 func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
 func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
+	// Accept only legacy transactions until EIP-2718/2930 activates.
+	if !pool.eip2718 && tx.Type() != types.LegacyTxType {
+		return ErrTxTypeNotSupported
+	}
 	// Reject transactions over defined size to prevent DOS attacks
 	// Reject transactions over defined size to prevent DOS attacks
 	if uint64(tx.Size()) > txMaxSize {
 	if uint64(tx.Size()) > txMaxSize {
 		return ErrOversizedData
 		return ErrOversizedData
@@ -535,7 +540,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
 	if pool.currentMaxGas < tx.Gas() {
 	if pool.currentMaxGas < tx.Gas() {
 		return ErrGasLimit
 		return ErrGasLimit
 	}
 	}
-	// Make sure the transaction is signed properly
+	// Make sure the transaction is signed properly.
 	from, err := types.Sender(pool.signer, tx)
 	from, err := types.Sender(pool.signer, tx)
 	if err != nil {
 	if err != nil {
 		return ErrInvalidSender
 		return ErrInvalidSender
@@ -554,7 +559,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
 		return ErrInsufficientFunds
 		return ErrInsufficientFunds
 	}
 	}
 	// Ensure the transaction has more gas than the basic tx fee.
 	// Ensure the transaction has more gas than the basic tx fee.
-	intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, true, pool.istanbul)
+	intrGas, err := IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -1199,6 +1204,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
 	// Update all fork indicator by next pending block number.
 	// Update all fork indicator by next pending block number.
 	next := new(big.Int).Add(newHead.Number, big.NewInt(1))
 	next := new(big.Int).Add(newHead.Number, big.NewInt(1))
 	pool.istanbul = pool.chainconfig.IsIstanbul(next)
 	pool.istanbul = pool.chainconfig.IsIstanbul(next)
+	pool.eip2718 = pool.chainconfig.IsYoloV3(next)
 }
 }
 
 
 // promoteExecutables moves transactions that have become processable from the
 // promoteExecutables moves transactions that have become processable from the

+ 115 - 0
core/types/access_list_tx.go

@@ -0,0 +1,115 @@
+// Copyright 2020 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package types
+
+import (
+	"math/big"
+
+	"github.com/ethereum/go-ethereum/common"
+)
+
+//go:generate gencodec -type AccessTuple -out gen_access_tuple.go
+
+// AccessList is an EIP-2930 access list.
+type AccessList []AccessTuple
+
+// AccessTuple is the element type of an access list.
+type AccessTuple struct {
+	Address     common.Address `json:"address"        gencodec:"required"`
+	StorageKeys []common.Hash  `json:"storageKeys"    gencodec:"required"`
+}
+
+// StorageKeys returns the total number of storage keys in the access list.
+func (al AccessList) StorageKeys() int {
+	sum := 0
+	for _, tuple := range al {
+		sum += len(tuple.StorageKeys)
+	}
+	return sum
+}
+
+// AccessListTx is the data of EIP-2930 access list transactions.
+type AccessListTx struct {
+	ChainID    *big.Int        // destination chain ID
+	Nonce      uint64          // nonce of sender account
+	GasPrice   *big.Int        // wei per gas
+	Gas        uint64          // gas limit
+	To         *common.Address `rlp:"nil"` // nil means contract creation
+	Value      *big.Int        // wei amount
+	Data       []byte          // contract invocation input data
+	AccessList AccessList      // EIP-2930 access list
+	V, R, S    *big.Int        // signature values
+}
+
+// copy creates a deep copy of the transaction data and initializes all fields.
+func (tx *AccessListTx) copy() TxData {
+	cpy := &AccessListTx{
+		Nonce: tx.Nonce,
+		To:    tx.To, // TODO: copy pointed-to address
+		Data:  common.CopyBytes(tx.Data),
+		Gas:   tx.Gas,
+		// These are copied below.
+		AccessList: make(AccessList, len(tx.AccessList)),
+		Value:      new(big.Int),
+		ChainID:    new(big.Int),
+		GasPrice:   new(big.Int),
+		V:          new(big.Int),
+		R:          new(big.Int),
+		S:          new(big.Int),
+	}
+	copy(cpy.AccessList, tx.AccessList)
+	if tx.Value != nil {
+		cpy.Value.Set(tx.Value)
+	}
+	if tx.ChainID != nil {
+		cpy.ChainID.Set(tx.ChainID)
+	}
+	if tx.GasPrice != nil {
+		cpy.GasPrice.Set(tx.GasPrice)
+	}
+	if tx.V != nil {
+		cpy.V.Set(tx.V)
+	}
+	if tx.R != nil {
+		cpy.R.Set(tx.R)
+	}
+	if tx.S != nil {
+		cpy.S.Set(tx.S)
+	}
+	return cpy
+}
+
+// accessors for innerTx.
+
+func (tx *AccessListTx) txType() byte           { return AccessListTxType }
+func (tx *AccessListTx) chainID() *big.Int      { return tx.ChainID }
+func (tx *AccessListTx) protected() bool        { return true }
+func (tx *AccessListTx) accessList() AccessList { return tx.AccessList }
+func (tx *AccessListTx) data() []byte           { return tx.Data }
+func (tx *AccessListTx) gas() uint64            { return tx.Gas }
+func (tx *AccessListTx) gasPrice() *big.Int     { return tx.GasPrice }
+func (tx *AccessListTx) value() *big.Int        { return tx.Value }
+func (tx *AccessListTx) nonce() uint64          { return tx.Nonce }
+func (tx *AccessListTx) to() *common.Address    { return tx.To }
+
+func (tx *AccessListTx) rawSignatureValues() (v, r, s *big.Int) {
+	return tx.V, tx.R, tx.S
+}
+
+func (tx *AccessListTx) setSignatureValues(chainID, v, r, s *big.Int) {
+	tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s
+}

+ 1 - 20
core/types/block.go

@@ -23,15 +23,12 @@ import (
 	"io"
 	"io"
 	"math/big"
 	"math/big"
 	"reflect"
 	"reflect"
-	"sync"
 	"sync/atomic"
 	"sync/atomic"
 	"time"
 	"time"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/common/hexutil"
-	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rlp"
-	"golang.org/x/crypto/sha3"
 )
 )
 
 
 var (
 var (
@@ -131,22 +128,6 @@ func (h *Header) SanityCheck() error {
 	return nil
 	return nil
 }
 }
 
 
-// hasherPool holds LegacyKeccak hashers.
-var hasherPool = sync.Pool{
-	New: func() interface{} {
-		return sha3.NewLegacyKeccak256()
-	},
-}
-
-func rlpHash(x interface{}) (h common.Hash) {
-	sha := hasherPool.Get().(crypto.KeccakState)
-	defer hasherPool.Put(sha)
-	sha.Reset()
-	rlp.Encode(sha, x)
-	sha.Read(h[:])
-	return h
-}
-
 // EmptyBody returns true if there is no additional 'body' to complete the header
 // EmptyBody returns true if there is no additional 'body' to complete the header
 // that is: no transactions and no uncles.
 // that is: no transactions and no uncles.
 func (h *Header) EmptyBody() bool {
 func (h *Header) EmptyBody() bool {
@@ -221,7 +202,7 @@ type storageblock struct {
 // The values of TxHash, UncleHash, ReceiptHash and Bloom in header
 // The values of TxHash, UncleHash, ReceiptHash and Bloom in header
 // are ignored and set to values derived from the given txs, uncles
 // are ignored and set to values derived from the given txs, uncles
 // and receipts.
 // and receipts.
-func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, hasher Hasher) *Block {
+func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, hasher TrieHasher) *Block {
 	b := &Block{header: CopyHeader(header), td: new(big.Int)}
 	b := &Block{header: CopyHeader(header), td: new(big.Int)}
 
 
 	// TODO: panic if len(txs) != len(receipts)
 	// TODO: panic if len(txs) != len(receipts)

+ 61 - 1
core/types/block_test.go

@@ -59,6 +59,66 @@ func TestBlockEncoding(t *testing.T) {
 	tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100"))
 	tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100"))
 	check("len(Transactions)", len(block.Transactions()), 1)
 	check("len(Transactions)", len(block.Transactions()), 1)
 	check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())
 	check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())
+	ourBlockEnc, err := rlp.EncodeToBytes(&block)
+	if err != nil {
+		t.Fatal("encode error: ", err)
+	}
+	if !bytes.Equal(ourBlockEnc, blockEnc) {
+		t.Errorf("encoded block mismatch:\ngot:  %x\nwant: %x", ourBlockEnc, blockEnc)
+	}
+}
+
+func TestEIP2718BlockEncoding(t *testing.T) {
+	blockEnc := common.FromHex("f90319f90211a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a0e6e49996c7ec59f7a23d22b83239a60151512c65613bf84a0d7da336399ebc4aa0cafe75574d59780665a97fbfd11365c7545aa8f1abf4e5e12e8243334ef7286bb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000820200832fefd882a410845506eb0796636f6f6c65737420626c6f636b206f6e20636861696ea0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4f90101f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b89e01f89b01800a8301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000001a03dbacc8d0259f2508625e97fdfc57cd85fdd16e5821bc2c10bdd1a52649e8335a0476e10695b183a87b0aa292a7f4b78ef0c3fbe62aa2c42c84e1d9c3da159ef14c0")
+	var block Block
+	if err := rlp.DecodeBytes(blockEnc, &block); err != nil {
+		t.Fatal("decode error: ", err)
+	}
+
+	check := func(f string, got, want interface{}) {
+		if !reflect.DeepEqual(got, want) {
+			t.Errorf("%s mismatch: got %v, want %v", f, got, want)
+		}
+	}
+	check("Difficulty", block.Difficulty(), big.NewInt(131072))
+	check("GasLimit", block.GasLimit(), uint64(3141592))
+	check("GasUsed", block.GasUsed(), uint64(42000))
+	check("Coinbase", block.Coinbase(), common.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1"))
+	check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498"))
+	check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017"))
+	check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4))
+	check("Time", block.Time(), uint64(1426516743))
+	check("Size", block.Size(), common.StorageSize(len(blockEnc)))
+
+	// Create legacy tx.
+	to := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87")
+	tx1 := NewTx(&LegacyTx{
+		Nonce:    0,
+		To:       &to,
+		Value:    big.NewInt(10),
+		Gas:      50000,
+		GasPrice: big.NewInt(10),
+	})
+	sig := common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")
+	tx1, _ = tx1.WithSignature(HomesteadSigner{}, sig)
+
+	// Create ACL tx.
+	addr := common.HexToAddress("0x0000000000000000000000000000000000000001")
+	tx2 := NewTx(&AccessListTx{
+		ChainID:    big.NewInt(1),
+		Nonce:      0,
+		To:         &to,
+		Gas:        123457,
+		GasPrice:   big.NewInt(10),
+		AccessList: AccessList{{Address: addr, StorageKeys: []common.Hash{{0}}}},
+	})
+	sig2 := common.Hex2Bytes("3dbacc8d0259f2508625e97fdfc57cd85fdd16e5821bc2c10bdd1a52649e8335476e10695b183a87b0aa292a7f4b78ef0c3fbe62aa2c42c84e1d9c3da159ef1401")
+	tx2, _ = tx2.WithSignature(NewEIP2930Signer(big.NewInt(1)), sig2)
+
+	check("len(Transactions)", len(block.Transactions()), 2)
+	check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())
+	check("Transactions[1].Hash", block.Transactions()[1].Hash(), tx2.Hash())
+	check("Transactions[1].Type()", block.Transactions()[1].Type(), uint8(AccessListTxType))
 
 
 	ourBlockEnc, err := rlp.EncodeToBytes(&block)
 	ourBlockEnc, err := rlp.EncodeToBytes(&block)
 	if err != nil {
 	if err != nil {
@@ -121,7 +181,7 @@ func makeBenchBlock() *Block {
 		key, _   = crypto.GenerateKey()
 		key, _   = crypto.GenerateKey()
 		txs      = make([]*Transaction, 70)
 		txs      = make([]*Transaction, 70)
 		receipts = make([]*Receipt, len(txs))
 		receipts = make([]*Receipt, len(txs))
-		signer   = NewEIP155Signer(params.TestChainConfig.ChainID)
+		signer   = LatestSigner(params.TestChainConfig)
 		uncles   = make([]*Header, 3)
 		uncles   = make([]*Header, 3)
 	)
 	)
 	header := &Header{
 	header := &Header{

+ 0 - 58
core/types/derive_sha.go

@@ -1,58 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package types
-
-import (
-	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/rlp"
-)
-
-type DerivableList interface {
-	Len() int
-	GetRlp(i int) []byte
-}
-
-// Hasher is the tool used to calculate the hash of derivable list.
-type Hasher interface {
-	Reset()
-	Update([]byte, []byte)
-	Hash() common.Hash
-}
-
-func DeriveSha(list DerivableList, hasher Hasher) common.Hash {
-	hasher.Reset()
-
-	// StackTrie requires values to be inserted in increasing
-	// hash order, which is not the order that `list` provides
-	// hashes in. This insertion sequence ensures that the
-	// order is correct.
-
-	var buf []byte
-	for i := 1; i < list.Len() && i <= 0x7f; i++ {
-		buf = rlp.AppendUint64(buf[:0], uint64(i))
-		hasher.Update(buf, list.GetRlp(i))
-	}
-	if list.Len() > 0 {
-		buf = rlp.AppendUint64(buf[:0], 0)
-		hasher.Update(buf, list.GetRlp(0))
-	}
-	for i := 0x80; i < list.Len(); i++ {
-		buf = rlp.AppendUint64(buf[:0], uint64(i))
-		hasher.Update(buf, list.GetRlp(i))
-	}
-	return hasher.Hash()
-}

+ 43 - 0
core/types/gen_access_tuple.go

@@ -0,0 +1,43 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package types
+
+import (
+	"encoding/json"
+	"errors"
+
+	"github.com/ethereum/go-ethereum/common"
+)
+
+// MarshalJSON marshals as JSON.
+func (a AccessTuple) MarshalJSON() ([]byte, error) {
+	type AccessTuple struct {
+		Address     common.Address `json:"address"        gencodec:"required"`
+		StorageKeys []common.Hash  `json:"storageKeys"    gencodec:"required"`
+	}
+	var enc AccessTuple
+	enc.Address = a.Address
+	enc.StorageKeys = a.StorageKeys
+	return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (a *AccessTuple) UnmarshalJSON(input []byte) error {
+	type AccessTuple struct {
+		Address     *common.Address `json:"address"        gencodec:"required"`
+		StorageKeys []common.Hash   `json:"storageKeys"    gencodec:"required"`
+	}
+	var dec AccessTuple
+	if err := json.Unmarshal(input, &dec); err != nil {
+		return err
+	}
+	if dec.Address == nil {
+		return errors.New("missing required field 'address' for AccessTuple")
+	}
+	a.Address = *dec.Address
+	if dec.StorageKeys == nil {
+		return errors.New("missing required field 'storageKeys' for AccessTuple")
+	}
+	a.StorageKeys = dec.StorageKeys
+	return nil
+}

+ 6 - 0
core/types/gen_receipt_json.go

@@ -16,6 +16,7 @@ var _ = (*receiptMarshaling)(nil)
 // MarshalJSON marshals as JSON.
 // MarshalJSON marshals as JSON.
 func (r Receipt) MarshalJSON() ([]byte, error) {
 func (r Receipt) MarshalJSON() ([]byte, error) {
 	type Receipt struct {
 	type Receipt struct {
+		Type              hexutil.Uint64 `json:"type,omitempty"`
 		PostState         hexutil.Bytes  `json:"root"`
 		PostState         hexutil.Bytes  `json:"root"`
 		Status            hexutil.Uint64 `json:"status"`
 		Status            hexutil.Uint64 `json:"status"`
 		CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
 		CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
@@ -29,6 +30,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
 		TransactionIndex  hexutil.Uint   `json:"transactionIndex"`
 		TransactionIndex  hexutil.Uint   `json:"transactionIndex"`
 	}
 	}
 	var enc Receipt
 	var enc Receipt
+	enc.Type = hexutil.Uint64(r.Type)
 	enc.PostState = r.PostState
 	enc.PostState = r.PostState
 	enc.Status = hexutil.Uint64(r.Status)
 	enc.Status = hexutil.Uint64(r.Status)
 	enc.CumulativeGasUsed = hexutil.Uint64(r.CumulativeGasUsed)
 	enc.CumulativeGasUsed = hexutil.Uint64(r.CumulativeGasUsed)
@@ -46,6 +48,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
 // UnmarshalJSON unmarshals from JSON.
 // UnmarshalJSON unmarshals from JSON.
 func (r *Receipt) UnmarshalJSON(input []byte) error {
 func (r *Receipt) UnmarshalJSON(input []byte) error {
 	type Receipt struct {
 	type Receipt struct {
+		Type              *hexutil.Uint64 `json:"type,omitempty"`
 		PostState         *hexutil.Bytes  `json:"root"`
 		PostState         *hexutil.Bytes  `json:"root"`
 		Status            *hexutil.Uint64 `json:"status"`
 		Status            *hexutil.Uint64 `json:"status"`
 		CumulativeGasUsed *hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
 		CumulativeGasUsed *hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
@@ -62,6 +65,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
 	if err := json.Unmarshal(input, &dec); err != nil {
 	if err := json.Unmarshal(input, &dec); err != nil {
 		return err
 		return err
 	}
 	}
+	if dec.Type != nil {
+		r.Type = uint8(*dec.Type)
+	}
 	if dec.PostState != nil {
 	if dec.PostState != nil {
 		r.PostState = *dec.PostState
 		r.PostState = *dec.PostState
 	}
 	}

+ 0 - 101
core/types/gen_tx_json.go

@@ -1,101 +0,0 @@
-// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
-
-package types
-
-import (
-	"encoding/json"
-	"errors"
-	"math/big"
-
-	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/common/hexutil"
-)
-
-var _ = (*txdataMarshaling)(nil)
-
-// MarshalJSON marshals as JSON.
-func (t txdata) MarshalJSON() ([]byte, error) {
-	type txdata struct {
-		AccountNonce hexutil.Uint64  `json:"nonce"    gencodec:"required"`
-		Price        *hexutil.Big    `json:"gasPrice" gencodec:"required"`
-		GasLimit     hexutil.Uint64  `json:"gas"      gencodec:"required"`
-		Recipient    *common.Address `json:"to"       rlp:"nil"`
-		Amount       *hexutil.Big    `json:"value"    gencodec:"required"`
-		Payload      hexutil.Bytes   `json:"input"    gencodec:"required"`
-		V            *hexutil.Big    `json:"v" gencodec:"required"`
-		R            *hexutil.Big    `json:"r" gencodec:"required"`
-		S            *hexutil.Big    `json:"s" gencodec:"required"`
-		Hash         *common.Hash    `json:"hash" rlp:"-"`
-	}
-	var enc txdata
-	enc.AccountNonce = hexutil.Uint64(t.AccountNonce)
-	enc.Price = (*hexutil.Big)(t.Price)
-	enc.GasLimit = hexutil.Uint64(t.GasLimit)
-	enc.Recipient = t.Recipient
-	enc.Amount = (*hexutil.Big)(t.Amount)
-	enc.Payload = t.Payload
-	enc.V = (*hexutil.Big)(t.V)
-	enc.R = (*hexutil.Big)(t.R)
-	enc.S = (*hexutil.Big)(t.S)
-	enc.Hash = t.Hash
-	return json.Marshal(&enc)
-}
-
-// UnmarshalJSON unmarshals from JSON.
-func (t *txdata) UnmarshalJSON(input []byte) error {
-	type txdata struct {
-		AccountNonce *hexutil.Uint64 `json:"nonce"    gencodec:"required"`
-		Price        *hexutil.Big    `json:"gasPrice" gencodec:"required"`
-		GasLimit     *hexutil.Uint64 `json:"gas"      gencodec:"required"`
-		Recipient    *common.Address `json:"to"       rlp:"nil"`
-		Amount       *hexutil.Big    `json:"value"    gencodec:"required"`
-		Payload      *hexutil.Bytes  `json:"input"    gencodec:"required"`
-		V            *hexutil.Big    `json:"v" gencodec:"required"`
-		R            *hexutil.Big    `json:"r" gencodec:"required"`
-		S            *hexutil.Big    `json:"s" gencodec:"required"`
-		Hash         *common.Hash    `json:"hash" rlp:"-"`
-	}
-	var dec txdata
-	if err := json.Unmarshal(input, &dec); err != nil {
-		return err
-	}
-	if dec.AccountNonce == nil {
-		return errors.New("missing required field 'nonce' for txdata")
-	}
-	t.AccountNonce = uint64(*dec.AccountNonce)
-	if dec.Price == nil {
-		return errors.New("missing required field 'gasPrice' for txdata")
-	}
-	t.Price = (*big.Int)(dec.Price)
-	if dec.GasLimit == nil {
-		return errors.New("missing required field 'gas' for txdata")
-	}
-	t.GasLimit = uint64(*dec.GasLimit)
-	if dec.Recipient != nil {
-		t.Recipient = dec.Recipient
-	}
-	if dec.Amount == nil {
-		return errors.New("missing required field 'value' for txdata")
-	}
-	t.Amount = (*big.Int)(dec.Amount)
-	if dec.Payload == nil {
-		return errors.New("missing required field 'input' for txdata")
-	}
-	t.Payload = *dec.Payload
-	if dec.V == nil {
-		return errors.New("missing required field 'v' for txdata")
-	}
-	t.V = (*big.Int)(dec.V)
-	if dec.R == nil {
-		return errors.New("missing required field 'r' for txdata")
-	}
-	t.R = (*big.Int)(dec.R)
-	if dec.S == nil {
-		return errors.New("missing required field 's' for txdata")
-	}
-	t.S = (*big.Int)(dec.S)
-	if dec.Hash != nil {
-		t.Hash = dec.Hash
-	}
-	return nil
-}

+ 112 - 0
core/types/hashing.go

@@ -0,0 +1,112 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package types
+
+import (
+	"bytes"
+	"sync"
+
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/crypto"
+	"github.com/ethereum/go-ethereum/rlp"
+	"golang.org/x/crypto/sha3"
+)
+
+// hasherPool holds LegacyKeccak256 hashers for rlpHash.
+var hasherPool = sync.Pool{
+	New: func() interface{} { return sha3.NewLegacyKeccak256() },
+}
+
+// deriveBufferPool holds temporary encoder buffers for DeriveSha and TX encoding.
+var encodeBufferPool = sync.Pool{
+	New: func() interface{} { return new(bytes.Buffer) },
+}
+
+func rlpHash(x interface{}) (h common.Hash) {
+	sha := hasherPool.Get().(crypto.KeccakState)
+	defer hasherPool.Put(sha)
+	sha.Reset()
+	rlp.Encode(sha, x)
+	sha.Read(h[:])
+	return h
+}
+
+// prefixedRlpHash writes the prefix into the hasher before rlp-encoding the
+// given interface. It's used for typed transactions.
+func prefixedRlpHash(prefix byte, x interface{}) (h common.Hash) {
+	sha := hasherPool.Get().(crypto.KeccakState)
+	defer hasherPool.Put(sha)
+	sha.Reset()
+	sha.Write([]byte{prefix})
+	rlp.Encode(sha, x)
+	sha.Read(h[:])
+	return h
+}
+
+// TrieHasher is the tool used to calculate the hash of derivable list.
+// This is internal, do not use.
+type TrieHasher interface {
+	Reset()
+	Update([]byte, []byte)
+	Hash() common.Hash
+}
+
+// DerivableList is the input to DeriveSha.
+// It is implemented by the 'Transactions' and 'Receipts' types.
+// This is internal, do not use these methods.
+type DerivableList interface {
+	Len() int
+	EncodeIndex(int, *bytes.Buffer)
+}
+
+func encodeForDerive(list DerivableList, i int, buf *bytes.Buffer) []byte {
+	buf.Reset()
+	list.EncodeIndex(i, buf)
+	// It's really unfortunate that we need to do perform this copy.
+	// StackTrie holds onto the values until Hash is called, so the values
+	// written to it must not alias.
+	return common.CopyBytes(buf.Bytes())
+}
+
+// DeriveSha creates the tree hashes of transactions and receipts in a block header.
+func DeriveSha(list DerivableList, hasher TrieHasher) common.Hash {
+	hasher.Reset()
+
+	valueBuf := encodeBufferPool.Get().(*bytes.Buffer)
+	defer encodeBufferPool.Put(valueBuf)
+
+	// StackTrie requires values to be inserted in increasing hash order, which is not the
+	// order that `list` provides hashes in. This insertion sequence ensures that the
+	// order is correct.
+	var indexBuf []byte
+	for i := 1; i < list.Len() && i <= 0x7f; i++ {
+		indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i))
+		value := encodeForDerive(list, i, valueBuf)
+		hasher.Update(indexBuf, value)
+	}
+	if list.Len() > 0 {
+		indexBuf = rlp.AppendUint64(indexBuf[:0], 0)
+		value := encodeForDerive(list, 0, valueBuf)
+		hasher.Update(indexBuf, value)
+	}
+	for i := 0x80; i < list.Len(); i++ {
+		indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i))
+		value := encodeForDerive(list, i, valueBuf)
+		hasher.Update(indexBuf, value)
+	}
+	return hasher.Hash()
+}

+ 212 - 0
core/types/hashing_test.go

@@ -0,0 +1,212 @@
+package types_test
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"math/big"
+	mrand "math/rand"
+	"testing"
+
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/common/hexutil"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/crypto"
+	"github.com/ethereum/go-ethereum/rlp"
+	"github.com/ethereum/go-ethereum/trie"
+)
+
+func TestDeriveSha(t *testing.T) {
+	txs, err := genTxs(0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	for len(txs) < 1000 {
+		exp := types.DeriveSha(txs, new(trie.Trie))
+		got := types.DeriveSha(txs, trie.NewStackTrie(nil))
+		if !bytes.Equal(got[:], exp[:]) {
+			t.Fatalf("%d txs: got %x exp %x", len(txs), got, exp)
+		}
+		newTxs, err := genTxs(uint64(len(txs) + 1))
+		if err != nil {
+			t.Fatal(err)
+		}
+		txs = append(txs, newTxs...)
+	}
+}
+
+// TestEIP2718DeriveSha tests that the input to the DeriveSha function is correct.
+func TestEIP2718DeriveSha(t *testing.T) {
+	for _, tc := range []struct {
+		rlpData string
+		exp     string
+	}{
+		{
+			rlpData: "0xb8a701f8a486796f6c6f763380843b9aca008262d4948a8eafb1cf62bfbeb1741769dae1a9dd479961928080f838f7940000000000000000000000000000000000001337e1a0000000000000000000000000000000000000000000000000000000000000000080a0775101f92dcca278a56bfe4d613428624a1ebfc3cd9e0bcc1de80c41455b9021a06c9deac205afe7b124907d4ba54a9f46161498bd3990b90d175aac12c9a40ee9",
+			exp:     "01 01f8a486796f6c6f763380843b9aca008262d4948a8eafb1cf62bfbeb1741769dae1a9dd479961928080f838f7940000000000000000000000000000000000001337e1a0000000000000000000000000000000000000000000000000000000000000000080a0775101f92dcca278a56bfe4d613428624a1ebfc3cd9e0bcc1de80c41455b9021a06c9deac205afe7b124907d4ba54a9f46161498bd3990b90d175aac12c9a40ee9\n80 01f8a486796f6c6f763380843b9aca008262d4948a8eafb1cf62bfbeb1741769dae1a9dd479961928080f838f7940000000000000000000000000000000000001337e1a0000000000000000000000000000000000000000000000000000000000000000080a0775101f92dcca278a56bfe4d613428624a1ebfc3cd9e0bcc1de80c41455b9021a06c9deac205afe7b124907d4ba54a9f46161498bd3990b90d175aac12c9a40ee9\n",
+		},
+	} {
+		d := &hashToHumanReadable{}
+		var t1, t2 types.Transaction
+		rlp.DecodeBytes(common.FromHex(tc.rlpData), &t1)
+		rlp.DecodeBytes(common.FromHex(tc.rlpData), &t2)
+		txs := types.Transactions{&t1, &t2}
+		types.DeriveSha(txs, d)
+		if tc.exp != string(d.data) {
+			t.Fatalf("Want\n%v\nhave:\n%v", tc.exp, string(d.data))
+		}
+	}
+}
+
+func BenchmarkDeriveSha200(b *testing.B) {
+	txs, err := genTxs(200)
+	if err != nil {
+		b.Fatal(err)
+	}
+	var exp common.Hash
+	var got common.Hash
+	b.Run("std_trie", func(b *testing.B) {
+		b.ResetTimer()
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			exp = types.DeriveSha(txs, new(trie.Trie))
+		}
+	})
+
+	b.Run("stack_trie", func(b *testing.B) {
+		b.ResetTimer()
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			got = types.DeriveSha(txs, trie.NewStackTrie(nil))
+		}
+	})
+	if got != exp {
+		b.Errorf("got %x exp %x", got, exp)
+	}
+}
+
+func TestFuzzDeriveSha(t *testing.T) {
+	// increase this for longer runs -- it's set to quite low for travis
+	rndSeed := mrand.Int()
+	for i := 0; i < 10; i++ {
+		seed := rndSeed + i
+		exp := types.DeriveSha(newDummy(i), new(trie.Trie))
+		got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil))
+		if !bytes.Equal(got[:], exp[:]) {
+			printList(newDummy(seed))
+			t.Fatalf("seed %d: got %x exp %x", seed, got, exp)
+		}
+	}
+}
+
+// TestDerivableList contains testcases found via fuzzing
+func TestDerivableList(t *testing.T) {
+	type tcase []string
+	tcs := []tcase{
+		{
+			"0xc041",
+		},
+		{
+			"0xf04cf757812428b0763112efb33b6f4fad7deb445e",
+			"0xf04cf757812428b0763112efb33b6f4fad7deb445e",
+		},
+		{
+			"0xca410605310cdc3bb8d4977ae4f0143df54a724ed873457e2272f39d66e0460e971d9d",
+			"0x6cd850eca0a7ac46bb1748d7b9cb88aa3bd21c57d852c28198ad8fa422c4595032e88a4494b4778b36b944fe47a52b8c5cd312910139dfcb4147ab8e972cc456bcb063f25dd78f54c4d34679e03142c42c662af52947d45bdb6e555751334ace76a5080ab5a0256a1d259855dfc5c0b8023b25befbb13fd3684f9f755cbd3d63544c78ee2001452dd54633a7593ade0b183891a0a4e9c7844e1254005fbe592b1b89149a502c24b6e1dca44c158aebedf01beae9c30cabe16a",
+			"0x14abd5c47c0be87b0454596baad2",
+			"0xca410605310cdc3bb8d4977ae4f0143df54a724ed873457e2272f39d66e0460e971d9d",
+		},
+	}
+	for i, tc := range tcs[1:] {
+		exp := types.DeriveSha(flatList(tc), new(trie.Trie))
+		got := types.DeriveSha(flatList(tc), trie.NewStackTrie(nil))
+		if !bytes.Equal(got[:], exp[:]) {
+			t.Fatalf("case %d: got %x exp %x", i, got, exp)
+		}
+	}
+}
+
+func genTxs(num uint64) (types.Transactions, error) {
+	key, err := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
+	if err != nil {
+		return nil, err
+	}
+	var addr = crypto.PubkeyToAddress(key.PublicKey)
+	newTx := func(i uint64) (*types.Transaction, error) {
+		signer := types.NewEIP155Signer(big.NewInt(18))
+		utx := types.NewTransaction(i, addr, new(big.Int), 0, new(big.Int).SetUint64(10000000), nil)
+		tx, err := types.SignTx(utx, signer, key)
+		return tx, err
+	}
+	var txs types.Transactions
+	for i := uint64(0); i < num; i++ {
+		tx, err := newTx(i)
+		if err != nil {
+			return nil, err
+		}
+		txs = append(txs, tx)
+	}
+	return txs, nil
+}
+
+type dummyDerivableList struct {
+	len  int
+	seed int
+}
+
+func newDummy(seed int) *dummyDerivableList {
+	d := &dummyDerivableList{}
+	src := mrand.NewSource(int64(seed))
+	// don't use lists longer than 4K items
+	d.len = int(src.Int63() & 0x0FFF)
+	d.seed = seed
+	return d
+}
+
+func (d *dummyDerivableList) Len() int {
+	return d.len
+}
+
+func (d *dummyDerivableList) EncodeIndex(i int, w *bytes.Buffer) {
+	src := mrand.NewSource(int64(d.seed + i))
+	// max item size 256, at least 1 byte per item
+	size := 1 + src.Int63()&0x00FF
+	io.CopyN(w, mrand.New(src), size)
+}
+
+func printList(l types.DerivableList) {
+	fmt.Printf("list length: %d\n", l.Len())
+	fmt.Printf("{\n")
+	for i := 0; i < l.Len(); i++ {
+		var buf bytes.Buffer
+		l.EncodeIndex(i, &buf)
+		fmt.Printf("\"0x%x\",\n", buf.Bytes())
+	}
+	fmt.Printf("},\n")
+}
+
+type flatList []string
+
+func (f flatList) Len() int {
+	return len(f)
+}
+func (f flatList) EncodeIndex(i int, w *bytes.Buffer) {
+	w.Write(hexutil.MustDecode(f[i]))
+}
+
+type hashToHumanReadable struct {
+	data []byte
+}
+
+func (d *hashToHumanReadable) Reset() {
+	d.data = make([]byte, 0)
+}
+
+func (d *hashToHumanReadable) Update(i []byte, i2 []byte) {
+	l := fmt.Sprintf("%x %x\n", i, i2)
+	d.data = append(d.data, []byte(l)...)
+}
+
+func (d *hashToHumanReadable) Hash() common.Hash {
+	return common.Hash{}
+}

+ 111 - 0
core/types/legacy_tx.go

@@ -0,0 +1,111 @@
+// Copyright 2020 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package types
+
+import (
+	"math/big"
+
+	"github.com/ethereum/go-ethereum/common"
+)
+
+// LegacyTx is the transaction data of regular Ethereum transactions.
+type LegacyTx struct {
+	Nonce    uint64          // nonce of sender account
+	GasPrice *big.Int        // wei per gas
+	Gas      uint64          // gas limit
+	To       *common.Address `rlp:"nil"` // nil means contract creation
+	Value    *big.Int        // wei amount
+	Data     []byte          // contract invocation input data
+	V, R, S  *big.Int        // signature values
+}
+
+// NewTransaction creates an unsigned legacy transaction.
+// Deprecated: use NewTx instead.
+func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
+	return NewTx(&LegacyTx{
+		Nonce:    nonce,
+		To:       &to,
+		Value:    amount,
+		Gas:      gasLimit,
+		GasPrice: gasPrice,
+		Data:     data,
+	})
+}
+
+// NewContractCreation creates an unsigned legacy transaction.
+// Deprecated: use NewTx instead.
+func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
+	return NewTx(&LegacyTx{
+		Nonce:    nonce,
+		Value:    amount,
+		Gas:      gasLimit,
+		GasPrice: gasPrice,
+		Data:     data,
+	})
+}
+
+// copy creates a deep copy of the transaction data and initializes all fields.
+func (tx *LegacyTx) copy() TxData {
+	cpy := &LegacyTx{
+		Nonce: tx.Nonce,
+		To:    tx.To, // TODO: copy pointed-to address
+		Data:  common.CopyBytes(tx.Data),
+		Gas:   tx.Gas,
+		// These are initialized below.
+		Value:    new(big.Int),
+		GasPrice: new(big.Int),
+		V:        new(big.Int),
+		R:        new(big.Int),
+		S:        new(big.Int),
+	}
+	if tx.Value != nil {
+		cpy.Value.Set(tx.Value)
+	}
+	if tx.GasPrice != nil {
+		cpy.GasPrice.Set(tx.GasPrice)
+	}
+	if tx.V != nil {
+		cpy.V.Set(tx.V)
+	}
+	if tx.R != nil {
+		cpy.R.Set(tx.R)
+	}
+	if tx.S != nil {
+		cpy.S.Set(tx.S)
+	}
+	return cpy
+}
+
+// accessors for innerTx.
+
+func (tx *LegacyTx) txType() byte           { return LegacyTxType }
+func (tx *LegacyTx) chainID() *big.Int      { return deriveChainId(tx.V) }
+func (tx *LegacyTx) accessList() AccessList { return nil }
+func (tx *LegacyTx) data() []byte           { return tx.Data }
+func (tx *LegacyTx) gas() uint64            { return tx.Gas }
+func (tx *LegacyTx) gasPrice() *big.Int     { return tx.GasPrice }
+func (tx *LegacyTx) value() *big.Int        { return tx.Value }
+func (tx *LegacyTx) nonce() uint64          { return tx.Nonce }
+func (tx *LegacyTx) to() *common.Address    { return tx.To }
+
+func (tx *LegacyTx) rawSignatureValues() (v, r, s *big.Int) {
+	return tx.V, tx.R, tx.S
+}
+
+func (tx *LegacyTx) setSignatureValues(chainID, v, r, s *big.Int) {
+	tx.V, tx.R, tx.S = v, r, s
+}

+ 81 - 20
core/types/receipt.go

@@ -38,6 +38,8 @@ var (
 	receiptStatusSuccessfulRLP = []byte{0x01}
 	receiptStatusSuccessfulRLP = []byte{0x01}
 )
 )
 
 
+var errEmptyTypedReceipt = errors.New("empty typed receipt bytes")
+
 const (
 const (
 	// ReceiptStatusFailed is the status code of a transaction if execution failed.
 	// ReceiptStatusFailed is the status code of a transaction if execution failed.
 	ReceiptStatusFailed = uint64(0)
 	ReceiptStatusFailed = uint64(0)
@@ -49,6 +51,7 @@ const (
 // Receipt represents the results of a transaction.
 // Receipt represents the results of a transaction.
 type Receipt struct {
 type Receipt struct {
 	// Consensus fields: These fields are defined by the Yellow Paper
 	// Consensus fields: These fields are defined by the Yellow Paper
+	Type              uint8  `json:"type,omitempty"`
 	PostState         []byte `json:"root"`
 	PostState         []byte `json:"root"`
 	Status            uint64 `json:"status"`
 	Status            uint64 `json:"status"`
 	CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"`
 	CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"`
@@ -69,6 +72,7 @@ type Receipt struct {
 }
 }
 
 
 type receiptMarshaling struct {
 type receiptMarshaling struct {
+	Type              hexutil.Uint64
 	PostState         hexutil.Bytes
 	PostState         hexutil.Bytes
 	Status            hexutil.Uint64
 	Status            hexutil.Uint64
 	CumulativeGasUsed hexutil.Uint64
 	CumulativeGasUsed hexutil.Uint64
@@ -114,8 +118,13 @@ type v3StoredReceiptRLP struct {
 }
 }
 
 
 // NewReceipt creates a barebone transaction receipt, copying the init fields.
 // NewReceipt creates a barebone transaction receipt, copying the init fields.
+// Deprecated: create receipts using a struct literal instead.
 func NewReceipt(root []byte, failed bool, cumulativeGasUsed uint64) *Receipt {
 func NewReceipt(root []byte, failed bool, cumulativeGasUsed uint64) *Receipt {
-	r := &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: cumulativeGasUsed}
+	r := &Receipt{
+		Type:              LegacyTxType,
+		PostState:         common.CopyBytes(root),
+		CumulativeGasUsed: cumulativeGasUsed,
+	}
 	if failed {
 	if failed {
 		r.Status = ReceiptStatusFailed
 		r.Status = ReceiptStatusFailed
 	} else {
 	} else {
@@ -127,21 +136,65 @@ func NewReceipt(root []byte, failed bool, cumulativeGasUsed uint64) *Receipt {
 // EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
 // EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
 // into an RLP stream. If no post state is present, byzantium fork is assumed.
 // into an RLP stream. If no post state is present, byzantium fork is assumed.
 func (r *Receipt) EncodeRLP(w io.Writer) error {
 func (r *Receipt) EncodeRLP(w io.Writer) error {
-	return rlp.Encode(w, &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs})
+	data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs}
+	if r.Type == LegacyTxType {
+		return rlp.Encode(w, data)
+	}
+	// It's an EIP-2718 typed TX receipt.
+	if r.Type != AccessListTxType {
+		return ErrTxTypeNotSupported
+	}
+	buf := encodeBufferPool.Get().(*bytes.Buffer)
+	defer encodeBufferPool.Put(buf)
+	buf.Reset()
+	buf.WriteByte(r.Type)
+	if err := rlp.Encode(buf, data); err != nil {
+		return err
+	}
+	return rlp.Encode(w, buf.Bytes())
 }
 }
 
 
 // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
 // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
 // from an RLP stream.
 // from an RLP stream.
 func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
 func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
-	var dec receiptRLP
-	if err := s.Decode(&dec); err != nil {
-		return err
-	}
-	if err := r.setStatus(dec.PostStateOrStatus); err != nil {
+	kind, _, err := s.Kind()
+	switch {
+	case err != nil:
 		return err
 		return err
+	case kind == rlp.List:
+		// It's a legacy receipt.
+		var dec receiptRLP
+		if err := s.Decode(&dec); err != nil {
+			return err
+		}
+		r.Type = LegacyTxType
+		return r.setFromRLP(dec)
+	case kind == rlp.String:
+		// It's an EIP-2718 typed tx receipt.
+		b, err := s.Bytes()
+		if err != nil {
+			return err
+		}
+		if len(b) == 0 {
+			return errEmptyTypedReceipt
+		}
+		r.Type = b[0]
+		if r.Type == AccessListTxType {
+			var dec receiptRLP
+			if err := rlp.DecodeBytes(b[1:], &dec); err != nil {
+				return err
+			}
+			return r.setFromRLP(dec)
+		}
+		return ErrTxTypeNotSupported
+	default:
+		return rlp.ErrExpectedList
 	}
 	}
-	r.CumulativeGasUsed, r.Bloom, r.Logs = dec.CumulativeGasUsed, dec.Bloom, dec.Logs
-	return nil
+}
+
+func (r *Receipt) setFromRLP(data receiptRLP) error {
+	r.CumulativeGasUsed, r.Bloom, r.Logs = data.CumulativeGasUsed, data.Bloom, data.Logs
+	return r.setStatus(data.PostStateOrStatus)
 }
 }
 
 
 func (r *Receipt) setStatus(postStateOrStatus []byte) error {
 func (r *Receipt) setStatus(postStateOrStatus []byte) error {
@@ -172,7 +225,6 @@ func (r *Receipt) statusEncoding() []byte {
 // to approximate and limit the memory consumption of various caches.
 // to approximate and limit the memory consumption of various caches.
 func (r *Receipt) Size() common.StorageSize {
 func (r *Receipt) Size() common.StorageSize {
 	size := common.StorageSize(unsafe.Sizeof(*r)) + common.StorageSize(len(r.PostState))
 	size := common.StorageSize(unsafe.Sizeof(*r)) + common.StorageSize(len(r.PostState))
-
 	size += common.StorageSize(len(r.Logs)) * common.StorageSize(unsafe.Sizeof(Log{}))
 	size += common.StorageSize(len(r.Logs)) * common.StorageSize(unsafe.Sizeof(Log{}))
 	for _, log := range r.Logs {
 	for _, log := range r.Logs {
 		size += common.StorageSize(len(log.Topics)*common.HashLength + len(log.Data))
 		size += common.StorageSize(len(log.Topics)*common.HashLength + len(log.Data))
@@ -277,19 +329,27 @@ func decodeV3StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
 	return nil
 	return nil
 }
 }
 
 
-// Receipts is a wrapper around a Receipt array to implement DerivableList.
+// Receipts implements DerivableList for receipts.
 type Receipts []*Receipt
 type Receipts []*Receipt
 
 
 // Len returns the number of receipts in this list.
 // Len returns the number of receipts in this list.
-func (r Receipts) Len() int { return len(r) }
-
-// GetRlp returns the RLP encoding of one receipt from the list.
-func (r Receipts) GetRlp(i int) []byte {
-	bytes, err := rlp.EncodeToBytes(r[i])
-	if err != nil {
-		panic(err)
+func (rs Receipts) Len() int { return len(rs) }
+
+// EncodeIndex encodes the i'th receipt to w.
+func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
+	r := rs[i]
+	data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs}
+	switch r.Type {
+	case LegacyTxType:
+		rlp.Encode(w, data)
+	case AccessListTxType:
+		w.WriteByte(AccessListTxType)
+		rlp.Encode(w, data)
+	default:
+		// For unsupported types, write nothing. Since this is for
+		// DeriveSha, the error will be caught matching the derived hash
+		// to the block.
 	}
 	}
-	return bytes
 }
 }
 
 
 // DeriveFields fills the receipts with their computed fields based on consensus
 // DeriveFields fills the receipts with their computed fields based on consensus
@@ -302,7 +362,8 @@ func (r Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, num
 		return errors.New("transaction and receipt count mismatch")
 		return errors.New("transaction and receipt count mismatch")
 	}
 	}
 	for i := 0; i < len(r); i++ {
 	for i := 0; i < len(r); i++ {
-		// The transaction hash can be retrieved from the transaction itself
+		// The transaction type and hash can be retrieved from the transaction itself
+		r[i].Type = txs[i].Type()
 		r[i].TxHash = txs[i].Hash()
 		r[i].TxHash = txs[i].Hash()
 
 
 		// block location fields
 		// block location fields

File diff suppressed because it is too large
+ 49 - 2
core/types/receipt_test.go


+ 279 - 187
core/types/transaction.go

@@ -17,6 +17,7 @@
 package types
 package types
 
 
 import (
 import (
+	"bytes"
 	"container/heap"
 	"container/heap"
 	"errors"
 	"errors"
 	"io"
 	"io"
@@ -25,20 +26,28 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rlp"
 )
 )
 
 
-//go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
-
 var (
 var (
-	ErrInvalidSig = errors.New("invalid transaction v, r, s values")
+	ErrInvalidSig           = errors.New("invalid transaction v, r, s values")
+	ErrUnexpectedProtection = errors.New("transaction type does not supported EIP-155 protected signatures")
+	ErrInvalidTxType        = errors.New("transaction type not valid in this context")
+	ErrTxTypeNotSupported   = errors.New("transaction type not supported")
+	errEmptyTypedTx         = errors.New("empty typed transaction bytes")
+)
+
+// Transaction types.
+const (
+	LegacyTxType = iota
+	AccessListTxType
 )
 )
 
 
+// Transaction is an Ethereum transaction.
 type Transaction struct {
 type Transaction struct {
-	data txdata    // Consensus contents of a transaction
-	time time.Time // Time first seen locally (spam avoidance)
+	inner TxData    // Consensus contents of a transaction
+	time  time.Time // Time first seen locally (spam avoidance)
 
 
 	// caches
 	// caches
 	hash atomic.Value
 	hash atomic.Value
@@ -46,170 +55,266 @@ type Transaction struct {
 	from atomic.Value
 	from atomic.Value
 }
 }
 
 
-type txdata struct {
-	AccountNonce uint64          `json:"nonce"    gencodec:"required"`
-	Price        *big.Int        `json:"gasPrice" gencodec:"required"`
-	GasLimit     uint64          `json:"gas"      gencodec:"required"`
-	Recipient    *common.Address `json:"to"       rlp:"nil"` // nil means contract creation
-	Amount       *big.Int        `json:"value"    gencodec:"required"`
-	Payload      []byte          `json:"input"    gencodec:"required"`
+// NewTx creates a new transaction.
+func NewTx(inner TxData) *Transaction {
+	tx := new(Transaction)
+	tx.setDecoded(inner.copy(), 0)
+	return tx
+}
+
+// TxData is the underlying data of a transaction.
+//
+// This is implemented by LegacyTx and AccessListTx.
+type TxData interface {
+	txType() byte // returns the type ID
+	copy() TxData // creates a deep copy and initializes all fields
 
 
-	// Signature values
-	V *big.Int `json:"v" gencodec:"required"`
-	R *big.Int `json:"r" gencodec:"required"`
-	S *big.Int `json:"s" gencodec:"required"`
+	chainID() *big.Int
+	accessList() AccessList
+	data() []byte
+	gas() uint64
+	gasPrice() *big.Int
+	value() *big.Int
+	nonce() uint64
+	to() *common.Address
 
 
-	// This is only used when marshaling to JSON.
-	Hash *common.Hash `json:"hash" rlp:"-"`
+	rawSignatureValues() (v, r, s *big.Int)
+	setSignatureValues(chainID, v, r, s *big.Int)
 }
 }
 
 
-type txdataMarshaling struct {
-	AccountNonce hexutil.Uint64
-	Price        *hexutil.Big
-	GasLimit     hexutil.Uint64
-	Amount       *hexutil.Big
-	Payload      hexutil.Bytes
-	V            *hexutil.Big
-	R            *hexutil.Big
-	S            *hexutil.Big
+// EncodeRLP implements rlp.Encoder
+func (tx *Transaction) EncodeRLP(w io.Writer) error {
+	if tx.Type() == LegacyTxType {
+		return rlp.Encode(w, tx.inner)
+	}
+	// It's an EIP-2718 typed TX envelope.
+	buf := encodeBufferPool.Get().(*bytes.Buffer)
+	defer encodeBufferPool.Put(buf)
+	buf.Reset()
+	if err := tx.encodeTyped(buf); err != nil {
+		return err
+	}
+	return rlp.Encode(w, buf.Bytes())
 }
 }
 
 
-func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
-	return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data)
+// encodeTyped writes the canonical encoding of a typed transaction to w.
+func (tx *Transaction) encodeTyped(w *bytes.Buffer) error {
+	w.WriteByte(tx.Type())
+	return rlp.Encode(w, tx.inner)
 }
 }
 
 
-func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
-	return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data)
+// MarshalBinary returns the canonical encoding of the transaction.
+// For legacy transactions, it returns the RLP encoding. For EIP-2718 typed
+// transactions, it returns the type and payload.
+func (tx *Transaction) MarshalBinary() ([]byte, error) {
+	if tx.Type() == LegacyTxType {
+		return rlp.EncodeToBytes(tx.inner)
+	}
+	var buf bytes.Buffer
+	err := tx.encodeTyped(&buf)
+	return buf.Bytes(), err
 }
 }
 
 
-func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
-	if len(data) > 0 {
-		data = common.CopyBytes(data)
+// DecodeRLP implements rlp.Decoder
+func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
+	kind, size, err := s.Kind()
+	switch {
+	case err != nil:
+		return err
+	case kind == rlp.List:
+		// It's a legacy transaction.
+		var inner LegacyTx
+		err := s.Decode(&inner)
+		if err == nil {
+			tx.setDecoded(&inner, int(rlp.ListSize(size)))
+		}
+		return err
+	case kind == rlp.String:
+		// It's an EIP-2718 typed TX envelope.
+		var b []byte
+		if b, err = s.Bytes(); err != nil {
+			return err
+		}
+		inner, err := tx.decodeTyped(b)
+		if err == nil {
+			tx.setDecoded(inner, len(b))
+		}
+		return err
+	default:
+		return rlp.ErrExpectedList
 	}
 	}
-	d := txdata{
-		AccountNonce: nonce,
-		Recipient:    to,
-		Payload:      data,
-		Amount:       new(big.Int),
-		GasLimit:     gasLimit,
-		Price:        new(big.Int),
-		V:            new(big.Int),
-		R:            new(big.Int),
-		S:            new(big.Int),
+}
+
+// UnmarshalBinary decodes the canonical encoding of transactions.
+// It supports legacy RLP transactions and EIP2718 typed transactions.
+func (tx *Transaction) UnmarshalBinary(b []byte) error {
+	if len(b) > 0 && b[0] > 0x7f {
+		// It's a legacy transaction.
+		var data LegacyTx
+		err := rlp.DecodeBytes(b, &data)
+		if err != nil {
+			return err
+		}
+		tx.setDecoded(&data, len(b))
+		return nil
 	}
 	}
-	if amount != nil {
-		d.Amount.Set(amount)
+	// It's an EIP2718 typed transaction envelope.
+	inner, err := tx.decodeTyped(b)
+	if err != nil {
+		return err
 	}
 	}
-	if gasPrice != nil {
-		d.Price.Set(gasPrice)
+	tx.setDecoded(inner, len(b))
+	return nil
+}
+
+// decodeTyped decodes a typed transaction from the canonical format.
+func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
+	if len(b) == 0 {
+		return nil, errEmptyTypedTx
 	}
 	}
-	return &Transaction{
-		data: d,
-		time: time.Now(),
+	switch b[0] {
+	case AccessListTxType:
+		var inner AccessListTx
+		err := rlp.DecodeBytes(b[1:], &inner)
+		return &inner, err
+	default:
+		return nil, ErrTxTypeNotSupported
 	}
 	}
 }
 }
 
 
-// ChainId returns which chain id this transaction was signed for (if at all)
-func (tx *Transaction) ChainId() *big.Int {
-	return deriveChainId(tx.data.V)
+// setDecoded sets the inner transaction and size after decoding.
+func (tx *Transaction) setDecoded(inner TxData, size int) {
+	tx.inner = inner
+	tx.time = time.Now()
+	if size > 0 {
+		tx.size.Store(common.StorageSize(size))
+	}
 }
 }
 
 
-// Protected returns whether the transaction is protected from replay protection.
-func (tx *Transaction) Protected() bool {
-	return isProtectedV(tx.data.V)
+func sanityCheckSignature(v *big.Int, r *big.Int, s *big.Int, maybeProtected bool) error {
+	if isProtectedV(v) && !maybeProtected {
+		return ErrUnexpectedProtection
+	}
+
+	var plainV byte
+	if isProtectedV(v) {
+		chainID := deriveChainId(v).Uint64()
+		plainV = byte(v.Uint64() - 35 - 2*chainID)
+	} else if maybeProtected {
+		// Only EIP-155 signatures can be optionally protected. Since
+		// we determined this v value is not protected, it must be a
+		// raw 27 or 28.
+		plainV = byte(v.Uint64() - 27)
+	} else {
+		// If the signature is not optionally protected, we assume it
+		// must already be equal to the recovery id.
+		plainV = byte(v.Uint64())
+	}
+	if !crypto.ValidateSignatureValues(plainV, r, s, false) {
+		return ErrInvalidSig
+	}
+
+	return nil
 }
 }
 
 
 func isProtectedV(V *big.Int) bool {
 func isProtectedV(V *big.Int) bool {
 	if V.BitLen() <= 8 {
 	if V.BitLen() <= 8 {
 		v := V.Uint64()
 		v := V.Uint64()
-		return v != 27 && v != 28
+		return v != 27 && v != 28 && v != 1 && v != 0
 	}
 	}
 	// anything not 27 or 28 is considered protected
 	// anything not 27 or 28 is considered protected
 	return true
 	return true
 }
 }
 
 
-// EncodeRLP implements rlp.Encoder
-func (tx *Transaction) EncodeRLP(w io.Writer) error {
-	return rlp.Encode(w, &tx.data)
-}
-
-// DecodeRLP implements rlp.Decoder
-func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
-	_, size, _ := s.Kind()
-	err := s.Decode(&tx.data)
-	if err == nil {
-		tx.size.Store(common.StorageSize(rlp.ListSize(size)))
-		tx.time = time.Now()
+// Protected says whether the transaction is replay-protected.
+func (tx *Transaction) Protected() bool {
+	switch tx := tx.inner.(type) {
+	case *LegacyTx:
+		return tx.V != nil && isProtectedV(tx.V)
+	default:
+		return true
 	}
 	}
-	return err
 }
 }
 
 
-// MarshalJSON encodes the web3 RPC transaction format.
-func (tx *Transaction) MarshalJSON() ([]byte, error) {
-	hash := tx.Hash()
-	data := tx.data
-	data.Hash = &hash
-	return data.MarshalJSON()
+// Type returns the transaction type.
+func (tx *Transaction) Type() uint8 {
+	return tx.inner.txType()
 }
 }
 
 
-// UnmarshalJSON decodes the web3 RPC transaction format.
-func (tx *Transaction) UnmarshalJSON(input []byte) error {
-	var dec txdata
-	if err := dec.UnmarshalJSON(input); err != nil {
-		return err
-	}
-	withSignature := dec.V.Sign() != 0 || dec.R.Sign() != 0 || dec.S.Sign() != 0
-	if withSignature {
-		var V byte
-		if isProtectedV(dec.V) {
-			chainID := deriveChainId(dec.V).Uint64()
-			V = byte(dec.V.Uint64() - 35 - 2*chainID)
-		} else {
-			V = byte(dec.V.Uint64() - 27)
-		}
-		if !crypto.ValidateSignatureValues(V, dec.R, dec.S, false) {
-			return ErrInvalidSig
-		}
-	}
-	*tx = Transaction{
-		data: dec,
-		time: time.Now(),
-	}
-	return nil
+// ChainId returns the EIP155 chain ID of the transaction. The return value will always be
+// non-nil. For legacy transactions which are not replay-protected, the return value is
+// zero.
+func (tx *Transaction) ChainId() *big.Int {
+	return tx.inner.chainID()
 }
 }
 
 
-func (tx *Transaction) Data() []byte       { return common.CopyBytes(tx.data.Payload) }
-func (tx *Transaction) Gas() uint64        { return tx.data.GasLimit }
-func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) }
-func (tx *Transaction) GasPriceCmp(other *Transaction) int {
-	return tx.data.Price.Cmp(other.data.Price)
-}
-func (tx *Transaction) GasPriceIntCmp(other *big.Int) int {
-	return tx.data.Price.Cmp(other)
-}
-func (tx *Transaction) Value() *big.Int  { return new(big.Int).Set(tx.data.Amount) }
-func (tx *Transaction) Nonce() uint64    { return tx.data.AccountNonce }
-func (tx *Transaction) CheckNonce() bool { return true }
+// Data returns the input data of the transaction.
+func (tx *Transaction) Data() []byte { return tx.inner.data() }
+
+// AccessList returns the access list of the transaction.
+func (tx *Transaction) AccessList() AccessList { return tx.inner.accessList() }
+
+// Gas returns the gas limit of the transaction.
+func (tx *Transaction) Gas() uint64 { return tx.inner.gas() }
+
+// GasPrice returns the gas price of the transaction.
+func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.inner.gasPrice()) }
+
+// Value returns the ether amount of the transaction.
+func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) }
+
+// Nonce returns the sender account nonce of the transaction.
+func (tx *Transaction) Nonce() uint64 { return tx.inner.nonce() }
 
 
 // To returns the recipient address of the transaction.
 // To returns the recipient address of the transaction.
-// It returns nil if the transaction is a contract creation.
+// For contract-creation transactions, To returns nil.
 func (tx *Transaction) To() *common.Address {
 func (tx *Transaction) To() *common.Address {
-	if tx.data.Recipient == nil {
+	// Copy the pointed-to address.
+	ito := tx.inner.to()
+	if ito == nil {
 		return nil
 		return nil
 	}
 	}
-	to := *tx.data.Recipient
-	return &to
+	cpy := *ito
+	return &cpy
+}
+
+// Cost returns gas * gasPrice + value.
+func (tx *Transaction) Cost() *big.Int {
+	total := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas()))
+	total.Add(total, tx.Value())
+	return total
+}
+
+// RawSignatureValues returns the V, R, S signature values of the transaction.
+// The return values should not be modified by the caller.
+func (tx *Transaction) RawSignatureValues() (v, r, s *big.Int) {
+	return tx.inner.rawSignatureValues()
+}
+
+// GasPriceCmp compares the gas prices of two transactions.
+func (tx *Transaction) GasPriceCmp(other *Transaction) int {
+	return tx.inner.gasPrice().Cmp(other.GasPrice())
 }
 }
 
 
-// Hash hashes the RLP encoding of tx.
-// It uniquely identifies the transaction.
+// GasPriceIntCmp compares the gas price of the transaction against the given price.
+func (tx *Transaction) GasPriceIntCmp(other *big.Int) int {
+	return tx.inner.gasPrice().Cmp(other)
+}
+
+// Hash returns the transaction hash.
 func (tx *Transaction) Hash() common.Hash {
 func (tx *Transaction) Hash() common.Hash {
 	if hash := tx.hash.Load(); hash != nil {
 	if hash := tx.hash.Load(); hash != nil {
 		return hash.(common.Hash)
 		return hash.(common.Hash)
 	}
 	}
-	v := rlpHash(tx)
-	tx.hash.Store(v)
-	return v
+
+	var h common.Hash
+	if tx.Type() == LegacyTxType {
+		h = rlpHash(tx.inner)
+	} else {
+		h = prefixedRlpHash(tx.Type(), tx.inner)
+	}
+	tx.hash.Store(h)
+	return h
 }
 }
 
 
 // Size returns the true RLP encoded storage size of the transaction, either by
 // Size returns the true RLP encoded storage size of the transaction, either by
@@ -219,32 +324,11 @@ func (tx *Transaction) Size() common.StorageSize {
 		return size.(common.StorageSize)
 		return size.(common.StorageSize)
 	}
 	}
 	c := writeCounter(0)
 	c := writeCounter(0)
-	rlp.Encode(&c, &tx.data)
+	rlp.Encode(&c, &tx.inner)
 	tx.size.Store(common.StorageSize(c))
 	tx.size.Store(common.StorageSize(c))
 	return common.StorageSize(c)
 	return common.StorageSize(c)
 }
 }
 
 
-// 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,
-		gasLimit:   tx.data.GasLimit,
-		gasPrice:   new(big.Int).Set(tx.data.Price),
-		to:         tx.data.Recipient,
-		amount:     tx.data.Amount,
-		data:       tx.data.Payload,
-		checkNonce: true,
-	}
-
-	var err error
-	msg.from, err = Sender(s, tx)
-	return msg, err
-}
-
 // WithSignature returns a new transaction with the given signature.
 // WithSignature returns a new transaction with the given signature.
 // This signature needs to be in the [R || S || V] format where V is 0 or 1.
 // This signature needs to be in the [R || S || V] format where V is 0 or 1.
 func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
 func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
@@ -252,40 +336,27 @@ func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, e
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	cpy := &Transaction{
-		data: tx.data,
-		time: tx.time,
-	}
-	cpy.data.R, cpy.data.S, cpy.data.V = r, s, v
-	return cpy, nil
+	cpy := tx.inner.copy()
+	cpy.setSignatureValues(signer.ChainID(), v, r, s)
+	return &Transaction{inner: cpy, time: tx.time}, nil
 }
 }
 
 
-// Cost returns amount + gasprice * gaslimit.
-func (tx *Transaction) Cost() *big.Int {
-	total := new(big.Int).Mul(tx.data.Price, new(big.Int).SetUint64(tx.data.GasLimit))
-	total.Add(total, tx.data.Amount)
-	return total
-}
-
-// RawSignatureValues returns the V, R, S signature values of the transaction.
-// The return values should not be modified by the caller.
-func (tx *Transaction) RawSignatureValues() (v, r, s *big.Int) {
-	return tx.data.V, tx.data.R, tx.data.S
-}
-
-// Transactions is a Transaction slice type for basic sorting.
+// Transactions implements DerivableList for transactions.
 type Transactions []*Transaction
 type Transactions []*Transaction
 
 
 // Len returns the length of s.
 // Len returns the length of s.
 func (s Transactions) Len() int { return len(s) }
 func (s Transactions) Len() int { return len(s) }
 
 
-// Swap swaps the i'th and the j'th element in s.
-func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
-// GetRlp implements Rlpable and returns the i'th element of s in rlp.
-func (s Transactions) GetRlp(i int) []byte {
-	enc, _ := rlp.EncodeToBytes(s[i])
-	return enc
+// EncodeIndex encodes the i'th transaction to w. Note that this does not check for errors
+// because we assume that *Transaction will only ever contain valid txs that were either
+// constructed by decoding or via public API in this package.
+func (s Transactions) EncodeIndex(i int, w *bytes.Buffer) {
+	tx := s[i]
+	if tx.Type() == LegacyTxType {
+		rlp.Encode(w, tx.inner)
+	} else {
+		tx.encodeTyped(w)
+	}
 }
 }
 
 
 // TxDifference returns a new set which is the difference between a and b.
 // TxDifference returns a new set which is the difference between a and b.
@@ -312,7 +383,7 @@ func TxDifference(a, b Transactions) Transactions {
 type TxByNonce Transactions
 type TxByNonce Transactions
 
 
 func (s TxByNonce) Len() int           { return len(s) }
 func (s TxByNonce) Len() int           { return len(s) }
-func (s TxByNonce) Less(i, j int) bool { return s[i].data.AccountNonce < s[j].data.AccountNonce }
+func (s TxByNonce) Less(i, j int) bool { return s[i].Nonce() < s[j].Nonce() }
 func (s TxByNonce) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
 func (s TxByNonce) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
 
 
 // TxByPriceAndTime implements both the sort and the heap interface, making it useful
 // TxByPriceAndTime implements both the sort and the heap interface, making it useful
@@ -323,7 +394,7 @@ func (s TxByPriceAndTime) Len() int { return len(s) }
 func (s TxByPriceAndTime) Less(i, j int) bool {
 func (s TxByPriceAndTime) Less(i, j int) bool {
 	// If the prices are equal, use the time the transaction was first seen for
 	// If the prices are equal, use the time the transaction was first seen for
 	// deterministic sorting
 	// deterministic sorting
-	cmp := s[i].data.Price.Cmp(s[j].data.Price)
+	cmp := s[i].GasPrice().Cmp(s[j].GasPrice())
 	if cmp == 0 {
 	if cmp == 0 {
 		return s[i].time.Before(s[j].time)
 		return s[i].time.Before(s[j].time)
 	}
 	}
@@ -361,13 +432,13 @@ func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transa
 	// Initialize a price and received time based heap with the head transactions
 	// Initialize a price and received time based heap with the head transactions
 	heads := make(TxByPriceAndTime, 0, len(txs))
 	heads := make(TxByPriceAndTime, 0, len(txs))
 	for from, accTxs := range txs {
 	for from, accTxs := range txs {
-		heads = append(heads, accTxs[0])
 		// Ensure the sender address is from the signer
 		// Ensure the sender address is from the signer
-		acc, _ := Sender(signer, accTxs[0])
-		txs[acc] = accTxs[1:]
-		if from != acc {
+		if acc, _ := Sender(signer, accTxs[0]); acc != from {
 			delete(txs, from)
 			delete(txs, from)
+			continue
 		}
 		}
+		heads = append(heads, accTxs[0])
+		txs[from] = accTxs[1:]
 	}
 	}
 	heap.Init(&heads)
 	heap.Init(&heads)
 
 
@@ -416,10 +487,11 @@ type Message struct {
 	gasLimit   uint64
 	gasLimit   uint64
 	gasPrice   *big.Int
 	gasPrice   *big.Int
 	data       []byte
 	data       []byte
+	accessList AccessList
 	checkNonce bool
 	checkNonce bool
 }
 }
 
 
-func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, checkNonce bool) Message {
+func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, accessList AccessList, checkNonce bool) Message {
 	return Message{
 	return Message{
 		from:       from,
 		from:       from,
 		to:         to,
 		to:         to,
@@ -428,15 +500,35 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b
 		gasLimit:   gasLimit,
 		gasLimit:   gasLimit,
 		gasPrice:   gasPrice,
 		gasPrice:   gasPrice,
 		data:       data,
 		data:       data,
+		accessList: accessList,
 		checkNonce: checkNonce,
 		checkNonce: checkNonce,
 	}
 	}
 }
 }
 
 
-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.gasPrice }
-func (m Message) Value() *big.Int      { return m.amount }
-func (m Message) Gas() uint64          { 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 m.checkNonce }
+// AsMessage returns the transaction as a core.Message.
+func (tx *Transaction) AsMessage(s Signer) (Message, error) {
+	msg := Message{
+		nonce:      tx.Nonce(),
+		gasLimit:   tx.Gas(),
+		gasPrice:   new(big.Int).Set(tx.GasPrice()),
+		to:         tx.To(),
+		amount:     tx.Value(),
+		data:       tx.Data(),
+		accessList: tx.AccessList(),
+		checkNonce: true,
+	}
+
+	var err error
+	msg.from, err = Sender(s, tx)
+	return msg, err
+}
+
+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.gasPrice }
+func (m Message) Value() *big.Int        { return m.amount }
+func (m Message) Gas() uint64            { return m.gasLimit }
+func (m Message) Nonce() uint64          { return m.nonce }
+func (m Message) Data() []byte           { return m.data }
+func (m Message) AccessList() AccessList { return m.accessList }
+func (m Message) CheckNonce() bool       { return m.checkNonce }

+ 187 - 0
core/types/transaction_marshalling.go

@@ -0,0 +1,187 @@
+package types
+
+import (
+	"encoding/json"
+	"errors"
+	"math/big"
+
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/common/hexutil"
+)
+
+// txJSON is the JSON representation of transactions.
+type txJSON struct {
+	Type hexutil.Uint64 `json:"type"`
+
+	// Common transaction fields:
+	Nonce    *hexutil.Uint64 `json:"nonce"`
+	GasPrice *hexutil.Big    `json:"gasPrice"`
+	Gas      *hexutil.Uint64 `json:"gas"`
+	Value    *hexutil.Big    `json:"value"`
+	Data     *hexutil.Bytes  `json:"input"`
+	V        *hexutil.Big    `json:"v"`
+	R        *hexutil.Big    `json:"r"`
+	S        *hexutil.Big    `json:"s"`
+	To       *common.Address `json:"to"`
+
+	// Access list transaction fields:
+	ChainID    *hexutil.Big `json:"chainId,omitempty"`
+	AccessList *AccessList  `json:"accessList,omitempty"`
+
+	// Only used for encoding:
+	Hash common.Hash `json:"hash"`
+}
+
+// MarshalJSON marshals as JSON with a hash.
+func (t *Transaction) MarshalJSON() ([]byte, error) {
+	var enc txJSON
+	// These are set for all tx types.
+	enc.Hash = t.Hash()
+	enc.Type = hexutil.Uint64(t.Type())
+
+	// Other fields are set conditionally depending on tx type.
+	switch tx := t.inner.(type) {
+	case *LegacyTx:
+		enc.Nonce = (*hexutil.Uint64)(&tx.Nonce)
+		enc.Gas = (*hexutil.Uint64)(&tx.Gas)
+		enc.GasPrice = (*hexutil.Big)(tx.GasPrice)
+		enc.Value = (*hexutil.Big)(tx.Value)
+		enc.Data = (*hexutil.Bytes)(&tx.Data)
+		enc.To = t.To()
+		enc.V = (*hexutil.Big)(tx.V)
+		enc.R = (*hexutil.Big)(tx.R)
+		enc.S = (*hexutil.Big)(tx.S)
+	case *AccessListTx:
+		enc.ChainID = (*hexutil.Big)(tx.ChainID)
+		enc.AccessList = &tx.AccessList
+		enc.Nonce = (*hexutil.Uint64)(&tx.Nonce)
+		enc.Gas = (*hexutil.Uint64)(&tx.Gas)
+		enc.GasPrice = (*hexutil.Big)(tx.GasPrice)
+		enc.Value = (*hexutil.Big)(tx.Value)
+		enc.Data = (*hexutil.Bytes)(&tx.Data)
+		enc.To = t.To()
+		enc.V = (*hexutil.Big)(tx.V)
+		enc.R = (*hexutil.Big)(tx.R)
+		enc.S = (*hexutil.Big)(tx.S)
+	}
+	return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (t *Transaction) UnmarshalJSON(input []byte) error {
+	var dec txJSON
+	if err := json.Unmarshal(input, &dec); err != nil {
+		return err
+	}
+
+	// Decode / verify fields according to transaction type.
+	var inner TxData
+	switch dec.Type {
+	case LegacyTxType:
+		var itx LegacyTx
+		inner = &itx
+		if dec.To != nil {
+			itx.To = dec.To
+		}
+		if dec.Nonce == nil {
+			return errors.New("missing required field 'nonce' in transaction")
+		}
+		itx.Nonce = uint64(*dec.Nonce)
+		if dec.GasPrice == nil {
+			return errors.New("missing required field 'gasPrice' in transaction")
+		}
+		itx.GasPrice = (*big.Int)(dec.GasPrice)
+		if dec.Gas == nil {
+			return errors.New("missing required field 'gas' in transaction")
+		}
+		itx.Gas = uint64(*dec.Gas)
+		if dec.Value == nil {
+			return errors.New("missing required field 'value' in transaction")
+		}
+		itx.Value = (*big.Int)(dec.Value)
+		if dec.Data == nil {
+			return errors.New("missing required field 'input' in transaction")
+		}
+		itx.Data = *dec.Data
+		if dec.V == nil {
+			return errors.New("missing required field 'v' in transaction")
+		}
+		itx.V = (*big.Int)(dec.V)
+		if dec.R == nil {
+			return errors.New("missing required field 'r' in transaction")
+		}
+		itx.R = (*big.Int)(dec.R)
+		if dec.S == nil {
+			return errors.New("missing required field 's' in transaction")
+		}
+		itx.S = (*big.Int)(dec.S)
+		withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0
+		if withSignature {
+			if err := sanityCheckSignature(itx.V, itx.R, itx.S, true); err != nil {
+				return err
+			}
+		}
+
+	case AccessListTxType:
+		var itx AccessListTx
+		inner = &itx
+		// Access list is optional for now.
+		if dec.AccessList != nil {
+			itx.AccessList = *dec.AccessList
+		}
+		if dec.ChainID == nil {
+			return errors.New("missing required field 'chainId' in transaction")
+		}
+		itx.ChainID = (*big.Int)(dec.ChainID)
+		if dec.To != nil {
+			itx.To = dec.To
+		}
+		if dec.Nonce == nil {
+			return errors.New("missing required field 'nonce' in transaction")
+		}
+		itx.Nonce = uint64(*dec.Nonce)
+		if dec.GasPrice == nil {
+			return errors.New("missing required field 'gasPrice' in transaction")
+		}
+		itx.GasPrice = (*big.Int)(dec.GasPrice)
+		if dec.Gas == nil {
+			return errors.New("missing required field 'gas' in transaction")
+		}
+		itx.Gas = uint64(*dec.Gas)
+		if dec.Value == nil {
+			return errors.New("missing required field 'value' in transaction")
+		}
+		itx.Value = (*big.Int)(dec.Value)
+		if dec.Data == nil {
+			return errors.New("missing required field 'input' in transaction")
+		}
+		itx.Data = *dec.Data
+		if dec.V == nil {
+			return errors.New("missing required field 'v' in transaction")
+		}
+		itx.V = (*big.Int)(dec.V)
+		if dec.R == nil {
+			return errors.New("missing required field 'r' in transaction")
+		}
+		itx.R = (*big.Int)(dec.R)
+		if dec.S == nil {
+			return errors.New("missing required field 's' in transaction")
+		}
+		itx.S = (*big.Int)(dec.S)
+		withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0
+		if withSignature {
+			if err := sanityCheckSignature(itx.V, itx.R, itx.S, false); err != nil {
+				return err
+			}
+		}
+
+	default:
+		return ErrTxTypeNotSupported
+	}
+
+	// Now set the inner transaction.
+	t.setDecoded(inner, 0)
+
+	// TODO: check hash here?
+	return nil
+}

+ 226 - 33
core/types/transaction_signing.go

@@ -27,9 +27,7 @@ import (
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
 )
 )
 
 
-var (
-	ErrInvalidChainId = errors.New("invalid chain id for signer")
-)
+var ErrInvalidChainId = errors.New("invalid chain id for signer")
 
 
 // sigCache is used to cache the derived sender and contains
 // sigCache is used to cache the derived sender and contains
 // the signer used to derive it.
 // the signer used to derive it.
@@ -42,6 +40,8 @@ type sigCache struct {
 func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
 func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
 	var signer Signer
 	var signer Signer
 	switch {
 	switch {
+	case config.IsYoloV3(blockNumber):
+		signer = NewEIP2930Signer(config.ChainID)
 	case config.IsEIP155(blockNumber):
 	case config.IsEIP155(blockNumber):
 		signer = NewEIP155Signer(config.ChainID)
 		signer = NewEIP155Signer(config.ChainID)
 	case config.IsHomestead(blockNumber):
 	case config.IsHomestead(blockNumber):
@@ -52,7 +52,40 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
 	return signer
 	return signer
 }
 }
 
 
-// SignTx signs the transaction using the given signer and private key
+// LatestSigner returns the 'most permissive' Signer available for the given chain
+// configuration. Specifically, this enables support of EIP-155 replay protection and
+// EIP-2930 access list transactions when their respective forks are scheduled to occur at
+// any block number in the chain config.
+//
+// Use this in transaction-handling code where the current block number is unknown. If you
+// have the current block number available, use MakeSigner instead.
+func LatestSigner(config *params.ChainConfig) Signer {
+	if config.ChainID != nil {
+		if config.YoloV3Block != nil {
+			return NewEIP2930Signer(config.ChainID)
+		}
+		if config.EIP155Block != nil {
+			return NewEIP155Signer(config.ChainID)
+		}
+	}
+	return HomesteadSigner{}
+}
+
+// LatestSignerForChainID returns the 'most permissive' Signer available. Specifically,
+// this enables support for EIP-155 replay protection and all implemented EIP-2718
+// transaction types if chainID is non-nil.
+//
+// Use this in transaction-handling code where the current block number and fork
+// configuration are unknown. If you have a ChainConfig, use LatestSigner instead.
+// If you have a ChainConfig and know the current block number, use MakeSigner instead.
+func LatestSignerForChainID(chainID *big.Int) Signer {
+	if chainID == nil {
+		return HomesteadSigner{}
+	}
+	return NewEIP2930Signer(chainID)
+}
+
+// SignTx signs the transaction using the given signer and private key.
 func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
 func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
 	h := s.Hash(tx)
 	h := s.Hash(tx)
 	sig, err := crypto.Sign(h[:], prv)
 	sig, err := crypto.Sign(h[:], prv)
@@ -62,6 +95,27 @@ func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, err
 	return tx.WithSignature(s, sig)
 	return tx.WithSignature(s, sig)
 }
 }
 
 
+// SignNewTx creates a transaction and signs it.
+func SignNewTx(prv *ecdsa.PrivateKey, s Signer, txdata TxData) (*Transaction, error) {
+	tx := NewTx(txdata)
+	h := s.Hash(tx)
+	sig, err := crypto.Sign(h[:], prv)
+	if err != nil {
+		return nil, err
+	}
+	return tx.WithSignature(s, sig)
+}
+
+// MustSignNewTx creates a transaction and signs it.
+// This panics if the transaction cannot be signed.
+func MustSignNewTx(prv *ecdsa.PrivateKey, s Signer, txdata TxData) *Transaction {
+	tx, err := SignNewTx(prv, s, txdata)
+	if err != nil {
+		panic(err)
+	}
+	return tx
+}
+
 // Sender returns the address derived from the signature (V, R, S) using secp256k1
 // 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
 // elliptic curve and an error if it failed deriving or upon an incorrect
 // signature.
 // signature.
@@ -88,21 +142,128 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) {
 	return addr, nil
 	return addr, nil
 }
 }
 
 
-// Signer encapsulates transaction signature handling. Note that this interface is not a
-// stable API and may change at any time to accommodate new protocol rules.
+// Signer encapsulates transaction signature handling. The name of this type is slightly
+// misleading because Signers don't actually sign, they're just for validating and
+// processing of signatures.
+//
+// Note that this interface is not a stable API and may change at any time to accommodate
+// new protocol rules.
 type Signer interface {
 type Signer interface {
 	// Sender returns the sender address of the transaction.
 	// Sender returns the sender address of the transaction.
 	Sender(tx *Transaction) (common.Address, error)
 	Sender(tx *Transaction) (common.Address, error)
+
 	// SignatureValues returns the raw R, S, V values corresponding to the
 	// SignatureValues returns the raw R, S, V values corresponding to the
 	// given signature.
 	// given signature.
 	SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error)
 	SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error)
-	// Hash returns the hash to be signed.
+	ChainID() *big.Int
+
+	// Hash returns 'signature hash', i.e. the transaction hash that is signed by the
+	// private key. This hash does not uniquely identify the transaction.
 	Hash(tx *Transaction) common.Hash
 	Hash(tx *Transaction) common.Hash
+
 	// Equal returns true if the given signer is the same as the receiver.
 	// Equal returns true if the given signer is the same as the receiver.
 	Equal(Signer) bool
 	Equal(Signer) bool
 }
 }
 
 
-// EIP155Transaction implements Signer using the EIP155 rules.
+type eip2930Signer struct{ EIP155Signer }
+
+// NewEIP2930Signer returns a signer that accepts EIP-2930 access list transactions,
+// EIP-155 replay protected transactions, and legacy Homestead transactions.
+func NewEIP2930Signer(chainId *big.Int) Signer {
+	return eip2930Signer{NewEIP155Signer(chainId)}
+}
+
+func (s eip2930Signer) ChainID() *big.Int {
+	return s.chainId
+}
+
+func (s eip2930Signer) Equal(s2 Signer) bool {
+	x, ok := s2.(eip2930Signer)
+	return ok && x.chainId.Cmp(s.chainId) == 0
+}
+
+func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) {
+	V, R, S := tx.RawSignatureValues()
+	switch tx.Type() {
+	case LegacyTxType:
+		if !tx.Protected() {
+			return HomesteadSigner{}.Sender(tx)
+		}
+		V = new(big.Int).Sub(V, s.chainIdMul)
+		V.Sub(V, big8)
+	case AccessListTxType:
+		// ACL txs are defined to use 0 and 1 as their recovery id, add
+		// 27 to become equivalent to unprotected Homestead signatures.
+		V = new(big.Int).Add(V, big.NewInt(27))
+	default:
+		return common.Address{}, ErrTxTypeNotSupported
+	}
+	if tx.ChainId().Cmp(s.chainId) != 0 {
+		return common.Address{}, ErrInvalidChainId
+	}
+	return recoverPlain(s.Hash(tx), R, S, V, true)
+}
+
+func (s eip2930Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
+	switch txdata := tx.inner.(type) {
+	case *LegacyTx:
+		R, S, V = decodeSignature(sig)
+		if s.chainId.Sign() != 0 {
+			V = big.NewInt(int64(sig[64] + 35))
+			V.Add(V, s.chainIdMul)
+		}
+	case *AccessListTx:
+		// Check that chain ID of tx matches the signer. We also accept ID zero here,
+		// because it indicates that the chain ID was not specified in the tx.
+		if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 {
+			return nil, nil, nil, ErrInvalidChainId
+		}
+		R, S, _ = decodeSignature(sig)
+		V = big.NewInt(int64(sig[64]))
+	default:
+		return nil, nil, nil, ErrTxTypeNotSupported
+	}
+	return R, S, V, nil
+}
+
+// Hash returns the hash to be signed by the sender.
+// It does not uniquely identify the transaction.
+func (s eip2930Signer) Hash(tx *Transaction) common.Hash {
+	switch tx.Type() {
+	case LegacyTxType:
+		return rlpHash([]interface{}{
+			tx.Nonce(),
+			tx.GasPrice(),
+			tx.Gas(),
+			tx.To(),
+			tx.Value(),
+			tx.Data(),
+			s.chainId, uint(0), uint(0),
+		})
+	case AccessListTxType:
+		return prefixedRlpHash(
+			tx.Type(),
+			[]interface{}{
+				s.chainId,
+				tx.Nonce(),
+				tx.GasPrice(),
+				tx.Gas(),
+				tx.To(),
+				tx.Value(),
+				tx.Data(),
+				tx.AccessList(),
+			})
+	default:
+		// This _should_ not happen, but in case someone sends in a bad
+		// json struct via RPC, it's probably more prudent to return an
+		// empty hash instead of killing the node with a panic
+		//panic("Unsupported transaction type: %d", tx.typ)
+		return common.Hash{}
+	}
+}
+
+// EIP155Signer implements Signer using the EIP-155 rules. This accepts transactions which
+// are replay-protected as well as unprotected homestead transactions.
 type EIP155Signer struct {
 type EIP155Signer struct {
 	chainId, chainIdMul *big.Int
 	chainId, chainIdMul *big.Int
 }
 }
@@ -117,6 +278,10 @@ func NewEIP155Signer(chainId *big.Int) EIP155Signer {
 	}
 	}
 }
 }
 
 
+func (s EIP155Signer) ChainID() *big.Int {
+	return s.chainId
+}
+
 func (s EIP155Signer) Equal(s2 Signer) bool {
 func (s EIP155Signer) Equal(s2 Signer) bool {
 	eip155, ok := s2.(EIP155Signer)
 	eip155, ok := s2.(EIP155Signer)
 	return ok && eip155.chainId.Cmp(s.chainId) == 0
 	return ok && eip155.chainId.Cmp(s.chainId) == 0
@@ -125,24 +290,28 @@ func (s EIP155Signer) Equal(s2 Signer) bool {
 var big8 = big.NewInt(8)
 var big8 = big.NewInt(8)
 
 
 func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
 func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
+	if tx.Type() != LegacyTxType {
+		return common.Address{}, ErrTxTypeNotSupported
+	}
 	if !tx.Protected() {
 	if !tx.Protected() {
 		return HomesteadSigner{}.Sender(tx)
 		return HomesteadSigner{}.Sender(tx)
 	}
 	}
 	if tx.ChainId().Cmp(s.chainId) != 0 {
 	if tx.ChainId().Cmp(s.chainId) != 0 {
 		return common.Address{}, ErrInvalidChainId
 		return common.Address{}, ErrInvalidChainId
 	}
 	}
-	V := new(big.Int).Sub(tx.data.V, s.chainIdMul)
+	V, R, S := tx.RawSignatureValues()
+	V = new(big.Int).Sub(V, s.chainIdMul)
 	V.Sub(V, big8)
 	V.Sub(V, big8)
-	return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true)
+	return recoverPlain(s.Hash(tx), R, S, V, true)
 }
 }
 
 
 // SignatureValues returns signature values. This signature
 // SignatureValues returns signature values. This signature
 // needs to be in the [R || S || V] format where V is 0 or 1.
 // needs to be in the [R || S || V] format where V is 0 or 1.
 func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
 func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
-	R, S, V, err = HomesteadSigner{}.SignatureValues(tx, sig)
-	if err != nil {
-		return nil, nil, nil, err
+	if tx.Type() != LegacyTxType {
+		return nil, nil, nil, ErrTxTypeNotSupported
 	}
 	}
+	R, S, V = decodeSignature(sig)
 	if s.chainId.Sign() != 0 {
 	if s.chainId.Sign() != 0 {
 		V = big.NewInt(int64(sig[64] + 35))
 		V = big.NewInt(int64(sig[64] + 35))
 		V.Add(V, s.chainIdMul)
 		V.Add(V, s.chainIdMul)
@@ -154,12 +323,12 @@ func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big
 // It does not uniquely identify the transaction.
 // It does not uniquely identify the transaction.
 func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
 func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
 	return rlpHash([]interface{}{
 	return rlpHash([]interface{}{
-		tx.data.AccountNonce,
-		tx.data.Price,
-		tx.data.GasLimit,
-		tx.data.Recipient,
-		tx.data.Amount,
-		tx.data.Payload,
+		tx.Nonce(),
+		tx.GasPrice(),
+		tx.Gas(),
+		tx.To(),
+		tx.Value(),
+		tx.Data(),
 		s.chainId, uint(0), uint(0),
 		s.chainId, uint(0), uint(0),
 	})
 	})
 }
 }
@@ -168,6 +337,10 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
 // homestead rules.
 // homestead rules.
 type HomesteadSigner struct{ FrontierSigner }
 type HomesteadSigner struct{ FrontierSigner }
 
 
+func (s HomesteadSigner) ChainID() *big.Int {
+	return nil
+}
+
 func (s HomesteadSigner) Equal(s2 Signer) bool {
 func (s HomesteadSigner) Equal(s2 Signer) bool {
 	_, ok := s2.(HomesteadSigner)
 	_, ok := s2.(HomesteadSigner)
 	return ok
 	return ok
@@ -180,25 +353,39 @@ func (hs HomesteadSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v
 }
 }
 
 
 func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
 func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
-	return recoverPlain(hs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, true)
+	if tx.Type() != LegacyTxType {
+		return common.Address{}, ErrTxTypeNotSupported
+	}
+	v, r, s := tx.RawSignatureValues()
+	return recoverPlain(hs.Hash(tx), r, s, v, true)
 }
 }
 
 
 type FrontierSigner struct{}
 type FrontierSigner struct{}
 
 
+func (s FrontierSigner) ChainID() *big.Int {
+	return nil
+}
+
 func (s FrontierSigner) Equal(s2 Signer) bool {
 func (s FrontierSigner) Equal(s2 Signer) bool {
 	_, ok := s2.(FrontierSigner)
 	_, ok := s2.(FrontierSigner)
 	return ok
 	return ok
 }
 }
 
 
+func (fs FrontierSigner) Sender(tx *Transaction) (common.Address, error) {
+	if tx.Type() != LegacyTxType {
+		return common.Address{}, ErrTxTypeNotSupported
+	}
+	v, r, s := tx.RawSignatureValues()
+	return recoverPlain(fs.Hash(tx), r, s, v, false)
+}
+
 // SignatureValues returns signature values. This signature
 // SignatureValues returns signature values. This signature
 // needs to be in the [R || S || V] format where V is 0 or 1.
 // needs to be in the [R || S || V] format where V is 0 or 1.
 func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
 func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
-	if len(sig) != crypto.SignatureLength {
-		panic(fmt.Sprintf("wrong size for signature: got %d, want %d", len(sig), crypto.SignatureLength))
+	if tx.Type() != LegacyTxType {
+		return nil, nil, nil, ErrTxTypeNotSupported
 	}
 	}
-	r = new(big.Int).SetBytes(sig[:32])
-	s = new(big.Int).SetBytes(sig[32:64])
-	v = new(big.Int).SetBytes([]byte{sig[64] + 27})
+	r, s, v = decodeSignature(sig)
 	return r, s, v, nil
 	return r, s, v, nil
 }
 }
 
 
@@ -206,17 +393,23 @@ func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *
 // It does not uniquely identify the transaction.
 // It does not uniquely identify the transaction.
 func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
 func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
 	return rlpHash([]interface{}{
 	return rlpHash([]interface{}{
-		tx.data.AccountNonce,
-		tx.data.Price,
-		tx.data.GasLimit,
-		tx.data.Recipient,
-		tx.data.Amount,
-		tx.data.Payload,
+		tx.Nonce(),
+		tx.GasPrice(),
+		tx.Gas(),
+		tx.To(),
+		tx.Value(),
+		tx.Data(),
 	})
 	})
 }
 }
 
 
-func (fs FrontierSigner) Sender(tx *Transaction) (common.Address, error) {
-	return recoverPlain(fs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, false)
+func decodeSignature(sig []byte) (r, s, v *big.Int) {
+	if len(sig) != crypto.SignatureLength {
+		panic(fmt.Sprintf("wrong size for signature: got %d, want %d", len(sig), crypto.SignatureLength))
+	}
+	r = new(big.Int).SetBytes(sig[:32])
+	s = new(big.Int).SetBytes(sig[32:64])
+	v = new(big.Int).SetBytes([]byte{sig[64] + 27})
+	return r, s, v
 }
 }
 
 
 func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
 func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {

+ 245 - 31
core/types/transaction_test.go

@@ -20,7 +20,9 @@ import (
 	"bytes"
 	"bytes"
 	"crypto/ecdsa"
 	"crypto/ecdsa"
 	"encoding/json"
 	"encoding/json"
+	"fmt"
 	"math/big"
 	"math/big"
+	"reflect"
 	"testing"
 	"testing"
 	"time"
 	"time"
 
 
@@ -32,6 +34,8 @@ import (
 // The values in those tests are from the Transaction Tests
 // The values in those tests are from the Transaction Tests
 // at github.com/ethereum/tests.
 // at github.com/ethereum/tests.
 var (
 var (
+	testAddr = common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b")
+
 	emptyTx = NewTransaction(
 	emptyTx = NewTransaction(
 		0,
 		0,
 		common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
 		common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
@@ -41,7 +45,7 @@ var (
 
 
 	rightvrsTx, _ = NewTransaction(
 	rightvrsTx, _ = NewTransaction(
 		3,
 		3,
-		common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
+		testAddr,
 		big.NewInt(10),
 		big.NewInt(10),
 		2000,
 		2000,
 		big.NewInt(1),
 		big.NewInt(1),
@@ -50,8 +54,32 @@ var (
 		HomesteadSigner{},
 		HomesteadSigner{},
 		common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a301"),
 		common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a301"),
 	)
 	)
+
+	emptyEip2718Tx = NewTx(&AccessListTx{
+		ChainID:  big.NewInt(1),
+		Nonce:    3,
+		To:       &testAddr,
+		Value:    big.NewInt(10),
+		Gas:      25000,
+		GasPrice: big.NewInt(1),
+		Data:     common.FromHex("5544"),
+	})
+
+	signedEip2718Tx, _ = emptyEip2718Tx.WithSignature(
+		NewEIP2930Signer(big.NewInt(1)),
+		common.Hex2Bytes("c9519f4f2b30335884581971573fadf60c6204f59a911df35ee8a540456b266032f1e8e2c5dd761f9e4f88f41c8310aeaba26a8bfcdacfedfa12ec3862d3752101"),
+	)
 )
 )
 
 
+func TestDecodeEmptyTypedTx(t *testing.T) {
+	input := []byte{0x80}
+	var tx Transaction
+	err := rlp.DecodeBytes(input, &tx)
+	if err != errEmptyTypedTx {
+		t.Fatal("wrong error:", err)
+	}
+}
+
 func TestTransactionSigHash(t *testing.T) {
 func TestTransactionSigHash(t *testing.T) {
 	var homestead HomesteadSigner
 	var homestead HomesteadSigner
 	if homestead.Hash(emptyTx) != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") {
 	if homestead.Hash(emptyTx) != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") {
@@ -73,10 +101,121 @@ func TestTransactionEncode(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestEIP2718TransactionSigHash(t *testing.T) {
+	s := NewEIP2930Signer(big.NewInt(1))
+	if s.Hash(emptyEip2718Tx) != common.HexToHash("49b486f0ec0a60dfbbca2d30cb07c9e8ffb2a2ff41f29a1ab6737475f6ff69f3") {
+		t.Errorf("empty EIP-2718 transaction hash mismatch, got %x", s.Hash(emptyEip2718Tx))
+	}
+	if s.Hash(signedEip2718Tx) != common.HexToHash("49b486f0ec0a60dfbbca2d30cb07c9e8ffb2a2ff41f29a1ab6737475f6ff69f3") {
+		t.Errorf("signed EIP-2718 transaction hash mismatch, got %x", s.Hash(signedEip2718Tx))
+	}
+}
+
+// This test checks signature operations on access list transactions.
+func TestEIP2930Signer(t *testing.T) {
+
+	var (
+		key, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+		keyAddr = crypto.PubkeyToAddress(key.PublicKey)
+		signer1 = NewEIP2930Signer(big.NewInt(1))
+		signer2 = NewEIP2930Signer(big.NewInt(2))
+		tx0     = NewTx(&AccessListTx{Nonce: 1})
+		tx1     = NewTx(&AccessListTx{ChainID: big.NewInt(1), Nonce: 1})
+		tx2, _  = SignNewTx(key, signer2, &AccessListTx{ChainID: big.NewInt(2), Nonce: 1})
+	)
+
+	tests := []struct {
+		tx             *Transaction
+		signer         Signer
+		wantSignerHash common.Hash
+		wantSenderErr  error
+		wantSignErr    error
+		wantHash       common.Hash // after signing
+	}{
+		{
+			tx:             tx0,
+			signer:         signer1,
+			wantSignerHash: common.HexToHash("846ad7672f2a3a40c1f959cd4a8ad21786d620077084d84c8d7c077714caa139"),
+			wantSenderErr:  ErrInvalidChainId,
+			wantHash:       common.HexToHash("1ccd12d8bbdb96ea391af49a35ab641e219b2dd638dea375f2bc94dd290f2549"),
+		},
+		{
+			tx:             tx1,
+			signer:         signer1,
+			wantSenderErr:  ErrInvalidSig,
+			wantSignerHash: common.HexToHash("846ad7672f2a3a40c1f959cd4a8ad21786d620077084d84c8d7c077714caa139"),
+			wantHash:       common.HexToHash("1ccd12d8bbdb96ea391af49a35ab641e219b2dd638dea375f2bc94dd290f2549"),
+		},
+		{
+			// This checks what happens when trying to sign an unsigned tx for the wrong chain.
+			tx:             tx1,
+			signer:         signer2,
+			wantSenderErr:  ErrInvalidChainId,
+			wantSignerHash: common.HexToHash("367967247499343401261d718ed5aa4c9486583e4d89251afce47f4a33c33362"),
+			wantSignErr:    ErrInvalidChainId,
+		},
+		{
+			// This checks what happens when trying to re-sign a signed tx for the wrong chain.
+			tx:             tx2,
+			signer:         signer1,
+			wantSenderErr:  ErrInvalidChainId,
+			wantSignerHash: common.HexToHash("846ad7672f2a3a40c1f959cd4a8ad21786d620077084d84c8d7c077714caa139"),
+			wantSignErr:    ErrInvalidChainId,
+		},
+	}
+
+	for i, test := range tests {
+		sigHash := test.signer.Hash(test.tx)
+		if sigHash != test.wantSignerHash {
+			t.Errorf("test %d: wrong sig hash: got %x, want %x", i, sigHash, test.wantSignerHash)
+		}
+		sender, err := Sender(test.signer, test.tx)
+		if err != test.wantSenderErr {
+			t.Errorf("test %d: wrong Sender error %q", i, err)
+		}
+		if err == nil && sender != keyAddr {
+			t.Errorf("test %d: wrong sender address %x", i, sender)
+		}
+		signedTx, err := SignTx(test.tx, test.signer, key)
+		if err != test.wantSignErr {
+			t.Fatalf("test %d: wrong SignTx error %q", i, err)
+		}
+		if signedTx != nil {
+			if signedTx.Hash() != test.wantHash {
+				t.Errorf("test %d: wrong tx hash after signing: got %x, want %x", i, signedTx.Hash(), test.wantHash)
+			}
+		}
+	}
+}
+
+func TestEIP2718TransactionEncode(t *testing.T) {
+	// RLP representation
+	{
+		have, err := rlp.EncodeToBytes(signedEip2718Tx)
+		if err != nil {
+			t.Fatalf("encode error: %v", err)
+		}
+		want := common.FromHex("b86601f8630103018261a894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a825544c001a0c9519f4f2b30335884581971573fadf60c6204f59a911df35ee8a540456b2660a032f1e8e2c5dd761f9e4f88f41c8310aeaba26a8bfcdacfedfa12ec3862d37521")
+		if !bytes.Equal(have, want) {
+			t.Errorf("encoded RLP mismatch, got %x", have)
+		}
+	}
+	// Binary representation
+	{
+		have, err := signedEip2718Tx.MarshalBinary()
+		if err != nil {
+			t.Fatalf("encode error: %v", err)
+		}
+		want := common.FromHex("01f8630103018261a894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a825544c001a0c9519f4f2b30335884581971573fadf60c6204f59a911df35ee8a540456b2660a032f1e8e2c5dd761f9e4f88f41c8310aeaba26a8bfcdacfedfa12ec3862d37521")
+		if !bytes.Equal(have, want) {
+			t.Errorf("encoded RLP mismatch, got %x", have)
+		}
+	}
+}
+
 func decodeTx(data []byte) (*Transaction, error) {
 func decodeTx(data []byte) (*Transaction, error) {
 	var tx Transaction
 	var tx Transaction
 	t, err := &tx, rlp.Decode(bytes.NewReader(data), &tx)
 	t, err := &tx, rlp.Decode(bytes.NewReader(data), &tx)
-
 	return t, err
 	return t, err
 }
 }
 
 
@@ -219,50 +358,125 @@ func TestTransactionTimeSort(t *testing.T) {
 	}
 	}
 }
 }
 
 
-// TestTransactionJSON tests serializing/de-serializing to/from JSON.
-func TestTransactionJSON(t *testing.T) {
+// TestTransactionCoding tests serializing/de-serializing to/from rlp and JSON.
+func TestTransactionCoding(t *testing.T) {
 	key, err := crypto.GenerateKey()
 	key, err := crypto.GenerateKey()
 	if err != nil {
 	if err != nil {
 		t.Fatalf("could not generate key: %v", err)
 		t.Fatalf("could not generate key: %v", err)
 	}
 	}
-	signer := NewEIP155Signer(common.Big1)
-
-	transactions := make([]*Transaction, 0, 50)
-	for i := uint64(0); i < 25; i++ {
-		var tx *Transaction
-		switch i % 2 {
+	var (
+		signer    = NewEIP2930Signer(common.Big1)
+		addr      = common.HexToAddress("0x0000000000000000000000000000000000000001")
+		recipient = common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87")
+		accesses  = AccessList{{Address: addr, StorageKeys: []common.Hash{{0}}}}
+	)
+	for i := uint64(0); i < 500; i++ {
+		var txdata TxData
+		switch i % 5 {
 		case 0:
 		case 0:
-			tx = NewTransaction(i, common.Address{1}, common.Big0, 1, common.Big2, []byte("abcdef"))
+			// Legacy tx.
+			txdata = &LegacyTx{
+				Nonce:    i,
+				To:       &recipient,
+				Gas:      1,
+				GasPrice: big.NewInt(2),
+				Data:     []byte("abcdef"),
+			}
 		case 1:
 		case 1:
-			tx = NewContractCreation(i, common.Big0, 1, common.Big2, []byte("abcdef"))
+			// Legacy tx contract creation.
+			txdata = &LegacyTx{
+				Nonce:    i,
+				Gas:      1,
+				GasPrice: big.NewInt(2),
+				Data:     []byte("abcdef"),
+			}
+		case 2:
+			// Tx with non-zero access list.
+			txdata = &AccessListTx{
+				ChainID:    big.NewInt(1),
+				Nonce:      i,
+				To:         &recipient,
+				Gas:        123457,
+				GasPrice:   big.NewInt(10),
+				AccessList: accesses,
+				Data:       []byte("abcdef"),
+			}
+		case 3:
+			// Tx with empty access list.
+			txdata = &AccessListTx{
+				ChainID:  big.NewInt(1),
+				Nonce:    i,
+				To:       &recipient,
+				Gas:      123457,
+				GasPrice: big.NewInt(10),
+				Data:     []byte("abcdef"),
+			}
+		case 4:
+			// Contract creation with access list.
+			txdata = &AccessListTx{
+				ChainID:    big.NewInt(1),
+				Nonce:      i,
+				Gas:        123457,
+				GasPrice:   big.NewInt(10),
+				AccessList: accesses,
+			}
 		}
 		}
-		transactions = append(transactions, tx)
-
-		signedTx, err := SignTx(tx, signer, key)
+		tx, err := SignNewTx(key, signer, txdata)
 		if err != nil {
 		if err != nil {
 			t.Fatalf("could not sign transaction: %v", err)
 			t.Fatalf("could not sign transaction: %v", err)
 		}
 		}
-
-		transactions = append(transactions, signedTx)
-	}
-
-	for _, tx := range transactions {
-		data, err := json.Marshal(tx)
+		// RLP
+		parsedTx, err := encodeDecodeBinary(tx)
 		if err != nil {
 		if err != nil {
-			t.Fatalf("json.Marshal failed: %v", err)
+			t.Fatal(err)
 		}
 		}
+		assertEqual(parsedTx, tx)
 
 
-		var parsedTx *Transaction
-		if err := json.Unmarshal(data, &parsedTx); err != nil {
-			t.Fatalf("json.Unmarshal failed: %v", err)
+		// JSON
+		parsedTx, err = encodeDecodeJSON(tx)
+		if err != nil {
+			t.Fatal(err)
 		}
 		}
+		assertEqual(parsedTx, tx)
+	}
+}
 
 
-		// compare nonce, price, gaslimit, recipient, amount, payload, V, R, S
-		if tx.Hash() != parsedTx.Hash() {
-			t.Errorf("parsed tx differs from original tx, want %v, got %v", tx, parsedTx)
-		}
-		if tx.ChainId().Cmp(parsedTx.ChainId()) != 0 {
-			t.Errorf("invalid chain id, want %d, got %d", tx.ChainId(), parsedTx.ChainId())
+func encodeDecodeJSON(tx *Transaction) (*Transaction, error) {
+	data, err := json.Marshal(tx)
+	if err != nil {
+		return nil, fmt.Errorf("json encoding failed: %v", err)
+	}
+	var parsedTx = &Transaction{}
+	if err := json.Unmarshal(data, &parsedTx); err != nil {
+		return nil, fmt.Errorf("json decoding failed: %v", err)
+	}
+	return parsedTx, nil
+}
+
+func encodeDecodeBinary(tx *Transaction) (*Transaction, error) {
+	data, err := tx.MarshalBinary()
+	if err != nil {
+		return nil, fmt.Errorf("rlp encoding failed: %v", err)
+	}
+	var parsedTx = &Transaction{}
+	if err := parsedTx.UnmarshalBinary(data); err != nil {
+		return nil, fmt.Errorf("rlp decoding failed: %v", err)
+	}
+	return parsedTx, nil
+}
+
+func assertEqual(orig *Transaction, cpy *Transaction) error {
+	// compare nonce, price, gaslimit, recipient, amount, payload, V, R, S
+	if want, got := orig.Hash(), cpy.Hash(); want != got {
+		return fmt.Errorf("parsed tx differs from original tx, want %v, got %v", want, got)
+	}
+	if want, got := orig.ChainId(), cpy.ChainId(); want.Cmp(got) != 0 {
+		return fmt.Errorf("invalid chain id, want %d, got %d", want, got)
+	}
+	if orig.AccessList() != nil {
+		if !reflect.DeepEqual(orig.AccessList(), cpy.AccessList()) {
+			return fmt.Errorf("access list wrong!")
 		}
 		}
 	}
 	}
+	return nil
 }
 }

+ 1 - 0
core/vm/interface.go

@@ -57,6 +57,7 @@ type StateDB interface {
 	// is defined according to EIP161 (balance = nonce = code = 0).
 	// is defined according to EIP161 (balance = nonce = code = 0).
 	Empty(common.Address) bool
 	Empty(common.Address) bool
 
 
+	PrepareAccessList(sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
 	AddressInAccessList(addr common.Address) bool
 	AddressInAccessList(addr common.Address) bool
 	SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
 	SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
 	// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
 	// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform

+ 4 - 14
core/vm/runtime/runtime.go

@@ -114,11 +114,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
 		sender  = vm.AccountRef(cfg.Origin)
 		sender  = vm.AccountRef(cfg.Origin)
 	)
 	)
 	if cfg.ChainConfig.IsYoloV3(vmenv.Context.BlockNumber) {
 	if cfg.ChainConfig.IsYoloV3(vmenv.Context.BlockNumber) {
-		cfg.State.AddAddressToAccessList(cfg.Origin)
-		cfg.State.AddAddressToAccessList(address)
-		for _, addr := range vmenv.ActivePrecompiles() {
-			cfg.State.AddAddressToAccessList(addr)
-		}
+		cfg.State.PrepareAccessList(cfg.Origin, &address, vmenv.ActivePrecompiles(), nil)
 	}
 	}
 	cfg.State.CreateAccount(address)
 	cfg.State.CreateAccount(address)
 	// set the receiver's (the executing contract) code for execution.
 	// set the receiver's (the executing contract) code for execution.
@@ -150,10 +146,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
 		sender = vm.AccountRef(cfg.Origin)
 		sender = vm.AccountRef(cfg.Origin)
 	)
 	)
 	if cfg.ChainConfig.IsYoloV3(vmenv.Context.BlockNumber) {
 	if cfg.ChainConfig.IsYoloV3(vmenv.Context.BlockNumber) {
-		cfg.State.AddAddressToAccessList(cfg.Origin)
-		for _, addr := range vmenv.ActivePrecompiles() {
-			cfg.State.AddAddressToAccessList(addr)
-		}
+		cfg.State.PrepareAccessList(cfg.Origin, nil, vmenv.ActivePrecompiles(), nil)
 	}
 	}
 
 
 	// Call the code with the given configuration.
 	// Call the code with the given configuration.
@@ -177,12 +170,9 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
 	vmenv := NewEnv(cfg)
 	vmenv := NewEnv(cfg)
 
 
 	sender := cfg.State.GetOrNewStateObject(cfg.Origin)
 	sender := cfg.State.GetOrNewStateObject(cfg.Origin)
+	statedb := cfg.State
 	if cfg.ChainConfig.IsYoloV3(vmenv.Context.BlockNumber) {
 	if cfg.ChainConfig.IsYoloV3(vmenv.Context.BlockNumber) {
-		cfg.State.AddAddressToAccessList(cfg.Origin)
-		cfg.State.AddAddressToAccessList(address)
-		for _, addr := range vmenv.ActivePrecompiles() {
-			cfg.State.AddAddressToAccessList(addr)
-		}
+		statedb.PrepareAccessList(cfg.Origin, &address, vmenv.ActivePrecompiles(), nil)
 	}
 	}
 
 
 	// Call the code with the given configuration.
 	// Call the code with the given configuration.

+ 1 - 1
eth/downloader/downloader.go

@@ -1387,7 +1387,7 @@ func (d *Downloader) fetchParts(deliveryCh chan dataPack, deliver func(dataPack)
 				case err == nil:
 				case err == nil:
 					peer.log.Trace("Delivered new batch of data", "type", kind, "count", packet.Stats())
 					peer.log.Trace("Delivered new batch of data", "type", kind, "count", packet.Stats())
 				default:
 				default:
-					peer.log.Trace("Failed to deliver retrieved data", "type", kind, "err", err)
+					peer.log.Debug("Failed to deliver retrieved data", "type", kind, "err", err)
 				}
 				}
 			}
 			}
 			// Blocks assembled, try to update the progress
 			// Blocks assembled, try to update the progress

+ 1 - 1
eth/gasprice/gasprice_test.go

@@ -63,7 +63,7 @@ func newTestBackend(t *testing.T) *testBackend {
 			Config: params.TestChainConfig,
 			Config: params.TestChainConfig,
 			Alloc:  core.GenesisAlloc{addr: {Balance: big.NewInt(math.MaxInt64)}},
 			Alloc:  core.GenesisAlloc{addr: {Balance: big.NewInt(math.MaxInt64)}},
 		}
 		}
-		signer = types.NewEIP155Signer(gspec.Config.ChainID)
+		signer = types.LatestSigner(gspec.Config)
 	)
 	)
 	engine := ethash.NewFaker()
 	engine := ethash.NewFaker()
 	db := rawdb.NewMemoryDatabase()
 	db := rawdb.NewMemoryDatabase()

+ 3 - 2
eth/tracers/api.go

@@ -753,14 +753,15 @@ func (api *API) traceTx(ctx context.Context, message core.Message, vmctx vm.Bloc
 	default:
 	default:
 		tracer = vm.NewStructLogger(config.LogConfig)
 		tracer = vm.NewStructLogger(config.LogConfig)
 	}
 	}
+
 	// Run the transaction with tracing enabled.
 	// Run the transaction with tracing enabled.
 	vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer})
 	vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer})
-
 	result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
 	result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
 	if err != nil {
 	if err != nil {
 		return nil, fmt.Errorf("tracing failed: %v", err)
 		return nil, fmt.Errorf("tracing failed: %v", err)
 	}
 	}
-	// Depending on the tracer type, format and return the output
+
+	// Depending on the tracer type, format and return the output.
 	switch tracer := tracer.(type) {
 	switch tracer := tracer.(type) {
 	case *vm.StructLogger:
 	case *vm.StructLogger:
 		// If the result contains a revert reason, return it.
 		// If the result contains a revert reason, return it.

+ 1 - 1
eth/tracers/tracer.go

@@ -556,7 +556,7 @@ func (jst *Tracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost
 			if data, ok := jst.ctx["input"].([]byte); ok {
 			if data, ok := jst.ctx["input"].([]byte); ok {
 				input = data
 				input = data
 			}
 			}
-			intrinsicGas, err := core.IntrinsicGas(input, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul)
+			intrinsicGas, err := core.IntrinsicGas(input, nil, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul)
 			if err != nil {
 			if err != nil {
 				return err
 				return err
 			}
 			}

+ 1 - 2
ethclient/ethclient.go

@@ -28,7 +28,6 @@ import (
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rpc"
 	"github.com/ethereum/go-ethereum/rpc"
 )
 )
 
 
@@ -521,7 +520,7 @@ func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64
 // If the transaction was a contract creation use the TransactionReceipt method to get the
 // If the transaction was a contract creation use the TransactionReceipt method to get the
 // contract address after the transaction has been mined.
 // contract address after the transaction has been mined.
 func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error {
 func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error {
-	data, err := rlp.EncodeToBytes(tx)
+	data, err := tx.MarshalBinary()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}

+ 1 - 1
ethclient/ethclient_test.go

@@ -560,7 +560,7 @@ func sendTransaction(ec *Client) error {
 	}
 	}
 	// Create transaction
 	// Create transaction
 	tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 22000, big.NewInt(1), nil)
 	tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 22000, big.NewInt(1), nil)
-	signer := types.NewEIP155Signer(chainID)
+	signer := types.LatestSignerForChainID(chainID)
 	signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey)
 	signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey)
 	if err != nil {
 	if err != nil {
 		return err
 		return err

+ 3 - 0
ethclient/signer.go

@@ -51,6 +51,9 @@ func (s *senderFromServer) Sender(tx *types.Transaction) (common.Address, error)
 	return s.addr, nil
 	return s.addr, nil
 }
 }
 
 
+func (s *senderFromServer) ChainID() *big.Int {
+	panic("can't sign with senderFromServer")
+}
 func (s *senderFromServer) Hash(tx *types.Transaction) common.Hash {
 func (s *senderFromServer) Hash(tx *types.Transaction) common.Hash {
 	panic("can't sign with senderFromServer")
 	panic("can't sign with senderFromServer")
 }
 }

+ 2 - 7
graphql/graphql.go

@@ -33,7 +33,6 @@ import (
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/eth/filters"
 	"github.com/ethereum/go-ethereum/eth/filters"
 	"github.com/ethereum/go-ethereum/internal/ethapi"
 	"github.com/ethereum/go-ethereum/internal/ethapi"
-	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rpc"
 	"github.com/ethereum/go-ethereum/rpc"
 )
 )
 
 
@@ -246,12 +245,8 @@ func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) (*Account,
 	if err != nil || tx == nil {
 	if err != nil || tx == nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	var signer types.Signer = types.HomesteadSigner{}
-	if tx.Protected() {
-		signer = types.NewEIP155Signer(tx.ChainId())
-	}
+	signer := types.LatestSigner(t.backend.ChainConfig())
 	from, _ := types.Sender(signer, tx)
 	from, _ := types.Sender(signer, tx)
-
 	return &Account{
 	return &Account{
 		backend:       t.backend,
 		backend:       t.backend,
 		address:       from,
 		address:       from,
@@ -1022,7 +1017,7 @@ func (r *Resolver) Transaction(ctx context.Context, args struct{ Hash common.Has
 
 
 func (r *Resolver) SendRawTransaction(ctx context.Context, args struct{ Data hexutil.Bytes }) (common.Hash, error) {
 func (r *Resolver) SendRawTransaction(ctx context.Context, args struct{ Data hexutil.Bytes }) (common.Hash, error) {
 	tx := new(types.Transaction)
 	tx := new(types.Transaction)
-	if err := rlp.DecodeBytes(args.Data, tx); err != nil {
+	if err := tx.UnmarshalBinary(args.Data); err != nil {
 		return common.Hash{}, err
 		return common.Hash{}, err
 	}
 	}
 	hash, err := ethapi.SubmitTransaction(ctx, r.backend, tx)
 	hash, err := ethapi.SubmitTransaction(ctx, r.backend, tx)

+ 2 - 0
interfaces.go

@@ -119,6 +119,8 @@ type CallMsg struct {
 	GasPrice *big.Int        // wei <-> gas exchange ratio
 	GasPrice *big.Int        // wei <-> gas exchange ratio
 	Value    *big.Int        // amount of wei sent along with the call
 	Value    *big.Int        // amount of wei sent along with the call
 	Data     []byte          // input data, usually an ABI-encoded contract method invocation
 	Data     []byte          // input data, usually an ABI-encoded contract method invocation
+
+	AccessList types.AccessList // EIP-2930 access list.
 }
 }
 
 
 // A ContractCaller provides contract calls, essentially transactions that are executed by
 // A ContractCaller provides contract calls, essentially transactions that are executed by

+ 107 - 62
internal/ethapi/api.go

@@ -410,7 +410,7 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args SendTxArgs
 		log.Warn("Failed transaction sign attempt", "from", args.From, "to", args.To, "value", args.Value.ToInt(), "err", err)
 		log.Warn("Failed transaction sign attempt", "from", args.From, "to", args.To, "value", args.Value.ToInt(), "err", err)
 		return nil, err
 		return nil, err
 	}
 	}
-	data, err := rlp.EncodeToBytes(signed)
+	data, err := signed.MarshalBinary()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -748,12 +748,13 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A
 
 
 // CallArgs represents the arguments for a call.
 // CallArgs represents the arguments for a call.
 type CallArgs struct {
 type CallArgs struct {
-	From     *common.Address `json:"from"`
-	To       *common.Address `json:"to"`
-	Gas      *hexutil.Uint64 `json:"gas"`
-	GasPrice *hexutil.Big    `json:"gasPrice"`
-	Value    *hexutil.Big    `json:"value"`
-	Data     *hexutil.Bytes  `json:"data"`
+	From       *common.Address   `json:"from"`
+	To         *common.Address   `json:"to"`
+	Gas        *hexutil.Uint64   `json:"gas"`
+	GasPrice   *hexutil.Big      `json:"gasPrice"`
+	Value      *hexutil.Big      `json:"value"`
+	Data       *hexutil.Bytes    `json:"data"`
+	AccessList *types.AccessList `json:"accessList"`
 }
 }
 
 
 // ToMessage converts CallArgs to the Message type used by the core evm
 // ToMessage converts CallArgs to the Message type used by the core evm
@@ -780,18 +781,20 @@ func (args *CallArgs) ToMessage(globalGasCap uint64) types.Message {
 	if args.GasPrice != nil {
 	if args.GasPrice != nil {
 		gasPrice = args.GasPrice.ToInt()
 		gasPrice = args.GasPrice.ToInt()
 	}
 	}
-
 	value := new(big.Int)
 	value := new(big.Int)
 	if args.Value != nil {
 	if args.Value != nil {
 		value = args.Value.ToInt()
 		value = args.Value.ToInt()
 	}
 	}
-
 	var data []byte
 	var data []byte
 	if args.Data != nil {
 	if args.Data != nil {
 		data = *args.Data
 		data = *args.Data
 	}
 	}
+	var accessList types.AccessList
+	if args.AccessList != nil {
+		accessList = *args.AccessList
+	}
 
 
-	msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false)
+	msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, accessList, false)
 	return msg
 	return msg
 }
 }
 
 
@@ -869,13 +872,13 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo
 		evm.Cancel()
 		evm.Cancel()
 	}()
 	}()
 
 
-	// Setup the gas pool (also for unmetered requests)
-	// and apply the message.
+	// Execute the message.
 	gp := new(core.GasPool).AddGas(math.MaxUint64)
 	gp := new(core.GasPool).AddGas(math.MaxUint64)
 	result, err := core.ApplyMessage(evm, msg, gp)
 	result, err := core.ApplyMessage(evm, msg, gp)
 	if err := vmError(); err != nil {
 	if err := vmError(); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+
 	// If the timer caused an abort, return an appropriate error message
 	// If the timer caused an abort, return an appropriate error message
 	if evm.Cancelled() {
 	if evm.Cancelled() {
 		return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
 		return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
@@ -1200,33 +1203,43 @@ func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Bloc
 
 
 // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
 // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
 type RPCTransaction struct {
 type RPCTransaction struct {
-	BlockHash        *common.Hash    `json:"blockHash"`
-	BlockNumber      *hexutil.Big    `json:"blockNumber"`
-	From             common.Address  `json:"from"`
-	Gas              hexutil.Uint64  `json:"gas"`
-	GasPrice         *hexutil.Big    `json:"gasPrice"`
-	Hash             common.Hash     `json:"hash"`
-	Input            hexutil.Bytes   `json:"input"`
-	Nonce            hexutil.Uint64  `json:"nonce"`
-	To               *common.Address `json:"to"`
-	TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
-	Value            *hexutil.Big    `json:"value"`
-	V                *hexutil.Big    `json:"v"`
-	R                *hexutil.Big    `json:"r"`
-	S                *hexutil.Big    `json:"s"`
+	BlockHash        *common.Hash      `json:"blockHash"`
+	BlockNumber      *hexutil.Big      `json:"blockNumber"`
+	From             common.Address    `json:"from"`
+	Gas              hexutil.Uint64    `json:"gas"`
+	GasPrice         *hexutil.Big      `json:"gasPrice"`
+	Hash             common.Hash       `json:"hash"`
+	Input            hexutil.Bytes     `json:"input"`
+	Nonce            hexutil.Uint64    `json:"nonce"`
+	To               *common.Address   `json:"to"`
+	TransactionIndex *hexutil.Uint64   `json:"transactionIndex"`
+	Value            *hexutil.Big      `json:"value"`
+	Type             hexutil.Uint64    `json:"type"`
+	Accesses         *types.AccessList `json:"accessList,omitempty"`
+	ChainID          *hexutil.Big      `json:"chainId,omitempty"`
+	V                *hexutil.Big      `json:"v"`
+	R                *hexutil.Big      `json:"r"`
+	S                *hexutil.Big      `json:"s"`
 }
 }
 
 
 // newRPCTransaction returns a transaction that will serialize to the RPC
 // newRPCTransaction returns a transaction that will serialize to the RPC
 // representation, with the given location metadata set (if available).
 // representation, with the given location metadata set (if available).
 func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction {
 func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction {
-	var signer types.Signer = types.FrontierSigner{}
+	// Determine the signer. For replay-protected transactions, use the most permissive
+	// signer, because we assume that signers are backwards-compatible with old
+	// transactions. For non-protected transactions, the homestead signer signer is used
+	// because the return value of ChainId is zero for those transactions.
+	var signer types.Signer
 	if tx.Protected() {
 	if tx.Protected() {
-		signer = types.NewEIP155Signer(tx.ChainId())
+		signer = types.LatestSignerForChainID(tx.ChainId())
+	} else {
+		signer = types.HomesteadSigner{}
 	}
 	}
+
 	from, _ := types.Sender(signer, tx)
 	from, _ := types.Sender(signer, tx)
 	v, r, s := tx.RawSignatureValues()
 	v, r, s := tx.RawSignatureValues()
-
 	result := &RPCTransaction{
 	result := &RPCTransaction{
+		Type:     hexutil.Uint64(tx.Type()),
 		From:     from,
 		From:     from,
 		Gas:      hexutil.Uint64(tx.Gas()),
 		Gas:      hexutil.Uint64(tx.Gas()),
 		GasPrice: (*hexutil.Big)(tx.GasPrice()),
 		GasPrice: (*hexutil.Big)(tx.GasPrice()),
@@ -1244,6 +1257,11 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
 		result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
 		result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
 		result.TransactionIndex = (*hexutil.Uint64)(&index)
 		result.TransactionIndex = (*hexutil.Uint64)(&index)
 	}
 	}
+	if tx.Type() == types.AccessListTxType {
+		al := tx.AccessList()
+		result.Accesses = &al
+		result.ChainID = (*hexutil.Big)(tx.ChainId())
+	}
 	return result
 	return result
 }
 }
 
 
@@ -1267,7 +1285,7 @@ func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.By
 	if index >= uint64(len(txs)) {
 	if index >= uint64(len(txs)) {
 		return nil
 		return nil
 	}
 	}
-	blob, _ := rlp.EncodeToBytes(txs[index])
+	blob, _ := txs[index].MarshalBinary()
 	return blob
 	return blob
 }
 }
 
 
@@ -1285,11 +1303,15 @@ func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransa
 type PublicTransactionPoolAPI struct {
 type PublicTransactionPoolAPI struct {
 	b         Backend
 	b         Backend
 	nonceLock *AddrLocker
 	nonceLock *AddrLocker
+	signer    types.Signer
 }
 }
 
 
 // NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
 // NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
 func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransactionPoolAPI {
 func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransactionPoolAPI {
-	return &PublicTransactionPoolAPI{b, nonceLock}
+	// The signer used by the API should always be the 'latest' known one because we expect
+	// signers to be backwards-compatible with old transactions.
+	signer := types.LatestSigner(b.ChainConfig())
+	return &PublicTransactionPoolAPI{b, nonceLock, signer}
 }
 }
 
 
 // GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
 // GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
@@ -1394,7 +1416,7 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context,
 		}
 		}
 	}
 	}
 	// Serialize to RLP and return
 	// Serialize to RLP and return
-	return rlp.EncodeToBytes(tx)
+	return tx.MarshalBinary()
 }
 }
 
 
 // GetTransactionReceipt returns the transaction receipt for the given transaction hash.
 // GetTransactionReceipt returns the transaction receipt for the given transaction hash.
@@ -1412,10 +1434,9 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
 	}
 	}
 	receipt := receipts[index]
 	receipt := receipts[index]
 
 
-	var signer types.Signer = types.FrontierSigner{}
-	if tx.Protected() {
-		signer = types.NewEIP155Signer(tx.ChainId())
-	}
+	// Derive the sender.
+	bigblock := new(big.Int).SetUint64(blockNumber)
+	signer := types.MakeSigner(s.b.ChainConfig(), bigblock)
 	from, _ := types.Sender(signer, tx)
 	from, _ := types.Sender(signer, tx)
 
 
 	fields := map[string]interface{}{
 	fields := map[string]interface{}{
@@ -1430,6 +1451,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
 		"contractAddress":   nil,
 		"contractAddress":   nil,
 		"logs":              receipt.Logs,
 		"logs":              receipt.Logs,
 		"logsBloom":         receipt.Bloom,
 		"logsBloom":         receipt.Bloom,
+		"type":              hexutil.Uint(tx.Type()),
 	}
 	}
 
 
 	// Assign receipt status or post state.
 	// Assign receipt status or post state.
@@ -1473,9 +1495,13 @@ type SendTxArgs struct {
 	// newer name and should be preferred by clients.
 	// newer name and should be preferred by clients.
 	Data  *hexutil.Bytes `json:"data"`
 	Data  *hexutil.Bytes `json:"data"`
 	Input *hexutil.Bytes `json:"input"`
 	Input *hexutil.Bytes `json:"input"`
+
+	// For non-legacy transactions
+	AccessList *types.AccessList `json:"accessList,omitempty"`
+	ChainID    *hexutil.Big      `json:"chainId,omitempty"`
 }
 }
 
 
-// setDefaults is a helper function that fills in default values for unspecified tx fields.
+// setDefaults fills in default values for unspecified tx fields.
 func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
 func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
 	if args.GasPrice == nil {
 	if args.GasPrice == nil {
 		price, err := b.SuggestPrice(ctx)
 		price, err := b.SuggestPrice(ctx)
@@ -1509,6 +1535,7 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
 			return errors.New(`contract creation without any data provided`)
 			return errors.New(`contract creation without any data provided`)
 		}
 		}
 	}
 	}
+
 	// Estimate the gas usage if necessary.
 	// Estimate the gas usage if necessary.
 	if args.Gas == nil {
 	if args.Gas == nil {
 		// For backwards-compatibility reason, we try both input and data
 		// For backwards-compatibility reason, we try both input and data
@@ -1518,11 +1545,12 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
 			input = args.Data
 			input = args.Data
 		}
 		}
 		callArgs := CallArgs{
 		callArgs := CallArgs{
-			From:     &args.From, // From shouldn't be nil
-			To:       args.To,
-			GasPrice: args.GasPrice,
-			Value:    args.Value,
-			Data:     input,
+			From:       &args.From, // From shouldn't be nil
+			To:         args.To,
+			GasPrice:   args.GasPrice,
+			Value:      args.Value,
+			Data:       input,
+			AccessList: args.AccessList,
 		}
 		}
 		pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
 		pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
 		estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, b.RPCGasCap())
 		estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, b.RPCGasCap())
@@ -1532,9 +1560,15 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
 		args.Gas = &estimated
 		args.Gas = &estimated
 		log.Trace("Estimate gas usage automatically", "gas", args.Gas)
 		log.Trace("Estimate gas usage automatically", "gas", args.Gas)
 	}
 	}
+	if args.ChainID == nil {
+		id := (*hexutil.Big)(b.ChainConfig().ChainID)
+		args.ChainID = id
+	}
 	return nil
 	return nil
 }
 }
 
 
+// toTransaction converts the arguments to a transaction.
+// This assumes that setDefaults has been called.
 func (args *SendTxArgs) toTransaction() *types.Transaction {
 func (args *SendTxArgs) toTransaction() *types.Transaction {
 	var input []byte
 	var input []byte
 	if args.Input != nil {
 	if args.Input != nil {
@@ -1542,10 +1576,30 @@ func (args *SendTxArgs) toTransaction() *types.Transaction {
 	} else if args.Data != nil {
 	} else if args.Data != nil {
 		input = *args.Data
 		input = *args.Data
 	}
 	}
-	if args.To == nil {
-		return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
+
+	var data types.TxData
+	if args.AccessList == nil {
+		data = &types.LegacyTx{
+			To:       args.To,
+			Nonce:    uint64(*args.Nonce),
+			Gas:      uint64(*args.Gas),
+			GasPrice: (*big.Int)(args.GasPrice),
+			Value:    (*big.Int)(args.Value),
+			Data:     input,
+		}
+	} else {
+		data = &types.AccessListTx{
+			To:         args.To,
+			ChainID:    (*big.Int)(args.ChainID),
+			Nonce:      uint64(*args.Nonce),
+			Gas:        uint64(*args.Gas),
+			GasPrice:   (*big.Int)(args.GasPrice),
+			Value:      (*big.Int)(args.Value),
+			Data:       input,
+			AccessList: *args.AccessList,
+		}
 	}
 	}
-	return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
+	return types.NewTx(data)
 }
 }
 
 
 // SubmitTransaction is a helper function that submits tx to txPool and logs a message.
 // SubmitTransaction is a helper function that submits tx to txPool and logs a message.
@@ -1619,7 +1673,7 @@ func (s *PublicTransactionPoolAPI) FillTransaction(ctx context.Context, args Sen
 	}
 	}
 	// Assemble the transaction and obtain rlp
 	// Assemble the transaction and obtain rlp
 	tx := args.toTransaction()
 	tx := args.toTransaction()
-	data, err := rlp.EncodeToBytes(tx)
+	data, err := tx.MarshalBinary()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -1628,9 +1682,9 @@ func (s *PublicTransactionPoolAPI) FillTransaction(ctx context.Context, args Sen
 
 
 // SendRawTransaction will add the signed transaction to the transaction pool.
 // SendRawTransaction will add the signed transaction to the transaction pool.
 // The sender is responsible for signing the transaction and using the correct nonce.
 // The sender is responsible for signing the transaction and using the correct nonce.
-func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) {
+func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) {
 	tx := new(types.Transaction)
 	tx := new(types.Transaction)
-	if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
+	if err := tx.UnmarshalBinary(input); err != nil {
 		return common.Hash{}, err
 		return common.Hash{}, err
 	}
 	}
 	return SubmitTransaction(ctx, s.b, tx)
 	return SubmitTransaction(ctx, s.b, tx)
@@ -1691,7 +1745,7 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	data, err := rlp.EncodeToBytes(tx)
+	data, err := tx.MarshalBinary()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -1713,11 +1767,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err
 	}
 	}
 	transactions := make([]*RPCTransaction, 0, len(pending))
 	transactions := make([]*RPCTransaction, 0, len(pending))
 	for _, tx := range pending {
 	for _, tx := range pending {
-		var signer types.Signer = types.HomesteadSigner{}
-		if tx.Protected() {
-			signer = types.NewEIP155Signer(tx.ChainId())
-		}
-		from, _ := types.Sender(signer, tx)
+		from, _ := types.Sender(s.signer, tx)
 		if _, exists := accounts[from]; exists {
 		if _, exists := accounts[from]; exists {
 			transactions = append(transactions, newRPCPendingTransaction(tx))
 			transactions = append(transactions, newRPCPendingTransaction(tx))
 		}
 		}
@@ -1754,13 +1804,9 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
 		return common.Hash{}, err
 		return common.Hash{}, err
 	}
 	}
 	for _, p := range pending {
 	for _, p := range pending {
-		var signer types.Signer = types.HomesteadSigner{}
-		if p.Protected() {
-			signer = types.NewEIP155Signer(p.ChainId())
-		}
-		wantSigHash := signer.Hash(matchTx)
-
-		if pFrom, err := types.Sender(signer, p); err == nil && pFrom == sendArgs.From && signer.Hash(p) == wantSigHash {
+		wantSigHash := s.signer.Hash(matchTx)
+		pFrom, err := types.Sender(s.signer, p)
+		if err == nil && pFrom == sendArgs.From && s.signer.Hash(p) == wantSigHash {
 			// Match. Re-sign and send the transaction.
 			// Match. Re-sign and send the transaction.
 			if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 {
 			if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 {
 				sendArgs.GasPrice = gasPrice
 				sendArgs.GasPrice = gasPrice
@@ -1778,7 +1824,6 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
 			return signedTx.Hash(), nil
 			return signedTx.Hash(), nil
 		}
 		}
 	}
 	}
-
 	return common.Hash{}, fmt.Errorf("transaction %#x not found", matchTx.Hash())
 	return common.Hash{}, fmt.Errorf("transaction %#x not found", matchTx.Hash())
 }
 }
 
 

+ 3 - 1
internal/guide/guide_test.go

@@ -31,6 +31,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/ethereum/go-ethereum/accounts/keystore"
 	"github.com/ethereum/go-ethereum/accounts/keystore"
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 )
 )
 
 
@@ -75,7 +76,8 @@ func TestAccountManagement(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create signer account: %v", err)
 		t.Fatalf("Failed to create signer account: %v", err)
 	}
 	}
-	tx, chain := new(types.Transaction), big.NewInt(1)
+	tx := types.NewTransaction(0, common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil)
+	chain := big.NewInt(1)
 
 
 	// Sign a transaction with a single authorization
 	// Sign a transaction with a single authorization
 	if _, err := ks.SignTxWithPassphrase(signer, "Signer password", tx, chain); err != nil {
 	if _, err := ks.SignTxWithPassphrase(signer, "Signer password", tx, chain); err != nil {

+ 1 - 1
les/benchmark.go

@@ -171,7 +171,7 @@ type benchmarkTxSend struct {
 func (b *benchmarkTxSend) init(h *serverHandler, count int) error {
 func (b *benchmarkTxSend) init(h *serverHandler, count int) error {
 	key, _ := crypto.GenerateKey()
 	key, _ := crypto.GenerateKey()
 	addr := crypto.PubkeyToAddress(key.PublicKey)
 	addr := crypto.PubkeyToAddress(key.PublicKey)
-	signer := types.NewEIP155Signer(big.NewInt(18))
+	signer := types.LatestSigner(h.server.chainConfig)
 	b.txs = make(types.Transactions, count)
 	b.txs = make(types.Transactions, count)
 
 
 	for i := range b.txs {
 	for i := range b.txs {

+ 2 - 2
les/odr_test.go

@@ -135,7 +135,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
 				from := statedb.GetOrNewStateObject(bankAddr)
 				from := statedb.GetOrNewStateObject(bankAddr)
 				from.SetBalance(math.MaxBig256)
 				from.SetBalance(math.MaxBig256)
 
 
-				msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)}
+				msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, nil, false)}
 
 
 				context := core.NewEVMBlockContext(header, bc, nil)
 				context := core.NewEVMBlockContext(header, bc, nil)
 				txContext := core.NewEVMTxContext(msg)
 				txContext := core.NewEVMTxContext(msg)
@@ -150,7 +150,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
 			header := lc.GetHeaderByHash(bhash)
 			header := lc.GetHeaderByHash(bhash)
 			state := light.NewState(ctx, header, lc.Odr())
 			state := light.NewState(ctx, header, lc.Odr())
 			state.SetBalance(bankAddr, math.MaxBig256)
 			state.SetBalance(bankAddr, math.MaxBig256)
-			msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)}
+			msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, nil, false)}
 			context := core.NewEVMBlockContext(header, lc, nil)
 			context := core.NewEVMBlockContext(header, lc, nil)
 			txContext := core.NewEVMTxContext(msg)
 			txContext := core.NewEVMTxContext(msg)
 			vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{})
 			vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{})

+ 1 - 1
light/odr_test.go

@@ -194,7 +194,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
 
 
 		// Perform read-only call.
 		// Perform read-only call.
 		st.SetBalance(testBankAddress, math.MaxBig256)
 		st.SetBalance(testBankAddress, math.MaxBig256)
-		msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false)}
+		msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, nil, false)}
 		txContext := core.NewEVMTxContext(msg)
 		txContext := core.NewEVMTxContext(msg)
 		context := core.NewEVMBlockContext(header, chain, nil)
 		context := core.NewEVMBlockContext(header, chain, nil)
 		vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{})
 		vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{})

+ 5 - 5
light/txpool.go

@@ -32,7 +32,6 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/rlp"
 )
 )
 
 
 const (
 const (
@@ -69,6 +68,7 @@ type TxPool struct {
 	clearIdx     uint64                               // earliest block nr that can contain mined tx info
 	clearIdx     uint64                               // earliest block nr that can contain mined tx info
 
 
 	istanbul bool // Fork indicator whether we are in the istanbul stage.
 	istanbul bool // Fork indicator whether we are in the istanbul stage.
+	eip2718  bool // Fork indicator whether we are in the eip2718 stage.
 }
 }
 
 
 // TxRelayBackend provides an interface to the mechanism that forwards transacions
 // TxRelayBackend provides an interface to the mechanism that forwards transacions
@@ -90,7 +90,7 @@ type TxRelayBackend interface {
 func NewTxPool(config *params.ChainConfig, chain *LightChain, relay TxRelayBackend) *TxPool {
 func NewTxPool(config *params.ChainConfig, chain *LightChain, relay TxRelayBackend) *TxPool {
 	pool := &TxPool{
 	pool := &TxPool{
 		config:      config,
 		config:      config,
-		signer:      types.NewEIP155Signer(config.ChainID),
+		signer:      types.LatestSigner(config),
 		nonce:       make(map[common.Address]uint64),
 		nonce:       make(map[common.Address]uint64),
 		pending:     make(map[common.Hash]*types.Transaction),
 		pending:     make(map[common.Hash]*types.Transaction),
 		mined:       make(map[common.Hash][]*types.Transaction),
 		mined:       make(map[common.Hash][]*types.Transaction),
@@ -314,6 +314,7 @@ func (pool *TxPool) setNewHead(head *types.Header) {
 	// Update fork indicator by next pending block number
 	// Update fork indicator by next pending block number
 	next := new(big.Int).Add(head.Number, big.NewInt(1))
 	next := new(big.Int).Add(head.Number, big.NewInt(1))
 	pool.istanbul = pool.config.IsIstanbul(next)
 	pool.istanbul = pool.config.IsIstanbul(next)
+	pool.eip2718 = pool.config.IsYoloV3(next)
 }
 }
 
 
 // Stop stops the light transaction pool
 // Stop stops the light transaction pool
@@ -381,7 +382,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
 	}
 	}
 
 
 	// Should supply enough intrinsic gas
 	// Should supply enough intrinsic gas
-	gas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, true, pool.istanbul)
+	gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -430,8 +431,7 @@ func (pool *TxPool) add(ctx context.Context, tx *types.Transaction) error {
 func (pool *TxPool) Add(ctx context.Context, tx *types.Transaction) error {
 func (pool *TxPool) Add(ctx context.Context, tx *types.Transaction) error {
 	pool.mu.Lock()
 	pool.mu.Lock()
 	defer pool.mu.Unlock()
 	defer pool.mu.Unlock()
-
-	data, err := rlp.EncodeToBytes(tx)
+	data, err := tx.MarshalBinary()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}

+ 6 - 1
miner/worker.go

@@ -654,7 +654,7 @@ func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error {
 	state.StartPrefetcher("miner")
 	state.StartPrefetcher("miner")
 
 
 	env := &environment{
 	env := &environment{
-		signer:    types.NewEIP155Signer(w.chainConfig.ChainID),
+		signer:    types.MakeSigner(w.chainConfig, header.Number),
 		state:     state,
 		state:     state,
 		ancestors: mapset.NewSet(),
 		ancestors: mapset.NewSet(),
 		family:    mapset.NewSet(),
 		family:    mapset.NewSet(),
@@ -829,6 +829,11 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
 			w.current.tcount++
 			w.current.tcount++
 			txs.Shift()
 			txs.Shift()
 
 
+		case errors.Is(err, core.ErrTxTypeNotSupported):
+			// Pop the unsupported transaction without shifting in the next from the account
+			log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type())
+			txs.Pop()
+
 		default:
 		default:
 			// Strange error, discard the transaction and get the next in line (note, the
 			// Strange error, discard the transaction and get the next in line (note, the
 			// nonce-too-high clause will prevent us from executing in vain).
 			// nonce-too-high clause will prevent us from executing in vain).

+ 17 - 2
miner/worker_test.go

@@ -81,10 +81,25 @@ func init() {
 		Period: 10,
 		Period: 10,
 		Epoch:  30000,
 		Epoch:  30000,
 	}
 	}
-	tx1, _ := types.SignTx(types.NewTransaction(0, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
+
+	signer := types.LatestSigner(params.TestChainConfig)
+	tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{
+		ChainID: params.TestChainConfig.ChainID,
+		Nonce:   0,
+		To:      &testUserAddress,
+		Value:   big.NewInt(1000),
+		Gas:     params.TxGas,
+	})
 	pendingTxs = append(pendingTxs, tx1)
 	pendingTxs = append(pendingTxs, tx1)
-	tx2, _ := types.SignTx(types.NewTransaction(1, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
+
+	tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{
+		Nonce: 1,
+		To:    &testUserAddress,
+		Value: big.NewInt(1000),
+		Gas:   params.TxGas,
+	})
 	newTxs = append(newTxs, tx2)
 	newTxs = append(newTxs, tx2)
+
 	rand.Seed(time.Now().UnixNano())
 	rand.Seed(time.Now().UnixNano())
 }
 }
 
 

+ 3 - 3
params/config.go

@@ -215,7 +215,7 @@ var (
 
 
 	// YoloV3ChainConfig contains the chain parameters to run a node on the YOLOv3 test network.
 	// YoloV3ChainConfig contains the chain parameters to run a node on the YOLOv3 test network.
 	YoloV3ChainConfig = &ChainConfig{
 	YoloV3ChainConfig = &ChainConfig{
-		ChainID:             big.NewInt(133519467574834),
+		ChainID:             new(big.Int).SetBytes([]byte("yolov3x")),
 		HomesteadBlock:      big.NewInt(0),
 		HomesteadBlock:      big.NewInt(0),
 		DAOForkBlock:        nil,
 		DAOForkBlock:        nil,
 		DAOForkSupport:      true,
 		DAOForkSupport:      true,
@@ -246,9 +246,9 @@ var (
 	//
 	//
 	// This configuration is intentionally not using keyed fields to force anyone
 	// This configuration is intentionally not using keyed fields to force anyone
 	// adding flags to the config to also have to set these fields.
 	// adding flags to the config to also have to set these fields.
-	AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
+	AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
 
 
-	TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, new(EthashConfig), nil}
+	TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, big.NewInt(0), nil, new(EthashConfig), nil}
 	TestRules       = TestChainConfig.Rules(new(big.Int))
 	TestRules       = TestChainConfig.Rules(new(big.Int))
 )
 )
 
 

+ 17 - 14
params/protocol_params.go

@@ -60,20 +60,23 @@ const (
 	JumpdestGas   uint64 = 1     // Once per JUMPDEST operation.
 	JumpdestGas   uint64 = 1     // Once per JUMPDEST operation.
 	EpochDuration uint64 = 30000 // Duration between proof-of-work epochs.
 	EpochDuration uint64 = 30000 // Duration between proof-of-work epochs.
 
 
-	CreateDataGas            uint64 = 200   //
-	CallCreateDepth          uint64 = 1024  // Maximum depth of call/create stack.
-	ExpGas                   uint64 = 10    // Once per EXP instruction
-	LogGas                   uint64 = 375   // Per LOG* operation.
-	CopyGas                  uint64 = 3     //
-	StackLimit               uint64 = 1024  // Maximum size of VM stack allowed.
-	TierStepGas              uint64 = 0     // Once per operation, for a selection of them.
-	LogTopicGas              uint64 = 375   // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
-	CreateGas                uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
-	Create2Gas               uint64 = 32000 // Once per CREATE2 operation
-	SelfdestructRefundGas    uint64 = 24000 // Refunded following a selfdestruct operation.
-	MemoryGas                uint64 = 3     // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
-	TxDataNonZeroGasFrontier uint64 = 68    // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
-	TxDataNonZeroGasEIP2028  uint64 = 16    // Per byte of non zero data attached to a transaction after EIP 2028 (part in Istanbul)
+	CreateDataGas         uint64 = 200   //
+	CallCreateDepth       uint64 = 1024  // Maximum depth of call/create stack.
+	ExpGas                uint64 = 10    // Once per EXP instruction
+	LogGas                uint64 = 375   // Per LOG* operation.
+	CopyGas               uint64 = 3     //
+	StackLimit            uint64 = 1024  // Maximum size of VM stack allowed.
+	TierStepGas           uint64 = 0     // Once per operation, for a selection of them.
+	LogTopicGas           uint64 = 375   // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
+	CreateGas             uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
+	Create2Gas            uint64 = 32000 // Once per CREATE2 operation
+	SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation.
+	MemoryGas             uint64 = 3     // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
+
+	TxDataNonZeroGasFrontier  uint64 = 68   // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
+	TxDataNonZeroGasEIP2028   uint64 = 16   // Per byte of non zero data attached to a transaction after EIP 2028 (part in Istanbul)
+	TxAccessListAddressGas    uint64 = 2400 // Per address specified in EIP 2930 access list
+	TxAccessListStorageKeyGas uint64 = 1900 // Per storage key specified in EIP 2930 access list
 
 
 	// These have been changed during the course of the chain
 	// These have been changed during the course of the chain
 	CallGasFrontier              uint64 = 40  // Once per CALL operation & message call transaction.
 	CallGasFrontier              uint64 = 40  // Once per CALL operation & message call transaction.

+ 2 - 3
signer/core/api.go

@@ -33,7 +33,6 @@ import (
 	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/internal/ethapi"
 	"github.com/ethereum/go-ethereum/internal/ethapi"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
-	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/signer/storage"
 	"github.com/ethereum/go-ethereum/signer/storage"
 )
 )
 
 
@@ -574,11 +573,11 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args SendTxArgs, meth
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	rlpdata, err := rlp.EncodeToBytes(signedTx)
+	data, err := signedTx.MarshalBinary()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	response := ethapi.SignTransactionResult{Raw: rlpdata, Tx: signedTx}
+	response := ethapi.SignTransactionResult{Raw: data, Tx: signedTx}
 
 
 	// Finally, send the signed tx to the UI
 	// Finally, send the signed tx to the UI
 	api.UI.OnApprovedTx(response)
 	api.UI.OnApprovedTx(response)

+ 6 - 12
tests/state_test_util.go

@@ -182,27 +182,21 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
 	if err != nil {
 	if err != nil {
 		return nil, nil, common.Hash{}, err
 		return nil, nil, common.Hash{}, err
 	}
 	}
+
+	// Prepare the EVM.
 	txContext := core.NewEVMTxContext(msg)
 	txContext := core.NewEVMTxContext(msg)
 	context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
 	context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
 	context.GetHash = vmTestBlockHash
 	context.GetHash = vmTestBlockHash
 	evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
 	evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
 
 
-	if config.IsYoloV3(context.BlockNumber) {
-		statedb.AddAddressToAccessList(msg.From())
-		if dst := msg.To(); dst != nil {
-			statedb.AddAddressToAccessList(*dst)
-			// If it's a create-tx, the destination will be added inside evm.create
-		}
-		for _, addr := range evm.ActivePrecompiles() {
-			statedb.AddAddressToAccessList(addr)
-		}
-	}
+	// Execute the message.
+	snapshot := statedb.Snapshot()
 	gaspool := new(core.GasPool)
 	gaspool := new(core.GasPool)
 	gaspool.AddGas(block.GasLimit())
 	gaspool.AddGas(block.GasLimit())
-	snapshot := statedb.Snapshot()
 	if _, err := core.ApplyMessage(evm, msg, gaspool); err != nil {
 	if _, err := core.ApplyMessage(evm, msg, gaspool); err != nil {
 		statedb.RevertToSnapshot(snapshot)
 		statedb.RevertToSnapshot(snapshot)
 	}
 	}
+
 	// Commit block
 	// Commit block
 	statedb.Commit(config.IsEIP158(block.Number()))
 	statedb.Commit(config.IsEIP158(block.Number()))
 	// Add 0-value mining reward. This only makes a difference in the cases
 	// Add 0-value mining reward. This only makes a difference in the cases
@@ -300,7 +294,7 @@ func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) {
 		return nil, fmt.Errorf("invalid tx data %q", dataHex)
 		return nil, fmt.Errorf("invalid tx data %q", dataHex)
 	}
 	}
 
 
-	msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, true)
+	msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, nil, true)
 	return msg, nil
 	return msg, nil
 }
 }
 
 

+ 1 - 1
tests/transaction_test_util.go

@@ -55,7 +55,7 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error {
 			return nil, nil, err
 			return nil, nil, err
 		}
 		}
 		// Intrinsic gas
 		// Intrinsic gas
-		requiredGas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, isHomestead, isIstanbul)
+		requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, isHomestead, isIstanbul)
 		if err != nil {
 		if err != nil {
 			return nil, nil, err
 			return nil, nil, err
 		}
 		}

+ 0 - 170
trie/stacktrie_test.go

@@ -1,16 +1,9 @@
 package trie
 package trie
 
 
 import (
 import (
-	"bytes"
-	"fmt"
-	"math/big"
-	mrand "math/rand"
 	"testing"
 	"testing"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/common/hexutil"
-	"github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethdb/memorydb"
 	"github.com/ethereum/go-ethereum/ethdb/memorydb"
 )
 )
 
 
@@ -78,169 +71,6 @@ func TestValLength56(t *testing.T) {
 	}
 	}
 }
 }
 
 
-func genTxs(num uint64) (types.Transactions, error) {
-	key, err := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
-	if err != nil {
-		return nil, err
-	}
-	var addr = crypto.PubkeyToAddress(key.PublicKey)
-	newTx := func(i uint64) (*types.Transaction, error) {
-		signer := types.NewEIP155Signer(big.NewInt(18))
-		tx, err := types.SignTx(types.NewTransaction(i, addr, new(big.Int), 0, new(big.Int).SetUint64(10000000), nil), signer, key)
-		return tx, err
-	}
-	var txs types.Transactions
-	for i := uint64(0); i < num; i++ {
-		tx, err := newTx(i)
-		if err != nil {
-			return nil, err
-		}
-		txs = append(txs, tx)
-	}
-	return txs, nil
-}
-
-func TestDeriveSha(t *testing.T) {
-	txs, err := genTxs(0)
-	if err != nil {
-		t.Fatal(err)
-	}
-	for len(txs) < 1000 {
-		exp := types.DeriveSha(txs, newEmpty())
-		got := types.DeriveSha(txs, NewStackTrie(nil))
-		if !bytes.Equal(got[:], exp[:]) {
-			t.Fatalf("%d txs: got %x exp %x", len(txs), got, exp)
-		}
-		newTxs, err := genTxs(uint64(len(txs) + 1))
-		if err != nil {
-			t.Fatal(err)
-		}
-		txs = append(txs, newTxs...)
-	}
-}
-
-func BenchmarkDeriveSha200(b *testing.B) {
-	txs, err := genTxs(200)
-	if err != nil {
-		b.Fatal(err)
-	}
-	var exp common.Hash
-	var got common.Hash
-	b.Run("std_trie", func(b *testing.B) {
-		b.ResetTimer()
-		b.ReportAllocs()
-		for i := 0; i < b.N; i++ {
-			exp = types.DeriveSha(txs, newEmpty())
-		}
-	})
-
-	b.Run("stack_trie", func(b *testing.B) {
-		b.ResetTimer()
-		b.ReportAllocs()
-		for i := 0; i < b.N; i++ {
-			got = types.DeriveSha(txs, NewStackTrie(nil))
-		}
-	})
-	if got != exp {
-		b.Errorf("got %x exp %x", got, exp)
-	}
-}
-
-type dummyDerivableList struct {
-	len  int
-	seed int
-}
-
-func newDummy(seed int) *dummyDerivableList {
-	d := &dummyDerivableList{}
-	src := mrand.NewSource(int64(seed))
-	// don't use lists longer than 4K items
-	d.len = int(src.Int63() & 0x0FFF)
-	d.seed = seed
-	return d
-}
-
-func (d *dummyDerivableList) Len() int {
-	return d.len
-}
-
-func (d *dummyDerivableList) GetRlp(i int) []byte {
-	src := mrand.NewSource(int64(d.seed + i))
-	// max item size 256, at least 1 byte per item
-	size := 1 + src.Int63()&0x00FF
-	data := make([]byte, size)
-	_, err := mrand.New(src).Read(data)
-	if err != nil {
-		panic(err)
-	}
-	return data
-}
-
-func printList(l types.DerivableList) {
-	fmt.Printf("list length: %d\n", l.Len())
-	fmt.Printf("{\n")
-	for i := 0; i < l.Len(); i++ {
-		v := l.GetRlp(i)
-		fmt.Printf("\"0x%x\",\n", v)
-	}
-	fmt.Printf("},\n")
-}
-
-func TestFuzzDeriveSha(t *testing.T) {
-	// increase this for longer runs -- it's set to quite low for travis
-	rndSeed := mrand.Int()
-	for i := 0; i < 10; i++ {
-		seed := rndSeed + i
-		exp := types.DeriveSha(newDummy(i), newEmpty())
-		got := types.DeriveSha(newDummy(i), NewStackTrie(nil))
-		if !bytes.Equal(got[:], exp[:]) {
-			printList(newDummy(seed))
-			t.Fatalf("seed %d: got %x exp %x", seed, got, exp)
-		}
-	}
-}
-
-type flatList struct {
-	rlpvals []string
-}
-
-func newFlatList(rlpvals []string) *flatList {
-	return &flatList{rlpvals}
-}
-func (f *flatList) Len() int {
-	return len(f.rlpvals)
-}
-func (f *flatList) GetRlp(i int) []byte {
-	return hexutil.MustDecode(f.rlpvals[i])
-}
-
-// TestDerivableList contains testcases found via fuzzing
-func TestDerivableList(t *testing.T) {
-	type tcase []string
-	tcs := []tcase{
-		{
-			"0xc041",
-		},
-		{
-			"0xf04cf757812428b0763112efb33b6f4fad7deb445e",
-			"0xf04cf757812428b0763112efb33b6f4fad7deb445e",
-		},
-		{
-			"0xca410605310cdc3bb8d4977ae4f0143df54a724ed873457e2272f39d66e0460e971d9d",
-			"0x6cd850eca0a7ac46bb1748d7b9cb88aa3bd21c57d852c28198ad8fa422c4595032e88a4494b4778b36b944fe47a52b8c5cd312910139dfcb4147ab8e972cc456bcb063f25dd78f54c4d34679e03142c42c662af52947d45bdb6e555751334ace76a5080ab5a0256a1d259855dfc5c0b8023b25befbb13fd3684f9f755cbd3d63544c78ee2001452dd54633a7593ade0b183891a0a4e9c7844e1254005fbe592b1b89149a502c24b6e1dca44c158aebedf01beae9c30cabe16a",
-			"0x14abd5c47c0be87b0454596baad2",
-			"0xca410605310cdc3bb8d4977ae4f0143df54a724ed873457e2272f39d66e0460e971d9d",
-		},
-	}
-	for i, tc := range tcs[1:] {
-		exp := types.DeriveSha(newFlatList(tc), newEmpty())
-		got := types.DeriveSha(newFlatList(tc), NewStackTrie(nil))
-		if !bytes.Equal(got[:], exp[:]) {
-			t.Fatalf("case %d: got %x exp %x", i, got, exp)
-		}
-	}
-}
-
 // TestUpdateSmallNodes tests a case where the leaves are small (both key and value),
 // TestUpdateSmallNodes tests a case where the leaves are small (both key and value),
 // which causes a lot of node-within-node. This case was found via fuzzing.
 // which causes a lot of node-within-node. This case was found via fuzzing.
 func TestUpdateSmallNodes(t *testing.T) {
 func TestUpdateSmallNodes(t *testing.T) {

Some files were not shown because too many files changed in this diff