all: implement EIP-1559 (#22837)
This is the initial implementation of EIP-1559 in packages core/types and core. Mining, RPC, etc. will be added in subsequent commits. Co-authored-by: Marius van der Wijden <m.vanderwijden@live.de> Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com> Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
		
							parent
							
								
									14bc6e5130
								
							
						
					
					
						commit
						94451c2788
					
				| @ -716,6 +716,8 @@ 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) FeeCap() *big.Int             { return m.CallMsg.FeeCap } | ||||
| func (m callMsg) Tip() *big.Int                { return m.CallMsg.Tip } | ||||
| 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 } | ||||
|  | ||||
							
								
								
									
										12
									
								
								accounts/external/backend.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								accounts/external/backend.go
									
									
									
									
										vendored
									
									
								
							| @ -217,12 +217,12 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio | ||||
| 	if chainID != nil { | ||||
| 		args.ChainID = (*hexutil.Big)(chainID) | ||||
| 	} | ||||
| 	// However, if the user asked for a particular chain id, then we should
 | ||||
| 	// use that instead.
 | ||||
| 	if tx.Type() != types.LegacyTxType && tx.ChainId() != nil { | ||||
| 		args.ChainID = (*hexutil.Big)(tx.ChainId()) | ||||
| 	} | ||||
| 	if tx.Type() == types.AccessListTxType { | ||||
| 	if tx.Type() != types.LegacyTxType { | ||||
| 		// However, if the user asked for a particular chain id, then we should
 | ||||
| 		// use that instead.
 | ||||
| 		if tx.ChainId() != nil { | ||||
| 			args.ChainID = (*hexutil.Big)(tx.ChainId()) | ||||
| 		} | ||||
| 		accessList := tx.AccessList() | ||||
| 		args.AccessList = &accessList | ||||
| 	} | ||||
|  | ||||
| @ -69,6 +69,7 @@ type stEnv struct { | ||||
| 	Timestamp   uint64                              `json:"currentTimestamp"  gencodec:"required"` | ||||
| 	BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` | ||||
| 	Ommers      []ommer                             `json:"ommers,omitempty"` | ||||
| 	BaseFee     *big.Int                            `json:"currentBaseFee,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type stEnvMarshaling struct { | ||||
| @ -77,6 +78,7 @@ type stEnvMarshaling struct { | ||||
| 	GasLimit   math.HexOrDecimal64 | ||||
| 	Number     math.HexOrDecimal64 | ||||
| 	Timestamp  math.HexOrDecimal64 | ||||
| 	BaseFee    *math.HexOrDecimal256 | ||||
| } | ||||
| 
 | ||||
| // Apply applies a set of transactions to a pre-state
 | ||||
| @ -120,6 +122,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, | ||||
| 		GasLimit:    pre.Env.GasLimit, | ||||
| 		GetHash:     getHash, | ||||
| 	} | ||||
| 	// If currentBaseFee is defined, add it to the vmContext.
 | ||||
| 	if pre.Env.BaseFee != nil { | ||||
| 		vmContext.BaseFee = new(big.Int).Set(pre.Env.BaseFee) | ||||
| 	} | ||||
| 	// If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's
 | ||||
| 	// done in StateProcessor.Process(block, ...), right before transactions are applied.
 | ||||
| 	if chainConfig.DAOForkSupport && | ||||
| @ -129,7 +135,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, | ||||
| 	} | ||||
| 
 | ||||
| 	for i, tx := range txs { | ||||
| 		msg, err := tx.AsMessage(signer) | ||||
| 		msg, err := tx.AsMessage(signer, pre.Env.BaseFee) | ||||
| 		if err != nil { | ||||
| 			log.Info("rejected tx", "index", i, "hash", tx.Hash(), "error", err) | ||||
| 			rejectedTxs = append(rejectedTxs, i) | ||||
|  | ||||
| @ -16,13 +16,14 @@ var _ = (*stEnvMarshaling)(nil) | ||||
| // MarshalJSON marshals as JSON.
 | ||||
| func (s stEnv) MarshalJSON() ([]byte, error) { | ||||
| 	type stEnv struct { | ||||
| 		Coinbase    common.UnprefixedAddress            `json:"currentCoinbase"   gencodec:"required"` | ||||
| 		Coinbase    common.UnprefixedAddress            `json:"currentCoinbase" gencodec:"required"` | ||||
| 		Difficulty  *math.HexOrDecimal256               `json:"currentDifficulty" gencodec:"required"` | ||||
| 		GasLimit    math.HexOrDecimal64                 `json:"currentGasLimit"   gencodec:"required"` | ||||
| 		Number      math.HexOrDecimal64                 `json:"currentNumber"     gencodec:"required"` | ||||
| 		Timestamp   math.HexOrDecimal64                 `json:"currentTimestamp"  gencodec:"required"` | ||||
| 		GasLimit    math.HexOrDecimal64                 `json:"currentGasLimit" gencodec:"required"` | ||||
| 		Number      math.HexOrDecimal64                 `json:"currentNumber" gencodec:"required"` | ||||
| 		Timestamp   math.HexOrDecimal64                 `json:"currentTimestamp" gencodec:"required"` | ||||
| 		BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` | ||||
| 		Ommers      []ommer                             `json:"ommers,omitempty"` | ||||
| 		BaseFee     *math.HexOrDecimal256               `json:"currentBaseFee,omitempty"` | ||||
| 	} | ||||
| 	var enc stEnv | ||||
| 	enc.Coinbase = common.UnprefixedAddress(s.Coinbase) | ||||
| @ -32,19 +33,21 @@ func (s stEnv) MarshalJSON() ([]byte, error) { | ||||
| 	enc.Timestamp = math.HexOrDecimal64(s.Timestamp) | ||||
| 	enc.BlockHashes = s.BlockHashes | ||||
| 	enc.Ommers = s.Ommers | ||||
| 	enc.BaseFee = (*math.HexOrDecimal256)(s.BaseFee) | ||||
| 	return json.Marshal(&enc) | ||||
| } | ||||
| 
 | ||||
| // UnmarshalJSON unmarshals from JSON.
 | ||||
| func (s *stEnv) UnmarshalJSON(input []byte) error { | ||||
| 	type stEnv struct { | ||||
| 		Coinbase    *common.UnprefixedAddress           `json:"currentCoinbase"   gencodec:"required"` | ||||
| 		Coinbase    *common.UnprefixedAddress           `json:"currentCoinbase" gencodec:"required"` | ||||
| 		Difficulty  *math.HexOrDecimal256               `json:"currentDifficulty" gencodec:"required"` | ||||
| 		GasLimit    *math.HexOrDecimal64                `json:"currentGasLimit"   gencodec:"required"` | ||||
| 		Number      *math.HexOrDecimal64                `json:"currentNumber"     gencodec:"required"` | ||||
| 		Timestamp   *math.HexOrDecimal64                `json:"currentTimestamp"  gencodec:"required"` | ||||
| 		GasLimit    *math.HexOrDecimal64                `json:"currentGasLimit" gencodec:"required"` | ||||
| 		Number      *math.HexOrDecimal64                `json:"currentNumber" gencodec:"required"` | ||||
| 		Timestamp   *math.HexOrDecimal64                `json:"currentTimestamp" gencodec:"required"` | ||||
| 		BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` | ||||
| 		Ommers      []ommer                             `json:"ommers,omitempty"` | ||||
| 		BaseFee     *math.HexOrDecimal256               `json:"currentBaseFee,omitempty"` | ||||
| 	} | ||||
| 	var dec stEnv | ||||
| 	if err := json.Unmarshal(input, &dec); err != nil { | ||||
| @ -76,5 +79,8 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { | ||||
| 	if dec.Ommers != nil { | ||||
| 		s.Ommers = dec.Ommers | ||||
| 	} | ||||
| 	if dec.BaseFee != nil { | ||||
| 		s.BaseFee = (*big.Int)(dec.BaseFee) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @ -19,6 +19,7 @@ package t8ntool | ||||
| import ( | ||||
| 	"crypto/ecdsa" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"math/big" | ||||
| @ -210,9 +211,12 @@ func Main(ctx *cli.Context) error { | ||||
| 	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
 | ||||
| 
 | ||||
| 	// Sanity check, to not `panic` in state_transition
 | ||||
| 	if chainConfig.IsLondon(big.NewInt(int64(prestate.Env.Number))) { | ||||
| 		if prestate.Env.BaseFee == nil { | ||||
| 			return NewError(ErrorVMConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) | ||||
| 		} | ||||
| 	} | ||||
| 	// Run the test and aggregate the result
 | ||||
| 	s, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer) | ||||
| 	if err != nil { | ||||
|  | ||||
| @ -1,23 +0,0 @@ | ||||
| { | ||||
|     "root": "f4157bb27bcb1d1a63001434a249a80948f2e9fe1f53d551244c1dae826b5b23", | ||||
|     "accounts": { | ||||
|         "0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": { | ||||
|             "balance": "4276951709", | ||||
|             "nonce": 1, | ||||
|             "root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", | ||||
|             "codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" | ||||
|         }, | ||||
|         "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { | ||||
|             "balance": "6916764286133345652", | ||||
|             "nonce": 172, | ||||
|             "root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", | ||||
|             "codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" | ||||
|         }, | ||||
|         "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b": { | ||||
|             "balance": "42500", | ||||
|             "nonce": 0, | ||||
|             "root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", | ||||
|             "codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										23
									
								
								cmd/evm/testdata/10/alloc.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								cmd/evm/testdata/10/alloc.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| { | ||||
|   "0x1111111111111111111111111111111111111111" : { | ||||
|     "balance" : "0x010000000000", | ||||
|     "code" : "0xfe", | ||||
|     "nonce" : "0x01", | ||||
|     "storage" : { | ||||
|     } | ||||
|   }, | ||||
|   "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|     "balance" : "0x010000000000", | ||||
|     "code" : "0x", | ||||
|     "nonce" : "0x01", | ||||
|     "storage" : { | ||||
|     } | ||||
|   }, | ||||
|   "0xd02d72e067e77158444ef2020ff2d325f929b363" : { | ||||
|     "balance" : "0x01000000000000", | ||||
|     "code" : "0x", | ||||
|     "nonce" : "0x01", | ||||
|     "storage" : { | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										12
									
								
								cmd/evm/testdata/10/env.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								cmd/evm/testdata/10/env.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| { | ||||
|   "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", | ||||
|   "currentDifficulty" : "0x020000", | ||||
|   "currentNumber" : "0x01", | ||||
|   "currentTimestamp" : "0x079e", | ||||
|   "previousHash" : "0xcb23ee65a163121f640673b41788ee94633941405f95009999b502eedfbbfd4f", | ||||
|   "currentGasLimit" : "0x40000000", | ||||
|   "currentBaseFee" : "0x036b", | ||||
|   "blockHashes" : { | ||||
|     "0" : "0xcb23ee65a163121f640673b41788ee94633941405f95009999b502eedfbbfd4f" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										79
									
								
								cmd/evm/testdata/10/readme.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								cmd/evm/testdata/10/readme.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | ||||
| ## EIP-1559 testing | ||||
| 
 | ||||
| This test contains testcases for EIP-1559, which were reported by Ori as misbehaving.  | ||||
| 
 | ||||
| ``` | ||||
| [user@work evm]$ dir=./testdata/10 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout --output.result=stdout 2>&1 | ||||
| INFO [05-09|22:11:59.436] rejected tx                              index=3 hash=db07bf..ede1e8 from=0xd02d72E067e77158444ef2020Ff2d325f929B363 error="gas limit reached" | ||||
| ``` | ||||
| Output: | ||||
| ```json | ||||
| { | ||||
|  "alloc": { | ||||
|   "0x1111111111111111111111111111111111111111": { | ||||
|    "code": "0xfe", | ||||
|    "balance": "0x10000000000", | ||||
|    "nonce": "0x1" | ||||
|   }, | ||||
|   "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { | ||||
|    "balance": "0x10000000000", | ||||
|    "nonce": "0x1" | ||||
|   }, | ||||
|   "0xd02d72e067e77158444ef2020ff2d325f929b363": { | ||||
|    "balance": "0xff5beffffc95", | ||||
|    "nonce": "0x4" | ||||
|   } | ||||
|  }, | ||||
|  "result": { | ||||
|   "stateRoot": "0xf91a7ec08e4bfea88719aab34deabb000c86902360532b52afa9599d41f2bb8b", | ||||
|   "txRoot": "0xda925f2306a52fa24c15d5cd212d736ee016415fd8dd0c45fd368de7917d64bb", | ||||
|   "receiptRoot": "0x439a25f7fc424c10fb1f89800e4aa1df74156b137239d9ac3eaa7c911c353cd5", | ||||
|   "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", | ||||
|   "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", | ||||
|   "receipts": [ | ||||
|    { | ||||
|     "type": "0x2", | ||||
|     "root": "0x", | ||||
|     "status": "0x0", | ||||
|     "cumulativeGasUsed": "0x10000001", | ||||
|     "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", | ||||
|     "logs": null, | ||||
|     "transactionHash": "0x88980f6efcc5358d9c359663e7b9414722d430497637340ea056b076bc206701", | ||||
|     "contractAddress": "0x0000000000000000000000000000000000000000", | ||||
|     "gasUsed": "0x10000001", | ||||
|     "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", | ||||
|     "transactionIndex": "0x0" | ||||
|    }, | ||||
|    { | ||||
|     "type": "0x2", | ||||
|     "root": "0x", | ||||
|     "status": "0x0", | ||||
|     "cumulativeGasUsed": "0x20000001", | ||||
|     "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", | ||||
|     "logs": null, | ||||
|     "transactionHash": "0xd7bf3886f4e2aef74d525ae072c680f3846f550254401b67cbfda4a233757582", | ||||
|     "contractAddress": "0x0000000000000000000000000000000000000000", | ||||
|     "gasUsed": "0x10000000", | ||||
|     "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", | ||||
|     "transactionIndex": "0x1" | ||||
|    }, | ||||
|    { | ||||
|     "type": "0x2", | ||||
|     "root": "0x", | ||||
|     "status": "0x0", | ||||
|     "cumulativeGasUsed": "0x30000001", | ||||
|     "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", | ||||
|     "logs": null, | ||||
|     "transactionHash": "0x50308296760f01f1eeec7500e9e73cad67469249b1f59e9a9f55e6625a4923db", | ||||
|     "contractAddress": "0x0000000000000000000000000000000000000000", | ||||
|     "gasUsed": "0x10000000", | ||||
|     "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", | ||||
|     "transactionIndex": "0x2" | ||||
|    } | ||||
|   ], | ||||
|   "rejected": [ | ||||
|    3 | ||||
|   ] | ||||
|  } | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										70
									
								
								cmd/evm/testdata/10/txs.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								cmd/evm/testdata/10/txs.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| [ | ||||
|   { | ||||
|     "input" : "0x", | ||||
|     "gas" : "0x10000001", | ||||
|     "nonce" : "0x1", | ||||
|     "to" : "0x1111111111111111111111111111111111111111", | ||||
|     "value" : "0x0", | ||||
|     "v" : "0x0", | ||||
|     "r" : "0x7a45f00bcde9036b026cdf1628b023cd8a31a95c62b5e4dbbee2fa7debe668fb", | ||||
|     "s" : "0x3cc9d6f2cd00a045b0263f2d6dad7d60938d5d13d061af4969f95928aa934d4a", | ||||
|     "secretKey" : "0x41f6e321b31e72173f8ff2e292359e1862f24fba42fe6f97efaf641980eff298", | ||||
|     "chainId" : "0x1", | ||||
|     "type" : "0x2", | ||||
|     "feeCap" : "0xfa0", | ||||
|     "tip" : "0x0", | ||||
|     "accessList" : [ | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "input" : "0x", | ||||
|     "gas" : "0x10000000", | ||||
|     "nonce" : "0x2", | ||||
|     "to" : "0x1111111111111111111111111111111111111111", | ||||
|     "value" : "0x0", | ||||
|     "v" : "0x0", | ||||
|     "r" : "0x4c564b94b0281a8210eeec2dd1fe2e16ff1c1903a8c3a1078d735d7f8208b2af", | ||||
|     "s" : "0x56432b2593e6de95db1cb997b7385217aca03f1615327e231734446b39f266d", | ||||
|     "secretKey" : "0x41f6e321b31e72173f8ff2e292359e1862f24fba42fe6f97efaf641980eff298", | ||||
|     "chainId" : "0x1", | ||||
|     "type" : "0x2", | ||||
|     "feeCap" : "0xfa0", | ||||
|     "tip" : "0x0", | ||||
|     "accessList" : [ | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "input" : "0x", | ||||
|     "gas" : "0x10000000", | ||||
|     "nonce" : "0x3", | ||||
|     "to" : "0x1111111111111111111111111111111111111111", | ||||
|     "value" : "0x0", | ||||
|     "v" : "0x0", | ||||
|     "r" : "0x2ed2ef52f924f59d4a21e1f2a50d3b1109303ce5e32334a7ece9b46f4fbc2a57", | ||||
|     "s" : "0x2980257129cbd3da987226f323d50ba3975a834d165e0681f991b75615605c44", | ||||
|     "secretKey" : "0x41f6e321b31e72173f8ff2e292359e1862f24fba42fe6f97efaf641980eff298", | ||||
|     "chainId" : "0x1", | ||||
|     "type" : "0x2", | ||||
|     "feeCap" : "0xfa0", | ||||
|     "tip" : "0x0", | ||||
|     "accessList" : [ | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "input" : "0x", | ||||
|     "gas" : "0x10000000", | ||||
|     "nonce" : "0x4", | ||||
|     "to" : "0x1111111111111111111111111111111111111111", | ||||
|     "value" : "0x0", | ||||
|     "v" : "0x0", | ||||
|     "r" : "0x5df7d7f8f8e15b36fc9f189cacb625040fad10398d08fc90812595922a2c49b2", | ||||
|     "s" : "0x565fc1803f77a84d754ffe3c5363ab54a8d93a06ea1bb9d4c73c73a282b35917", | ||||
|     "secretKey" : "0x41f6e321b31e72173f8ff2e292359e1862f24fba42fe6f97efaf641980eff298", | ||||
|     "chainId" : "0x1", | ||||
|     "type" : "0x2", | ||||
|     "feeCap" : "0xfa0", | ||||
|     "tip" : "0x0", | ||||
|     "accessList" : [ | ||||
|     ] | ||||
|   } | ||||
| ] | ||||
							
								
								
									
										25
									
								
								cmd/evm/testdata/11/alloc.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								cmd/evm/testdata/11/alloc.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| { | ||||
|     "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|         "balance" : "0x0de0b6b3a7640000", | ||||
|         "code" : "0x61ffff5060046000f3", | ||||
|         "nonce" : "0x01", | ||||
|         "storage" : { | ||||
|         } | ||||
|     }, | ||||
|     "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|         "balance" : "0x0de0b6b3a7640000", | ||||
|         "code" : "0x", | ||||
|         "nonce" : "0x00", | ||||
|         "storage" : { | ||||
|             "0x00" : "0x00" | ||||
|         } | ||||
|     }, | ||||
|     "0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|         "balance" : "0x00", | ||||
|         "code" : "0x6001600055", | ||||
|         "nonce" : "0x00", | ||||
|         "storage" : { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										12
									
								
								cmd/evm/testdata/11/env.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								cmd/evm/testdata/11/env.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| { | ||||
|     "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", | ||||
|     "currentDifficulty" : "0x020000", | ||||
|     "currentNumber" : "0x01", | ||||
|     "currentTimestamp" : "0x03e8", | ||||
|     "previousHash" : "0xfda4419b3660e99f37e536dae1ab081c180136bb38c837a93e93d9aab58553b2", | ||||
|     "currentGasLimit" : "0x0f4240", | ||||
|     "blockHashes" : { | ||||
|         "0" : "0xfda4419b3660e99f37e536dae1ab081c180136bb38c837a93e93d9aab58553b2" | ||||
|     } | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										13
									
								
								cmd/evm/testdata/11/readme.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								cmd/evm/testdata/11/readme.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| ## Test missing basefee | ||||
| 
 | ||||
| In this test, the `currentBaseFee` is missing from the env portion.  | ||||
| On a live blockchain, the basefee is present in the header, and verified as part of header validation.  | ||||
| 
 | ||||
| In `evm t8n`, we don't have blocks, so it needs to be added in the `env`instead.  | ||||
| 
 | ||||
| When it's missing, an error is expected.  | ||||
| 
 | ||||
| ``` | ||||
| dir=./testdata/11 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout --output.result=stdout 2>&1>/dev/null | ||||
| ERROR(3): EIP-1559 config but missing 'currentBaseFee' in env section | ||||
| ``` | ||||
							
								
								
									
										14
									
								
								cmd/evm/testdata/11/txs.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								cmd/evm/testdata/11/txs.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| [ | ||||
|     { | ||||
|         "input" : "0x38600060013960015160005560006000f3", | ||||
|         "gas" : "0x61a80", | ||||
|         "gasPrice" : "0x1", | ||||
|         "nonce" : "0x0", | ||||
|         "value" : "0x186a0", | ||||
|         "v" : "0x1c", | ||||
|         "r" : "0x2e1391fd903387f1cc2b51df083805fb4bbb0d4710a2cdf4a044d191ff7be63e", | ||||
|         "s" : "0x7f10a933c42ab74927db02b1db009e923d9d2ab24ac24d63c399f2fe5d9c9b22", | ||||
|         "secretKey" : "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" | ||||
|     } | ||||
| ] | ||||
| 
 | ||||
							
								
								
									
										11
									
								
								cmd/evm/testdata/9/alloc.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								cmd/evm/testdata/9/alloc.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| { | ||||
|   "0x000000000000000000000000000000000000aaaa": { | ||||
|     "balance": "0x03", | ||||
|     "code": "0x58585454", | ||||
|     "nonce": "0x1" | ||||
|   }, | ||||
|   "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { | ||||
|     "balance": "0x100000000000000", | ||||
|     "nonce": "0x00" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										8
									
								
								cmd/evm/testdata/9/env.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								cmd/evm/testdata/9/env.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| { | ||||
|   "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", | ||||
|   "currentDifficulty": "0x20000", | ||||
|   "currentGasTarget": "0x1000000000", | ||||
|   "currentBaseFee": "0x3B9ACA00", | ||||
|   "currentNumber": "0x1000000", | ||||
|   "currentTimestamp": "0x04" | ||||
| } | ||||
							
								
								
									
										75
									
								
								cmd/evm/testdata/9/readme.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								cmd/evm/testdata/9/readme.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| ## EIP-1559 testing | ||||
| 
 | ||||
| This test contains testcases for EIP-1559, which uses an new transaction type and has a new block parameter.  | ||||
| 
 | ||||
| ### Prestate | ||||
| 
 | ||||
| The alloc portion contains one contract (`0x000000000000000000000000000000000000aaaa`), containing the  | ||||
| following code: `0x58585454`: `PC; PC; SLOAD; SLOAD`. | ||||
| 
 | ||||
| Essentialy, this contract does `SLOAD(0)` and `SLOAD(1)`. | ||||
| 
 | ||||
| The alloc also contains some funds on `0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b`.  | ||||
| 
 | ||||
| ## Transactions | ||||
| 
 | ||||
| There are two transactions, each invokes the contract above.  | ||||
| 
 | ||||
| 1. EIP-1559 ACL-transaction, which contains the `0x0` slot for `0xaaaa` | ||||
| 2. Legacy transaction | ||||
| 
 | ||||
| ## Execution  | ||||
| 
 | ||||
| Running it yields:  | ||||
| ``` | ||||
| $ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace && cat trace-* | grep SLOAD | ||||
| {"pc":2,"op":84,"gas":"0x48c28","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x1"],"returnStack":null,"returnD | ||||
| ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} | ||||
| {"pc":3,"op":84,"gas":"0x483f4","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0","0x0"],"returnStack":null,"returnDa | ||||
| ta":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} | ||||
| {"pc":2,"op":84,"gas":"0x49cf4","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x1"],"returnStack":null,"returnD | ||||
| ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} | ||||
| {"pc":3,"op":84,"gas":"0x494c0","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x0"],"returnStack":null,"returnD | ||||
| ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} | ||||
| ``` | ||||
| 
 | ||||
| We can also get the post-alloc: | ||||
| ``` | ||||
| $ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout | ||||
| { | ||||
|  "alloc": { | ||||
|   "0x000000000000000000000000000000000000aaaa": { | ||||
|    "code": "0x58585454", | ||||
|    "balance": "0x3", | ||||
|    "nonce": "0x1" | ||||
|   }, | ||||
|   "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { | ||||
|    "balance": "0xbfc02677a000" | ||||
|   }, | ||||
|   "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { | ||||
|    "balance": "0xff104fcfea7800", | ||||
|    "nonce": "0x2" | ||||
|   } | ||||
|  } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| If we try to execute it on older rules:  | ||||
| ``` | ||||
| dir=./testdata/9 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout | ||||
| ERROR(10): Failed signing transactions: ERROR(10): Tx 0: failed to sign tx: transaction type not supported | ||||
| ``` | ||||
| 
 | ||||
| It fails, due to the `evm t8n` cannot sign them in with the given signer. We can bypass that, however,  | ||||
| by feeding it presigned transactions, located in `txs_signed.json`.  | ||||
| 
 | ||||
| ``` | ||||
| dir=./testdata/9 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs_signed.json --input.env=$dir/env.json  | ||||
| INFO [05-07|12:28:42.072] rejected tx                              index=0 hash=b4821e..536819 error="transaction type not supported" | ||||
| INFO [05-07|12:28:42.072] rejected tx                              index=1 hash=a9c6c6..fa4036 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="nonce too high: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B, tx: 1 state: 0" | ||||
| INFO [05-07|12:28:42.073] Wrote file                               file=alloc.json | ||||
| INFO [05-07|12:28:42.073] Wrote file                               file=result.json | ||||
| ``` | ||||
| 
 | ||||
| Number `0` is not applicable, and therefore number `1` has wrong nonce, and both are rejected. | ||||
| 
 | ||||
							
								
								
									
										37
									
								
								cmd/evm/testdata/9/txs.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								cmd/evm/testdata/9/txs.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| [ | ||||
|   { | ||||
|     "gas": "0x4ef00", | ||||
|     "tip": "0x2", | ||||
|     "feeCap": "0x12A05F200", | ||||
|     "chainId": "0x1", | ||||
|     "input": "0x", | ||||
|     "nonce": "0x0", | ||||
|     "to": "0x000000000000000000000000000000000000aaaa", | ||||
|     "value": "0x0", | ||||
|     "type" : "0x2", | ||||
|     "accessList": [ | ||||
|       {"address": "0x000000000000000000000000000000000000aaaa", | ||||
|         "storageKeys": [ | ||||
|           "0x0000000000000000000000000000000000000000000000000000000000000000" | ||||
|         ] | ||||
|       } | ||||
|     ], | ||||
|     "v": "0x0", | ||||
|     "r": "0x0", | ||||
|     "s": "0x0", | ||||
|     "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" | ||||
|   }, | ||||
|   { | ||||
|     "gas": "0x4ef00", | ||||
|     "gasPrice": "0x12A05F200", | ||||
|     "chainId": "0x1", | ||||
|     "input": "0x", | ||||
|     "nonce": "0x1", | ||||
|     "to": "0x000000000000000000000000000000000000aaaa", | ||||
|     "value": "0x0", | ||||
|     "v": "0x0", | ||||
|     "r": "0x0", | ||||
|     "s": "0x0", | ||||
|     "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" | ||||
|   } | ||||
| ] | ||||
| @ -299,10 +299,6 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H | ||||
| 	if header.GasLimit > cap { | ||||
| 		return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) | ||||
| 	} | ||||
| 	// Verify that the gasUsed is <= gasLimit
 | ||||
| 	if header.GasUsed > header.GasLimit { | ||||
| 		return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) | ||||
| 	} | ||||
| 	// If all checks passed, validate any special fields for hard forks
 | ||||
| 	if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil { | ||||
| 		return err | ||||
| @ -334,14 +330,21 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainHeaderReader, header | ||||
| 	if parent.Time+c.config.Period > header.Time { | ||||
| 		return errInvalidTimestamp | ||||
| 	} | ||||
| 	// Verify that the gas limit remains within allowed bounds
 | ||||
| 	diff := int64(parent.GasLimit) - int64(header.GasLimit) | ||||
| 	if diff < 0 { | ||||
| 		diff *= -1 | ||||
| 	// Verify that the gasUsed is <= gasLimit
 | ||||
| 	if header.GasUsed > header.GasLimit { | ||||
| 		return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) | ||||
| 	} | ||||
| 	limit := parent.GasLimit / params.GasLimitBoundDivisor | ||||
| 	if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit { | ||||
| 		return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit) | ||||
| 	if !chain.Config().IsLondon(header.Number) { | ||||
| 		// Verify BaseFee not present before EIP-1559 fork.
 | ||||
| 		if header.BaseFee != nil { | ||||
| 			return fmt.Errorf("invalid baseFee before fork: have %d, want <nil>", header.BaseFee) | ||||
| 		} | ||||
| 		if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil { | ||||
| 		// Verify the header's EIP-1559 attributes.
 | ||||
| 		return err | ||||
| 	} | ||||
| 	// Retrieve the snapshot needed to verify this header and cache it
 | ||||
| 	snap, err := c.snapshot(chain, number-1, header.ParentHash, parents) | ||||
| @ -725,7 +728,7 @@ func CliqueRLP(header *types.Header) []byte { | ||||
| } | ||||
| 
 | ||||
| func encodeSigHeader(w io.Writer, header *types.Header) { | ||||
| 	err := rlp.Encode(w, []interface{}{ | ||||
| 	enc := []interface{}{ | ||||
| 		header.ParentHash, | ||||
| 		header.UncleHash, | ||||
| 		header.Coinbase, | ||||
| @ -741,8 +744,11 @@ func encodeSigHeader(w io.Writer, header *types.Header) { | ||||
| 		header.Extra[:len(header.Extra)-crypto.SignatureLength], // Yes, this will panic if extra is too short
 | ||||
| 		header.MixDigest, | ||||
| 		header.Nonce, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 	} | ||||
| 	if header.BaseFee != nil { | ||||
| 		enc = append(enc, header.BaseFee) | ||||
| 	} | ||||
| 	if err := rlp.Encode(w, enc); err != nil { | ||||
| 		panic("can't encode: " + err.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -284,16 +284,18 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa | ||||
| 	if header.GasUsed > header.GasLimit { | ||||
| 		return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) | ||||
| 	} | ||||
| 
 | ||||
| 	// Verify that the gas limit remains within allowed bounds
 | ||||
| 	diff := int64(parent.GasLimit) - int64(header.GasLimit) | ||||
| 	if diff < 0 { | ||||
| 		diff *= -1 | ||||
| 	} | ||||
| 	limit := parent.GasLimit / params.GasLimitBoundDivisor | ||||
| 
 | ||||
| 	if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit { | ||||
| 		return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit) | ||||
| 	// Verify the block's gas usage and (if applicable) verify the base fee.
 | ||||
| 	if !chain.Config().IsLondon(header.Number) { | ||||
| 		// Verify BaseFee not present before EIP-1559 fork.
 | ||||
| 		if header.BaseFee != nil { | ||||
| 			return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee) | ||||
| 		} | ||||
| 		if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil { | ||||
| 		// Verify the header's EIP-1559 attributes.
 | ||||
| 		return err | ||||
| 	} | ||||
| 	// Verify that the block number is parent's +1
 | ||||
| 	if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { | ||||
| @ -604,7 +606,7 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea | ||||
| func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) { | ||||
| 	hasher := sha3.NewLegacyKeccak256() | ||||
| 
 | ||||
| 	rlp.Encode(hasher, []interface{}{ | ||||
| 	enc := []interface{}{ | ||||
| 		header.ParentHash, | ||||
| 		header.UncleHash, | ||||
| 		header.Coinbase, | ||||
| @ -618,7 +620,11 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) { | ||||
| 		header.GasUsed, | ||||
| 		header.Time, | ||||
| 		header.Extra, | ||||
| 	}) | ||||
| 	} | ||||
| 	if header.BaseFee != nil { | ||||
| 		enc = append(enc, header.BaseFee) | ||||
| 	} | ||||
| 	rlp.Encode(hasher, enc) | ||||
| 	hasher.Sum(hash[:0]) | ||||
| 	return hash | ||||
| } | ||||
|  | ||||
							
								
								
									
										93
									
								
								consensus/misc/eip1559.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								consensus/misc/eip1559.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | ||||
| // Copyright 2021 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 misc | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math/big" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/common/math" | ||||
| 	"github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/params" | ||||
| ) | ||||
| 
 | ||||
| // VerifyEip1559Header verifies some header attributes which were changed in EIP-1559,
 | ||||
| // - gas limit check
 | ||||
| // - basefee check
 | ||||
| func VerifyEip1559Header(config *params.ChainConfig, parent, header *types.Header) error { | ||||
| 	// Verify that the gas limit remains within allowed bounds
 | ||||
| 	parentGasLimit := parent.GasLimit | ||||
| 	if !config.IsLondon(parent.Number) { | ||||
| 		parentGasLimit = parent.GasLimit * params.ElasticityMultiplier | ||||
| 	} | ||||
| 	if err := VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	// Verify the header is not malformed
 | ||||
| 	if header.BaseFee == nil { | ||||
| 		return fmt.Errorf("header is missing baseFee") | ||||
| 	} | ||||
| 	// Verify the baseFee is correct based on the parent header.
 | ||||
| 	expectedBaseFee := CalcBaseFee(config, parent) | ||||
| 	if header.BaseFee.Cmp(expectedBaseFee) != 0 { | ||||
| 		return fmt.Errorf("invalid baseFee: have %s, want %s, parentBaseFee %s, parentGasUsed %d", | ||||
| 			expectedBaseFee, header.BaseFee, parent.BaseFee, parent.GasUsed) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // CalcBaseFee calculates the basefee of the header.
 | ||||
| func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { | ||||
| 	// If the current block is the first EIP-1559 block, return the InitialBaseFee.
 | ||||
| 	if !config.IsLondon(parent.Number) { | ||||
| 		return new(big.Int).SetUint64(params.InitialBaseFee) | ||||
| 	} | ||||
| 
 | ||||
| 	var ( | ||||
| 		parentGasTarget          = parent.GasLimit / params.ElasticityMultiplier | ||||
| 		parentGasTargetBig       = new(big.Int).SetUint64(parentGasTarget) | ||||
| 		baseFeeChangeDenominator = new(big.Int).SetUint64(params.BaseFeeChangeDenominator) | ||||
| 	) | ||||
| 	// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
 | ||||
| 	if parent.GasUsed == parentGasTarget { | ||||
| 		return new(big.Int).Set(parent.BaseFee) | ||||
| 	} | ||||
| 	if parent.GasUsed > parentGasTarget { | ||||
| 		// If the parent block used more gas than its target, the baseFee should increase.
 | ||||
| 		gasUsedDelta := new(big.Int).SetUint64(parent.GasUsed - parentGasTarget) | ||||
| 		x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta) | ||||
| 		y := x.Div(x, parentGasTargetBig) | ||||
| 		baseFeeDelta := math.BigMax( | ||||
| 			x.Div(y, baseFeeChangeDenominator), | ||||
| 			common.Big1, | ||||
| 		) | ||||
| 
 | ||||
| 		return x.Add(parent.BaseFee, baseFeeDelta) | ||||
| 	} else { | ||||
| 		// Otherwise if the parent block used less gas than its target, the baseFee should decrease.
 | ||||
| 		gasUsedDelta := new(big.Int).SetUint64(parentGasTarget - parent.GasUsed) | ||||
| 		x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta) | ||||
| 		y := x.Div(x, parentGasTargetBig) | ||||
| 		baseFeeDelta := x.Div(y, baseFeeChangeDenominator) | ||||
| 
 | ||||
| 		return math.BigMax( | ||||
| 			x.Sub(parent.BaseFee, baseFeeDelta), | ||||
| 			common.Big0, | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										133
									
								
								consensus/misc/eip1559_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								consensus/misc/eip1559_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,133 @@ | ||||
| // Copyright 2021 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 misc | ||||
| 
 | ||||
| import ( | ||||
| 	"math/big" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/params" | ||||
| ) | ||||
| 
 | ||||
| // copyConfig does a _shallow_ copy of a given config. Safe to set new values, but
 | ||||
| // do not use e.g. SetInt() on the numbers. For testing only
 | ||||
| func copyConfig(original *params.ChainConfig) *params.ChainConfig { | ||||
| 	return ¶ms.ChainConfig{ | ||||
| 		ChainID:             original.ChainID, | ||||
| 		HomesteadBlock:      original.HomesteadBlock, | ||||
| 		DAOForkBlock:        original.DAOForkBlock, | ||||
| 		DAOForkSupport:      original.DAOForkSupport, | ||||
| 		EIP150Block:         original.EIP150Block, | ||||
| 		EIP150Hash:          original.EIP150Hash, | ||||
| 		EIP155Block:         original.EIP155Block, | ||||
| 		EIP158Block:         original.EIP158Block, | ||||
| 		ByzantiumBlock:      original.ByzantiumBlock, | ||||
| 		ConstantinopleBlock: original.ConstantinopleBlock, | ||||
| 		PetersburgBlock:     original.PetersburgBlock, | ||||
| 		IstanbulBlock:       original.IstanbulBlock, | ||||
| 		MuirGlacierBlock:    original.MuirGlacierBlock, | ||||
| 		BerlinBlock:         original.BerlinBlock, | ||||
| 		LondonBlock:         original.LondonBlock, | ||||
| 		EWASMBlock:          original.EWASMBlock, | ||||
| 		CatalystBlock:       original.CatalystBlock, | ||||
| 		Ethash:              original.Ethash, | ||||
| 		Clique:              original.Clique, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func config() *params.ChainConfig { | ||||
| 	config := copyConfig(params.TestChainConfig) | ||||
| 	config.LondonBlock = big.NewInt(5) | ||||
| 	return config | ||||
| } | ||||
| 
 | ||||
| // TestBlockGasLimits tests the gasLimit checks for blocks both across
 | ||||
| // the EIP-1559 boundary and post-1559 blocks
 | ||||
| func TestBlockGasLimits(t *testing.T) { | ||||
| 	initial := new(big.Int).SetUint64(params.InitialBaseFee) | ||||
| 
 | ||||
| 	for i, tc := range []struct { | ||||
| 		pGasLimit uint64 | ||||
| 		pNum      int64 | ||||
| 		gasLimit  uint64 | ||||
| 		ok        bool | ||||
| 	}{ | ||||
| 		// Transitions from non-london to london
 | ||||
| 		{10000000, 4, 20000000, true},  // No change
 | ||||
| 		{10000000, 4, 20019530, true},  // Upper limit
 | ||||
| 		{10000000, 4, 20019531, false}, // Upper +1
 | ||||
| 		{10000000, 4, 19980470, true},  // Lower limit
 | ||||
| 		{10000000, 4, 19980469, false}, // Lower limit -1
 | ||||
| 		// London to London
 | ||||
| 		{20000000, 5, 20000000, true}, | ||||
| 		{20000000, 5, 20019530, true},  // Upper limit
 | ||||
| 		{20000000, 5, 20019531, false}, // Upper limit +1
 | ||||
| 		{20000000, 5, 19980470, true},  // Lower limit
 | ||||
| 		{20000000, 5, 19980469, false}, // Lower limit -1
 | ||||
| 		{40000000, 5, 40039061, true},  // Upper limit
 | ||||
| 		{40000000, 5, 40039062, false}, // Upper limit +1
 | ||||
| 		{40000000, 5, 39960939, true},  // lower limit
 | ||||
| 		{40000000, 5, 39960938, false}, // Lower limit -1
 | ||||
| 	} { | ||||
| 		parent := &types.Header{ | ||||
| 			GasUsed:  tc.pGasLimit / 2, | ||||
| 			GasLimit: tc.pGasLimit, | ||||
| 			BaseFee:  initial, | ||||
| 			Number:   big.NewInt(tc.pNum), | ||||
| 		} | ||||
| 		header := &types.Header{ | ||||
| 			GasUsed:  tc.gasLimit / 2, | ||||
| 			GasLimit: tc.gasLimit, | ||||
| 			BaseFee:  initial, | ||||
| 			Number:   big.NewInt(tc.pNum + 1), | ||||
| 		} | ||||
| 		err := VerifyEip1559Header(config(), parent, header) | ||||
| 		if tc.ok && err != nil { | ||||
| 			t.Errorf("test %d: Expected valid header: %s", i, err) | ||||
| 		} | ||||
| 		if !tc.ok && err == nil { | ||||
| 			t.Errorf("test %d: Expected invalid header", i) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // TestCalcBaseFee assumes all blocks are 1559-blocks
 | ||||
| func TestCalcBaseFee(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		parentBaseFee   int64 | ||||
| 		parentGasLimit  uint64 | ||||
| 		parentGasUsed   uint64 | ||||
| 		expectedBaseFee int64 | ||||
| 	}{ | ||||
| 		{params.InitialBaseFee, 20000000, 10000000, params.InitialBaseFee}, // usage == target
 | ||||
| 		{params.InitialBaseFee, 20000000, 9000000, 987500000},              // usage below target
 | ||||
| 		{params.InitialBaseFee, 20000000, 11000000, 1012500000},            // usage above target
 | ||||
| 	} | ||||
| 	for i, test := range tests { | ||||
| 		parent := &types.Header{ | ||||
| 			Number:   common.Big32, | ||||
| 			GasLimit: test.parentGasLimit, | ||||
| 			GasUsed:  test.parentGasUsed, | ||||
| 			BaseFee:  big.NewInt(test.parentBaseFee), | ||||
| 		} | ||||
| 		if have, want := CalcBaseFee(config(), parent), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 { | ||||
| 			t.Errorf("test %d: have %d  want %d, ", i, have, want) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										42
									
								
								consensus/misc/gaslimit.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								consensus/misc/gaslimit.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| // Copyright 2021 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 misc | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/params" | ||||
| ) | ||||
| 
 | ||||
| // VerifyGaslimit verifies the header gas limit according increase/decrease
 | ||||
| // in relation to the parent gas limit.
 | ||||
| func VerifyGaslimit(parentGasLimit, headerGasLimit uint64) error { | ||||
| 	// Verify that the gas limit remains within allowed bounds
 | ||||
| 	diff := int64(parentGasLimit) - int64(headerGasLimit) | ||||
| 	if diff < 0 { | ||||
| 		diff *= -1 | ||||
| 	} | ||||
| 	limit := parentGasLimit / params.GasLimitBoundDivisor | ||||
| 	if uint64(diff) >= limit { | ||||
| 		return fmt.Errorf("invalid gas limit: have %d, want %d +-= %d", headerGasLimit, parentGasLimit, limit-1) | ||||
| 	} | ||||
| 	if headerGasLimit < params.MinGasLimit { | ||||
| 		return errors.New("invalid gas limit below 5000") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @ -73,6 +73,10 @@ func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *B | ||||
| 	return db, blockchain, err | ||||
| } | ||||
| 
 | ||||
| func newGwei(n int64) *big.Int { | ||||
| 	return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei)) | ||||
| } | ||||
| 
 | ||||
| // Test fork of length N starting from block i
 | ||||
| func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int)) { | ||||
| 	// Copy old chain up to #i into a new db
 | ||||
| @ -3109,3 +3113,156 @@ func TestEIP2718Transition(t *testing.T) { | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // TestEIP1559Transition tests the following:
 | ||||
| //
 | ||||
| // 1. A tranaction whose feeCap is greater than the baseFee is valid.
 | ||||
| // 2. Gas accounting for access lists on EIP-1559 transactions is correct.
 | ||||
| // 3. Only the transaction's tip will be received by the coinbase.
 | ||||
| // 4. The transaction sender pays for both the tip and baseFee.
 | ||||
| // 5. The coinbase receives only the partially realized tip when
 | ||||
| //    feeCap - tip < baseFee.
 | ||||
| // 6. Legacy transaction behave as expected (e.g. gasPrice = feeCap = tip).
 | ||||
| func TestEIP1559Transition(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
 | ||||
| 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | ||||
| 		key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") | ||||
| 		addr1   = crypto.PubkeyToAddress(key1.PublicKey) | ||||
| 		addr2   = crypto.PubkeyToAddress(key2.PublicKey) | ||||
| 		funds   = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) | ||||
| 		gspec   = &Genesis{ | ||||
| 			Config: params.AllEthashProtocolChanges, | ||||
| 			Alloc: GenesisAlloc{ | ||||
| 				addr1: {Balance: funds}, | ||||
| 				addr2: {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), | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 	) | ||||
| 
 | ||||
| 	gspec.Config.BerlinBlock = common.Big0 | ||||
| 	gspec.Config.LondonBlock = common.Big0 | ||||
| 	genesis := gspec.MustCommit(db) | ||||
| 	signer := types.LatestSigner(gspec.Config) | ||||
| 
 | ||||
| 	blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) { | ||||
| 		b.SetCoinbase(common.Address{1}) | ||||
| 
 | ||||
| 		// One transaction to 0xAAAA
 | ||||
| 		accesses := types.AccessList{types.AccessTuple{ | ||||
| 			Address:     aa, | ||||
| 			StorageKeys: []common.Hash{{0}}, | ||||
| 		}} | ||||
| 
 | ||||
| 		txdata := &types.DynamicFeeTx{ | ||||
| 			ChainID:    gspec.Config.ChainID, | ||||
| 			Nonce:      0, | ||||
| 			To:         &aa, | ||||
| 			Gas:        30000, | ||||
| 			FeeCap:     newGwei(5), | ||||
| 			Tip:        big.NewInt(2), | ||||
| 			AccessList: accesses, | ||||
| 			Data:       []byte{}, | ||||
| 		} | ||||
| 		tx := types.NewTx(txdata) | ||||
| 		tx, _ = types.SignTx(tx, signer, key1) | ||||
| 
 | ||||
| 		b.AddTx(tx) | ||||
| 	}) | ||||
| 
 | ||||
| 	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) | ||||
| 
 | ||||
| 	// 1+2: Ensure EIP-1559 access lists are accounted for via gas usage.
 | ||||
| 	expectedGas := params.TxGas + params.TxAccessListAddressGas + params.TxAccessListStorageKeyGas + | ||||
| 		vm.GasQuickStep*2 + params.WarmStorageReadCostEIP2929 + params.ColdSloadCostEIP2929 | ||||
| 	if block.GasUsed() != expectedGas { | ||||
| 		t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGas, block.GasUsed()) | ||||
| 	} | ||||
| 
 | ||||
| 	state, _ := chain.State() | ||||
| 
 | ||||
| 	// 3: Ensure that miner received only the tx's tip.
 | ||||
| 	actual := state.GetBalance(block.Coinbase()) | ||||
| 	expected := new(big.Int).Add( | ||||
| 		new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].Tip().Uint64()), | ||||
| 		ethash.ConstantinopleBlockReward, | ||||
| 	) | ||||
| 	if actual.Cmp(expected) != 0 { | ||||
| 		t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual) | ||||
| 	} | ||||
| 
 | ||||
| 	// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
 | ||||
| 	actual = new(big.Int).Sub(funds, state.GetBalance(addr1)) | ||||
| 	expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].Tip().Uint64() + block.BaseFee().Uint64())) | ||||
| 	if actual.Cmp(expected) != 0 { | ||||
| 		t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual) | ||||
| 	} | ||||
| 
 | ||||
| 	blocks, _ = GenerateChain(gspec.Config, block, engine, db, 1, func(i int, b *BlockGen) { | ||||
| 		b.SetCoinbase(common.Address{2}) | ||||
| 
 | ||||
| 		txdata := &types.LegacyTx{ | ||||
| 			Nonce:    0, | ||||
| 			To:       &aa, | ||||
| 			Gas:      30000, | ||||
| 			GasPrice: newGwei(5), | ||||
| 		} | ||||
| 		tx := types.NewTx(txdata) | ||||
| 		tx, _ = types.SignTx(tx, signer, key2) | ||||
| 
 | ||||
| 		b.AddTx(tx) | ||||
| 	}) | ||||
| 
 | ||||
| 	if n, err := chain.InsertChain(blocks); err != nil { | ||||
| 		t.Fatalf("block %d: failed to insert into chain: %v", n, err) | ||||
| 	} | ||||
| 
 | ||||
| 	block = chain.GetBlockByNumber(2) | ||||
| 	state, _ = chain.State() | ||||
| 	effectiveTip := block.Transactions()[0].Tip().Uint64() - block.BaseFee().Uint64() | ||||
| 
 | ||||
| 	// 6+5: Ensure that miner received only the tx's effective tip.
 | ||||
| 	actual = state.GetBalance(block.Coinbase()) | ||||
| 	expected = new(big.Int).Add( | ||||
| 		new(big.Int).SetUint64(block.GasUsed()*effectiveTip), | ||||
| 		ethash.ConstantinopleBlockReward, | ||||
| 	) | ||||
| 	if actual.Cmp(expected) != 0 { | ||||
| 		t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual) | ||||
| 	} | ||||
| 
 | ||||
| 	// 4: Ensure the tx sender paid for the gasUsed * (effectiveTip + block baseFee).
 | ||||
| 	actual = new(big.Int).Sub(funds, state.GetBalance(addr2)) | ||||
| 	expected = new(big.Int).SetUint64(block.GasUsed() * (effectiveTip + block.BaseFee().Uint64())) | ||||
| 	if actual.Cmp(expected) != 0 { | ||||
| 		t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -253,7 +253,7 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S | ||||
| 		time = parent.Time() + 10 // block time is fixed at 10 seconds
 | ||||
| 	} | ||||
| 
 | ||||
| 	return &types.Header{ | ||||
| 	header := &types.Header{ | ||||
| 		Root:       state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())), | ||||
| 		ParentHash: parent.Hash(), | ||||
| 		Coinbase:   parent.Coinbase(), | ||||
| @ -267,6 +267,12 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S | ||||
| 		Number:   new(big.Int).Add(parent.Number(), common.Big1), | ||||
| 		Time:     time, | ||||
| 	} | ||||
| 
 | ||||
| 	if chain.Config().IsLondon(parent.Number()) { | ||||
| 		header.BaseFee = misc.CalcBaseFee(chain.Config(), parent.Header()) | ||||
| 	} | ||||
| 
 | ||||
| 	return header | ||||
| } | ||||
| 
 | ||||
| // makeHeaderChain creates a deterministic chain of headers rooted at parent.
 | ||||
|  | ||||
| @ -71,4 +71,8 @@ var ( | ||||
| 	// ErrTxTypeNotSupported is returned if a transaction is not supported in the
 | ||||
| 	// current network configuration.
 | ||||
| 	ErrTxTypeNotSupported = types.ErrTxTypeNotSupported | ||||
| 
 | ||||
| 	// ErrFeeCapTooLow is returned if the transaction fee cap is less than the
 | ||||
| 	// the base fee of the block.
 | ||||
| 	ErrFeeCapTooLow = errors.New("fee cap less than block base fee") | ||||
| ) | ||||
|  | ||||
							
								
								
									
										10
									
								
								core/evm.go
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								core/evm.go
									
									
									
									
									
								
							| @ -37,13 +37,20 @@ type ChainContext interface { | ||||
| 
 | ||||
| // NewEVMBlockContext creates a new context for use in the EVM.
 | ||||
| func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common.Address) vm.BlockContext { | ||||
| 	var ( | ||||
| 		beneficiary common.Address | ||||
| 		baseFee     *big.Int | ||||
| 	) | ||||
| 
 | ||||
| 	// If we don't have an explicit author (i.e. not mining), extract from the header
 | ||||
| 	var beneficiary common.Address | ||||
| 	if author == nil { | ||||
| 		beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation
 | ||||
| 	} else { | ||||
| 		beneficiary = *author | ||||
| 	} | ||||
| 	if header.BaseFee != nil { | ||||
| 		baseFee = new(big.Int).Set(header.BaseFee) | ||||
| 	} | ||||
| 	return vm.BlockContext{ | ||||
| 		CanTransfer: CanTransfer, | ||||
| 		Transfer:    Transfer, | ||||
| @ -52,6 +59,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common | ||||
| 		BlockNumber: new(big.Int).Set(header.Number), | ||||
| 		Time:        new(big.Int).SetUint64(header.Time), | ||||
| 		Difficulty:  new(big.Int).Set(header.Difficulty), | ||||
| 		BaseFee:     baseFee, | ||||
| 		GasLimit:    header.GasLimit, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -291,6 +291,9 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { | ||||
| 	if g.Difficulty == nil { | ||||
| 		head.Difficulty = params.GenesisDifficulty | ||||
| 	} | ||||
| 	if g.Config != nil && g.Config.IsLondon(common.Big0) { | ||||
| 		head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee) | ||||
| 	} | ||||
| 	statedb.Commit(false) | ||||
| 	statedb.Database().TrieDB().Commit(root, true, nil) | ||||
| 
 | ||||
|  | ||||
| @ -63,7 +63,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c | ||||
| 			return | ||||
| 		} | ||||
| 		// Convert the transaction into an executable message and pre-cache its sender
 | ||||
| 		msg, err := tx.AsMessage(signer) | ||||
| 		msg, err := tx.AsMessage(signer, header.BaseFee) | ||||
| 		if err != nil { | ||||
| 			return // Also invalid block, bail out
 | ||||
| 		} | ||||
|  | ||||
| @ -71,9 +71,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg | ||||
| 	vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) | ||||
| 	// Iterate over and process the individual transactions
 | ||||
| 	for i, tx := range block.Transactions() { | ||||
| 		msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number)) | ||||
| 		msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, 0, err | ||||
| 			return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) | ||||
| 		} | ||||
| 		statedb.Prepare(tx.Hash(), block.Hash(), i) | ||||
| 		receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv) | ||||
| @ -139,7 +139,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon | ||||
| // for the transaction, gas used and an error if the transaction failed,
 | ||||
| // indicating the block was invalid.
 | ||||
| func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { | ||||
| 	msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) | ||||
| 	msg, err := tx.AsMessage(types.MakeSigner(config, header.Number), header.BaseFee) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| @ -23,6 +23,7 @@ import ( | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/consensus" | ||||
| 	"github.com/ethereum/go-ethereum/consensus/ethash" | ||||
| 	"github.com/ethereum/go-ethereum/consensus/misc" | ||||
| 	"github.com/ethereum/go-ethereum/core/rawdb" | ||||
| 	"github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/core/vm" | ||||
| @ -38,75 +39,157 @@ import ( | ||||
| // contain invalid transactions
 | ||||
| func TestStateProcessorErrors(t *testing.T) { | ||||
| 	var ( | ||||
| 		signer     = types.HomesteadSigner{} | ||||
| 		signer     = types.LatestSigner(params.TestChainConfig) | ||||
| 		testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | ||||
| 		db         = rawdb.NewMemoryDatabase() | ||||
| 		gspec      = &Genesis{ | ||||
| 			Config: params.TestChainConfig, | ||||
| 		} | ||||
| 		genesis       = gspec.MustCommit(db) | ||||
| 		blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | ||||
| 	) | ||||
| 	defer blockchain.Stop() | ||||
| 	var makeTx = func(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction { | ||||
| 		tx, _ := types.SignTx(types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data), signer, testKey) | ||||
| 		return tx | ||||
| 	} | ||||
| 	for i, tt := range []struct { | ||||
| 		txs  []*types.Transaction | ||||
| 		want string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			txs: []*types.Transaction{ | ||||
| 				makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, nil, nil), | ||||
| 				makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, nil, nil), | ||||
| 	var mkDynamicTx = func(nonce uint64, to common.Address, gasLimit uint64, tip, feeCap *big.Int) *types.Transaction { | ||||
| 		tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{ | ||||
| 			Nonce:  nonce, | ||||
| 			Tip:    tip, | ||||
| 			FeeCap: feeCap, | ||||
| 			Gas:    0, | ||||
| 			To:     &to, | ||||
| 			Value:  big.NewInt(0), | ||||
| 		}), signer, testKey) | ||||
| 		return tx | ||||
| 	} | ||||
| 	{ // Tests against a 'recent' chain definition
 | ||||
| 		var ( | ||||
| 			db    = rawdb.NewMemoryDatabase() | ||||
| 			gspec = &Genesis{ | ||||
| 				Config: params.TestChainConfig, | ||||
| 				Alloc: GenesisAlloc{ | ||||
| 					common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ | ||||
| 						Balance: big.NewInt(1000000000000000000), // 1 ether
 | ||||
| 						Nonce:   0, | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 			genesis       = gspec.MustCommit(db) | ||||
| 			blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | ||||
| 		) | ||||
| 		defer blockchain.Stop() | ||||
| 
 | ||||
| 		for i, tt := range []struct { | ||||
| 			txs  []*types.Transaction | ||||
| 			want string | ||||
| 		}{ | ||||
| 			{ // ErrNonceTooLow
 | ||||
| 				txs: []*types.Transaction{ | ||||
| 					makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil), | ||||
| 					makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil), | ||||
| 				}, | ||||
| 				want: "could not apply tx 1 [0x0026256b3939ed97e2c4a6f3fce8ecf83bdcfa6d507c47838c308a1fb0436f62]: nonce too low: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1", | ||||
| 			}, | ||||
| 			want: "could not apply tx 1 [0x36bfa6d14f1cd35a1be8cc2322982a595fabc0e799f09c1de3bad7bd5b1f7626]: nonce too low: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1", | ||||
| 		}, | ||||
| 		{ | ||||
| 			txs: []*types.Transaction{ | ||||
| 				makeTx(100, common.Address{}, big.NewInt(0), params.TxGas, nil, nil), | ||||
| 			{ // ErrNonceTooHigh
 | ||||
| 				txs: []*types.Transaction{ | ||||
| 					makeTx(100, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil), | ||||
| 				}, | ||||
| 				want: "could not apply tx 0 [0xdebad714ca7f363bd0d8121c4518ad48fa469ca81b0a081be3d10c17460f751b]: nonce too high: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 100 state: 0", | ||||
| 			}, | ||||
| 			want: "could not apply tx 0 [0x51cd272d41ef6011d8138e18bf4043797aca9b713c7d39a97563f9bbe6bdbe6f]: nonce too high: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 100 state: 0", | ||||
| 		}, | ||||
| 		{ | ||||
| 			txs: []*types.Transaction{ | ||||
| 				makeTx(0, common.Address{}, big.NewInt(0), 21000000, nil, nil), | ||||
| 			{ // ErrGasLimitReached
 | ||||
| 				txs: []*types.Transaction{ | ||||
| 					makeTx(0, common.Address{}, big.NewInt(0), 21000000, big.NewInt(875000000), nil), | ||||
| 				}, | ||||
| 				want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached", | ||||
| 			}, | ||||
| 			want: "could not apply tx 0 [0x54c58b530824b0bb84b7a98183f08913b5d74e1cebc368515ef3c65edf8eb56a]: gas limit reached", | ||||
| 		}, | ||||
| 		{ | ||||
| 			txs: []*types.Transaction{ | ||||
| 				makeTx(0, common.Address{}, big.NewInt(1), params.TxGas, nil, nil), | ||||
| 			{ // ErrInsufficientFundsForTransfer
 | ||||
| 				txs: []*types.Transaction{ | ||||
| 					makeTx(0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(875000000), nil), | ||||
| 				}, | ||||
| 				want: "could not apply tx 0 [0x98c796b470f7fcab40aaef5c965a602b0238e1034cce6fb73823042dd0638d74]: insufficient funds for transfer: address 0x71562b71999873DB5b286dF957af199Ec94617F7", | ||||
| 			}, | ||||
| 			want: "could not apply tx 0 [0x3094b17498940d92b13baccf356ce8bfd6f221e926abc903d642fa1466c5b50e]: insufficient funds for transfer: address 0x71562b71999873DB5b286dF957af199Ec94617F7", | ||||
| 		}, | ||||
| 		{ | ||||
| 			txs: []*types.Transaction{ | ||||
| 				makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(0xffffff), nil), | ||||
| 			{ // ErrInsufficientFunds
 | ||||
| 				txs: []*types.Transaction{ | ||||
| 					makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(900000000000000000), nil), | ||||
| 				}, | ||||
| 				want: "could not apply tx 0 [0x4a69690c4b0cd85e64d0d9ea06302455b01e10a83db964d60281739752003440]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 18900000000000000000000", | ||||
| 			}, | ||||
| 			want: "could not apply tx 0 [0xaa3f7d86802b1f364576d9071bf231e31d61b392d306831ac9cf706ff5371ce0]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 0 want 352321515000", | ||||
| 		}, | ||||
| 		{ | ||||
| 			txs: []*types.Transaction{ | ||||
| 				makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, nil, nil), | ||||
| 				makeTx(1, common.Address{}, big.NewInt(0), params.TxGas, nil, nil), | ||||
| 				makeTx(2, common.Address{}, big.NewInt(0), params.TxGas, nil, nil), | ||||
| 				makeTx(3, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(0), nil), | ||||
| 			// ErrGasUintOverflow
 | ||||
| 			// One missing 'core' error is ErrGasUintOverflow: "gas uint64 overflow",
 | ||||
| 			// In order to trigger that one, we'd have to allocate a _huge_ chunk of data, such that the
 | ||||
| 			// multiplication len(data) +gas_per_byte overflows uint64. Not testable at the moment
 | ||||
| 			{ // ErrIntrinsicGas
 | ||||
| 				txs: []*types.Transaction{ | ||||
| 					makeTx(0, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(875000000), nil), | ||||
| 				}, | ||||
| 				want: "could not apply tx 0 [0xcf3b049a0b516cb4f9274b3e2a264359e2ba53b2fb64b7bda2c634d5c9d01fca]: intrinsic gas too low: have 20000, want 21000", | ||||
| 			}, | ||||
| 			want: "could not apply tx 3 [0x836fab5882205362680e49b311a20646de03b630920f18ec6ee3b111a2cf6835]: intrinsic gas too low: have 20000, want 21000", | ||||
| 		}, | ||||
| 		// The last 'core' error is ErrGasUintOverflow: "gas uint64 overflow", but in order to
 | ||||
| 		// trigger that one, we'd have to allocate a _huge_ chunk of data, such that the
 | ||||
| 		// multiplication len(data) +gas_per_byte overflows uint64. Not testable at the moment
 | ||||
| 	} { | ||||
| 		block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs) | ||||
| 		_, err := blockchain.InsertChain(types.Blocks{block}) | ||||
| 		if err == nil { | ||||
| 			t.Fatal("block imported without errors") | ||||
| 			{ // ErrGasLimitReached
 | ||||
| 				txs: []*types.Transaction{ | ||||
| 					makeTx(0, common.Address{}, big.NewInt(0), params.TxGas*1000, big.NewInt(875000000), nil), | ||||
| 				}, | ||||
| 				want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached", | ||||
| 			}, | ||||
| 			{ // ErrFeeCapTooLow
 | ||||
| 				txs: []*types.Transaction{ | ||||
| 					mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)), | ||||
| 				}, | ||||
| 				want: "could not apply tx 0 [0x21e9b9015150fc7f6bd5059890a5e1727f2452df285e8a84f4ca61a74c159ded]: fee cap less than block base fee: address 0x71562b71999873DB5b286dF957af199Ec94617F7, feeCap: 0 baseFee: 875000000", | ||||
| 			}, | ||||
| 		} { | ||||
| 			block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config) | ||||
| 			_, err := blockchain.InsertChain(types.Blocks{block}) | ||||
| 			if err == nil { | ||||
| 				t.Fatal("block imported without errors") | ||||
| 			} | ||||
| 			if have, want := err.Error(), tt.want; have != want { | ||||
| 				t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) | ||||
| 			} | ||||
| 		} | ||||
| 		if have, want := err.Error(), tt.want; have != want { | ||||
| 			t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) | ||||
| 	} | ||||
| 
 | ||||
| 	// One final error is ErrTxTypeNotSupported. For this, we need an older chain
 | ||||
| 	{ | ||||
| 		var ( | ||||
| 			db    = rawdb.NewMemoryDatabase() | ||||
| 			gspec = &Genesis{ | ||||
| 				Config: ¶ms.ChainConfig{ | ||||
| 					ChainID:             big.NewInt(1), | ||||
| 					HomesteadBlock:      big.NewInt(0), | ||||
| 					EIP150Block:         big.NewInt(0), | ||||
| 					EIP155Block:         big.NewInt(0), | ||||
| 					EIP158Block:         big.NewInt(0), | ||||
| 					ByzantiumBlock:      big.NewInt(0), | ||||
| 					ConstantinopleBlock: big.NewInt(0), | ||||
| 					PetersburgBlock:     big.NewInt(0), | ||||
| 					IstanbulBlock:       big.NewInt(0), | ||||
| 					MuirGlacierBlock:    big.NewInt(0), | ||||
| 				}, | ||||
| 				Alloc: GenesisAlloc{ | ||||
| 					common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ | ||||
| 						Balance: big.NewInt(1000000000000000000), // 1 ether
 | ||||
| 						Nonce:   0, | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 			genesis       = gspec.MustCommit(db) | ||||
| 			blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) | ||||
| 		) | ||||
| 		defer blockchain.Stop() | ||||
| 		for i, tt := range []struct { | ||||
| 			txs  []*types.Transaction | ||||
| 			want string | ||||
| 		}{ | ||||
| 			{ // ErrTxTypeNotSupported
 | ||||
| 				txs: []*types.Transaction{ | ||||
| 					mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)), | ||||
| 				}, | ||||
| 				want: "could not apply tx 0 [0x21e9b9015150fc7f6bd5059890a5e1727f2452df285e8a84f4ca61a74c159ded]: transaction type not supported", | ||||
| 			}, | ||||
| 		} { | ||||
| 			block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config) | ||||
| 			_, err := blockchain.InsertChain(types.Blocks{block}) | ||||
| 			if err == nil { | ||||
| 				t.Fatal("block imported without errors") | ||||
| 			} | ||||
| 			if have, want := err.Error(), tt.want; have != want { | ||||
| 				t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -115,11 +198,11 @@ func TestStateProcessorErrors(t *testing.T) { | ||||
| // valid, and no proper post-state can be made. But from the perspective of the blockchain, the block is sufficiently
 | ||||
| // valid to be considered for import:
 | ||||
| // - valid pow (fake), ancestry, difficulty, gaslimit etc
 | ||||
| func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Transactions) *types.Block { | ||||
| func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Transactions, config *params.ChainConfig) *types.Block { | ||||
| 	header := &types.Header{ | ||||
| 		ParentHash: parent.Hash(), | ||||
| 		Coinbase:   parent.Coinbase(), | ||||
| 		Difficulty: engine.CalcDifficulty(&fakeChainReader{params.TestChainConfig}, parent.Time()+10, &types.Header{ | ||||
| 		Difficulty: engine.CalcDifficulty(&fakeChainReader{config}, parent.Time()+10, &types.Header{ | ||||
| 			Number:     parent.Number(), | ||||
| 			Time:       parent.Time(), | ||||
| 			Difficulty: parent.Difficulty(), | ||||
| @ -130,8 +213,10 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr | ||||
| 		Time:      parent.Time() + 10, | ||||
| 		UncleHash: types.EmptyUncleHash, | ||||
| 	} | ||||
| 	if config.IsLondon(header.Number) { | ||||
| 		header.BaseFee = misc.CalcBaseFee(config, parent.Header()) | ||||
| 	} | ||||
| 	var receipts []*types.Receipt | ||||
| 
 | ||||
| 	// The post-state result doesn't need to be correct (this is a bad block), but we do need something there
 | ||||
| 	// Preferably something unique. So let's use a combo of blocknum + txhash
 | ||||
| 	hasher := sha3.NewLegacyKeccak256() | ||||
|  | ||||
| @ -22,6 +22,7 @@ import ( | ||||
| 	"math/big" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	cmath "github.com/ethereum/go-ethereum/common/math" | ||||
| 	"github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/core/vm" | ||||
| 	"github.com/ethereum/go-ethereum/params" | ||||
| @ -49,6 +50,8 @@ type StateTransition struct { | ||||
| 	msg        Message | ||||
| 	gas        uint64 | ||||
| 	gasPrice   *big.Int | ||||
| 	feeCap     *big.Int | ||||
| 	tip        *big.Int | ||||
| 	initialGas uint64 | ||||
| 	value      *big.Int | ||||
| 	data       []byte | ||||
| @ -62,6 +65,8 @@ type Message interface { | ||||
| 	To() *common.Address | ||||
| 
 | ||||
| 	GasPrice() *big.Int | ||||
| 	FeeCap() *big.Int | ||||
| 	Tip() *big.Int | ||||
| 	Gas() uint64 | ||||
| 	Value() *big.Int | ||||
| 
 | ||||
| @ -154,6 +159,8 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition | ||||
| 		evm:      evm, | ||||
| 		msg:      msg, | ||||
| 		gasPrice: msg.GasPrice(), | ||||
| 		feeCap:   msg.FeeCap(), | ||||
| 		tip:      msg.Tip(), | ||||
| 		value:    msg.Value(), | ||||
| 		data:     msg.Data(), | ||||
| 		state:    evm.StateDB, | ||||
| @ -206,6 +213,15 @@ func (st *StateTransition) preCheck() error { | ||||
| 				st.msg.From().Hex(), msgNonce, stNonce) | ||||
| 		} | ||||
| 	} | ||||
| 	// Make sure that transaction feeCap is greater than the baseFee (post london)
 | ||||
| 	if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) { | ||||
| 		// This will panic if baseFee is nil, but basefee presence is verified
 | ||||
| 		// as part of header validation.
 | ||||
| 		if st.feeCap.Cmp(st.evm.Context.BaseFee) < 0 { | ||||
| 			return fmt.Errorf("%w: address %v, feeCap: %s baseFee: %s", ErrFeeCapTooLow, | ||||
| 				st.msg.From().Hex(), st.feeCap, st.evm.Context.BaseFee) | ||||
| 		} | ||||
| 	} | ||||
| 	return st.buyGas() | ||||
| } | ||||
| 
 | ||||
| @ -281,7 +297,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { | ||||
| 		// After EIP-3529: refunds are capped to gasUsed / 5
 | ||||
| 		st.refundGas(params.RefundQuotientEIP3529) | ||||
| 	} | ||||
| 	st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) | ||||
| 	effectiveTip := st.gasPrice | ||||
| 	if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) { | ||||
| 		effectiveTip = cmath.BigMin(st.tip, new(big.Int).Sub(st.feeCap, st.evm.Context.BaseFee)) | ||||
| 	} | ||||
| 	st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)) | ||||
| 
 | ||||
| 	return &ExecutionResult{ | ||||
| 		UsedGas:    st.gasUsed(), | ||||
|  | ||||
| @ -94,7 +94,6 @@ func (tx *AccessListTx) copy() TxData { | ||||
| } | ||||
| 
 | ||||
| // 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 } | ||||
| @ -102,6 +101,8 @@ 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) tip() *big.Int          { return tx.GasPrice } | ||||
| func (tx *AccessListTx) feeCap() *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 } | ||||
|  | ||||
| @ -82,6 +82,9 @@ type Header struct { | ||||
| 	Extra       []byte         `json:"extraData"        gencodec:"required"` | ||||
| 	MixDigest   common.Hash    `json:"mixHash"` | ||||
| 	Nonce       BlockNonce     `json:"nonce"` | ||||
| 
 | ||||
| 	// BaseFee was added by EIP-1559 and is ignored in legacy headers.
 | ||||
| 	BaseFee *big.Int `json:"baseFee" rlp:"optional"` | ||||
| } | ||||
| 
 | ||||
| // field type overrides for gencodec
 | ||||
| @ -92,6 +95,7 @@ type headerMarshaling struct { | ||||
| 	GasUsed    hexutil.Uint64 | ||||
| 	Time       hexutil.Uint64 | ||||
| 	Extra      hexutil.Bytes | ||||
| 	BaseFee    *hexutil.Big | ||||
| 	Hash       common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
 | ||||
| } | ||||
| 
 | ||||
| @ -229,6 +233,9 @@ func CopyHeader(h *Header) *Header { | ||||
| 	if cpy.Number = new(big.Int); h.Number != nil { | ||||
| 		cpy.Number.Set(h.Number) | ||||
| 	} | ||||
| 	if h.BaseFee != nil { | ||||
| 		cpy.BaseFee = new(big.Int).Set(h.BaseFee) | ||||
| 	} | ||||
| 	if len(h.Extra) > 0 { | ||||
| 		cpy.Extra = make([]byte, len(h.Extra)) | ||||
| 		copy(cpy.Extra, h.Extra) | ||||
| @ -289,6 +296,13 @@ func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash } | ||||
| func (b *Block) UncleHash() common.Hash   { return b.header.UncleHash } | ||||
| func (b *Block) Extra() []byte            { return common.CopyBytes(b.header.Extra) } | ||||
| 
 | ||||
| func (b *Block) BaseFee() *big.Int { | ||||
| 	if b.header.BaseFee == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return new(big.Int).Set(b.header.BaseFee) | ||||
| } | ||||
| 
 | ||||
| func (b *Block) Header() *Header { return CopyHeader(b.header) } | ||||
| 
 | ||||
| // Body returns the non-header content of the block.
 | ||||
|  | ||||
| @ -68,6 +68,71 @@ func TestBlockEncoding(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestEIP1559BlockEncoding(t *testing.T) { | ||||
| 	blockEnc := common.FromHex("f9030bf901fea083cafc574e1f51ba9dc0568fc617a08ea2429fb384059c972f13b19fa1c8dd55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a05fe50b260da6308036625b850b5d6ced6d0a9f814c0688bc91ffb7b7a3a54b67a0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4843b9aca00f90106f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b8a302f8a0018080843b9aca008301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8c0") | ||||
| 	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(21000)) | ||||
| 	check("Coinbase", block.Coinbase(), common.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1")) | ||||
| 	check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498")) | ||||
| 	check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017")) | ||||
| 	check("Hash", block.Hash(), common.HexToHash("c7252048cd273fe0dac09650027d07f0e3da4ee0675ebbb26627cea92729c372")) | ||||
| 	check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4)) | ||||
| 	check("Time", block.Time(), uint64(1426516743)) | ||||
| 	check("Size", block.Size(), common.StorageSize(len(blockEnc))) | ||||
| 	check("BaseFee", block.BaseFee(), new(big.Int).SetUint64(params.InitialBaseFee)) | ||||
| 
 | ||||
| 	tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil) | ||||
| 	tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")) | ||||
| 
 | ||||
| 	addr := common.HexToAddress("0x0000000000000000000000000000000000000001") | ||||
| 	accesses := AccessList{AccessTuple{ | ||||
| 		Address: addr, | ||||
| 		StorageKeys: []common.Hash{ | ||||
| 			{0}, | ||||
| 		}, | ||||
| 	}} | ||||
| 	to := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") | ||||
| 	txdata := &DynamicFeeTx{ | ||||
| 		ChainID:    big.NewInt(1), | ||||
| 		Nonce:      0, | ||||
| 		To:         &to, | ||||
| 		Gas:        123457, | ||||
| 		FeeCap:     new(big.Int).Set(block.BaseFee()), | ||||
| 		Tip:        big.NewInt(0), | ||||
| 		AccessList: accesses, | ||||
| 		Data:       []byte{}, | ||||
| 	} | ||||
| 	tx2 := NewTx(txdata) | ||||
| 	tx2, err := tx2.WithSignature(LatestSignerForChainID(big.NewInt(1)), common.Hex2Bytes("fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a800")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("invalid signature error: ", err) | ||||
| 	} | ||||
| 
 | ||||
| 	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(), tx2.Type()) | ||||
| 	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 | ||||
|  | ||||
							
								
								
									
										104
									
								
								core/types/dynamic_fee_tx.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								core/types/dynamic_fee_tx.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | ||||
| // Copyright 2021 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" | ||||
| ) | ||||
| 
 | ||||
| type DynamicFeeTx struct { | ||||
| 	ChainID    *big.Int | ||||
| 	Nonce      uint64 | ||||
| 	Tip        *big.Int | ||||
| 	FeeCap     *big.Int | ||||
| 	Gas        uint64 | ||||
| 	To         *common.Address `rlp:"nil"` // nil means contract creation
 | ||||
| 	Value      *big.Int | ||||
| 	Data       []byte | ||||
| 	AccessList AccessList | ||||
| 
 | ||||
| 	// Signature values
 | ||||
| 	V *big.Int `json:"v" gencodec:"required"` | ||||
| 	R *big.Int `json:"r" gencodec:"required"` | ||||
| 	S *big.Int `json:"s" gencodec:"required"` | ||||
| } | ||||
| 
 | ||||
| // copy creates a deep copy of the transaction data and initializes all fields.
 | ||||
| func (tx *DynamicFeeTx) copy() TxData { | ||||
| 	cpy := &DynamicFeeTx{ | ||||
| 		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), | ||||
| 		Tip:        new(big.Int), | ||||
| 		FeeCap:     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.Tip != nil { | ||||
| 		cpy.Tip.Set(tx.Tip) | ||||
| 	} | ||||
| 	if tx.FeeCap != nil { | ||||
| 		cpy.FeeCap.Set(tx.FeeCap) | ||||
| 	} | ||||
| 	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 *DynamicFeeTx) txType() byte           { return DynamicFeeTxType } | ||||
| func (tx *DynamicFeeTx) chainID() *big.Int      { return tx.ChainID } | ||||
| func (tx *DynamicFeeTx) protected() bool        { return true } | ||||
| func (tx *DynamicFeeTx) accessList() AccessList { return tx.AccessList } | ||||
| func (tx *DynamicFeeTx) data() []byte           { return tx.Data } | ||||
| func (tx *DynamicFeeTx) gas() uint64            { return tx.Gas } | ||||
| func (tx *DynamicFeeTx) feeCap() *big.Int       { return tx.FeeCap } | ||||
| func (tx *DynamicFeeTx) tip() *big.Int          { return tx.Tip } | ||||
| func (tx *DynamicFeeTx) gasPrice() *big.Int     { return tx.FeeCap } | ||||
| func (tx *DynamicFeeTx) value() *big.Int        { return tx.Value } | ||||
| func (tx *DynamicFeeTx) nonce() uint64          { return tx.Nonce } | ||||
| func (tx *DynamicFeeTx) to() *common.Address    { return tx.To } | ||||
| 
 | ||||
| func (tx *DynamicFeeTx) rawSignatureValues() (v, r, s *big.Int) { | ||||
| 	return tx.V, tx.R, tx.S | ||||
| } | ||||
| 
 | ||||
| func (tx *DynamicFeeTx) setSignatureValues(chainID, v, r, s *big.Int) { | ||||
| 	tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s | ||||
| } | ||||
| @ -91,13 +91,14 @@ func (tx *LegacyTx) copy() TxData { | ||||
| } | ||||
| 
 | ||||
| // 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) tip() *big.Int          { return tx.GasPrice } | ||||
| func (tx *LegacyTx) feeCap() *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 } | ||||
|  | ||||
| @ -120,10 +120,6 @@ func (r *Receipt) EncodeRLP(w io.Writer) error { | ||||
| 	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() | ||||
| @ -159,7 +155,7 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error { | ||||
| 			return errEmptyTypedReceipt | ||||
| 		} | ||||
| 		r.Type = b[0] | ||||
| 		if r.Type == AccessListTxType { | ||||
| 		if r.Type == AccessListTxType || r.Type == DynamicFeeTxType { | ||||
| 			var dec receiptRLP | ||||
| 			if err := rlp.DecodeBytes(b[1:], &dec); err != nil { | ||||
| 				return err | ||||
| @ -263,6 +259,9 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) { | ||||
| 	case AccessListTxType: | ||||
| 		w.WriteByte(AccessListTxType) | ||||
| 		rlp.Encode(w, data) | ||||
| 	case DynamicFeeTxType: | ||||
| 		w.WriteByte(DynamicFeeTxType) | ||||
| 		rlp.Encode(w, data) | ||||
| 	default: | ||||
| 		// For unsupported types, write nothing. Since this is for
 | ||||
| 		// DeriveSha, the error will be caught matching the derived hash
 | ||||
|  | ||||
| @ -26,6 +26,7 @@ import ( | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/common/math" | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| 	"github.com/ethereum/go-ethereum/rlp" | ||||
| ) | ||||
| @ -42,6 +43,7 @@ var ( | ||||
| const ( | ||||
| 	LegacyTxType = iota | ||||
| 	AccessListTxType | ||||
| 	DynamicFeeTxType | ||||
| ) | ||||
| 
 | ||||
| // Transaction is an Ethereum transaction.
 | ||||
| @ -74,6 +76,8 @@ type TxData interface { | ||||
| 	data() []byte | ||||
| 	gas() uint64 | ||||
| 	gasPrice() *big.Int | ||||
| 	tip() *big.Int | ||||
| 	feeCap() *big.Int | ||||
| 	value() *big.Int | ||||
| 	nonce() uint64 | ||||
| 	to() *common.Address | ||||
| @ -177,6 +181,10 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { | ||||
| 		var inner AccessListTx | ||||
| 		err := rlp.DecodeBytes(b[1:], &inner) | ||||
| 		return &inner, err | ||||
| 	case DynamicFeeTxType: | ||||
| 		var inner DynamicFeeTx | ||||
| 		err := rlp.DecodeBytes(b[1:], &inner) | ||||
| 		return &inner, err | ||||
| 	default: | ||||
| 		return nil, ErrTxTypeNotSupported | ||||
| 	} | ||||
| @ -260,6 +268,12 @@ 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()) } | ||||
| 
 | ||||
| // Tip returns the tip per gas of the transaction.
 | ||||
| func (tx *Transaction) Tip() *big.Int { return new(big.Int).Set(tx.inner.tip()) } | ||||
| 
 | ||||
| // FeeCap returns the fee cap per gas of the transaction.
 | ||||
| func (tx *Transaction) FeeCap() *big.Int { return new(big.Int).Set(tx.inner.feeCap()) } | ||||
| 
 | ||||
| // Value returns the ether amount of the transaction.
 | ||||
| func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) } | ||||
| 
 | ||||
| @ -486,12 +500,14 @@ type Message struct { | ||||
| 	amount     *big.Int | ||||
| 	gasLimit   uint64 | ||||
| 	gasPrice   *big.Int | ||||
| 	feeCap     *big.Int | ||||
| 	tip        *big.Int | ||||
| 	data       []byte | ||||
| 	accessList AccessList | ||||
| 	checkNonce bool | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
| func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice, feeCap, tip *big.Int, data []byte, accessList AccessList, checkNonce bool) Message { | ||||
| 	return Message{ | ||||
| 		from:       from, | ||||
| 		to:         to, | ||||
| @ -499,6 +515,8 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b | ||||
| 		amount:     amount, | ||||
| 		gasLimit:   gasLimit, | ||||
| 		gasPrice:   gasPrice, | ||||
| 		feeCap:     feeCap, | ||||
| 		tip:        tip, | ||||
| 		data:       data, | ||||
| 		accessList: accessList, | ||||
| 		checkNonce: checkNonce, | ||||
| @ -506,11 +524,13 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b | ||||
| } | ||||
| 
 | ||||
| // AsMessage returns the transaction as a core.Message.
 | ||||
| func (tx *Transaction) AsMessage(s Signer) (Message, error) { | ||||
| func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) { | ||||
| 	msg := Message{ | ||||
| 		nonce:      tx.Nonce(), | ||||
| 		gasLimit:   tx.Gas(), | ||||
| 		gasPrice:   new(big.Int).Set(tx.GasPrice()), | ||||
| 		feeCap:     new(big.Int).Set(tx.FeeCap()), | ||||
| 		tip:        new(big.Int).Set(tx.Tip()), | ||||
| 		to:         tx.To(), | ||||
| 		amount:     tx.Value(), | ||||
| 		data:       tx.Data(), | ||||
| @ -518,6 +538,11 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) { | ||||
| 		checkNonce: true, | ||||
| 	} | ||||
| 
 | ||||
| 	// If baseFee provided, set gasPrice to effectiveGasPrice.
 | ||||
| 	if baseFee != nil { | ||||
| 		msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.tip, baseFee), msg.feeCap) | ||||
| 	} | ||||
| 
 | ||||
| 	var err error | ||||
| 	msg.from, err = Sender(s, tx) | ||||
| 	return msg, err | ||||
| @ -526,6 +551,8 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) { | ||||
| 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) FeeCap() *big.Int       { return m.feeCap } | ||||
| func (m Message) Tip() *big.Int          { return m.tip } | ||||
| 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 } | ||||
|  | ||||
| @ -30,15 +30,19 @@ 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"` | ||||
| 	Nonce                *hexutil.Uint64 `json:"nonce"` | ||||
| 	GasPrice             *hexutil.Big    `json:"gasPrice"` | ||||
| 	FeeCap               *hexutil.Big    `json:"feeCap"` | ||||
| 	Tip                  *hexutil.Big    `json:"tip"` | ||||
| 	MaxPriorityFeePerGas *hexutil.Big    `json:"maxPriorityFeePerGas"` | ||||
| 	MaxFeePerGas         *hexutil.Big    `json:"maxFeePerGas"` | ||||
| 	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"` | ||||
| @ -79,6 +83,19 @@ func (t *Transaction) MarshalJSON() ([]byte, error) { | ||||
| 		enc.V = (*hexutil.Big)(tx.V) | ||||
| 		enc.R = (*hexutil.Big)(tx.R) | ||||
| 		enc.S = (*hexutil.Big)(tx.S) | ||||
| 	case *DynamicFeeTx: | ||||
| 		enc.ChainID = (*hexutil.Big)(tx.ChainID) | ||||
| 		enc.AccessList = &tx.AccessList | ||||
| 		enc.Nonce = (*hexutil.Uint64)(&tx.Nonce) | ||||
| 		enc.Gas = (*hexutil.Uint64)(&tx.Gas) | ||||
| 		enc.FeeCap = (*hexutil.Big)(tx.FeeCap) | ||||
| 		enc.Tip = (*hexutil.Big)(tx.Tip) | ||||
| 		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) | ||||
| } | ||||
| @ -191,6 +208,75 @@ func (t *Transaction) UnmarshalJSON(input []byte) error { | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	case DynamicFeeTxType: | ||||
| 		var itx DynamicFeeTx | ||||
| 		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) | ||||
| 		switch { | ||||
| 		case dec.Tip == nil && dec.MaxPriorityFeePerGas == nil: | ||||
| 			return errors.New("at least one of 'tip' or 'maxPriorityFeePerGas' must be defined") | ||||
| 		case dec.Tip != nil && dec.MaxPriorityFeePerGas != nil: | ||||
| 			return errors.New("only one of 'tip' or 'maxPriorityFeePerGas' may be defined") | ||||
| 		case dec.Tip != nil && dec.MaxPriorityFeePerGas == nil: | ||||
| 			itx.Tip = (*big.Int)(dec.Tip) | ||||
| 		case dec.Tip == nil && dec.MaxPriorityFeePerGas != nil: | ||||
| 			itx.Tip = (*big.Int)(dec.MaxPriorityFeePerGas) | ||||
| 		} | ||||
| 		switch { | ||||
| 		case dec.FeeCap == nil && dec.MaxFeePerGas == nil: | ||||
| 			return errors.New("at least one of 'feeCap' or 'maxFeePerGas' must be defined") | ||||
| 		case dec.FeeCap != nil && dec.MaxFeePerGas != nil: | ||||
| 			return errors.New("only one of 'feeCap' or 'maxFeePerGas' may be defined") | ||||
| 		case dec.FeeCap != nil && dec.MaxFeePerGas == nil: | ||||
| 			itx.FeeCap = (*big.Int)(dec.FeeCap) | ||||
| 		case dec.FeeCap == nil && dec.MaxFeePerGas != nil: | ||||
| 			itx.FeeCap = (*big.Int)(dec.MaxFeePerGas) | ||||
| 		} | ||||
| 		if dec.Gas == nil { | ||||
| 			return errors.New("missing required field 'gas' for txdata") | ||||
| 		} | ||||
| 		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 | ||||
| 	} | ||||
|  | ||||
| @ -40,6 +40,8 @@ type sigCache struct { | ||||
| func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { | ||||
| 	var signer Signer | ||||
| 	switch { | ||||
| 	case config.IsLondon(blockNumber): | ||||
| 		signer = NewLondonSigner(config.ChainID) | ||||
| 	case config.IsBerlin(blockNumber): | ||||
| 		signer = NewEIP2930Signer(config.ChainID) | ||||
| 	case config.IsEIP155(blockNumber): | ||||
| @ -61,6 +63,9 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { | ||||
| // have the current block number available, use MakeSigner instead.
 | ||||
| func LatestSigner(config *params.ChainConfig) Signer { | ||||
| 	if config.ChainID != nil { | ||||
| 		if config.LondonBlock != nil { | ||||
| 			return NewLondonSigner(config.ChainID) | ||||
| 		} | ||||
| 		if config.BerlinBlock != nil { | ||||
| 			return NewEIP2930Signer(config.ChainID) | ||||
| 		} | ||||
| @ -82,7 +87,7 @@ func LatestSignerForChainID(chainID *big.Int) Signer { | ||||
| 	if chainID == nil { | ||||
| 		return HomesteadSigner{} | ||||
| 	} | ||||
| 	return NewEIP2930Signer(chainID) | ||||
| 	return NewLondonSigner(chainID) | ||||
| } | ||||
| 
 | ||||
| // SignTx signs the transaction using the given signer and private key.
 | ||||
| @ -165,6 +170,72 @@ type Signer interface { | ||||
| 	Equal(Signer) bool | ||||
| } | ||||
| 
 | ||||
| type londonSigner struct{ eip2930Signer } | ||||
| 
 | ||||
| // NewLondonSigner returns a signer that accepts
 | ||||
| // - EIP-1559 dynamic fee transactions
 | ||||
| // - EIP-2930 access list transactions,
 | ||||
| // - EIP-155 replay protected transactions, and
 | ||||
| // - legacy Homestead transactions.
 | ||||
| func NewLondonSigner(chainId *big.Int) Signer { | ||||
| 	return londonSigner{eip2930Signer{NewEIP155Signer(chainId)}} | ||||
| } | ||||
| 
 | ||||
| func (s londonSigner) Sender(tx *Transaction) (common.Address, error) { | ||||
| 	if tx.Type() != DynamicFeeTxType { | ||||
| 		return s.eip2930Signer.Sender(tx) | ||||
| 	} | ||||
| 	V, R, S := tx.RawSignatureValues() | ||||
| 	// DynamicFee 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)) | ||||
| 	if tx.ChainId().Cmp(s.chainId) != 0 { | ||||
| 		return common.Address{}, ErrInvalidChainId | ||||
| 	} | ||||
| 	return recoverPlain(s.Hash(tx), R, S, V, true) | ||||
| } | ||||
| 
 | ||||
| func (s londonSigner) Equal(s2 Signer) bool { | ||||
| 	x, ok := s2.(londonSigner) | ||||
| 	return ok && x.chainId.Cmp(s.chainId) == 0 | ||||
| } | ||||
| 
 | ||||
| func (s londonSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) { | ||||
| 	txdata, ok := tx.inner.(*DynamicFeeTx) | ||||
| 	if !ok { | ||||
| 		return s.eip2930Signer.SignatureValues(tx, sig) | ||||
| 	} | ||||
| 	// 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])) | ||||
| 	return R, S, V, nil | ||||
| } | ||||
| 
 | ||||
| // Hash returns the hash to be signed by the sender.
 | ||||
| // It does not uniquely identify the transaction.
 | ||||
| func (s londonSigner) Hash(tx *Transaction) common.Hash { | ||||
| 	if tx.Type() != DynamicFeeTxType { | ||||
| 		return s.eip2930Signer.Hash(tx) | ||||
| 	} | ||||
| 	return prefixedRlpHash( | ||||
| 		tx.Type(), | ||||
| 		[]interface{}{ | ||||
| 			s.chainId, | ||||
| 			tx.Nonce(), | ||||
| 			tx.Tip(), | ||||
| 			tx.FeeCap(), | ||||
| 			tx.Gas(), | ||||
| 			tx.To(), | ||||
| 			tx.Value(), | ||||
| 			tx.Data(), | ||||
| 			tx.AccessList(), | ||||
| 		}) | ||||
| } | ||||
| 
 | ||||
| type eip2930Signer struct{ EIP155Signer } | ||||
| 
 | ||||
| // NewEIP2930Signer returns a signer that accepts EIP-2930 access list transactions,
 | ||||
| @ -192,8 +263,8 @@ func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) { | ||||
| 		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.
 | ||||
| 		// AL 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 | ||||
|  | ||||
| @ -26,6 +26,7 @@ import ( | ||||
| 
 | ||||
| var activators = map[int]func(*JumpTable){ | ||||
| 	3529: enable3529, | ||||
| 	3198: enable3198, | ||||
| 	2929: enable2929, | ||||
| 	2200: enable2200, | ||||
| 	1884: enable1884, | ||||
| @ -154,3 +155,22 @@ func enable3529(jt *JumpTable) { | ||||
| 	jt[SSTORE].dynamicGas = gasSStoreEIP3529 | ||||
| 	jt[SELFDESTRUCT].dynamicGas = gasSelfdestructEIP3529 | ||||
| } | ||||
| 
 | ||||
| // enable3198 applies EIP-3198 (BASEFEE Opcode)
 | ||||
| // - Adds an opcode that returns the current block's base fee.
 | ||||
| func enable3198(jt *JumpTable) { | ||||
| 	// New opcode
 | ||||
| 	jt[BASEFEE] = &operation{ | ||||
| 		execute:     opBaseFee, | ||||
| 		constantGas: GasQuickStep, | ||||
| 		minStack:    minStack(0, 1), | ||||
| 		maxStack:    maxStack(0, 1), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // opBaseFee implements BASEFEE opcode
 | ||||
| func opBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { | ||||
| 	baseFee, _ := uint256.FromBig(interpreter.evm.Context.BaseFee) | ||||
| 	scope.Stack.push(baseFee) | ||||
| 	return nil, nil | ||||
| } | ||||
|  | ||||
| @ -93,6 +93,7 @@ type BlockContext struct { | ||||
| 	BlockNumber *big.Int       // Provides information for NUMBER
 | ||||
| 	Time        *big.Int       // Provides information for TIME
 | ||||
| 	Difficulty  *big.Int       // Provides information for DIFFICULTY
 | ||||
| 	BaseFee     *big.Int       // Provides information for BASEFEE
 | ||||
| } | ||||
| 
 | ||||
| // TxContext provides the EVM with information about a transaction.
 | ||||
|  | ||||
| @ -68,6 +68,7 @@ type JumpTable [256]*operation | ||||
| func newLondonInstructionSet() JumpTable { | ||||
| 	instructionSet := newBerlinInstructionSet() | ||||
| 	enable3529(&instructionSet) // EIP-3529: Reduction in refunds https://eips.ethereum.org/EIPS/eip-3529
 | ||||
| 	enable3198(&instructionSet) // Base fee opcode https://eips.ethereum.org/EIPS/eip-3198
 | ||||
| 	return instructionSet | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -103,6 +103,7 @@ const ( | ||||
| 	GASLIMIT | ||||
| 	CHAINID     OpCode = 0x46 | ||||
| 	SELFBALANCE OpCode = 0x47 | ||||
| 	BASEFEE     OpCode = 0x48 | ||||
| ) | ||||
| 
 | ||||
| // 0x50 range - 'storage' and execution.
 | ||||
| @ -280,6 +281,7 @@ var opCodeToString = map[OpCode]string{ | ||||
| 	GASLIMIT:    "GASLIMIT", | ||||
| 	CHAINID:     "CHAINID", | ||||
| 	SELFBALANCE: "SELFBALANCE", | ||||
| 	BASEFEE:     "BASEFEE", | ||||
| 
 | ||||
| 	// 0x50 range - 'storage' and execution.
 | ||||
| 	POP: "POP", | ||||
| @ -432,6 +434,7 @@ var stringToOp = map[string]OpCode{ | ||||
| 	"CALLDATASIZE":   CALLDATASIZE, | ||||
| 	"CALLDATACOPY":   CALLDATACOPY, | ||||
| 	"CHAINID":        CHAINID, | ||||
| 	"BASEFEE":        BASEFEE, | ||||
| 	"DELEGATECALL":   DELEGATECALL, | ||||
| 	"STATICCALL":     STATICCALL, | ||||
| 	"CODESIZE":       CODESIZE, | ||||
|  | ||||
| @ -162,7 +162,7 @@ func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec | ||||
| 	signer := types.MakeSigner(eth.blockchain.Config(), block.Number()) | ||||
| 	for idx, tx := range block.Transactions() { | ||||
| 		// Assemble the transaction call message and return if the requested offset
 | ||||
| 		msg, _ := tx.AsMessage(signer) | ||||
| 		msg, _ := tx.AsMessage(signer, block.BaseFee()) | ||||
| 		txContext := core.NewEVMTxContext(msg) | ||||
| 		context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) | ||||
| 		if idx == txIndex { | ||||
|  | ||||
| @ -271,7 +271,7 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config | ||||
| 				blockCtx := core.NewEVMBlockContext(task.block.Header(), api.chainContext(localctx), nil) | ||||
| 				// Trace all the transactions contained within
 | ||||
| 				for i, tx := range task.block.Transactions() { | ||||
| 					msg, _ := tx.AsMessage(signer) | ||||
| 					msg, _ := tx.AsMessage(signer, task.block.BaseFee()) | ||||
| 					txctx := &txTraceContext{ | ||||
| 						index: i, | ||||
| 						hash:  tx.Hash(), | ||||
| @ -523,7 +523,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac | ||||
| 			defer pend.Done() | ||||
| 			// Fetch and execute the next transaction trace tasks
 | ||||
| 			for task := range jobs { | ||||
| 				msg, _ := txs[task.index].AsMessage(signer) | ||||
| 				msg, _ := txs[task.index].AsMessage(signer, block.BaseFee()) | ||||
| 				txctx := &txTraceContext{ | ||||
| 					index: task.index, | ||||
| 					hash:  txs[task.index].Hash(), | ||||
| @ -545,7 +545,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac | ||||
| 		jobs <- &txTraceTask{statedb: statedb.Copy(), index: i} | ||||
| 
 | ||||
| 		// Generate the next state snapshot fast without tracing
 | ||||
| 		msg, _ := tx.AsMessage(signer) | ||||
| 		msg, _ := tx.AsMessage(signer, block.BaseFee()) | ||||
| 		statedb.Prepare(tx.Hash(), block.Hash(), i) | ||||
| 		vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{}) | ||||
| 		if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { | ||||
| @ -630,7 +630,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block | ||||
| 	for i, tx := range block.Transactions() { | ||||
| 		// Prepare the trasaction for un-traced execution
 | ||||
| 		var ( | ||||
| 			msg, _    = tx.AsMessage(signer) | ||||
| 			msg, _    = tx.AsMessage(signer, block.BaseFee()) | ||||
| 			txContext = core.NewEVMTxContext(msg) | ||||
| 			vmConf    vm.Config | ||||
| 			dump      *os.File | ||||
|  | ||||
| @ -161,7 +161,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block | ||||
| 	// Recompute transactions up to the target index.
 | ||||
| 	signer := types.MakeSigner(b.chainConfig, block.Number()) | ||||
| 	for idx, tx := range block.Transactions() { | ||||
| 		msg, _ := tx.AsMessage(signer) | ||||
| 		msg, _ := tx.AsMessage(signer, block.BaseFee()) | ||||
| 		txContext := core.NewEVMTxContext(msg) | ||||
| 		context := core.NewEVMBlockContext(block.Header(), b.chain, nil) | ||||
| 		if idx == txIndex { | ||||
|  | ||||
| @ -179,7 +179,7 @@ func TestPrestateTracerCreate2(t *testing.T) { | ||||
| 	} | ||||
| 	evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) | ||||
| 
 | ||||
| 	msg, err := tx.AsMessage(signer) | ||||
| 	msg, err := tx.AsMessage(signer, nil) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("failed to prepare transaction for tracing: %v", err) | ||||
| 	} | ||||
| @ -254,7 +254,7 @@ func TestCallTracer(t *testing.T) { | ||||
| 			} | ||||
| 			evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) | ||||
| 
 | ||||
| 			msg, err := tx.AsMessage(signer) | ||||
| 			msg, err := tx.AsMessage(signer, nil) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("failed to prepare transaction for tracing: %v", err) | ||||
| 			} | ||||
|  | ||||
| @ -120,6 +120,9 @@ type CallMsg struct { | ||||
| 	Value    *big.Int        // amount of wei sent along with the call
 | ||||
| 	Data     []byte          // input data, usually an ABI-encoded contract method invocation
 | ||||
| 
 | ||||
| 	FeeCap *big.Int // EIP-1559 fee cap per gas.
 | ||||
| 	Tip    *big.Int // EIP-1559 tip per gas.
 | ||||
| 
 | ||||
| 	AccessList types.AccessList // EIP-2930 access list.
 | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -799,7 +799,7 @@ func (args *CallArgs) ToMessage(globalGasCap uint64) types.Message { | ||||
| 		accessList = *args.AccessList | ||||
| 	} | ||||
| 
 | ||||
| 	msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, accessList, false) | ||||
| 	msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, nil, nil, data, accessList, false) | ||||
| 	return msg | ||||
| } | ||||
| 
 | ||||
| @ -1271,7 +1271,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber | ||||
| 		result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) | ||||
| 		result.TransactionIndex = (*hexutil.Uint64)(&index) | ||||
| 	} | ||||
| 	if tx.Type() == types.AccessListTxType { | ||||
| 	if tx.Type() != types.LegacyTxType { | ||||
| 		al := tx.AccessList() | ||||
| 		result.Accesses = &al | ||||
| 		result.ChainID = (*hexutil.Big)(tx.ChainId()) | ||||
| @ -1393,7 +1393,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH | ||||
| 		} | ||||
| 		// Copy the original db so we don't modify it
 | ||||
| 		statedb := db.Copy() | ||||
| 		msg := types.NewMessage(args.From, args.To, uint64(*args.Nonce), args.Value.ToInt(), uint64(*args.Gas), args.GasPrice.ToInt(), input, accessList, false) | ||||
| 		msg := types.NewMessage(args.From, args.To, uint64(*args.Nonce), args.Value.ToInt(), uint64(*args.Gas), args.GasPrice.ToInt(), nil, nil, input, accessList, false) | ||||
| 
 | ||||
| 		// Apply the transaction with the access list tracer
 | ||||
| 		tracer := vm.NewAccessListTracer(accessList, args.From, to, precompiles) | ||||
|  | ||||
| @ -135,7 +135,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai | ||||
| 				from := statedb.GetOrNewStateObject(bankAddr) | ||||
| 				from.SetBalance(math.MaxBig256) | ||||
| 
 | ||||
| 				msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, nil, false)} | ||||
| 				msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), nil, nil, data, nil, false)} | ||||
| 
 | ||||
| 				context := core.NewEVMBlockContext(header, bc, nil) | ||||
| 				txContext := core.NewEVMTxContext(msg) | ||||
| @ -150,7 +150,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai | ||||
| 			header := lc.GetHeaderByHash(bhash) | ||||
| 			state := light.NewState(ctx, header, lc.Odr()) | ||||
| 			state.SetBalance(bankAddr, math.MaxBig256) | ||||
| 			msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, nil, false)} | ||||
| 			msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), nil, nil, data, nil, false)} | ||||
| 			context := core.NewEVMBlockContext(header, lc, nil) | ||||
| 			txContext := core.NewEVMTxContext(msg) | ||||
| 			vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{}) | ||||
|  | ||||
| @ -55,7 +55,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types. | ||||
| 	signer := types.MakeSigner(leth.blockchain.Config(), block.Number()) | ||||
| 	for idx, tx := range block.Transactions() { | ||||
| 		// Assemble the transaction call message and return if the requested offset
 | ||||
| 		msg, _ := tx.AsMessage(signer) | ||||
| 		msg, _ := tx.AsMessage(signer, block.BaseFee()) | ||||
| 		txContext := core.NewEVMTxContext(msg) | ||||
| 		context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil) | ||||
| 		statedb.Prepare(tx.Hash(), block.Hash(), idx) | ||||
|  | ||||
| @ -194,7 +194,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain | ||||
| 
 | ||||
| 		// Perform read-only call.
 | ||||
| 		st.SetBalance(testBankAddress, math.MaxBig256) | ||||
| 		msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, nil, false)} | ||||
| 		msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), nil, nil, data, nil, false)} | ||||
| 		txContext := core.NewEVMTxContext(msg) | ||||
| 		context := core.NewEVMBlockContext(header, chain, nil) | ||||
| 		vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{}) | ||||
|  | ||||
| @ -69,9 +69,8 @@ var GoerliBootnodes = []string{ | ||||
| 
 | ||||
| // BaikalBootnodes are the enode URLs of the P2P bootstrap nodes running on the
 | ||||
| // Baikal ephemeral test network.
 | ||||
| // TODO: Set Baikal bootnodes
 | ||||
| var BaikalBootnodes = []string{ | ||||
| 	"", | ||||
| 	"enode://9e1096aa59862a6f164994cb5cb16f5124d6c992cdbf4535ff7dea43ea1512afe5448dca9df1b7ab0726129603f1a3336b631e4d7a1a44c94daddd03241587f9@3.9.20.133:30303", | ||||
| } | ||||
| 
 | ||||
| var V5Bootnodes = []string{ | ||||
|  | ||||
| @ -231,7 +231,7 @@ var ( | ||||
| 		IstanbulBlock:       big.NewInt(0), | ||||
| 		MuirGlacierBlock:    nil, | ||||
| 		BerlinBlock:         big.NewInt(0), | ||||
| 		LondonBlock:         big.NewInt(0), | ||||
| 		LondonBlock:         big.NewInt(500), | ||||
| 		Clique: &CliqueConfig{ | ||||
| 			Period: 30, | ||||
| 			Epoch:  30000, | ||||
|  | ||||
| @ -118,6 +118,10 @@ const ( | ||||
| 	// Introduced in Tangerine Whistle (Eip 150)
 | ||||
| 	CreateBySelfdestructGas uint64 = 25000 | ||||
| 
 | ||||
| 	BaseFeeChangeDenominator = 8          // Bounds the amount the base fee can change between blocks.
 | ||||
| 	ElasticityMultiplier     = 2          // Bounds the maximum gas limit an EIP-1559 block may have.
 | ||||
| 	InitialBaseFee           = 1000000000 // Initial base fee for EIP-1559 blocks.
 | ||||
| 
 | ||||
| 	MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
 | ||||
| 
 | ||||
| 	// Precompiled contract gas prices
 | ||||
|  | ||||
| @ -179,6 +179,19 @@ var Forks = map[string]*params.ChainConfig{ | ||||
| 		BerlinBlock:         big.NewInt(0), | ||||
| 		LondonBlock:         big.NewInt(0), | ||||
| 	}, | ||||
| 	"Aleut": { | ||||
| 		ChainID:             big.NewInt(1), | ||||
| 		HomesteadBlock:      big.NewInt(0), | ||||
| 		EIP150Block:         big.NewInt(0), | ||||
| 		EIP155Block:         big.NewInt(0), | ||||
| 		EIP158Block:         big.NewInt(0), | ||||
| 		ByzantiumBlock:      big.NewInt(0), | ||||
| 		ConstantinopleBlock: big.NewInt(0), | ||||
| 		PetersburgBlock:     big.NewInt(0), | ||||
| 		IstanbulBlock:       big.NewInt(0), | ||||
| 		BerlinBlock:         big.NewInt(0), | ||||
| 		LondonBlock:         big.NewInt(0), | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| // Returns the set of defined fork names
 | ||||
|  | ||||
| @ -297,7 +297,7 @@ func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) { | ||||
| 	if tx.AccessLists != nil && tx.AccessLists[ps.Indexes.Data] != nil { | ||||
| 		accessList = *tx.AccessLists[ps.Indexes.Data] | ||||
| 	} | ||||
| 	msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, accessList, true) | ||||
| 	msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, nil, nil, data, accessList, true) | ||||
| 	return msg, nil | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user