forked from cerc-io/plugeth
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) CheckNonce() bool { return false }
|
||||||
func (m callMsg) To() *common.Address { return m.CallMsg.To }
|
func (m callMsg) To() *common.Address { return m.CallMsg.To }
|
||||||
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
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) Gas() uint64 { return m.CallMsg.Gas }
|
||||||
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
|
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
|
||||||
func (m callMsg) Data() []byte { return m.CallMsg.Data }
|
func (m callMsg) Data() []byte { return m.CallMsg.Data }
|
||||||
|
4
accounts/external/backend.go
vendored
4
accounts/external/backend.go
vendored
@ -217,12 +217,12 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
|
|||||||
if chainID != nil {
|
if chainID != nil {
|
||||||
args.ChainID = (*hexutil.Big)(chainID)
|
args.ChainID = (*hexutil.Big)(chainID)
|
||||||
}
|
}
|
||||||
|
if tx.Type() != types.LegacyTxType {
|
||||||
// However, if the user asked for a particular chain id, then we should
|
// However, if the user asked for a particular chain id, then we should
|
||||||
// use that instead.
|
// use that instead.
|
||||||
if tx.Type() != types.LegacyTxType && tx.ChainId() != nil {
|
if tx.ChainId() != nil {
|
||||||
args.ChainID = (*hexutil.Big)(tx.ChainId())
|
args.ChainID = (*hexutil.Big)(tx.ChainId())
|
||||||
}
|
}
|
||||||
if tx.Type() == types.AccessListTxType {
|
|
||||||
accessList := tx.AccessList()
|
accessList := tx.AccessList()
|
||||||
args.AccessList = &accessList
|
args.AccessList = &accessList
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,7 @@ type stEnv struct {
|
|||||||
Timestamp uint64 `json:"currentTimestamp" gencodec:"required"`
|
Timestamp uint64 `json:"currentTimestamp" gencodec:"required"`
|
||||||
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
|
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
|
||||||
Ommers []ommer `json:"ommers,omitempty"`
|
Ommers []ommer `json:"ommers,omitempty"`
|
||||||
|
BaseFee *big.Int `json:"currentBaseFee,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type stEnvMarshaling struct {
|
type stEnvMarshaling struct {
|
||||||
@ -77,6 +78,7 @@ type stEnvMarshaling struct {
|
|||||||
GasLimit math.HexOrDecimal64
|
GasLimit math.HexOrDecimal64
|
||||||
Number math.HexOrDecimal64
|
Number math.HexOrDecimal64
|
||||||
Timestamp math.HexOrDecimal64
|
Timestamp math.HexOrDecimal64
|
||||||
|
BaseFee *math.HexOrDecimal256
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply applies a set of transactions to a pre-state
|
// 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,
|
GasLimit: pre.Env.GasLimit,
|
||||||
GetHash: getHash,
|
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
|
// 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.
|
// done in StateProcessor.Process(block, ...), right before transactions are applied.
|
||||||
if chainConfig.DAOForkSupport &&
|
if chainConfig.DAOForkSupport &&
|
||||||
@ -129,7 +135,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
msg, err := tx.AsMessage(signer)
|
msg, err := tx.AsMessage(signer, pre.Env.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "error", err)
|
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "error", err)
|
||||||
rejectedTxs = append(rejectedTxs, i)
|
rejectedTxs = append(rejectedTxs, i)
|
||||||
|
@ -23,6 +23,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) {
|
|||||||
Timestamp math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"`
|
Timestamp math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"`
|
||||||
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
|
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
|
||||||
Ommers []ommer `json:"ommers,omitempty"`
|
Ommers []ommer `json:"ommers,omitempty"`
|
||||||
|
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
|
||||||
}
|
}
|
||||||
var enc stEnv
|
var enc stEnv
|
||||||
enc.Coinbase = common.UnprefixedAddress(s.Coinbase)
|
enc.Coinbase = common.UnprefixedAddress(s.Coinbase)
|
||||||
@ -32,6 +33,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) {
|
|||||||
enc.Timestamp = math.HexOrDecimal64(s.Timestamp)
|
enc.Timestamp = math.HexOrDecimal64(s.Timestamp)
|
||||||
enc.BlockHashes = s.BlockHashes
|
enc.BlockHashes = s.BlockHashes
|
||||||
enc.Ommers = s.Ommers
|
enc.Ommers = s.Ommers
|
||||||
|
enc.BaseFee = (*math.HexOrDecimal256)(s.BaseFee)
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +47,7 @@ func (s *stEnv) UnmarshalJSON(input []byte) error {
|
|||||||
Timestamp *math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"`
|
Timestamp *math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"`
|
||||||
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
|
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
|
||||||
Ommers []ommer `json:"ommers,omitempty"`
|
Ommers []ommer `json:"ommers,omitempty"`
|
||||||
|
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
|
||||||
}
|
}
|
||||||
var dec stEnv
|
var dec stEnv
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
@ -76,5 +79,8 @@ func (s *stEnv) UnmarshalJSON(input []byte) error {
|
|||||||
if dec.Ommers != nil {
|
if dec.Ommers != nil {
|
||||||
s.Ommers = dec.Ommers
|
s.Ommers = dec.Ommers
|
||||||
}
|
}
|
||||||
|
if dec.BaseFee != nil {
|
||||||
|
s.BaseFee = (*big.Int)(dec.BaseFee)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package t8ntool
|
|||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
@ -210,9 +211,12 @@ func Main(ctx *cli.Context) error {
|
|||||||
if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil {
|
if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil {
|
||||||
return NewError(ErrorJson, fmt.Errorf("failed signing transactions: %v", err))
|
return NewError(ErrorJson, fmt.Errorf("failed signing transactions: %v", err))
|
||||||
}
|
}
|
||||||
|
// Sanity check, to not `panic` in state_transition
|
||||||
// Iterate over all the tests, run them and aggregate the results
|
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
|
// Run the test and aggregate the result
|
||||||
s, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer)
|
s, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer)
|
||||||
if err != nil {
|
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 {
|
if header.GasLimit > cap {
|
||||||
return fmt.Errorf("invalid gasLimit: have %v, max %v", 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 all checks passed, validate any special fields for hard forks
|
||||||
if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil {
|
if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -334,14 +330,21 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainHeaderReader, header
|
|||||||
if parent.Time+c.config.Period > header.Time {
|
if parent.Time+c.config.Period > header.Time {
|
||||||
return errInvalidTimestamp
|
return errInvalidTimestamp
|
||||||
}
|
}
|
||||||
// Verify that the gas limit remains within allowed bounds
|
// Verify that the gasUsed is <= gasLimit
|
||||||
diff := int64(parent.GasLimit) - int64(header.GasLimit)
|
if header.GasUsed > header.GasLimit {
|
||||||
if diff < 0 {
|
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
|
||||||
diff *= -1
|
|
||||||
}
|
}
|
||||||
limit := parent.GasLimit / params.GasLimitBoundDivisor
|
if !chain.Config().IsLondon(header.Number) {
|
||||||
if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit {
|
// Verify BaseFee not present before EIP-1559 fork.
|
||||||
return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit)
|
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
|
// Retrieve the snapshot needed to verify this header and cache it
|
||||||
snap, err := c.snapshot(chain, number-1, header.ParentHash, parents)
|
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) {
|
func encodeSigHeader(w io.Writer, header *types.Header) {
|
||||||
err := rlp.Encode(w, []interface{}{
|
enc := []interface{}{
|
||||||
header.ParentHash,
|
header.ParentHash,
|
||||||
header.UncleHash,
|
header.UncleHash,
|
||||||
header.Coinbase,
|
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.Extra[:len(header.Extra)-crypto.SignatureLength], // Yes, this will panic if extra is too short
|
||||||
header.MixDigest,
|
header.MixDigest,
|
||||||
header.Nonce,
|
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())
|
panic("can't encode: " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,16 +284,18 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
|||||||
if header.GasUsed > header.GasLimit {
|
if header.GasUsed > header.GasLimit {
|
||||||
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
|
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
|
||||||
}
|
}
|
||||||
|
// Verify the block's gas usage and (if applicable) verify the base fee.
|
||||||
// Verify that the gas limit remains within allowed bounds
|
if !chain.Config().IsLondon(header.Number) {
|
||||||
diff := int64(parent.GasLimit) - int64(header.GasLimit)
|
// Verify BaseFee not present before EIP-1559 fork.
|
||||||
if diff < 0 {
|
if header.BaseFee != nil {
|
||||||
diff *= -1
|
return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee)
|
||||||
}
|
}
|
||||||
limit := parent.GasLimit / params.GasLimitBoundDivisor
|
if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
|
||||||
|
return err
|
||||||
if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit {
|
}
|
||||||
return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit)
|
} 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
|
// 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 {
|
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) {
|
func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
|
||||||
hasher := sha3.NewLegacyKeccak256()
|
hasher := sha3.NewLegacyKeccak256()
|
||||||
|
|
||||||
rlp.Encode(hasher, []interface{}{
|
enc := []interface{}{
|
||||||
header.ParentHash,
|
header.ParentHash,
|
||||||
header.UncleHash,
|
header.UncleHash,
|
||||||
header.Coinbase,
|
header.Coinbase,
|
||||||
@ -618,7 +620,11 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
|
|||||||
header.GasUsed,
|
header.GasUsed,
|
||||||
header.Time,
|
header.Time,
|
||||||
header.Extra,
|
header.Extra,
|
||||||
})
|
}
|
||||||
|
if header.BaseFee != nil {
|
||||||
|
enc = append(enc, header.BaseFee)
|
||||||
|
}
|
||||||
|
rlp.Encode(hasher, enc)
|
||||||
hasher.Sum(hash[:0])
|
hasher.Sum(hash[:0])
|
||||||
return hash
|
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
|
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
|
// 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)) {
|
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
|
// 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
|
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())),
|
Root: state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())),
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Coinbase: parent.Coinbase(),
|
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),
|
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
||||||
Time: time,
|
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.
|
// 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
|
// ErrTxTypeNotSupported is returned if a transaction is not supported in the
|
||||||
// current network configuration.
|
// current network configuration.
|
||||||
ErrTxTypeNotSupported = types.ErrTxTypeNotSupported
|
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.
|
// NewEVMBlockContext creates a new context for use in the EVM.
|
||||||
func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common.Address) vm.BlockContext {
|
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
|
// If we don't have an explicit author (i.e. not mining), extract from the header
|
||||||
var beneficiary common.Address
|
|
||||||
if author == nil {
|
if author == nil {
|
||||||
beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation
|
beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation
|
||||||
} else {
|
} else {
|
||||||
beneficiary = *author
|
beneficiary = *author
|
||||||
}
|
}
|
||||||
|
if header.BaseFee != nil {
|
||||||
|
baseFee = new(big.Int).Set(header.BaseFee)
|
||||||
|
}
|
||||||
return vm.BlockContext{
|
return vm.BlockContext{
|
||||||
CanTransfer: CanTransfer,
|
CanTransfer: CanTransfer,
|
||||||
Transfer: Transfer,
|
Transfer: Transfer,
|
||||||
@ -52,6 +59,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
|
|||||||
BlockNumber: new(big.Int).Set(header.Number),
|
BlockNumber: new(big.Int).Set(header.Number),
|
||||||
Time: new(big.Int).SetUint64(header.Time),
|
Time: new(big.Int).SetUint64(header.Time),
|
||||||
Difficulty: new(big.Int).Set(header.Difficulty),
|
Difficulty: new(big.Int).Set(header.Difficulty),
|
||||||
|
BaseFee: baseFee,
|
||||||
GasLimit: header.GasLimit,
|
GasLimit: header.GasLimit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,6 +291,9 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
|
|||||||
if g.Difficulty == nil {
|
if g.Difficulty == nil {
|
||||||
head.Difficulty = params.GenesisDifficulty
|
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.Commit(false)
|
||||||
statedb.Database().TrieDB().Commit(root, true, nil)
|
statedb.Database().TrieDB().Commit(root, true, nil)
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Convert the transaction into an executable message and pre-cache its sender
|
// 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 {
|
if err != nil {
|
||||||
return // Also invalid block, bail out
|
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)
|
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
for i, tx := range block.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 {
|
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)
|
statedb.Prepare(tx.Hash(), block.Hash(), i)
|
||||||
receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv)
|
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,
|
// for the transaction, gas used and an error if the transaction failed,
|
||||||
// indicating the block was invalid.
|
// 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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"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/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
@ -38,69 +39,100 @@ import (
|
|||||||
// contain invalid transactions
|
// contain invalid transactions
|
||||||
func TestStateProcessorErrors(t *testing.T) {
|
func TestStateProcessorErrors(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
signer = types.HomesteadSigner{}
|
signer = types.LatestSigner(params.TestChainConfig)
|
||||||
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec = &Genesis{
|
gspec = &Genesis{
|
||||||
Config: params.TestChainConfig,
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: GenesisAlloc{
|
||||||
|
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
|
||||||
|
Balance: big.NewInt(1000000000000000000), // 1 ether
|
||||||
|
Nonce: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||||
)
|
)
|
||||||
defer blockchain.Stop()
|
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 {
|
for i, tt := range []struct {
|
||||||
txs []*types.Transaction
|
txs []*types.Transaction
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{
|
{ // ErrNonceTooLow
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, nil, nil),
|
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, nil, nil),
|
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 1 [0x36bfa6d14f1cd35a1be8cc2322982a595fabc0e799f09c1de3bad7bd5b1f7626]: nonce too low: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1",
|
want: "could not apply tx 1 [0x0026256b3939ed97e2c4a6f3fce8ecf83bdcfa6d507c47838c308a1fb0436f62]: nonce too low: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1",
|
||||||
},
|
},
|
||||||
{
|
{ // ErrNonceTooHigh
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
makeTx(100, common.Address{}, big.NewInt(0), params.TxGas, nil, nil),
|
makeTx(100, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 0 [0x51cd272d41ef6011d8138e18bf4043797aca9b713c7d39a97563f9bbe6bdbe6f]: nonce too high: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 100 state: 0",
|
want: "could not apply tx 0 [0xdebad714ca7f363bd0d8121c4518ad48fa469ca81b0a081be3d10c17460f751b]: nonce too high: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 100 state: 0",
|
||||||
},
|
},
|
||||||
{
|
{ // ErrGasLimitReached
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
makeTx(0, common.Address{}, big.NewInt(0), 21000000, nil, nil),
|
makeTx(0, common.Address{}, big.NewInt(0), 21000000, big.NewInt(875000000), nil),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 0 [0x54c58b530824b0bb84b7a98183f08913b5d74e1cebc368515ef3c65edf8eb56a]: gas limit reached",
|
want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached",
|
||||||
},
|
},
|
||||||
{
|
{ // ErrInsufficientFundsForTransfer
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
makeTx(0, common.Address{}, big.NewInt(1), params.TxGas, nil, nil),
|
makeTx(0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(875000000), nil),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 0 [0x3094b17498940d92b13baccf356ce8bfd6f221e926abc903d642fa1466c5b50e]: insufficient funds for transfer: address 0x71562b71999873DB5b286dF957af199Ec94617F7",
|
want: "could not apply tx 0 [0x98c796b470f7fcab40aaef5c965a602b0238e1034cce6fb73823042dd0638d74]: insufficient funds for transfer: address 0x71562b71999873DB5b286dF957af199Ec94617F7",
|
||||||
},
|
},
|
||||||
{
|
{ // ErrInsufficientFunds
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(0xffffff), nil),
|
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(900000000000000000), nil),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 0 [0xaa3f7d86802b1f364576d9071bf231e31d61b392d306831ac9cf706ff5371ce0]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 0 want 352321515000",
|
want: "could not apply tx 0 [0x4a69690c4b0cd85e64d0d9ea06302455b01e10a83db964d60281739752003440]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 18900000000000000000000",
|
||||||
},
|
},
|
||||||
{
|
// ErrGasUintOverflow
|
||||||
txs: []*types.Transaction{
|
// One missing 'core' error is ErrGasUintOverflow: "gas uint64 overflow",
|
||||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, nil, nil),
|
// In order to trigger that one, we'd have to allocate a _huge_ chunk of data, such that the
|
||||||
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),
|
|
||||||
},
|
|
||||||
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
|
// 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",
|
||||||
|
},
|
||||||
|
{ // 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)
|
block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config)
|
||||||
_, err := blockchain.InsertChain(types.Blocks{block})
|
_, err := blockchain.InsertChain(types.Blocks{block})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("block imported without errors")
|
t.Fatal("block imported without errors")
|
||||||
@ -111,15 +143,66 @@ func TestStateProcessorErrors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be
|
// GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be
|
||||||
// valid, and no proper post-state can be made. But from the perspective of the blockchain, the block is sufficiently
|
// 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 to be considered for import:
|
||||||
// - valid pow (fake), ancestry, difficulty, gaslimit etc
|
// - 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{
|
header := &types.Header{
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Coinbase: parent.Coinbase(),
|
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(),
|
Number: parent.Number(),
|
||||||
Time: parent.Time(),
|
Time: parent.Time(),
|
||||||
Difficulty: parent.Difficulty(),
|
Difficulty: parent.Difficulty(),
|
||||||
@ -130,8 +213,10 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
|
|||||||
Time: parent.Time() + 10,
|
Time: parent.Time() + 10,
|
||||||
UncleHash: types.EmptyUncleHash,
|
UncleHash: types.EmptyUncleHash,
|
||||||
}
|
}
|
||||||
|
if config.IsLondon(header.Number) {
|
||||||
|
header.BaseFee = misc.CalcBaseFee(config, parent.Header())
|
||||||
|
}
|
||||||
var receipts []*types.Receipt
|
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
|
// 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
|
// Preferably something unique. So let's use a combo of blocknum + txhash
|
||||||
hasher := sha3.NewLegacyKeccak256()
|
hasher := sha3.NewLegacyKeccak256()
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
@ -49,6 +50,8 @@ type StateTransition struct {
|
|||||||
msg Message
|
msg Message
|
||||||
gas uint64
|
gas uint64
|
||||||
gasPrice *big.Int
|
gasPrice *big.Int
|
||||||
|
feeCap *big.Int
|
||||||
|
tip *big.Int
|
||||||
initialGas uint64
|
initialGas uint64
|
||||||
value *big.Int
|
value *big.Int
|
||||||
data []byte
|
data []byte
|
||||||
@ -62,6 +65,8 @@ type Message interface {
|
|||||||
To() *common.Address
|
To() *common.Address
|
||||||
|
|
||||||
GasPrice() *big.Int
|
GasPrice() *big.Int
|
||||||
|
FeeCap() *big.Int
|
||||||
|
Tip() *big.Int
|
||||||
Gas() uint64
|
Gas() uint64
|
||||||
Value() *big.Int
|
Value() *big.Int
|
||||||
|
|
||||||
@ -154,6 +159,8 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
|
|||||||
evm: evm,
|
evm: evm,
|
||||||
msg: msg,
|
msg: msg,
|
||||||
gasPrice: msg.GasPrice(),
|
gasPrice: msg.GasPrice(),
|
||||||
|
feeCap: msg.FeeCap(),
|
||||||
|
tip: msg.Tip(),
|
||||||
value: msg.Value(),
|
value: msg.Value(),
|
||||||
data: msg.Data(),
|
data: msg.Data(),
|
||||||
state: evm.StateDB,
|
state: evm.StateDB,
|
||||||
@ -206,6 +213,15 @@ func (st *StateTransition) preCheck() error {
|
|||||||
st.msg.From().Hex(), msgNonce, stNonce)
|
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()
|
return st.buyGas()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +297,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
|||||||
// After EIP-3529: refunds are capped to gasUsed / 5
|
// After EIP-3529: refunds are capped to gasUsed / 5
|
||||||
st.refundGas(params.RefundQuotientEIP3529)
|
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{
|
return &ExecutionResult{
|
||||||
UsedGas: st.gasUsed(),
|
UsedGas: st.gasUsed(),
|
||||||
|
@ -94,7 +94,6 @@ func (tx *AccessListTx) copy() TxData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// accessors for innerTx.
|
// accessors for innerTx.
|
||||||
|
|
||||||
func (tx *AccessListTx) txType() byte { return AccessListTxType }
|
func (tx *AccessListTx) txType() byte { return AccessListTxType }
|
||||||
func (tx *AccessListTx) chainID() *big.Int { return tx.ChainID }
|
func (tx *AccessListTx) chainID() *big.Int { return tx.ChainID }
|
||||||
func (tx *AccessListTx) protected() bool { return true }
|
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) data() []byte { return tx.Data }
|
||||||
func (tx *AccessListTx) gas() uint64 { return tx.Gas }
|
func (tx *AccessListTx) gas() uint64 { return tx.Gas }
|
||||||
func (tx *AccessListTx) gasPrice() *big.Int { return tx.GasPrice }
|
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) value() *big.Int { return tx.Value }
|
||||||
func (tx *AccessListTx) nonce() uint64 { return tx.Nonce }
|
func (tx *AccessListTx) nonce() uint64 { return tx.Nonce }
|
||||||
func (tx *AccessListTx) to() *common.Address { return tx.To }
|
func (tx *AccessListTx) to() *common.Address { return tx.To }
|
||||||
|
@ -82,6 +82,9 @@ type Header struct {
|
|||||||
Extra []byte `json:"extraData" gencodec:"required"`
|
Extra []byte `json:"extraData" gencodec:"required"`
|
||||||
MixDigest common.Hash `json:"mixHash"`
|
MixDigest common.Hash `json:"mixHash"`
|
||||||
Nonce BlockNonce `json:"nonce"`
|
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
|
// field type overrides for gencodec
|
||||||
@ -92,6 +95,7 @@ type headerMarshaling struct {
|
|||||||
GasUsed hexutil.Uint64
|
GasUsed hexutil.Uint64
|
||||||
Time hexutil.Uint64
|
Time hexutil.Uint64
|
||||||
Extra hexutil.Bytes
|
Extra hexutil.Bytes
|
||||||
|
BaseFee *hexutil.Big
|
||||||
Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
|
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 {
|
if cpy.Number = new(big.Int); h.Number != nil {
|
||||||
cpy.Number.Set(h.Number)
|
cpy.Number.Set(h.Number)
|
||||||
}
|
}
|
||||||
|
if h.BaseFee != nil {
|
||||||
|
cpy.BaseFee = new(big.Int).Set(h.BaseFee)
|
||||||
|
}
|
||||||
if len(h.Extra) > 0 {
|
if len(h.Extra) > 0 {
|
||||||
cpy.Extra = make([]byte, len(h.Extra))
|
cpy.Extra = make([]byte, len(h.Extra))
|
||||||
copy(cpy.Extra, 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) UncleHash() common.Hash { return b.header.UncleHash }
|
||||||
func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) }
|
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) }
|
func (b *Block) Header() *Header { return CopyHeader(b.header) }
|
||||||
|
|
||||||
// Body returns the non-header content of the block.
|
// 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) {
|
func TestEIP2718BlockEncoding(t *testing.T) {
|
||||||
blockEnc := common.FromHex("f90319f90211a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a0e6e49996c7ec59f7a23d22b83239a60151512c65613bf84a0d7da336399ebc4aa0cafe75574d59780665a97fbfd11365c7545aa8f1abf4e5e12e8243334ef7286bb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000820200832fefd882a410845506eb0796636f6f6c65737420626c6f636b206f6e20636861696ea0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4f90101f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b89e01f89b01800a8301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000001a03dbacc8d0259f2508625e97fdfc57cd85fdd16e5821bc2c10bdd1a52649e8335a0476e10695b183a87b0aa292a7f4b78ef0c3fbe62aa2c42c84e1d9c3da159ef14c0")
|
blockEnc := common.FromHex("f90319f90211a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a0e6e49996c7ec59f7a23d22b83239a60151512c65613bf84a0d7da336399ebc4aa0cafe75574d59780665a97fbfd11365c7545aa8f1abf4e5e12e8243334ef7286bb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000820200832fefd882a410845506eb0796636f6f6c65737420626c6f636b206f6e20636861696ea0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4f90101f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b89e01f89b01800a8301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000001a03dbacc8d0259f2508625e97fdfc57cd85fdd16e5821bc2c10bdd1a52649e8335a0476e10695b183a87b0aa292a7f4b78ef0c3fbe62aa2c42c84e1d9c3da159ef14c0")
|
||||||
var block Block
|
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.
|
// accessors for innerTx.
|
||||||
|
|
||||||
func (tx *LegacyTx) txType() byte { return LegacyTxType }
|
func (tx *LegacyTx) txType() byte { return LegacyTxType }
|
||||||
func (tx *LegacyTx) chainID() *big.Int { return deriveChainId(tx.V) }
|
func (tx *LegacyTx) chainID() *big.Int { return deriveChainId(tx.V) }
|
||||||
func (tx *LegacyTx) accessList() AccessList { return nil }
|
func (tx *LegacyTx) accessList() AccessList { return nil }
|
||||||
func (tx *LegacyTx) data() []byte { return tx.Data }
|
func (tx *LegacyTx) data() []byte { return tx.Data }
|
||||||
func (tx *LegacyTx) gas() uint64 { return tx.Gas }
|
func (tx *LegacyTx) gas() uint64 { return tx.Gas }
|
||||||
func (tx *LegacyTx) gasPrice() *big.Int { return tx.GasPrice }
|
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) value() *big.Int { return tx.Value }
|
||||||
func (tx *LegacyTx) nonce() uint64 { return tx.Nonce }
|
func (tx *LegacyTx) nonce() uint64 { return tx.Nonce }
|
||||||
func (tx *LegacyTx) to() *common.Address { return tx.To }
|
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 {
|
if r.Type == LegacyTxType {
|
||||||
return rlp.Encode(w, data)
|
return rlp.Encode(w, data)
|
||||||
}
|
}
|
||||||
// It's an EIP-2718 typed TX receipt.
|
|
||||||
if r.Type != AccessListTxType {
|
|
||||||
return ErrTxTypeNotSupported
|
|
||||||
}
|
|
||||||
buf := encodeBufferPool.Get().(*bytes.Buffer)
|
buf := encodeBufferPool.Get().(*bytes.Buffer)
|
||||||
defer encodeBufferPool.Put(buf)
|
defer encodeBufferPool.Put(buf)
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
@ -159,7 +155,7 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
|
|||||||
return errEmptyTypedReceipt
|
return errEmptyTypedReceipt
|
||||||
}
|
}
|
||||||
r.Type = b[0]
|
r.Type = b[0]
|
||||||
if r.Type == AccessListTxType {
|
if r.Type == AccessListTxType || r.Type == DynamicFeeTxType {
|
||||||
var dec receiptRLP
|
var dec receiptRLP
|
||||||
if err := rlp.DecodeBytes(b[1:], &dec); err != nil {
|
if err := rlp.DecodeBytes(b[1:], &dec); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -263,6 +259,9 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
|
|||||||
case AccessListTxType:
|
case AccessListTxType:
|
||||||
w.WriteByte(AccessListTxType)
|
w.WriteByte(AccessListTxType)
|
||||||
rlp.Encode(w, data)
|
rlp.Encode(w, data)
|
||||||
|
case DynamicFeeTxType:
|
||||||
|
w.WriteByte(DynamicFeeTxType)
|
||||||
|
rlp.Encode(w, data)
|
||||||
default:
|
default:
|
||||||
// For unsupported types, write nothing. Since this is for
|
// For unsupported types, write nothing. Since this is for
|
||||||
// DeriveSha, the error will be caught matching the derived hash
|
// DeriveSha, the error will be caught matching the derived hash
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
@ -42,6 +43,7 @@ var (
|
|||||||
const (
|
const (
|
||||||
LegacyTxType = iota
|
LegacyTxType = iota
|
||||||
AccessListTxType
|
AccessListTxType
|
||||||
|
DynamicFeeTxType
|
||||||
)
|
)
|
||||||
|
|
||||||
// Transaction is an Ethereum transaction.
|
// Transaction is an Ethereum transaction.
|
||||||
@ -74,6 +76,8 @@ type TxData interface {
|
|||||||
data() []byte
|
data() []byte
|
||||||
gas() uint64
|
gas() uint64
|
||||||
gasPrice() *big.Int
|
gasPrice() *big.Int
|
||||||
|
tip() *big.Int
|
||||||
|
feeCap() *big.Int
|
||||||
value() *big.Int
|
value() *big.Int
|
||||||
nonce() uint64
|
nonce() uint64
|
||||||
to() *common.Address
|
to() *common.Address
|
||||||
@ -177,6 +181,10 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
|
|||||||
var inner AccessListTx
|
var inner AccessListTx
|
||||||
err := rlp.DecodeBytes(b[1:], &inner)
|
err := rlp.DecodeBytes(b[1:], &inner)
|
||||||
return &inner, err
|
return &inner, err
|
||||||
|
case DynamicFeeTxType:
|
||||||
|
var inner DynamicFeeTx
|
||||||
|
err := rlp.DecodeBytes(b[1:], &inner)
|
||||||
|
return &inner, err
|
||||||
default:
|
default:
|
||||||
return nil, ErrTxTypeNotSupported
|
return nil, ErrTxTypeNotSupported
|
||||||
}
|
}
|
||||||
@ -260,6 +268,12 @@ func (tx *Transaction) Gas() uint64 { return tx.inner.gas() }
|
|||||||
// GasPrice returns the gas price of the transaction.
|
// GasPrice returns the gas price of the transaction.
|
||||||
func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.inner.gasPrice()) }
|
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.
|
// Value returns the ether amount of the transaction.
|
||||||
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) }
|
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) }
|
||||||
|
|
||||||
@ -486,12 +500,14 @@ type Message struct {
|
|||||||
amount *big.Int
|
amount *big.Int
|
||||||
gasLimit uint64
|
gasLimit uint64
|
||||||
gasPrice *big.Int
|
gasPrice *big.Int
|
||||||
|
feeCap *big.Int
|
||||||
|
tip *big.Int
|
||||||
data []byte
|
data []byte
|
||||||
accessList AccessList
|
accessList AccessList
|
||||||
checkNonce bool
|
checkNonce bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, 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{
|
return Message{
|
||||||
from: from,
|
from: from,
|
||||||
to: to,
|
to: to,
|
||||||
@ -499,6 +515,8 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b
|
|||||||
amount: amount,
|
amount: amount,
|
||||||
gasLimit: gasLimit,
|
gasLimit: gasLimit,
|
||||||
gasPrice: gasPrice,
|
gasPrice: gasPrice,
|
||||||
|
feeCap: feeCap,
|
||||||
|
tip: tip,
|
||||||
data: data,
|
data: data,
|
||||||
accessList: accessList,
|
accessList: accessList,
|
||||||
checkNonce: checkNonce,
|
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.
|
// 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{
|
msg := Message{
|
||||||
nonce: tx.Nonce(),
|
nonce: tx.Nonce(),
|
||||||
gasLimit: tx.Gas(),
|
gasLimit: tx.Gas(),
|
||||||
gasPrice: new(big.Int).Set(tx.GasPrice()),
|
gasPrice: new(big.Int).Set(tx.GasPrice()),
|
||||||
|
feeCap: new(big.Int).Set(tx.FeeCap()),
|
||||||
|
tip: new(big.Int).Set(tx.Tip()),
|
||||||
to: tx.To(),
|
to: tx.To(),
|
||||||
amount: tx.Value(),
|
amount: tx.Value(),
|
||||||
data: tx.Data(),
|
data: tx.Data(),
|
||||||
@ -518,6 +538,11 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) {
|
|||||||
checkNonce: true,
|
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
|
var err error
|
||||||
msg.from, err = Sender(s, tx)
|
msg.from, err = Sender(s, tx)
|
||||||
return msg, err
|
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) From() common.Address { return m.from }
|
||||||
func (m Message) To() *common.Address { return m.to }
|
func (m Message) To() *common.Address { return m.to }
|
||||||
func (m Message) GasPrice() *big.Int { return m.gasPrice }
|
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) Value() *big.Int { return m.amount }
|
||||||
func (m Message) Gas() uint64 { return m.gasLimit }
|
func (m Message) Gas() uint64 { return m.gasLimit }
|
||||||
func (m Message) Nonce() uint64 { return m.nonce }
|
func (m Message) Nonce() uint64 { return m.nonce }
|
||||||
|
@ -32,6 +32,10 @@ type txJSON struct {
|
|||||||
// Common transaction fields:
|
// Common transaction fields:
|
||||||
Nonce *hexutil.Uint64 `json:"nonce"`
|
Nonce *hexutil.Uint64 `json:"nonce"`
|
||||||
GasPrice *hexutil.Big `json:"gasPrice"`
|
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"`
|
Gas *hexutil.Uint64 `json:"gas"`
|
||||||
Value *hexutil.Big `json:"value"`
|
Value *hexutil.Big `json:"value"`
|
||||||
Data *hexutil.Bytes `json:"input"`
|
Data *hexutil.Bytes `json:"input"`
|
||||||
@ -79,6 +83,19 @@ func (t *Transaction) MarshalJSON() ([]byte, error) {
|
|||||||
enc.V = (*hexutil.Big)(tx.V)
|
enc.V = (*hexutil.Big)(tx.V)
|
||||||
enc.R = (*hexutil.Big)(tx.R)
|
enc.R = (*hexutil.Big)(tx.R)
|
||||||
enc.S = (*hexutil.Big)(tx.S)
|
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)
|
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:
|
default:
|
||||||
return ErrTxTypeNotSupported
|
return ErrTxTypeNotSupported
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,8 @@ type sigCache struct {
|
|||||||
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
|
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
|
||||||
var signer Signer
|
var signer Signer
|
||||||
switch {
|
switch {
|
||||||
|
case config.IsLondon(blockNumber):
|
||||||
|
signer = NewLondonSigner(config.ChainID)
|
||||||
case config.IsBerlin(blockNumber):
|
case config.IsBerlin(blockNumber):
|
||||||
signer = NewEIP2930Signer(config.ChainID)
|
signer = NewEIP2930Signer(config.ChainID)
|
||||||
case config.IsEIP155(blockNumber):
|
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.
|
// have the current block number available, use MakeSigner instead.
|
||||||
func LatestSigner(config *params.ChainConfig) Signer {
|
func LatestSigner(config *params.ChainConfig) Signer {
|
||||||
if config.ChainID != nil {
|
if config.ChainID != nil {
|
||||||
|
if config.LondonBlock != nil {
|
||||||
|
return NewLondonSigner(config.ChainID)
|
||||||
|
}
|
||||||
if config.BerlinBlock != nil {
|
if config.BerlinBlock != nil {
|
||||||
return NewEIP2930Signer(config.ChainID)
|
return NewEIP2930Signer(config.ChainID)
|
||||||
}
|
}
|
||||||
@ -82,7 +87,7 @@ func LatestSignerForChainID(chainID *big.Int) Signer {
|
|||||||
if chainID == nil {
|
if chainID == nil {
|
||||||
return HomesteadSigner{}
|
return HomesteadSigner{}
|
||||||
}
|
}
|
||||||
return NewEIP2930Signer(chainID)
|
return NewLondonSigner(chainID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignTx signs the transaction using the given signer and private key.
|
// SignTx signs the transaction using the given signer and private key.
|
||||||
@ -165,6 +170,72 @@ type Signer interface {
|
|||||||
Equal(Signer) bool
|
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 }
|
type eip2930Signer struct{ EIP155Signer }
|
||||||
|
|
||||||
// NewEIP2930Signer returns a signer that accepts EIP-2930 access list transactions,
|
// 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 = new(big.Int).Sub(V, s.chainIdMul)
|
||||||
V.Sub(V, big8)
|
V.Sub(V, big8)
|
||||||
case AccessListTxType:
|
case AccessListTxType:
|
||||||
// ACL txs are defined to use 0 and 1 as their recovery id, add
|
// AL txs are defined to use 0 and 1 as their recovery
|
||||||
// 27 to become equivalent to unprotected Homestead signatures.
|
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
||||||
V = new(big.Int).Add(V, big.NewInt(27))
|
V = new(big.Int).Add(V, big.NewInt(27))
|
||||||
default:
|
default:
|
||||||
return common.Address{}, ErrTxTypeNotSupported
|
return common.Address{}, ErrTxTypeNotSupported
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
|
|
||||||
var activators = map[int]func(*JumpTable){
|
var activators = map[int]func(*JumpTable){
|
||||||
3529: enable3529,
|
3529: enable3529,
|
||||||
|
3198: enable3198,
|
||||||
2929: enable2929,
|
2929: enable2929,
|
||||||
2200: enable2200,
|
2200: enable2200,
|
||||||
1884: enable1884,
|
1884: enable1884,
|
||||||
@ -154,3 +155,22 @@ func enable3529(jt *JumpTable) {
|
|||||||
jt[SSTORE].dynamicGas = gasSStoreEIP3529
|
jt[SSTORE].dynamicGas = gasSStoreEIP3529
|
||||||
jt[SELFDESTRUCT].dynamicGas = gasSelfdestructEIP3529
|
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
|
BlockNumber *big.Int // Provides information for NUMBER
|
||||||
Time *big.Int // Provides information for TIME
|
Time *big.Int // Provides information for TIME
|
||||||
Difficulty *big.Int // Provides information for DIFFICULTY
|
Difficulty *big.Int // Provides information for DIFFICULTY
|
||||||
|
BaseFee *big.Int // Provides information for BASEFEE
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxContext provides the EVM with information about a transaction.
|
// TxContext provides the EVM with information about a transaction.
|
||||||
|
@ -68,6 +68,7 @@ type JumpTable [256]*operation
|
|||||||
func newLondonInstructionSet() JumpTable {
|
func newLondonInstructionSet() JumpTable {
|
||||||
instructionSet := newBerlinInstructionSet()
|
instructionSet := newBerlinInstructionSet()
|
||||||
enable3529(&instructionSet) // EIP-3529: Reduction in refunds https://eips.ethereum.org/EIPS/eip-3529
|
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
|
return instructionSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +103,7 @@ const (
|
|||||||
GASLIMIT
|
GASLIMIT
|
||||||
CHAINID OpCode = 0x46
|
CHAINID OpCode = 0x46
|
||||||
SELFBALANCE OpCode = 0x47
|
SELFBALANCE OpCode = 0x47
|
||||||
|
BASEFEE OpCode = 0x48
|
||||||
)
|
)
|
||||||
|
|
||||||
// 0x50 range - 'storage' and execution.
|
// 0x50 range - 'storage' and execution.
|
||||||
@ -280,6 +281,7 @@ var opCodeToString = map[OpCode]string{
|
|||||||
GASLIMIT: "GASLIMIT",
|
GASLIMIT: "GASLIMIT",
|
||||||
CHAINID: "CHAINID",
|
CHAINID: "CHAINID",
|
||||||
SELFBALANCE: "SELFBALANCE",
|
SELFBALANCE: "SELFBALANCE",
|
||||||
|
BASEFEE: "BASEFEE",
|
||||||
|
|
||||||
// 0x50 range - 'storage' and execution.
|
// 0x50 range - 'storage' and execution.
|
||||||
POP: "POP",
|
POP: "POP",
|
||||||
@ -432,6 +434,7 @@ var stringToOp = map[string]OpCode{
|
|||||||
"CALLDATASIZE": CALLDATASIZE,
|
"CALLDATASIZE": CALLDATASIZE,
|
||||||
"CALLDATACOPY": CALLDATACOPY,
|
"CALLDATACOPY": CALLDATACOPY,
|
||||||
"CHAINID": CHAINID,
|
"CHAINID": CHAINID,
|
||||||
|
"BASEFEE": BASEFEE,
|
||||||
"DELEGATECALL": DELEGATECALL,
|
"DELEGATECALL": DELEGATECALL,
|
||||||
"STATICCALL": STATICCALL,
|
"STATICCALL": STATICCALL,
|
||||||
"CODESIZE": CODESIZE,
|
"CODESIZE": CODESIZE,
|
||||||
|
@ -162,7 +162,7 @@ func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec
|
|||||||
signer := types.MakeSigner(eth.blockchain.Config(), block.Number())
|
signer := types.MakeSigner(eth.blockchain.Config(), block.Number())
|
||||||
for idx, tx := range block.Transactions() {
|
for idx, tx := range block.Transactions() {
|
||||||
// Assemble the transaction call message and return if the requested offset
|
// 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)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
|
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
|
||||||
if idx == txIndex {
|
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)
|
blockCtx := core.NewEVMBlockContext(task.block.Header(), api.chainContext(localctx), nil)
|
||||||
// Trace all the transactions contained within
|
// Trace all the transactions contained within
|
||||||
for i, tx := range task.block.Transactions() {
|
for i, tx := range task.block.Transactions() {
|
||||||
msg, _ := tx.AsMessage(signer)
|
msg, _ := tx.AsMessage(signer, task.block.BaseFee())
|
||||||
txctx := &txTraceContext{
|
txctx := &txTraceContext{
|
||||||
index: i,
|
index: i,
|
||||||
hash: tx.Hash(),
|
hash: tx.Hash(),
|
||||||
@ -523,7 +523,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
|||||||
defer pend.Done()
|
defer pend.Done()
|
||||||
// Fetch and execute the next transaction trace tasks
|
// Fetch and execute the next transaction trace tasks
|
||||||
for task := range jobs {
|
for task := range jobs {
|
||||||
msg, _ := txs[task.index].AsMessage(signer)
|
msg, _ := txs[task.index].AsMessage(signer, block.BaseFee())
|
||||||
txctx := &txTraceContext{
|
txctx := &txTraceContext{
|
||||||
index: task.index,
|
index: task.index,
|
||||||
hash: txs[task.index].Hash(),
|
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}
|
jobs <- &txTraceTask{statedb: statedb.Copy(), index: i}
|
||||||
|
|
||||||
// Generate the next state snapshot fast without tracing
|
// 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)
|
statedb.Prepare(tx.Hash(), block.Hash(), i)
|
||||||
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
|
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 {
|
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() {
|
for i, tx := range block.Transactions() {
|
||||||
// Prepare the trasaction for un-traced execution
|
// Prepare the trasaction for un-traced execution
|
||||||
var (
|
var (
|
||||||
msg, _ = tx.AsMessage(signer)
|
msg, _ = tx.AsMessage(signer, block.BaseFee())
|
||||||
txContext = core.NewEVMTxContext(msg)
|
txContext = core.NewEVMTxContext(msg)
|
||||||
vmConf vm.Config
|
vmConf vm.Config
|
||||||
dump *os.File
|
dump *os.File
|
||||||
|
@ -161,7 +161,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
|
|||||||
// Recompute transactions up to the target index.
|
// Recompute transactions up to the target index.
|
||||||
signer := types.MakeSigner(b.chainConfig, block.Number())
|
signer := types.MakeSigner(b.chainConfig, block.Number())
|
||||||
for idx, tx := range block.Transactions() {
|
for idx, tx := range block.Transactions() {
|
||||||
msg, _ := tx.AsMessage(signer)
|
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
|
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
|
||||||
if idx == txIndex {
|
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})
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
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})
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
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
|
Value *big.Int // amount of wei sent along with the call
|
||||||
Data []byte // input data, usually an ABI-encoded contract method invocation
|
Data []byte // input data, usually an ABI-encoded contract method invocation
|
||||||
|
|
||||||
|
FeeCap *big.Int // EIP-1559 fee cap per gas.
|
||||||
|
Tip *big.Int // EIP-1559 tip per gas.
|
||||||
|
|
||||||
AccessList types.AccessList // EIP-2930 access list.
|
AccessList types.AccessList // EIP-2930 access list.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -799,7 +799,7 @@ func (args *CallArgs) ToMessage(globalGasCap uint64) types.Message {
|
|||||||
accessList = *args.AccessList
|
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
|
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.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
|
||||||
result.TransactionIndex = (*hexutil.Uint64)(&index)
|
result.TransactionIndex = (*hexutil.Uint64)(&index)
|
||||||
}
|
}
|
||||||
if tx.Type() == types.AccessListTxType {
|
if tx.Type() != types.LegacyTxType {
|
||||||
al := tx.AccessList()
|
al := tx.AccessList()
|
||||||
result.Accesses = &al
|
result.Accesses = &al
|
||||||
result.ChainID = (*hexutil.Big)(tx.ChainId())
|
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
|
// Copy the original db so we don't modify it
|
||||||
statedb := db.Copy()
|
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
|
// Apply the transaction with the access list tracer
|
||||||
tracer := vm.NewAccessListTracer(accessList, args.From, to, precompiles)
|
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 := statedb.GetOrNewStateObject(bankAddr)
|
||||||
from.SetBalance(math.MaxBig256)
|
from.SetBalance(math.MaxBig256)
|
||||||
|
|
||||||
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, 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)
|
context := core.NewEVMBlockContext(header, bc, nil)
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
@ -150,7 +150,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
|||||||
header := lc.GetHeaderByHash(bhash)
|
header := lc.GetHeaderByHash(bhash)
|
||||||
state := light.NewState(ctx, header, lc.Odr())
|
state := light.NewState(ctx, header, lc.Odr())
|
||||||
state.SetBalance(bankAddr, math.MaxBig256)
|
state.SetBalance(bankAddr, math.MaxBig256)
|
||||||
msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, 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)
|
context := core.NewEVMBlockContext(header, lc, nil)
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{})
|
vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{})
|
||||||
|
@ -55,7 +55,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.
|
|||||||
signer := types.MakeSigner(leth.blockchain.Config(), block.Number())
|
signer := types.MakeSigner(leth.blockchain.Config(), block.Number())
|
||||||
for idx, tx := range block.Transactions() {
|
for idx, tx := range block.Transactions() {
|
||||||
// Assemble the transaction call message and return if the requested offset
|
// 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)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil)
|
context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil)
|
||||||
statedb.Prepare(tx.Hash(), block.Hash(), idx)
|
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.
|
// Perform read-only call.
|
||||||
st.SetBalance(testBankAddress, math.MaxBig256)
|
st.SetBalance(testBankAddress, math.MaxBig256)
|
||||||
msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, 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)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(header, chain, nil)
|
context := core.NewEVMBlockContext(header, chain, nil)
|
||||||
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{})
|
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{})
|
||||||
|
@ -69,9 +69,8 @@ var GoerliBootnodes = []string{
|
|||||||
|
|
||||||
// BaikalBootnodes are the enode URLs of the P2P bootstrap nodes running on the
|
// BaikalBootnodes are the enode URLs of the P2P bootstrap nodes running on the
|
||||||
// Baikal ephemeral test network.
|
// Baikal ephemeral test network.
|
||||||
// TODO: Set Baikal bootnodes
|
|
||||||
var BaikalBootnodes = []string{
|
var BaikalBootnodes = []string{
|
||||||
"",
|
"enode://9e1096aa59862a6f164994cb5cb16f5124d6c992cdbf4535ff7dea43ea1512afe5448dca9df1b7ab0726129603f1a3336b631e4d7a1a44c94daddd03241587f9@3.9.20.133:30303",
|
||||||
}
|
}
|
||||||
|
|
||||||
var V5Bootnodes = []string{
|
var V5Bootnodes = []string{
|
||||||
|
@ -231,7 +231,7 @@ var (
|
|||||||
IstanbulBlock: big.NewInt(0),
|
IstanbulBlock: big.NewInt(0),
|
||||||
MuirGlacierBlock: nil,
|
MuirGlacierBlock: nil,
|
||||||
BerlinBlock: big.NewInt(0),
|
BerlinBlock: big.NewInt(0),
|
||||||
LondonBlock: big.NewInt(0),
|
LondonBlock: big.NewInt(500),
|
||||||
Clique: &CliqueConfig{
|
Clique: &CliqueConfig{
|
||||||
Period: 30,
|
Period: 30,
|
||||||
Epoch: 30000,
|
Epoch: 30000,
|
||||||
|
@ -118,6 +118,10 @@ const (
|
|||||||
// Introduced in Tangerine Whistle (Eip 150)
|
// Introduced in Tangerine Whistle (Eip 150)
|
||||||
CreateBySelfdestructGas uint64 = 25000
|
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
|
MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
|
||||||
|
|
||||||
// Precompiled contract gas prices
|
// Precompiled contract gas prices
|
||||||
|
@ -179,6 +179,19 @@ var Forks = map[string]*params.ChainConfig{
|
|||||||
BerlinBlock: big.NewInt(0),
|
BerlinBlock: big.NewInt(0),
|
||||||
LondonBlock: 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
|
// 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 {
|
if tx.AccessLists != nil && tx.AccessLists[ps.Indexes.Data] != nil {
|
||||||
accessList = *tx.AccessLists[ps.Indexes.Data]
|
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
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user