forked from cerc-io/plugeth
		
	all: implement withdrawals (EIP-4895) (#26484)
This change implements withdrawals as specified in EIP-4895. Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com> Co-authored-by: marioevz <marioevz@gmail.com> Co-authored-by: Martin Holst Swende <martin@swende.se> Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
		
							parent
							
								
									2b57a27d9e
								
							
						
					
					
						commit
						2a2b0419fb
					
				| @ -54,6 +54,7 @@ type header struct { | |||||||
| 	MixDigest       common.Hash       `json:"mixHash"` | 	MixDigest       common.Hash       `json:"mixHash"` | ||||||
| 	Nonce           *types.BlockNonce `json:"nonce"` | 	Nonce           *types.BlockNonce `json:"nonce"` | ||||||
| 	BaseFee         *big.Int          `json:"baseFeePerGas" rlp:"optional"` | 	BaseFee         *big.Int          `json:"baseFeePerGas" rlp:"optional"` | ||||||
|  | 	WithdrawalsHash *common.Hash      `json:"withdrawalsRoot" rlp:"optional"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type headerMarshaling struct { | type headerMarshaling struct { | ||||||
| @ -70,6 +71,7 @@ type bbInput struct { | |||||||
| 	Header      *header             `json:"header,omitempty"` | 	Header      *header             `json:"header,omitempty"` | ||||||
| 	OmmersRlp   []string            `json:"ommers,omitempty"` | 	OmmersRlp   []string            `json:"ommers,omitempty"` | ||||||
| 	TxRlp       string              `json:"txs,omitempty"` | 	TxRlp       string              `json:"txs,omitempty"` | ||||||
|  | 	Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` | ||||||
| 	Clique      *cliqueInput        `json:"clique,omitempty"` | 	Clique      *cliqueInput        `json:"clique,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	Ethash    bool                 `json:"-"` | 	Ethash    bool                 `json:"-"` | ||||||
| @ -129,6 +131,7 @@ func (i *bbInput) ToBlock() *types.Block { | |||||||
| 		Extra:           i.Header.Extra, | 		Extra:           i.Header.Extra, | ||||||
| 		MixDigest:       i.Header.MixDigest, | 		MixDigest:       i.Header.MixDigest, | ||||||
| 		BaseFee:         i.Header.BaseFee, | 		BaseFee:         i.Header.BaseFee, | ||||||
|  | 		WithdrawalsHash: i.Header.WithdrawalsHash, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Fill optional values.
 | 	// Fill optional values.
 | ||||||
| @ -153,7 +156,7 @@ func (i *bbInput) ToBlock() *types.Block { | |||||||
| 	if header.Difficulty != nil { | 	if header.Difficulty != nil { | ||||||
| 		header.Difficulty = i.Header.Difficulty | 		header.Difficulty = i.Header.Difficulty | ||||||
| 	} | 	} | ||||||
| 	return types.NewBlockWithHeader(header).WithBody(i.Txs, i.Ommers) | 	return types.NewBlockWithHeader(header).WithBody(i.Txs, i.Ommers).WithWithdrawals(i.Withdrawals) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SealBlock seals the given block using the configured engine.
 | // SealBlock seals the given block using the configured engine.
 | ||||||
| @ -261,6 +264,7 @@ func readInput(ctx *cli.Context) (*bbInput, error) { | |||||||
| 	var ( | 	var ( | ||||||
| 		headerStr      = ctx.String(InputHeaderFlag.Name) | 		headerStr      = ctx.String(InputHeaderFlag.Name) | ||||||
| 		ommersStr      = ctx.String(InputOmmersFlag.Name) | 		ommersStr      = ctx.String(InputOmmersFlag.Name) | ||||||
|  | 		withdrawalsStr = ctx.String(InputWithdrawalsFlag.Name) | ||||||
| 		txsStr         = ctx.String(InputTxsRlpFlag.Name) | 		txsStr         = ctx.String(InputTxsRlpFlag.Name) | ||||||
| 		cliqueStr      = ctx.String(SealCliqueFlag.Name) | 		cliqueStr      = ctx.String(SealCliqueFlag.Name) | ||||||
| 		ethashOn       = ctx.Bool(SealEthashFlag.Name) | 		ethashOn       = ctx.Bool(SealEthashFlag.Name) | ||||||
| @ -312,6 +316,13 @@ func readInput(ctx *cli.Context) (*bbInput, error) { | |||||||
| 		} | 		} | ||||||
| 		inputData.OmmersRlp = ommers | 		inputData.OmmersRlp = ommers | ||||||
| 	} | 	} | ||||||
|  | 	if withdrawalsStr != stdinSelector && withdrawalsStr != "" { | ||||||
|  | 		var withdrawals []*types.Withdrawal | ||||||
|  | 		if err := readFile(withdrawalsStr, "withdrawals", &withdrawals); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		inputData.Withdrawals = withdrawals | ||||||
|  | 	} | ||||||
| 	if txsStr != stdinSelector { | 	if txsStr != stdinSelector { | ||||||
| 		var txs string | 		var txs string | ||||||
| 		if err := readFile(txsStr, "txs", &txs); err != nil { | 		if err := readFile(txsStr, "txs", &txs); err != nil { | ||||||
| @ -351,15 +362,14 @@ func readInput(ctx *cli.Context) (*bbInput, error) { | |||||||
| // files
 | // files
 | ||||||
| func dispatchBlock(ctx *cli.Context, baseDir string, block *types.Block) error { | func dispatchBlock(ctx *cli.Context, baseDir string, block *types.Block) error { | ||||||
| 	raw, _ := rlp.EncodeToBytes(block) | 	raw, _ := rlp.EncodeToBytes(block) | ||||||
| 
 |  | ||||||
| 	type blockInfo struct { | 	type blockInfo struct { | ||||||
| 		Rlp  hexutil.Bytes `json:"rlp"` | 		Rlp  hexutil.Bytes `json:"rlp"` | ||||||
| 		Hash common.Hash   `json:"hash"` | 		Hash common.Hash   `json:"hash"` | ||||||
| 	} | 	} | ||||||
| 	var enc blockInfo | 	enc := blockInfo{ | ||||||
| 	enc.Rlp = raw | 		Rlp:  raw, | ||||||
| 	enc.Hash = block.Hash() | 		Hash: block.Hash(), | ||||||
| 
 | 	} | ||||||
| 	b, err := json.MarshalIndent(enc, "", "  ") | 	b, err := json.MarshalIndent(enc, "", "  ") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) | 		return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) | ||||||
|  | |||||||
| @ -57,6 +57,7 @@ type ExecutionResult struct { | |||||||
| 	Difficulty      *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"` | 	Difficulty      *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"` | ||||||
| 	GasUsed         math.HexOrDecimal64   `json:"gasUsed"` | 	GasUsed         math.HexOrDecimal64   `json:"gasUsed"` | ||||||
| 	BaseFee         *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` | 	BaseFee         *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` | ||||||
|  | 	WithdrawalsRoot *common.Hash          `json:"withdrawalsRoot,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type ommer struct { | type ommer struct { | ||||||
| @ -79,6 +80,7 @@ type stEnv struct { | |||||||
| 	ParentTimestamp  uint64                              `json:"parentTimestamp,omitempty"` | 	ParentTimestamp  uint64                              `json:"parentTimestamp,omitempty"` | ||||||
| 	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"` | ||||||
|  | 	Withdrawals      []*types.Withdrawal                 `json:"withdrawals,omitempty"` | ||||||
| 	BaseFee          *big.Int                            `json:"currentBaseFee,omitempty"` | 	BaseFee          *big.Int                            `json:"currentBaseFee,omitempty"` | ||||||
| 	ParentUncleHash  common.Hash                         `json:"parentUncleHash"` | 	ParentUncleHash  common.Hash                         `json:"parentUncleHash"` | ||||||
| } | } | ||||||
| @ -254,6 +256,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, | |||||||
| 		} | 		} | ||||||
| 		statedb.AddBalance(pre.Env.Coinbase, minerReward) | 		statedb.AddBalance(pre.Env.Coinbase, minerReward) | ||||||
| 	} | 	} | ||||||
|  | 	// Apply withdrawals
 | ||||||
|  | 	for _, w := range pre.Env.Withdrawals { | ||||||
|  | 		// Amount is in gwei, turn into wei
 | ||||||
|  | 		amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) | ||||||
|  | 		statedb.AddBalance(w.Address, amount) | ||||||
|  | 	} | ||||||
| 	// Commit block
 | 	// Commit block
 | ||||||
| 	root, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber)) | 	root, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @ -272,6 +280,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, | |||||||
| 		GasUsed:     (math.HexOrDecimal64)(gasUsed), | 		GasUsed:     (math.HexOrDecimal64)(gasUsed), | ||||||
| 		BaseFee:     (*math.HexOrDecimal256)(vmContext.BaseFee), | 		BaseFee:     (*math.HexOrDecimal256)(vmContext.BaseFee), | ||||||
| 	} | 	} | ||||||
|  | 	if pre.Env.Withdrawals != nil { | ||||||
|  | 		h := types.DeriveSha(types.Withdrawals(pre.Env.Withdrawals), trie.NewStackTrie(nil)) | ||||||
|  | 		execRs.WithdrawalsRoot = &h | ||||||
|  | 	} | ||||||
| 	return statedb, execRs, nil | 	return statedb, execRs, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -112,6 +112,10 @@ var ( | |||||||
| 		Name:  "input.ommers", | 		Name:  "input.ommers", | ||||||
| 		Usage: "`stdin` or file name of where to find the list of ommer header RLPs to use.", | 		Usage: "`stdin` or file name of where to find the list of ommer header RLPs to use.", | ||||||
| 	} | 	} | ||||||
|  | 	InputWithdrawalsFlag = &cli.StringFlag{ | ||||||
|  | 		Name:  "input.withdrawals", | ||||||
|  | 		Usage: "`stdin` or file name of where to find the list of withdrawals to use.", | ||||||
|  | 	} | ||||||
| 	InputTxsRlpFlag = &cli.StringFlag{ | 	InputTxsRlpFlag = &cli.StringFlag{ | ||||||
| 		Name:  "input.txs", | 		Name:  "input.txs", | ||||||
| 		Usage: "`stdin` or file name of where to find the transactions list in RLP form.", | 		Usage: "`stdin` or file name of where to find the transactions list in RLP form.", | ||||||
|  | |||||||
| @ -34,6 +34,7 @@ func (h header) MarshalJSON() ([]byte, error) { | |||||||
| 		MixDigest       common.Hash           `json:"mixHash"` | 		MixDigest       common.Hash           `json:"mixHash"` | ||||||
| 		Nonce           *types.BlockNonce     `json:"nonce"` | 		Nonce           *types.BlockNonce     `json:"nonce"` | ||||||
| 		BaseFee         *math.HexOrDecimal256 `json:"baseFeePerGas" rlp:"optional"` | 		BaseFee         *math.HexOrDecimal256 `json:"baseFeePerGas" rlp:"optional"` | ||||||
|  | 		WithdrawalsHash *common.Hash          `json:"withdrawalsRoot" rlp:"optional"` | ||||||
| 	} | 	} | ||||||
| 	var enc header | 	var enc header | ||||||
| 	enc.ParentHash = h.ParentHash | 	enc.ParentHash = h.ParentHash | ||||||
| @ -52,6 +53,7 @@ func (h header) MarshalJSON() ([]byte, error) { | |||||||
| 	enc.MixDigest = h.MixDigest | 	enc.MixDigest = h.MixDigest | ||||||
| 	enc.Nonce = h.Nonce | 	enc.Nonce = h.Nonce | ||||||
| 	enc.BaseFee = (*math.HexOrDecimal256)(h.BaseFee) | 	enc.BaseFee = (*math.HexOrDecimal256)(h.BaseFee) | ||||||
|  | 	enc.WithdrawalsHash = h.WithdrawalsHash | ||||||
| 	return json.Marshal(&enc) | 	return json.Marshal(&enc) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -74,6 +76,7 @@ func (h *header) UnmarshalJSON(input []byte) error { | |||||||
| 		MixDigest       *common.Hash          `json:"mixHash"` | 		MixDigest       *common.Hash          `json:"mixHash"` | ||||||
| 		Nonce           *types.BlockNonce     `json:"nonce"` | 		Nonce           *types.BlockNonce     `json:"nonce"` | ||||||
| 		BaseFee         *math.HexOrDecimal256 `json:"baseFeePerGas" rlp:"optional"` | 		BaseFee         *math.HexOrDecimal256 `json:"baseFeePerGas" rlp:"optional"` | ||||||
|  | 		WithdrawalsHash *common.Hash          `json:"withdrawalsRoot" rlp:"optional"` | ||||||
| 	} | 	} | ||||||
| 	var dec header | 	var dec header | ||||||
| 	if err := json.Unmarshal(input, &dec); err != nil { | 	if err := json.Unmarshal(input, &dec); err != nil { | ||||||
| @ -131,5 +134,8 @@ func (h *header) UnmarshalJSON(input []byte) error { | |||||||
| 	if dec.BaseFee != nil { | 	if dec.BaseFee != nil { | ||||||
| 		h.BaseFee = (*big.Int)(dec.BaseFee) | 		h.BaseFee = (*big.Int)(dec.BaseFee) | ||||||
| 	} | 	} | ||||||
|  | 	if dec.WithdrawalsHash != nil { | ||||||
|  | 		h.WithdrawalsHash = dec.WithdrawalsHash | ||||||
|  | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ import ( | |||||||
| 
 | 
 | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/common/math" | 	"github.com/ethereum/go-ethereum/common/math" | ||||||
|  | 	"github.com/ethereum/go-ethereum/core/types" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var _ = (*stEnvMarshaling)(nil) | var _ = (*stEnvMarshaling)(nil) | ||||||
| @ -29,6 +30,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) { | |||||||
| 		ParentTimestamp  math.HexOrDecimal64                 `json:"parentTimestamp,omitempty"` | 		ParentTimestamp  math.HexOrDecimal64                 `json:"parentTimestamp,omitempty"` | ||||||
| 		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"` | ||||||
|  | 		Withdrawals      []*types.Withdrawal                 `json:"withdrawals,omitempty"` | ||||||
| 		BaseFee          *math.HexOrDecimal256               `json:"currentBaseFee,omitempty"` | 		BaseFee          *math.HexOrDecimal256               `json:"currentBaseFee,omitempty"` | ||||||
| 		ParentUncleHash  common.Hash                         `json:"parentUncleHash"` | 		ParentUncleHash  common.Hash                         `json:"parentUncleHash"` | ||||||
| 	} | 	} | ||||||
| @ -46,6 +48,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) { | |||||||
| 	enc.ParentTimestamp = math.HexOrDecimal64(s.ParentTimestamp) | 	enc.ParentTimestamp = math.HexOrDecimal64(s.ParentTimestamp) | ||||||
| 	enc.BlockHashes = s.BlockHashes | 	enc.BlockHashes = s.BlockHashes | ||||||
| 	enc.Ommers = s.Ommers | 	enc.Ommers = s.Ommers | ||||||
|  | 	enc.Withdrawals = s.Withdrawals | ||||||
| 	enc.BaseFee = (*math.HexOrDecimal256)(s.BaseFee) | 	enc.BaseFee = (*math.HexOrDecimal256)(s.BaseFee) | ||||||
| 	enc.ParentUncleHash = s.ParentUncleHash | 	enc.ParentUncleHash = s.ParentUncleHash | ||||||
| 	return json.Marshal(&enc) | 	return json.Marshal(&enc) | ||||||
| @ -67,6 +70,7 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { | |||||||
| 		ParentTimestamp  *math.HexOrDecimal64                `json:"parentTimestamp,omitempty"` | 		ParentTimestamp  *math.HexOrDecimal64                `json:"parentTimestamp,omitempty"` | ||||||
| 		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"` | ||||||
|  | 		Withdrawals      []*types.Withdrawal                 `json:"withdrawals,omitempty"` | ||||||
| 		BaseFee          *math.HexOrDecimal256               `json:"currentBaseFee,omitempty"` | 		BaseFee          *math.HexOrDecimal256               `json:"currentBaseFee,omitempty"` | ||||||
| 		ParentUncleHash  *common.Hash                        `json:"parentUncleHash"` | 		ParentUncleHash  *common.Hash                        `json:"parentUncleHash"` | ||||||
| 	} | 	} | ||||||
| @ -117,6 +121,9 @@ 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.Withdrawals != nil { | ||||||
|  | 		s.Withdrawals = dec.Withdrawals | ||||||
|  | 	} | ||||||
| 	if dec.BaseFee != nil { | 	if dec.BaseFee != nil { | ||||||
| 		s.BaseFee = (*big.Int)(dec.BaseFee) | 		s.BaseFee = (*big.Int)(dec.BaseFee) | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -262,6 +262,9 @@ func Transition(ctx *cli.Context) error { | |||||||
| 			return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) | 			return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if chainConfig.IsShanghai(prestate.Env.Number) && prestate.Env.Withdrawals == nil { | ||||||
|  | 		return NewError(ErrorConfig, errors.New("Shanghai config but missing 'withdrawals' in env section")) | ||||||
|  | 	} | ||||||
| 	isMerged := chainConfig.TerminalTotalDifficulty != nil && chainConfig.TerminalTotalDifficulty.BitLen() == 0 | 	isMerged := chainConfig.TerminalTotalDifficulty != nil && chainConfig.TerminalTotalDifficulty.BitLen() == 0 | ||||||
| 	env := prestate.Env | 	env := prestate.Env | ||||||
| 	if isMerged { | 	if isMerged { | ||||||
|  | |||||||
| @ -176,6 +176,7 @@ var blockBuilderCommand = &cli.Command{ | |||||||
| 		t8ntool.OutputBlockFlag, | 		t8ntool.OutputBlockFlag, | ||||||
| 		t8ntool.InputHeaderFlag, | 		t8ntool.InputHeaderFlag, | ||||||
| 		t8ntool.InputOmmersFlag, | 		t8ntool.InputOmmersFlag, | ||||||
|  | 		t8ntool.InputWithdrawalsFlag, | ||||||
| 		t8ntool.InputTxsRlpFlag, | 		t8ntool.InputTxsRlpFlag, | ||||||
| 		t8ntool.SealCliqueFlag, | 		t8ntool.SealCliqueFlag, | ||||||
| 		t8ntool.SealEthashFlag, | 		t8ntool.SealEthashFlag, | ||||||
|  | |||||||
| @ -251,6 +251,14 @@ func TestT8n(t *testing.T) { | |||||||
| 			output: t8nOutput{alloc: true, result: true}, | 			output: t8nOutput{alloc: true, result: true}, | ||||||
| 			expOut: "exp.json", | 			expOut: "exp.json", | ||||||
| 		}, | 		}, | ||||||
|  | 		{ // Test withdrawals transition
 | ||||||
|  | 			base: "./testdata/26", | ||||||
|  | 			input: t8nInput{ | ||||||
|  | 				"alloc.json", "txs.json", "env.json", "Shanghai", "", | ||||||
|  | 			}, | ||||||
|  | 			output: t8nOutput{alloc: true, result: true}, | ||||||
|  | 			expOut: "exp.json", | ||||||
|  | 		}, | ||||||
| 	} { | 	} { | ||||||
| 		args := []string{"t8n"} | 		args := []string{"t8n"} | ||||||
| 		args = append(args, tc.output.get()...) | 		args = append(args, tc.output.get()...) | ||||||
| @ -393,6 +401,7 @@ func TestT9n(t *testing.T) { | |||||||
| type b11rInput struct { | type b11rInput struct { | ||||||
| 	inEnv         string | 	inEnv         string | ||||||
| 	inOmmersRlp   string | 	inOmmersRlp   string | ||||||
|  | 	inWithdrawals string | ||||||
| 	inTxsRlp      string | 	inTxsRlp      string | ||||||
| 	inClique      string | 	inClique      string | ||||||
| 	ethash        bool | 	ethash        bool | ||||||
| @ -410,6 +419,10 @@ func (args *b11rInput) get(base string) []string { | |||||||
| 		out = append(out, "--input.ommers") | 		out = append(out, "--input.ommers") | ||||||
| 		out = append(out, fmt.Sprintf("%v/%v", base, opt)) | 		out = append(out, fmt.Sprintf("%v/%v", base, opt)) | ||||||
| 	} | 	} | ||||||
|  | 	if opt := args.inWithdrawals; opt != "" { | ||||||
|  | 		out = append(out, "--input.withdrawals") | ||||||
|  | 		out = append(out, fmt.Sprintf("%v/%v", base, opt)) | ||||||
|  | 	} | ||||||
| 	if opt := args.inTxsRlp; opt != "" { | 	if opt := args.inTxsRlp; opt != "" { | ||||||
| 		out = append(out, "--input.txs") | 		out = append(out, "--input.txs") | ||||||
| 		out = append(out, fmt.Sprintf("%v/%v", base, opt)) | 		out = append(out, fmt.Sprintf("%v/%v", base, opt)) | ||||||
| @ -480,6 +493,16 @@ func TestB11r(t *testing.T) { | |||||||
| 			}, | 			}, | ||||||
| 			expOut: "exp.json", | 			expOut: "exp.json", | ||||||
| 		}, | 		}, | ||||||
|  | 		{ // block with withdrawals
 | ||||||
|  | 			base: "./testdata/27", | ||||||
|  | 			input: b11rInput{ | ||||||
|  | 				inEnv:         "header.json", | ||||||
|  | 				inOmmersRlp:   "ommers.json", | ||||||
|  | 				inWithdrawals: "withdrawals.json", | ||||||
|  | 				inTxsRlp:      "txs.rlp", | ||||||
|  | 			}, | ||||||
|  | 			expOut: "exp.json", | ||||||
|  | 		}, | ||||||
| 	} { | 	} { | ||||||
| 		args := []string{"b11r"} | 		args := []string{"b11r"} | ||||||
| 		args = append(args, tc.input.get(tc.base)...) | 		args = append(args, tc.input.get(tc.base)...) | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								cmd/evm/testdata/26/alloc.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								cmd/evm/testdata/26/alloc.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | { | ||||||
|  |   "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { | ||||||
|  |     "balance": "0x0", | ||||||
|  |     "code": "0x", | ||||||
|  |     "nonce": "0xac", | ||||||
|  |     "storage": {} | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								cmd/evm/testdata/26/env.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								cmd/evm/testdata/26/env.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | { | ||||||
|  |   "currentCoinbase": "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b", | ||||||
|  |   "currentDifficulty": null, | ||||||
|  |   "currentRandom": "0xdeadc0de", | ||||||
|  |   "currentGasLimit": "0x750a163df65e8a", | ||||||
|  |   "currentBaseFee": "0x500", | ||||||
|  |   "currentNumber": "1", | ||||||
|  |   "currentTimestamp": "1000", | ||||||
|  |   "withdrawals": [ | ||||||
|  |     { | ||||||
|  |       "index": "0x42", | ||||||
|  |       "validatorIndex": "0x42", | ||||||
|  |       "address": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", | ||||||
|  |       "amount": "0x2a" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								cmd/evm/testdata/26/exp.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								cmd/evm/testdata/26/exp.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | { | ||||||
|  |   "alloc": { | ||||||
|  |     "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { | ||||||
|  |       "balance": "0x9c7652400", | ||||||
|  |       "nonce": "0xac" | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "result": { | ||||||
|  |     "stateRoot": "0x6e061c2f6513af27d267a0e3b07cb9a10f1ba3a0f65ab648d3a17c36e15021d2", | ||||||
|  |     "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", | ||||||
|  |     "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", | ||||||
|  |     "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", | ||||||
|  |     "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", | ||||||
|  |     "receipts": [], | ||||||
|  |     "currentDifficulty": null, | ||||||
|  |     "gasUsed": "0x0", | ||||||
|  |     "currentBaseFee": "0x500", | ||||||
|  |     "withdrawalsRoot": "0x4921c0162c359755b2ae714a0978a1dad2eb8edce7ff9b38b9b6fc4cbc547eb5" | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								cmd/evm/testdata/26/txs.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								cmd/evm/testdata/26/txs.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | [] | ||||||
							
								
								
									
										4
									
								
								cmd/evm/testdata/27/exp.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								cmd/evm/testdata/27/exp.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | { | ||||||
|  |   "rlp": "0xf90239f9021aa0d6d785d33cbecf30f30d07e00e226af58f72efdf385d46bc3e6326c23b11e34ea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0325aea6db48e9d737cddf59034843e99f05bec269453be83c9b9a981a232cc2ea056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082100082c3be83050785808455c5277e80a05865e417635a26db6d1d39ac70d1abf373e5398b3c6fd506acd038fa1334eedf88000000000000000080a04921c0162c359755b2ae714a0978a1dad2eb8edce7ff9b38b9b6fc4cbc547eb5c0c0d9d8424394a94f5374fce5edbc8e2a8697c15331677e6ebf0b2a", | ||||||
|  |   "hash": "0xdc42abd3698499675819e0a85cc1266f16da90277509b867446a6b25fa2b9d87" | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								cmd/evm/testdata/27/header.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								cmd/evm/testdata/27/header.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | { | ||||||
|  |     "parentHash": "0xd6d785d33cbecf30f30d07e00e226af58f72efdf385d46bc3e6326c23b11e34e", | ||||||
|  |     "stateRoot": "0x325aea6db48e9d737cddf59034843e99f05bec269453be83c9b9a981a232cc2e", | ||||||
|  |     "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", | ||||||
|  |     "difficulty": "0x1000", | ||||||
|  |     "number": "0xc3be", | ||||||
|  |     "gasLimit": "0x50785", | ||||||
|  |     "gasUsed": "0x0", | ||||||
|  |     "timestamp": "0x55c5277e", | ||||||
|  |     "mixHash": "0x5865e417635a26db6d1d39ac70d1abf373e5398b3c6fd506acd038fa1334eedf", | ||||||
|  |     "withdrawalsRoot": "0x4921c0162c359755b2ae714a0978a1dad2eb8edce7ff9b38b9b6fc4cbc547eb5" | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								cmd/evm/testdata/27/ommers.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								cmd/evm/testdata/27/ommers.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | [] | ||||||
							
								
								
									
										1
									
								
								cmd/evm/testdata/27/txs.rlp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								cmd/evm/testdata/27/txs.rlp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | "c0" | ||||||
							
								
								
									
										8
									
								
								cmd/evm/testdata/27/withdrawals.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								cmd/evm/testdata/27/withdrawals.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | [ | ||||||
|  |     { | ||||||
|  |       "index": "0x42", | ||||||
|  |       "validatorIndex": "0x43", | ||||||
|  |       "address": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", | ||||||
|  |       "amount": "0x2a" | ||||||
|  |     } | ||||||
|  | ] | ||||||
| @ -257,7 +257,18 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa | |||||||
| 		return consensus.ErrInvalidNumber | 		return consensus.ErrInvalidNumber | ||||||
| 	} | 	} | ||||||
| 	// Verify the header's EIP-1559 attributes.
 | 	// Verify the header's EIP-1559 attributes.
 | ||||||
| 	return misc.VerifyEip1559Header(chain.Config(), parent, header) | 	if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	// Verify existence / non-existence of withdrawalsHash.
 | ||||||
|  | 	shanghai := chain.Config().IsShanghai(header.Time) | ||||||
|  | 	if shanghai && header.WithdrawalsHash == nil { | ||||||
|  | 		return fmt.Errorf("missing withdrawalsHash") | ||||||
|  | 	} | ||||||
|  | 	if !shanghai && header.WithdrawalsHash != nil { | ||||||
|  | 		return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // verifyHeaders is similar to verifyHeader, but verifies a batch of headers
 | // verifyHeaders is similar to verifyHeader, but verifies a batch of headers
 | ||||||
| @ -316,13 +327,20 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Finalize implements consensus.Engine, setting the final state on the header
 | // Finalize implements consensus.Engine, setting the final state on the header
 | ||||||
| func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { | func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { | ||||||
| 	// Finalize is different with Prepare, it can be used in both block generation
 | 	// Finalize is different with Prepare, it can be used in both block generation
 | ||||||
| 	// and verification. So determine the consensus rules by header type.
 | 	// and verification. So determine the consensus rules by header type.
 | ||||||
| 	if !beacon.IsPoSHeader(header) { | 	if !beacon.IsPoSHeader(header) { | ||||||
| 		beacon.ethone.Finalize(chain, header, state, txs, uncles) | 		beacon.ethone.Finalize(chain, header, state, txs, uncles, nil) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	// Withdrawals processing.
 | ||||||
|  | 	for _, w := range withdrawals { | ||||||
|  | 		// Convert amount from gwei to wei.
 | ||||||
|  | 		amount := new(big.Int).SetUint64(w.Amount) | ||||||
|  | 		amount = amount.Mul(amount, big.NewInt(params.GWei)) | ||||||
|  | 		state.AddBalance(w.Address, amount) | ||||||
|  | 	} | ||||||
| 	// The block reward is no longer handled here. It's done by the
 | 	// The block reward is no longer handled here. It's done by the
 | ||||||
| 	// external consensus engine.
 | 	// external consensus engine.
 | ||||||
| 	header.Root = state.IntermediateRoot(true) | 	header.Root = state.IntermediateRoot(true) | ||||||
| @ -330,15 +348,26 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. | |||||||
| 
 | 
 | ||||||
| // FinalizeAndAssemble implements consensus.Engine, setting the final state and
 | // FinalizeAndAssemble implements consensus.Engine, setting the final state and
 | ||||||
| // assembling the block.
 | // assembling the block.
 | ||||||
| func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { | func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) { | ||||||
| 	// FinalizeAndAssemble is different with Prepare, it can be used in both block
 | 	// FinalizeAndAssemble is different with Prepare, it can be used in both block
 | ||||||
| 	// generation and verification. So determine the consensus rules by header type.
 | 	// generation and verification. So determine the consensus rules by header type.
 | ||||||
| 	if !beacon.IsPoSHeader(header) { | 	if !beacon.IsPoSHeader(header) { | ||||||
| 		return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts) | 		return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts, nil) | ||||||
| 	} | 	} | ||||||
| 	// Finalize and assemble the block
 | 	shanghai := chain.Config().IsShanghai(header.Time) | ||||||
| 	beacon.Finalize(chain, header, state, txs, uncles) | 	if shanghai { | ||||||
| 	return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil | 		// All blocks after Shanghai must include a withdrawals root.
 | ||||||
|  | 		if withdrawals == nil { | ||||||
|  | 			withdrawals = make([]*types.Withdrawal, 0) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		if len(withdrawals) > 0 { | ||||||
|  | 			return nil, errors.New("withdrawals set before Shanghai activation") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// Finalize and assemble the block.
 | ||||||
|  | 	beacon.Finalize(chain, header, state, txs, uncles, withdrawals) | ||||||
|  | 	return types.NewBlockWithWithdrawals(header, txs, uncles, receipts, withdrawals, trie.NewStackTrie(nil)), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Seal generates a new sealing request for the given input block and pushes
 | // Seal generates a new sealing request for the given input block and pushes
 | ||||||
|  | |||||||
							
								
								
									
										41
									
								
								consensus/beacon/faker.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								consensus/beacon/faker.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | // Copyright 2023 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 beacon | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"math/big" | ||||||
|  | 
 | ||||||
|  | 	"github.com/ethereum/go-ethereum/consensus" | ||||||
|  | 	"github.com/ethereum/go-ethereum/core/types" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // NewFaker creates a fake consensus engine for testing.
 | ||||||
|  | // The fake engine simulates a merged network.
 | ||||||
|  | // It can not be used to test the merge transition.
 | ||||||
|  | // This type is needed since the fakeChainReader can not be used with
 | ||||||
|  | // a normal beacon consensus engine.
 | ||||||
|  | func NewFaker() consensus.Engine { | ||||||
|  | 	return new(faker) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type faker struct { | ||||||
|  | 	Beacon | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (f *faker) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { | ||||||
|  | 	return beaconDifficulty | ||||||
|  | } | ||||||
| @ -298,6 +298,9 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H | |||||||
| 	if header.GasLimit > params.MaxGasLimit { | 	if header.GasLimit > params.MaxGasLimit { | ||||||
| 		return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit) | 		return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit) | ||||||
| 	} | 	} | ||||||
|  | 	if chain.Config().IsShanghai(header.Time) { | ||||||
|  | 		return fmt.Errorf("clique does not support shanghai fork") | ||||||
|  | 	} | ||||||
| 	// 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 | ||||||
| @ -564,7 +567,7 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header | |||||||
| 
 | 
 | ||||||
| // Finalize implements consensus.Engine, ensuring no uncles are set, nor block
 | // Finalize implements consensus.Engine, ensuring no uncles are set, nor block
 | ||||||
| // rewards given.
 | // rewards given.
 | ||||||
| func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { | func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { | ||||||
| 	// No block rewards in PoA, so the state remains as is and uncles are dropped
 | 	// No block rewards in PoA, so the state remains as is and uncles are dropped
 | ||||||
| 	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) | 	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) | ||||||
| 	header.UncleHash = types.CalcUncleHash(nil) | 	header.UncleHash = types.CalcUncleHash(nil) | ||||||
| @ -572,9 +575,13 @@ func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Heade | |||||||
| 
 | 
 | ||||||
| // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
 | // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
 | ||||||
| // nor block rewards given, and returns the final block.
 | // nor block rewards given, and returns the final block.
 | ||||||
| func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { | func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) { | ||||||
|  | 	if len(withdrawals) > 0 { | ||||||
|  | 		return nil, errors.New("clique does not support withdrawals") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// Finalize block
 | 	// Finalize block
 | ||||||
| 	c.Finalize(chain, header, state, txs, uncles) | 	c.Finalize(chain, header, state, txs, uncles, nil) | ||||||
| 
 | 
 | ||||||
| 	// Assemble and return the final block for sealing
 | 	// Assemble and return the final block for sealing
 | ||||||
| 	return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), nil | 	return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), nil | ||||||
| @ -743,6 +750,9 @@ func encodeSigHeader(w io.Writer, header *types.Header) { | |||||||
| 	if header.BaseFee != nil { | 	if header.BaseFee != nil { | ||||||
| 		enc = append(enc, header.BaseFee) | 		enc = append(enc, header.BaseFee) | ||||||
| 	} | 	} | ||||||
|  | 	if header.WithdrawalsHash != nil { | ||||||
|  | 		panic("unexpected withdrawal hash value in clique") | ||||||
|  | 	} | ||||||
| 	if err := rlp.Encode(w, enc); err != nil { | 	if err := rlp.Encode(w, enc); err != nil { | ||||||
| 		panic("can't encode: " + err.Error()) | 		panic("can't encode: " + err.Error()) | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -90,7 +90,7 @@ type Engine interface { | |||||||
| 	// Note: The block header and state database might be updated to reflect any
 | 	// Note: The block header and state database might be updated to reflect any
 | ||||||
| 	// consensus rules that happen at finalization (e.g. block rewards).
 | 	// consensus rules that happen at finalization (e.g. block rewards).
 | ||||||
| 	Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, | 	Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, | ||||||
| 		uncles []*types.Header) | 		uncles []*types.Header, withdrawals []*types.Withdrawal) | ||||||
| 
 | 
 | ||||||
| 	// FinalizeAndAssemble runs any post-transaction state modifications (e.g. block
 | 	// FinalizeAndAssemble runs any post-transaction state modifications (e.g. block
 | ||||||
| 	// rewards) and assembles the final block.
 | 	// rewards) and assembles the final block.
 | ||||||
| @ -98,7 +98,7 @@ type Engine interface { | |||||||
| 	// Note: The block header and state database might be updated to reflect any
 | 	// Note: The block header and state database might be updated to reflect any
 | ||||||
| 	// consensus rules that happen at finalization (e.g. block rewards).
 | 	// consensus rules that happen at finalization (e.g. block rewards).
 | ||||||
| 	FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, | 	FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, | ||||||
| 		uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) | 		uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) | ||||||
| 
 | 
 | ||||||
| 	// Seal generates a new sealing request for the given input block and pushes
 | 	// Seal generates a new sealing request for the given input block and pushes
 | ||||||
| 	// the result into the given channel.
 | 	// the result into the given channel.
 | ||||||
|  | |||||||
| @ -310,6 +310,9 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa | |||||||
| 	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 { | ||||||
| 		return consensus.ErrInvalidNumber | 		return consensus.ErrInvalidNumber | ||||||
| 	} | 	} | ||||||
|  | 	if chain.Config().IsShanghai(header.Time) { | ||||||
|  | 		return fmt.Errorf("ethash does not support shanghai fork") | ||||||
|  | 	} | ||||||
| 	// Verify the engine specific seal securing the block
 | 	// Verify the engine specific seal securing the block
 | ||||||
| 	if seal { | 	if seal { | ||||||
| 		if err := ethash.verifySeal(chain, header, false); err != nil { | 		if err := ethash.verifySeal(chain, header, false); err != nil { | ||||||
| @ -597,7 +600,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H | |||||||
| 
 | 
 | ||||||
| // Finalize implements consensus.Engine, accumulating the block and uncle rewards,
 | // Finalize implements consensus.Engine, accumulating the block and uncle rewards,
 | ||||||
| // setting the final state on the header
 | // setting the final state on the header
 | ||||||
| func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { | func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { | ||||||
| 	// Accumulate any block and uncle rewards and commit the final state root
 | 	// Accumulate any block and uncle rewards and commit the final state root
 | ||||||
| 	accumulateRewards(chain.Config(), state, header, uncles) | 	accumulateRewards(chain.Config(), state, header, uncles) | ||||||
| 	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) | 	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) | ||||||
| @ -605,10 +608,13 @@ func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types. | |||||||
| 
 | 
 | ||||||
| // FinalizeAndAssemble implements consensus.Engine, accumulating the block and
 | // FinalizeAndAssemble implements consensus.Engine, accumulating the block and
 | ||||||
| // uncle rewards, setting the final state and assembling the block.
 | // uncle rewards, setting the final state and assembling the block.
 | ||||||
| func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { | func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) { | ||||||
| 	// Finalize block
 | 	if len(withdrawals) > 0 { | ||||||
| 	ethash.Finalize(chain, header, state, txs, uncles) | 		return nil, errors.New("ethash does not support withdrawals") | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// Finalize block
 | ||||||
|  | 	ethash.Finalize(chain, header, state, txs, uncles, nil) | ||||||
| 	// Header seems complete, assemble into a block and return
 | 	// Header seems complete, assemble into a block and return
 | ||||||
| 	return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil | 	return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil | ||||||
| } | } | ||||||
| @ -635,6 +641,9 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) { | |||||||
| 	if header.BaseFee != nil { | 	if header.BaseFee != nil { | ||||||
| 		enc = append(enc, header.BaseFee) | 		enc = append(enc, header.BaseFee) | ||||||
| 	} | 	} | ||||||
|  | 	if header.WithdrawalsHash != nil { | ||||||
|  | 		panic("withdrawal hash set on ethash") | ||||||
|  | 	} | ||||||
| 	rlp.Encode(hasher, enc) | 	rlp.Encode(hasher, enc) | ||||||
| 	hasher.Sum(hash[:0]) | 	hasher.Sum(hash[:0]) | ||||||
| 	return hash | 	return hash | ||||||
|  | |||||||
| @ -8,46 +8,53 @@ import ( | |||||||
| 
 | 
 | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/common/hexutil" | 	"github.com/ethereum/go-ethereum/common/hexutil" | ||||||
|  | 	"github.com/ethereum/go-ethereum/core/types" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var _ = (*payloadAttributesMarshaling)(nil) | var _ = (*payloadAttributesMarshaling)(nil) | ||||||
| 
 | 
 | ||||||
| // MarshalJSON marshals as JSON.
 | // MarshalJSON marshals as JSON.
 | ||||||
| func (p PayloadAttributesV1) MarshalJSON() ([]byte, error) { | func (p PayloadAttributes) MarshalJSON() ([]byte, error) { | ||||||
| 	type PayloadAttributesV1 struct { | 	type PayloadAttributes struct { | ||||||
| 		Timestamp             hexutil.Uint64      `json:"timestamp"             gencodec:"required"` | 		Timestamp             hexutil.Uint64      `json:"timestamp"             gencodec:"required"` | ||||||
| 		Random                common.Hash         `json:"prevRandao"            gencodec:"required"` | 		Random                common.Hash         `json:"prevRandao"            gencodec:"required"` | ||||||
| 		SuggestedFeeRecipient common.Address      `json:"suggestedFeeRecipient" gencodec:"required"` | 		SuggestedFeeRecipient common.Address      `json:"suggestedFeeRecipient" gencodec:"required"` | ||||||
|  | 		Withdrawals           []*types.Withdrawal `json:"withdrawals"` | ||||||
| 	} | 	} | ||||||
| 	var enc PayloadAttributesV1 | 	var enc PayloadAttributes | ||||||
| 	enc.Timestamp = hexutil.Uint64(p.Timestamp) | 	enc.Timestamp = hexutil.Uint64(p.Timestamp) | ||||||
| 	enc.Random = p.Random | 	enc.Random = p.Random | ||||||
| 	enc.SuggestedFeeRecipient = p.SuggestedFeeRecipient | 	enc.SuggestedFeeRecipient = p.SuggestedFeeRecipient | ||||||
|  | 	enc.Withdrawals = p.Withdrawals | ||||||
| 	return json.Marshal(&enc) | 	return json.Marshal(&enc) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // UnmarshalJSON unmarshals from JSON.
 | // UnmarshalJSON unmarshals from JSON.
 | ||||||
| func (p *PayloadAttributesV1) UnmarshalJSON(input []byte) error { | func (p *PayloadAttributes) UnmarshalJSON(input []byte) error { | ||||||
| 	type PayloadAttributesV1 struct { | 	type PayloadAttributes struct { | ||||||
| 		Timestamp             *hexutil.Uint64     `json:"timestamp"             gencodec:"required"` | 		Timestamp             *hexutil.Uint64     `json:"timestamp"             gencodec:"required"` | ||||||
| 		Random                *common.Hash        `json:"prevRandao"            gencodec:"required"` | 		Random                *common.Hash        `json:"prevRandao"            gencodec:"required"` | ||||||
| 		SuggestedFeeRecipient *common.Address     `json:"suggestedFeeRecipient" gencodec:"required"` | 		SuggestedFeeRecipient *common.Address     `json:"suggestedFeeRecipient" gencodec:"required"` | ||||||
|  | 		Withdrawals           []*types.Withdrawal `json:"withdrawals"` | ||||||
| 	} | 	} | ||||||
| 	var dec PayloadAttributesV1 | 	var dec PayloadAttributes | ||||||
| 	if err := json.Unmarshal(input, &dec); err != nil { | 	if err := json.Unmarshal(input, &dec); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	if dec.Timestamp == nil { | 	if dec.Timestamp == nil { | ||||||
| 		return errors.New("missing required field 'timestamp' for PayloadAttributesV1") | 		return errors.New("missing required field 'timestamp' for PayloadAttributes") | ||||||
| 	} | 	} | ||||||
| 	p.Timestamp = uint64(*dec.Timestamp) | 	p.Timestamp = uint64(*dec.Timestamp) | ||||||
| 	if dec.Random == nil { | 	if dec.Random == nil { | ||||||
| 		return errors.New("missing required field 'prevRandao' for PayloadAttributesV1") | 		return errors.New("missing required field 'prevRandao' for PayloadAttributes") | ||||||
| 	} | 	} | ||||||
| 	p.Random = *dec.Random | 	p.Random = *dec.Random | ||||||
| 	if dec.SuggestedFeeRecipient == nil { | 	if dec.SuggestedFeeRecipient == nil { | ||||||
| 		return errors.New("missing required field 'suggestedFeeRecipient' for PayloadAttributesV1") | 		return errors.New("missing required field 'suggestedFeeRecipient' for PayloadAttributes") | ||||||
| 	} | 	} | ||||||
| 	p.SuggestedFeeRecipient = *dec.SuggestedFeeRecipient | 	p.SuggestedFeeRecipient = *dec.SuggestedFeeRecipient | ||||||
|  | 	if dec.Withdrawals != nil { | ||||||
|  | 		p.Withdrawals = dec.Withdrawals | ||||||
|  | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,13 +9,14 @@ import ( | |||||||
| 
 | 
 | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/common/hexutil" | 	"github.com/ethereum/go-ethereum/common/hexutil" | ||||||
|  | 	"github.com/ethereum/go-ethereum/core/types" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var _ = (*executableDataMarshaling)(nil) | var _ = (*executableDataMarshaling)(nil) | ||||||
| 
 | 
 | ||||||
| // MarshalJSON marshals as JSON.
 | // MarshalJSON marshals as JSON.
 | ||||||
| func (e ExecutableDataV1) MarshalJSON() ([]byte, error) { | func (e ExecutableData) MarshalJSON() ([]byte, error) { | ||||||
| 	type ExecutableDataV1 struct { | 	type ExecutableData struct { | ||||||
| 		ParentHash    common.Hash         `json:"parentHash"    gencodec:"required"` | 		ParentHash    common.Hash         `json:"parentHash"    gencodec:"required"` | ||||||
| 		FeeRecipient  common.Address      `json:"feeRecipient"  gencodec:"required"` | 		FeeRecipient  common.Address      `json:"feeRecipient"  gencodec:"required"` | ||||||
| 		StateRoot     common.Hash         `json:"stateRoot"     gencodec:"required"` | 		StateRoot     common.Hash         `json:"stateRoot"     gencodec:"required"` | ||||||
| @ -30,8 +31,9 @@ func (e ExecutableDataV1) MarshalJSON() ([]byte, error) { | |||||||
| 		BaseFeePerGas *hexutil.Big        `json:"baseFeePerGas" gencodec:"required"` | 		BaseFeePerGas *hexutil.Big        `json:"baseFeePerGas" gencodec:"required"` | ||||||
| 		BlockHash     common.Hash         `json:"blockHash"     gencodec:"required"` | 		BlockHash     common.Hash         `json:"blockHash"     gencodec:"required"` | ||||||
| 		Transactions  []hexutil.Bytes     `json:"transactions"  gencodec:"required"` | 		Transactions  []hexutil.Bytes     `json:"transactions"  gencodec:"required"` | ||||||
|  | 		Withdrawals   []*types.Withdrawal `json:"withdrawals"` | ||||||
| 	} | 	} | ||||||
| 	var enc ExecutableDataV1 | 	var enc ExecutableData | ||||||
| 	enc.ParentHash = e.ParentHash | 	enc.ParentHash = e.ParentHash | ||||||
| 	enc.FeeRecipient = e.FeeRecipient | 	enc.FeeRecipient = e.FeeRecipient | ||||||
| 	enc.StateRoot = e.StateRoot | 	enc.StateRoot = e.StateRoot | ||||||
| @ -51,12 +53,13 @@ func (e ExecutableDataV1) MarshalJSON() ([]byte, error) { | |||||||
| 			enc.Transactions[k] = v | 			enc.Transactions[k] = v | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	enc.Withdrawals = e.Withdrawals | ||||||
| 	return json.Marshal(&enc) | 	return json.Marshal(&enc) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // UnmarshalJSON unmarshals from JSON.
 | // UnmarshalJSON unmarshals from JSON.
 | ||||||
| func (e *ExecutableDataV1) UnmarshalJSON(input []byte) error { | func (e *ExecutableData) UnmarshalJSON(input []byte) error { | ||||||
| 	type ExecutableDataV1 struct { | 	type ExecutableData struct { | ||||||
| 		ParentHash    *common.Hash        `json:"parentHash"    gencodec:"required"` | 		ParentHash    *common.Hash        `json:"parentHash"    gencodec:"required"` | ||||||
| 		FeeRecipient  *common.Address     `json:"feeRecipient"  gencodec:"required"` | 		FeeRecipient  *common.Address     `json:"feeRecipient"  gencodec:"required"` | ||||||
| 		StateRoot     *common.Hash        `json:"stateRoot"     gencodec:"required"` | 		StateRoot     *common.Hash        `json:"stateRoot"     gencodec:"required"` | ||||||
| @ -71,69 +74,73 @@ func (e *ExecutableDataV1) UnmarshalJSON(input []byte) error { | |||||||
| 		BaseFeePerGas *hexutil.Big        `json:"baseFeePerGas" gencodec:"required"` | 		BaseFeePerGas *hexutil.Big        `json:"baseFeePerGas" gencodec:"required"` | ||||||
| 		BlockHash     *common.Hash        `json:"blockHash"     gencodec:"required"` | 		BlockHash     *common.Hash        `json:"blockHash"     gencodec:"required"` | ||||||
| 		Transactions  []hexutil.Bytes     `json:"transactions"  gencodec:"required"` | 		Transactions  []hexutil.Bytes     `json:"transactions"  gencodec:"required"` | ||||||
|  | 		Withdrawals   []*types.Withdrawal `json:"withdrawals"` | ||||||
| 	} | 	} | ||||||
| 	var dec ExecutableDataV1 | 	var dec ExecutableData | ||||||
| 	if err := json.Unmarshal(input, &dec); err != nil { | 	if err := json.Unmarshal(input, &dec); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	if dec.ParentHash == nil { | 	if dec.ParentHash == nil { | ||||||
| 		return errors.New("missing required field 'parentHash' for ExecutableDataV1") | 		return errors.New("missing required field 'parentHash' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.ParentHash = *dec.ParentHash | 	e.ParentHash = *dec.ParentHash | ||||||
| 	if dec.FeeRecipient == nil { | 	if dec.FeeRecipient == nil { | ||||||
| 		return errors.New("missing required field 'feeRecipient' for ExecutableDataV1") | 		return errors.New("missing required field 'feeRecipient' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.FeeRecipient = *dec.FeeRecipient | 	e.FeeRecipient = *dec.FeeRecipient | ||||||
| 	if dec.StateRoot == nil { | 	if dec.StateRoot == nil { | ||||||
| 		return errors.New("missing required field 'stateRoot' for ExecutableDataV1") | 		return errors.New("missing required field 'stateRoot' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.StateRoot = *dec.StateRoot | 	e.StateRoot = *dec.StateRoot | ||||||
| 	if dec.ReceiptsRoot == nil { | 	if dec.ReceiptsRoot == nil { | ||||||
| 		return errors.New("missing required field 'receiptsRoot' for ExecutableDataV1") | 		return errors.New("missing required field 'receiptsRoot' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.ReceiptsRoot = *dec.ReceiptsRoot | 	e.ReceiptsRoot = *dec.ReceiptsRoot | ||||||
| 	if dec.LogsBloom == nil { | 	if dec.LogsBloom == nil { | ||||||
| 		return errors.New("missing required field 'logsBloom' for ExecutableDataV1") | 		return errors.New("missing required field 'logsBloom' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.LogsBloom = *dec.LogsBloom | 	e.LogsBloom = *dec.LogsBloom | ||||||
| 	if dec.Random == nil { | 	if dec.Random == nil { | ||||||
| 		return errors.New("missing required field 'prevRandao' for ExecutableDataV1") | 		return errors.New("missing required field 'prevRandao' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.Random = *dec.Random | 	e.Random = *dec.Random | ||||||
| 	if dec.Number == nil { | 	if dec.Number == nil { | ||||||
| 		return errors.New("missing required field 'blockNumber' for ExecutableDataV1") | 		return errors.New("missing required field 'blockNumber' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.Number = uint64(*dec.Number) | 	e.Number = uint64(*dec.Number) | ||||||
| 	if dec.GasLimit == nil { | 	if dec.GasLimit == nil { | ||||||
| 		return errors.New("missing required field 'gasLimit' for ExecutableDataV1") | 		return errors.New("missing required field 'gasLimit' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.GasLimit = uint64(*dec.GasLimit) | 	e.GasLimit = uint64(*dec.GasLimit) | ||||||
| 	if dec.GasUsed == nil { | 	if dec.GasUsed == nil { | ||||||
| 		return errors.New("missing required field 'gasUsed' for ExecutableDataV1") | 		return errors.New("missing required field 'gasUsed' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.GasUsed = uint64(*dec.GasUsed) | 	e.GasUsed = uint64(*dec.GasUsed) | ||||||
| 	if dec.Timestamp == nil { | 	if dec.Timestamp == nil { | ||||||
| 		return errors.New("missing required field 'timestamp' for ExecutableDataV1") | 		return errors.New("missing required field 'timestamp' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.Timestamp = uint64(*dec.Timestamp) | 	e.Timestamp = uint64(*dec.Timestamp) | ||||||
| 	if dec.ExtraData == nil { | 	if dec.ExtraData == nil { | ||||||
| 		return errors.New("missing required field 'extraData' for ExecutableDataV1") | 		return errors.New("missing required field 'extraData' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.ExtraData = *dec.ExtraData | 	e.ExtraData = *dec.ExtraData | ||||||
| 	if dec.BaseFeePerGas == nil { | 	if dec.BaseFeePerGas == nil { | ||||||
| 		return errors.New("missing required field 'baseFeePerGas' for ExecutableDataV1") | 		return errors.New("missing required field 'baseFeePerGas' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.BaseFeePerGas = (*big.Int)(dec.BaseFeePerGas) | 	e.BaseFeePerGas = (*big.Int)(dec.BaseFeePerGas) | ||||||
| 	if dec.BlockHash == nil { | 	if dec.BlockHash == nil { | ||||||
| 		return errors.New("missing required field 'blockHash' for ExecutableDataV1") | 		return errors.New("missing required field 'blockHash' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.BlockHash = *dec.BlockHash | 	e.BlockHash = *dec.BlockHash | ||||||
| 	if dec.Transactions == nil { | 	if dec.Transactions == nil { | ||||||
| 		return errors.New("missing required field 'transactions' for ExecutableDataV1") | 		return errors.New("missing required field 'transactions' for ExecutableData") | ||||||
| 	} | 	} | ||||||
| 	e.Transactions = make([][]byte, len(dec.Transactions)) | 	e.Transactions = make([][]byte, len(dec.Transactions)) | ||||||
| 	for k, v := range dec.Transactions { | 	for k, v := range dec.Transactions { | ||||||
| 		e.Transactions[k] = v | 		e.Transactions[k] = v | ||||||
| 	} | 	} | ||||||
|  | 	if dec.Withdrawals != nil { | ||||||
|  | 		e.Withdrawals = dec.Withdrawals | ||||||
|  | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										46
									
								
								core/beacon/gen_epe.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								core/beacon/gen_epe.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | // Code generated by github.com/fjl/gencodec. DO NOT EDIT.
 | ||||||
|  | 
 | ||||||
|  | package beacon | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
|  | 	"math/big" | ||||||
|  | 
 | ||||||
|  | 	"github.com/ethereum/go-ethereum/common/hexutil" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var _ = (*executionPayloadEnvelopeMarshaling)(nil) | ||||||
|  | 
 | ||||||
|  | // MarshalJSON marshals as JSON.
 | ||||||
|  | func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) { | ||||||
|  | 	type ExecutionPayloadEnvelope struct { | ||||||
|  | 		ExecutionPayload *ExecutableData `json:"executionPayload"  gencodec:"required"` | ||||||
|  | 		BlockValue       *hexutil.Big    `json:"blockValue"  gencodec:"required"` | ||||||
|  | 	} | ||||||
|  | 	var enc ExecutionPayloadEnvelope | ||||||
|  | 	enc.ExecutionPayload = e.ExecutionPayload | ||||||
|  | 	enc.BlockValue = (*hexutil.Big)(e.BlockValue) | ||||||
|  | 	return json.Marshal(&enc) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // UnmarshalJSON unmarshals from JSON.
 | ||||||
|  | func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error { | ||||||
|  | 	type ExecutionPayloadEnvelope struct { | ||||||
|  | 		ExecutionPayload *ExecutableData `json:"executionPayload"  gencodec:"required"` | ||||||
|  | 		BlockValue       *hexutil.Big    `json:"blockValue"  gencodec:"required"` | ||||||
|  | 	} | ||||||
|  | 	var dec ExecutionPayloadEnvelope | ||||||
|  | 	if err := json.Unmarshal(input, &dec); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if dec.ExecutionPayload == nil { | ||||||
|  | 		return errors.New("missing required field 'executionPayload' for ExecutionPayloadEnvelope") | ||||||
|  | 	} | ||||||
|  | 	e.ExecutionPayload = dec.ExecutionPayload | ||||||
|  | 	if dec.BlockValue == nil { | ||||||
|  | 		return errors.New("missing required field 'blockValue' for ExecutionPayloadEnvelope") | ||||||
|  | 	} | ||||||
|  | 	e.BlockValue = (*big.Int)(dec.BlockValue) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
| @ -26,24 +26,26 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/trie" | 	"github.com/ethereum/go-ethereum/trie" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| //go:generate go run github.com/fjl/gencodec -type PayloadAttributesV1 -field-override payloadAttributesMarshaling -out gen_blockparams.go
 | //go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
 | ||||||
| 
 | 
 | ||||||
| // PayloadAttributesV1 structure described at https://github.com/ethereum/execution-apis/pull/74
 | // PayloadAttributes describes the environment context in which a block should
 | ||||||
| type PayloadAttributesV1 struct { | // be built.
 | ||||||
|  | type PayloadAttributes struct { | ||||||
| 	Timestamp             uint64              `json:"timestamp"             gencodec:"required"` | 	Timestamp             uint64              `json:"timestamp"             gencodec:"required"` | ||||||
| 	Random                common.Hash         `json:"prevRandao"            gencodec:"required"` | 	Random                common.Hash         `json:"prevRandao"            gencodec:"required"` | ||||||
| 	SuggestedFeeRecipient common.Address      `json:"suggestedFeeRecipient" gencodec:"required"` | 	SuggestedFeeRecipient common.Address      `json:"suggestedFeeRecipient" gencodec:"required"` | ||||||
|  | 	Withdrawals           []*types.Withdrawal `json:"withdrawals"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // JSON type overrides for PayloadAttributesV1.
 | // JSON type overrides for PayloadAttributes.
 | ||||||
| type payloadAttributesMarshaling struct { | type payloadAttributesMarshaling struct { | ||||||
| 	Timestamp hexutil.Uint64 | 	Timestamp hexutil.Uint64 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //go:generate go run github.com/fjl/gencodec -type ExecutableDataV1 -field-override executableDataMarshaling -out gen_ed.go
 | //go:generate go run github.com/fjl/gencodec -type ExecutableData -field-override executableDataMarshaling -out gen_ed.go
 | ||||||
| 
 | 
 | ||||||
| // ExecutableDataV1 structure described at https://github.com/ethereum/execution-apis/tree/main/src/engine/specification.md
 | // ExecutableData is the data necessary to execute an EL payload.
 | ||||||
| type ExecutableDataV1 struct { | type ExecutableData struct { | ||||||
| 	ParentHash    common.Hash         `json:"parentHash"    gencodec:"required"` | 	ParentHash    common.Hash         `json:"parentHash"    gencodec:"required"` | ||||||
| 	FeeRecipient  common.Address      `json:"feeRecipient"  gencodec:"required"` | 	FeeRecipient  common.Address      `json:"feeRecipient"  gencodec:"required"` | ||||||
| 	StateRoot     common.Hash         `json:"stateRoot"     gencodec:"required"` | 	StateRoot     common.Hash         `json:"stateRoot"     gencodec:"required"` | ||||||
| @ -58,6 +60,7 @@ type ExecutableDataV1 struct { | |||||||
| 	BaseFeePerGas *big.Int            `json:"baseFeePerGas" gencodec:"required"` | 	BaseFeePerGas *big.Int            `json:"baseFeePerGas" gencodec:"required"` | ||||||
| 	BlockHash     common.Hash         `json:"blockHash"     gencodec:"required"` | 	BlockHash     common.Hash         `json:"blockHash"     gencodec:"required"` | ||||||
| 	Transactions  [][]byte            `json:"transactions"  gencodec:"required"` | 	Transactions  [][]byte            `json:"transactions"  gencodec:"required"` | ||||||
|  | 	Withdrawals   []*types.Withdrawal `json:"withdrawals"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // JSON type overrides for executableData.
 | // JSON type overrides for executableData.
 | ||||||
| @ -72,6 +75,18 @@ type executableDataMarshaling struct { | |||||||
| 	Transactions  []hexutil.Bytes | 	Transactions  []hexutil.Bytes | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | //go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go
 | ||||||
|  | 
 | ||||||
|  | type ExecutionPayloadEnvelope struct { | ||||||
|  | 	ExecutionPayload *ExecutableData `json:"executionPayload"  gencodec:"required"` | ||||||
|  | 	BlockValue       *big.Int        `json:"blockValue"  gencodec:"required"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // JSON type overrides for ExecutionPayloadEnvelope.
 | ||||||
|  | type executionPayloadEnvelopeMarshaling struct { | ||||||
|  | 	BlockValue *hexutil.Big | ||||||
|  | } | ||||||
|  | 
 | ||||||
| type PayloadStatusV1 struct { | type PayloadStatusV1 struct { | ||||||
| 	Status          string       `json:"status"` | 	Status          string       `json:"status"` | ||||||
| 	LatestValidHash *common.Hash `json:"latestValidHash"` | 	LatestValidHash *common.Hash `json:"latestValidHash"` | ||||||
| @ -141,8 +156,10 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) { | |||||||
| //	uncleHash = emptyUncleHash
 | //	uncleHash = emptyUncleHash
 | ||||||
| //	difficulty = 0
 | //	difficulty = 0
 | ||||||
| //
 | //
 | ||||||
| // and that the blockhash of the constructed block matches the parameters.
 | // and that the blockhash of the constructed block matches the parameters. Nil
 | ||||||
| func ExecutableDataToBlock(params ExecutableDataV1) (*types.Block, error) { | // Withdrawals value will propagate through the returned block. Empty
 | ||||||
|  | // Withdrawals value must be passed via non-nil, length 0 value in params.
 | ||||||
|  | func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) { | ||||||
| 	txs, err := decodeTransactions(params.Transactions) | 	txs, err := decodeTransactions(params.Transactions) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @ -157,6 +174,14 @@ func ExecutableDataToBlock(params ExecutableDataV1) (*types.Block, error) { | |||||||
| 	if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) { | 	if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) { | ||||||
| 		return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas) | 		return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas) | ||||||
| 	} | 	} | ||||||
|  | 	// Only set withdrawalsRoot if it is non-nil. This allows CLs to use
 | ||||||
|  | 	// ExecutableData before withdrawals are enabled by marshaling
 | ||||||
|  | 	// Withdrawals as the json null value.
 | ||||||
|  | 	var withdrawalsRoot *common.Hash | ||||||
|  | 	if params.Withdrawals != nil { | ||||||
|  | 		h := types.DeriveSha(types.Withdrawals(params.Withdrawals), trie.NewStackTrie(nil)) | ||||||
|  | 		withdrawalsRoot = &h | ||||||
|  | 	} | ||||||
| 	header := &types.Header{ | 	header := &types.Header{ | ||||||
| 		ParentHash:      params.ParentHash, | 		ParentHash:      params.ParentHash, | ||||||
| 		UncleHash:       types.EmptyUncleHash, | 		UncleHash:       types.EmptyUncleHash, | ||||||
| @ -173,18 +198,19 @@ func ExecutableDataToBlock(params ExecutableDataV1) (*types.Block, error) { | |||||||
| 		BaseFee:         params.BaseFeePerGas, | 		BaseFee:         params.BaseFeePerGas, | ||||||
| 		Extra:           params.ExtraData, | 		Extra:           params.ExtraData, | ||||||
| 		MixDigest:       params.Random, | 		MixDigest:       params.Random, | ||||||
|  | 		WithdrawalsHash: withdrawalsRoot, | ||||||
| 	} | 	} | ||||||
| 	block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */) | 	block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals) | ||||||
| 	if block.Hash() != params.BlockHash { | 	if block.Hash() != params.BlockHash { | ||||||
| 		return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash()) | 		return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash()) | ||||||
| 	} | 	} | ||||||
| 	return block, nil | 	return block, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // BlockToExecutableData constructs the executableDataV1 structure by filling the
 | // BlockToExecutableData constructs the ExecutableData structure by filling the
 | ||||||
| // fields from the given block. It assumes the given block is post-merge block.
 | // fields from the given block. It assumes the given block is post-merge block.
 | ||||||
| func BlockToExecutableData(block *types.Block) *ExecutableDataV1 { | func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutionPayloadEnvelope { | ||||||
| 	return &ExecutableDataV1{ | 	data := &ExecutableData{ | ||||||
| 		BlockHash:     block.Hash(), | 		BlockHash:     block.Hash(), | ||||||
| 		ParentHash:    block.ParentHash(), | 		ParentHash:    block.ParentHash(), | ||||||
| 		FeeRecipient:  block.Coinbase(), | 		FeeRecipient:  block.Coinbase(), | ||||||
| @ -199,5 +225,7 @@ func BlockToExecutableData(block *types.Block) *ExecutableDataV1 { | |||||||
| 		Transactions:  encodeTransactions(block.Transactions()), | 		Transactions:  encodeTransactions(block.Transactions()), | ||||||
| 		Random:        block.MixDigest(), | 		Random:        block.MixDigest(), | ||||||
| 		ExtraData:     block.Extra(), | 		ExtraData:     block.Extra(), | ||||||
|  | 		Withdrawals:   block.Withdrawals(), | ||||||
| 	} | 	} | ||||||
|  | 	return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees} | ||||||
| } | } | ||||||
|  | |||||||
| @ -65,6 +65,11 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { | |||||||
| 	if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash { | 	if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash { | ||||||
| 		return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash) | 		return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash) | ||||||
| 	} | 	} | ||||||
|  | 	if header.WithdrawalsHash != nil { | ||||||
|  | 		if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash { | ||||||
|  | 			return fmt.Errorf("withdrawals root hash mismatch: have %x, want %x", hash, *header.WithdrawalsHash) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { | 	if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { | ||||||
| 		if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { | 		if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { | ||||||
| 			return consensus.ErrUnknownAncestor | 			return consensus.ErrUnknownAncestor | ||||||
|  | |||||||
| @ -4229,7 +4229,7 @@ func TestEIP3651(t *testing.T) { | |||||||
| 	var ( | 	var ( | ||||||
| 		aa     = common.HexToAddress("0x000000000000000000000000000000000000aaaa") | 		aa     = common.HexToAddress("0x000000000000000000000000000000000000aaaa") | ||||||
| 		bb     = common.HexToAddress("0x000000000000000000000000000000000000bbbb") | 		bb     = common.HexToAddress("0x000000000000000000000000000000000000bbbb") | ||||||
| 		engine = ethash.NewFaker() | 		engine = beacon.NewFaker() | ||||||
| 
 | 
 | ||||||
| 		// A sender who makes transactions, has some funds
 | 		// A sender who makes transactions, has some funds
 | ||||||
| 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | ||||||
| @ -4237,8 +4237,9 @@ func TestEIP3651(t *testing.T) { | |||||||
| 		addr1   = crypto.PubkeyToAddress(key1.PublicKey) | 		addr1   = crypto.PubkeyToAddress(key1.PublicKey) | ||||||
| 		addr2   = crypto.PubkeyToAddress(key2.PublicKey) | 		addr2   = crypto.PubkeyToAddress(key2.PublicKey) | ||||||
| 		funds   = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) | 		funds   = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) | ||||||
|  | 		config  = *params.AllEthashProtocolChanges | ||||||
| 		gspec   = &Genesis{ | 		gspec   = &Genesis{ | ||||||
| 			Config: params.AllEthashProtocolChanges, | 			Config: &config, | ||||||
| 			Alloc: GenesisAlloc{ | 			Alloc: GenesisAlloc{ | ||||||
| 				addr1: {Balance: funds}, | 				addr1: {Balance: funds}, | ||||||
| 				addr2: {Balance: funds}, | 				addr2: {Balance: funds}, | ||||||
| @ -4275,6 +4276,8 @@ func TestEIP3651(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	gspec.Config.BerlinBlock = common.Big0 | 	gspec.Config.BerlinBlock = common.Big0 | ||||||
| 	gspec.Config.LondonBlock = common.Big0 | 	gspec.Config.LondonBlock = common.Big0 | ||||||
|  | 	gspec.Config.TerminalTotalDifficulty = common.Big0 | ||||||
|  | 	gspec.Config.TerminalTotalDifficultyPassed = true | ||||||
| 	gspec.Config.ShanghaiTime = u64(0) | 	gspec.Config.ShanghaiTime = u64(0) | ||||||
| 	signer := types.LatestSigner(gspec.Config) | 	signer := types.LatestSigner(gspec.Config) | ||||||
| 
 | 
 | ||||||
| @ -4317,10 +4320,7 @@ func TestEIP3651(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	// 3: Ensure that miner received only the tx's tip.
 | 	// 3: Ensure that miner received only the tx's tip.
 | ||||||
| 	actual := state.GetBalance(block.Coinbase()) | 	actual := state.GetBalance(block.Coinbase()) | ||||||
| 	expected := new(big.Int).Add( | 	expected := new(big.Int).SetUint64(block.GasUsed() * block.Transactions()[0].GasTipCap().Uint64()) | ||||||
| 		new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()), |  | ||||||
| 		ethash.ConstantinopleBlockReward, |  | ||||||
| 	) |  | ||||||
| 	if actual.Cmp(expected) != 0 { | 	if actual.Cmp(expected) != 0 { | ||||||
| 		t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual) | 		t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual) | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -45,6 +45,7 @@ type BlockGen struct { | |||||||
| 	txs         []*types.Transaction | 	txs         []*types.Transaction | ||||||
| 	receipts    []*types.Receipt | 	receipts    []*types.Receipt | ||||||
| 	uncles      []*types.Header | 	uncles      []*types.Header | ||||||
|  | 	withdrawals []*types.Withdrawal | ||||||
| 
 | 
 | ||||||
| 	config *params.ChainConfig | 	config *params.ChainConfig | ||||||
| 	engine consensus.Engine | 	engine consensus.Engine | ||||||
| @ -205,6 +206,26 @@ func (b *BlockGen) AddUncle(h *types.Header) { | |||||||
| 	b.uncles = append(b.uncles, h) | 	b.uncles = append(b.uncles, h) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // AddWithdrawal adds a withdrawal to the generated block.
 | ||||||
|  | func (b *BlockGen) AddWithdrawal(w *types.Withdrawal) { | ||||||
|  | 	// The withdrawal will be assigned the next valid index.
 | ||||||
|  | 	var idx uint64 | ||||||
|  | 	for i := b.i - 1; i >= 0; i-- { | ||||||
|  | 		if wd := b.chain[i].Withdrawals(); len(wd) != 0 { | ||||||
|  | 			idx = wd[len(wd)-1].Index + 1 | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		if i == 0 { | ||||||
|  | 			// Correctly set the index if no parent had withdrawals
 | ||||||
|  | 			if wd := b.parent.Withdrawals(); len(wd) != 0 { | ||||||
|  | 				idx = wd[len(wd)-1].Index + 1 | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	w.Index = idx | ||||||
|  | 	b.withdrawals = append(b.withdrawals, w) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // PrevBlock returns a previously generated block by number. It panics if
 | // PrevBlock returns a previously generated block by number. It panics if
 | ||||||
| // num is greater or equal to the number of the block being generated.
 | // num is greater or equal to the number of the block being generated.
 | ||||||
| // For index -1, PrevBlock returns the parent block given to GenerateChain.
 | // For index -1, PrevBlock returns the parent block given to GenerateChain.
 | ||||||
| @ -281,8 +302,10 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse | |||||||
| 			gen(i, b) | 			gen(i, b) | ||||||
| 		} | 		} | ||||||
| 		if b.engine != nil { | 		if b.engine != nil { | ||||||
| 			// Finalize and seal the block
 | 			block, err := b.engine.FinalizeAndAssemble(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts, b.withdrawals) | ||||||
| 			block, _ := b.engine.FinalizeAndAssemble(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts) | 			if err != nil { | ||||||
|  | 				panic(err) | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			// Write state changes to db
 | 			// Write state changes to db
 | ||||||
| 			root, err := statedb.Commit(config.IsEIP158(b.header.Number)) | 			root, err := statedb.Commit(config.IsEIP158(b.header.Number)) | ||||||
|  | |||||||
| @ -469,6 +469,9 @@ func (g *Genesis) ToBlock() *types.Block { | |||||||
| 			head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee) | 			head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if g.Config != nil && g.Config.IsShanghai(g.Timestamp) { | ||||||
|  | 		head.WithdrawalsHash = &types.EmptyRootHash | ||||||
|  | 	} | ||||||
| 	return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)) | 	return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -760,7 +760,7 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block { | |||||||
| 	if body == nil { | 	if body == nil { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) | 	return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles).WithWithdrawals(body.Withdrawals) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WriteBlock serializes a block into the database, header and body separately.
 | // WriteBlock serializes a block into the database, header and body separately.
 | ||||||
| @ -860,7 +860,7 @@ func ReadBadBlock(db ethdb.Reader, hash common.Hash) *types.Block { | |||||||
| 	} | 	} | ||||||
| 	for _, bad := range badBlocks { | 	for _, bad := range badBlocks { | ||||||
| 		if bad.Header.Hash() == hash { | 		if bad.Header.Hash() == hash { | ||||||
| 			return types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles) | 			return types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles).WithWithdrawals(bad.Body.Withdrawals) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| @ -879,7 +879,7 @@ func ReadAllBadBlocks(db ethdb.Reader) []*types.Block { | |||||||
| 	} | 	} | ||||||
| 	var blocks []*types.Block | 	var blocks []*types.Block | ||||||
| 	for _, bad := range badBlocks { | 	for _, bad := range badBlocks { | ||||||
| 		blocks = append(blocks, types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles)) | 		blocks = append(blocks, types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles).WithWithdrawals(bad.Body.Withdrawals)) | ||||||
| 	} | 	} | ||||||
| 	return blocks | 	return blocks | ||||||
| } | } | ||||||
|  | |||||||
| @ -86,8 +86,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg | |||||||
| 		receipts = append(receipts, receipt) | 		receipts = append(receipts, receipt) | ||||||
| 		allLogs = append(allLogs, receipt.Logs...) | 		allLogs = append(allLogs, receipt.Logs...) | ||||||
| 	} | 	} | ||||||
|  | 	// Fail if Shanghai not enabled and len(withdrawals) is non-zero.
 | ||||||
|  | 	withdrawals := block.Withdrawals() | ||||||
|  | 	if len(withdrawals) > 0 && !p.config.IsShanghai(block.Time()) { | ||||||
|  | 		return nil, nil, 0, fmt.Errorf("withdrawals before shanghai") | ||||||
|  | 	} | ||||||
| 	// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
 | 	// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
 | ||||||
| 	p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) | 	p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), withdrawals) | ||||||
| 
 | 
 | ||||||
| 	return receipts, allLogs, *usedGas, nil | 	return receipts, allLogs, *usedGas, nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/common/math" | 	"github.com/ethereum/go-ethereum/common/math" | ||||||
| 	"github.com/ethereum/go-ethereum/consensus" | 	"github.com/ethereum/go-ethereum/consensus" | ||||||
|  | 	"github.com/ethereum/go-ethereum/consensus/beacon" | ||||||
| 	"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/consensus/misc" | ||||||
| 	"github.com/ethereum/go-ethereum/core/rawdb" | 	"github.com/ethereum/go-ethereum/core/rawdb" | ||||||
| @ -329,6 +330,8 @@ func TestStateProcessorErrors(t *testing.T) { | |||||||
| 					ArrowGlacierBlock:             big.NewInt(0), | 					ArrowGlacierBlock:             big.NewInt(0), | ||||||
| 					GrayGlacierBlock:              big.NewInt(0), | 					GrayGlacierBlock:              big.NewInt(0), | ||||||
| 					MergeNetsplitBlock:            big.NewInt(0), | 					MergeNetsplitBlock:            big.NewInt(0), | ||||||
|  | 					TerminalTotalDifficulty:       big.NewInt(0), | ||||||
|  | 					TerminalTotalDifficultyPassed: true, | ||||||
| 					ShanghaiTime:                  u64(0), | 					ShanghaiTime:                  u64(0), | ||||||
| 				}, | 				}, | ||||||
| 				Alloc: GenesisAlloc{ | 				Alloc: GenesisAlloc{ | ||||||
| @ -339,7 +342,7 @@ func TestStateProcessorErrors(t *testing.T) { | |||||||
| 				}, | 				}, | ||||||
| 			} | 			} | ||||||
| 			genesis        = gspec.MustCommit(db) | 			genesis        = gspec.MustCommit(db) | ||||||
| 			blockchain, _  = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) | 			blockchain, _  = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) | ||||||
| 			tooBigInitCode = [params.MaxInitCodeSize + 1]byte{} | 			tooBigInitCode = [params.MaxInitCodeSize + 1]byte{} | ||||||
| 			smallInitCode  = [320]byte{} | 			smallInitCode  = [320]byte{} | ||||||
| 		) | 		) | ||||||
| @ -361,7 +364,7 @@ func TestStateProcessorErrors(t *testing.T) { | |||||||
| 				want: "could not apply tx 0 [0x39b7436cb432d3662a25626474282c5c4c1a213326fd87e4e18a91477bae98b2]: intrinsic gas too low: have 54299, want 54300", | 				want: "could not apply tx 0 [0x39b7436cb432d3662a25626474282c5c4c1a213326fd87e4e18a91477bae98b2]: intrinsic gas too low: have 54299, want 54300", | ||||||
| 			}, | 			}, | ||||||
| 		} { | 		} { | ||||||
| 			block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config) | 			block := GenerateBadBlock(genesis, beacon.New(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") | ||||||
| @ -378,15 +381,20 @@ func TestStateProcessorErrors(t *testing.T) { | |||||||
| // 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, config *params.ChainConfig) *types.Block { | func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Transactions, config *params.ChainConfig) *types.Block { | ||||||
| 	header := &types.Header{ | 	difficulty := big.NewInt(0) | ||||||
| 		ParentHash: parent.Hash(), | 	if !config.TerminalTotalDifficultyPassed { | ||||||
| 		Coinbase:   parent.Coinbase(), | 		difficulty = engine.CalcDifficulty(&fakeChainReader{config}, 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(), | ||||||
| 			UncleHash:  parent.UncleHash(), | 			UncleHash:  parent.UncleHash(), | ||||||
| 		}), | 		}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	header := &types.Header{ | ||||||
|  | 		ParentHash: parent.Hash(), | ||||||
|  | 		Coinbase:   parent.Coinbase(), | ||||||
|  | 		Difficulty: difficulty, | ||||||
| 		GasLimit:   parent.GasLimit(), | 		GasLimit:   parent.GasLimit(), | ||||||
| 		Number:     new(big.Int).Add(parent.Number(), common.Big1), | 		Number:     new(big.Int).Add(parent.Number(), common.Big1), | ||||||
| 		Time:       parent.Time() + 10, | 		Time:       parent.Time() + 10, | ||||||
| @ -395,6 +403,9 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr | |||||||
| 	if config.IsLondon(header.Number) { | 	if config.IsLondon(header.Number) { | ||||||
| 		header.BaseFee = misc.CalcBaseFee(config, parent.Header()) | 		header.BaseFee = misc.CalcBaseFee(config, parent.Header()) | ||||||
| 	} | 	} | ||||||
|  | 	if config.IsShanghai(header.Time) { | ||||||
|  | 		header.WithdrawalsHash = &types.EmptyRootHash | ||||||
|  | 	} | ||||||
| 	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
 | ||||||
|  | |||||||
| @ -87,6 +87,9 @@ type Header struct { | |||||||
| 	// BaseFee was added by EIP-1559 and is ignored in legacy headers.
 | 	// BaseFee was added by EIP-1559 and is ignored in legacy headers.
 | ||||||
| 	BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` | 	BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` | ||||||
| 
 | 
 | ||||||
|  | 	// WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers.
 | ||||||
|  | 	WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` | ||||||
|  | 
 | ||||||
| 	/* | 	/* | ||||||
| 		TODO (MariusVanDerWijden) Add this field once needed | 		TODO (MariusVanDerWijden) Add this field once needed | ||||||
| 		// Random was added during the merge and contains the BeaconState randomness
 | 		// Random was added during the merge and contains the BeaconState randomness
 | ||||||
| @ -149,9 +152,12 @@ func (h *Header) SanityCheck() error { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // EmptyBody returns true if there is no additional 'body' to complete the header
 | // EmptyBody returns true if there is no additional 'body' to complete the header
 | ||||||
| // that is: no transactions and no uncles.
 | // that is: no transactions, no uncles and no withdrawals.
 | ||||||
| func (h *Header) EmptyBody() bool { | func (h *Header) EmptyBody() bool { | ||||||
|  | 	if h.WithdrawalsHash == nil { | ||||||
| 		return h.TxHash == EmptyRootHash && h.UncleHash == EmptyUncleHash | 		return h.TxHash == EmptyRootHash && h.UncleHash == EmptyUncleHash | ||||||
|  | 	} | ||||||
|  | 	return h.TxHash == EmptyRootHash && h.UncleHash == EmptyUncleHash && *h.WithdrawalsHash == EmptyRootHash | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // EmptyReceipts returns true if there are no receipts for this header/block.
 | // EmptyReceipts returns true if there are no receipts for this header/block.
 | ||||||
| @ -164,6 +170,7 @@ func (h *Header) EmptyReceipts() bool { | |||||||
| type Body struct { | type Body struct { | ||||||
| 	Transactions []*Transaction | 	Transactions []*Transaction | ||||||
| 	Uncles       []*Header | 	Uncles       []*Header | ||||||
|  | 	Withdrawals  []*Withdrawal `rlp:"optional"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Block represents an entire block in the Ethereum blockchain.
 | // Block represents an entire block in the Ethereum blockchain.
 | ||||||
| @ -171,6 +178,7 @@ type Block struct { | |||||||
| 	header       *Header | 	header       *Header | ||||||
| 	uncles       []*Header | 	uncles       []*Header | ||||||
| 	transactions Transactions | 	transactions Transactions | ||||||
|  | 	withdrawals  Withdrawals | ||||||
| 
 | 
 | ||||||
| 	// caches
 | 	// caches
 | ||||||
| 	hash atomic.Value | 	hash atomic.Value | ||||||
| @ -187,6 +195,7 @@ type extblock struct { | |||||||
| 	Header      *Header | 	Header      *Header | ||||||
| 	Txs         []*Transaction | 	Txs         []*Transaction | ||||||
| 	Uncles      []*Header | 	Uncles      []*Header | ||||||
|  | 	Withdrawals []*Withdrawal `rlp:"optional"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewBlock creates a new block. The input data is copied,
 | // NewBlock creates a new block. The input data is copied,
 | ||||||
| @ -228,6 +237,28 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []* | |||||||
| 	return b | 	return b | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // NewBlockWithWithdrawals creates a new block with withdrawals. The input data
 | ||||||
|  | // is copied, changes to header and to the field values will not
 | ||||||
|  | // affect the block.
 | ||||||
|  | //
 | ||||||
|  | // The values of TxHash, UncleHash, ReceiptHash and Bloom in header
 | ||||||
|  | // are ignored and set to values derived from the given txs, uncles
 | ||||||
|  | // and receipts.
 | ||||||
|  | func NewBlockWithWithdrawals(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, withdrawals []*Withdrawal, hasher TrieHasher) *Block { | ||||||
|  | 	b := NewBlock(header, txs, uncles, receipts, hasher) | ||||||
|  | 
 | ||||||
|  | 	if withdrawals == nil { | ||||||
|  | 		b.header.WithdrawalsHash = nil | ||||||
|  | 	} else if len(withdrawals) == 0 { | ||||||
|  | 		b.header.WithdrawalsHash = &EmptyRootHash | ||||||
|  | 	} else { | ||||||
|  | 		h := DeriveSha(Withdrawals(withdrawals), hasher) | ||||||
|  | 		b.header.WithdrawalsHash = &h | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return b.WithWithdrawals(withdrawals) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // NewBlockWithHeader creates a block with the given header data. The
 | // NewBlockWithHeader creates a block with the given header data. The
 | ||||||
| // header data is copied, changes to header and to the field values
 | // header data is copied, changes to header and to the field values
 | ||||||
| // will not affect the block.
 | // will not affect the block.
 | ||||||
| @ -252,6 +283,9 @@ func CopyHeader(h *Header) *Header { | |||||||
| 		cpy.Extra = make([]byte, len(h.Extra)) | 		cpy.Extra = make([]byte, len(h.Extra)) | ||||||
| 		copy(cpy.Extra, h.Extra) | 		copy(cpy.Extra, h.Extra) | ||||||
| 	} | 	} | ||||||
|  | 	if h.WithdrawalsHash != nil { | ||||||
|  | 		*cpy.WithdrawalsHash = *h.WithdrawalsHash | ||||||
|  | 	} | ||||||
| 	return &cpy | 	return &cpy | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -262,7 +296,7 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error { | |||||||
| 	if err := s.Decode(&eb); err != nil { | 	if err := s.Decode(&eb); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	b.header, b.uncles, b.transactions = eb.Header, eb.Uncles, eb.Txs | 	b.header, b.uncles, b.transactions, b.withdrawals = eb.Header, eb.Uncles, eb.Txs, eb.Withdrawals | ||||||
| 	b.size.Store(rlp.ListSize(size)) | 	b.size.Store(rlp.ListSize(size)) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| @ -273,6 +307,7 @@ func (b *Block) EncodeRLP(w io.Writer) error { | |||||||
| 		Header:      b.header, | 		Header:      b.header, | ||||||
| 		Txs:         b.transactions, | 		Txs:         b.transactions, | ||||||
| 		Uncles:      b.uncles, | 		Uncles:      b.uncles, | ||||||
|  | 		Withdrawals: b.withdrawals, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -315,10 +350,14 @@ func (b *Block) BaseFee() *big.Int { | |||||||
| 	return new(big.Int).Set(b.header.BaseFee) | 	return new(big.Int).Set(b.header.BaseFee) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (b *Block) Withdrawals() Withdrawals { | ||||||
|  | 	return b.withdrawals | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 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.
 | ||||||
| func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles} } | func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles, b.withdrawals} } | ||||||
| 
 | 
 | ||||||
| // Size returns the true RLP encoded storage size of the block, either by encoding
 | // Size returns the true RLP encoded storage size of the block, either by encoding
 | ||||||
| // and returning it, or returning a previously cached value.
 | // and returning it, or returning a previously cached value.
 | ||||||
| @ -361,6 +400,7 @@ func (b *Block) WithSeal(header *Header) *Block { | |||||||
| 		header:       &cpy, | 		header:       &cpy, | ||||||
| 		transactions: b.transactions, | 		transactions: b.transactions, | ||||||
| 		uncles:       b.uncles, | 		uncles:       b.uncles, | ||||||
|  | 		withdrawals:  b.withdrawals, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -378,6 +418,15 @@ func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block { | |||||||
| 	return block | 	return block | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // WithWithdrawals sets the withdrawal contents of a block, does not return a new block.
 | ||||||
|  | func (b *Block) WithWithdrawals(withdrawals []*Withdrawal) *Block { | ||||||
|  | 	if withdrawals != nil { | ||||||
|  | 		b.withdrawals = make([]*Withdrawal, len(withdrawals)) | ||||||
|  | 		copy(b.withdrawals, withdrawals) | ||||||
|  | 	} | ||||||
|  | 	return b | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Hash returns the keccak256 hash of b's header.
 | // Hash returns the keccak256 hash of b's header.
 | ||||||
| // The hash is computed on the first call and cached thereafter.
 | // The hash is computed on the first call and cached thereafter.
 | ||||||
| func (b *Block) Hash() common.Hash { | func (b *Block) Hash() common.Hash { | ||||||
|  | |||||||
| @ -32,6 +32,7 @@ func (h Header) MarshalJSON() ([]byte, error) { | |||||||
| 		MixDigest       common.Hash    `json:"mixHash"` | 		MixDigest       common.Hash    `json:"mixHash"` | ||||||
| 		Nonce           BlockNonce     `json:"nonce"` | 		Nonce           BlockNonce     `json:"nonce"` | ||||||
| 		BaseFee         *hexutil.Big   `json:"baseFeePerGas" rlp:"optional"` | 		BaseFee         *hexutil.Big   `json:"baseFeePerGas" rlp:"optional"` | ||||||
|  | 		WithdrawalsHash *common.Hash   `json:"withdrawalsRoot" rlp:"optional"` | ||||||
| 		Hash            common.Hash    `json:"hash"` | 		Hash            common.Hash    `json:"hash"` | ||||||
| 	} | 	} | ||||||
| 	var enc Header | 	var enc Header | ||||||
| @ -51,6 +52,7 @@ func (h Header) MarshalJSON() ([]byte, error) { | |||||||
| 	enc.MixDigest = h.MixDigest | 	enc.MixDigest = h.MixDigest | ||||||
| 	enc.Nonce = h.Nonce | 	enc.Nonce = h.Nonce | ||||||
| 	enc.BaseFee = (*hexutil.Big)(h.BaseFee) | 	enc.BaseFee = (*hexutil.Big)(h.BaseFee) | ||||||
|  | 	enc.WithdrawalsHash = h.WithdrawalsHash | ||||||
| 	enc.Hash = h.Hash() | 	enc.Hash = h.Hash() | ||||||
| 	return json.Marshal(&enc) | 	return json.Marshal(&enc) | ||||||
| } | } | ||||||
| @ -74,6 +76,7 @@ func (h *Header) UnmarshalJSON(input []byte) error { | |||||||
| 		MixDigest       *common.Hash    `json:"mixHash"` | 		MixDigest       *common.Hash    `json:"mixHash"` | ||||||
| 		Nonce           *BlockNonce     `json:"nonce"` | 		Nonce           *BlockNonce     `json:"nonce"` | ||||||
| 		BaseFee         *hexutil.Big    `json:"baseFeePerGas" rlp:"optional"` | 		BaseFee         *hexutil.Big    `json:"baseFeePerGas" rlp:"optional"` | ||||||
|  | 		WithdrawalsHash *common.Hash    `json:"withdrawalsRoot" rlp:"optional"` | ||||||
| 	} | 	} | ||||||
| 	var dec Header | 	var dec Header | ||||||
| 	if err := json.Unmarshal(input, &dec); err != nil { | 	if err := json.Unmarshal(input, &dec); err != nil { | ||||||
| @ -139,5 +142,8 @@ func (h *Header) UnmarshalJSON(input []byte) error { | |||||||
| 	if dec.BaseFee != nil { | 	if dec.BaseFee != nil { | ||||||
| 		h.BaseFee = (*big.Int)(dec.BaseFee) | 		h.BaseFee = (*big.Int)(dec.BaseFee) | ||||||
| 	} | 	} | ||||||
|  | 	if dec.WithdrawalsHash != nil { | ||||||
|  | 		h.WithdrawalsHash = dec.WithdrawalsHash | ||||||
|  | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -41,7 +41,8 @@ func (obj *Header) EncodeRLP(_w io.Writer) error { | |||||||
| 	w.WriteBytes(obj.MixDigest[:]) | 	w.WriteBytes(obj.MixDigest[:]) | ||||||
| 	w.WriteBytes(obj.Nonce[:]) | 	w.WriteBytes(obj.Nonce[:]) | ||||||
| 	_tmp1 := obj.BaseFee != nil | 	_tmp1 := obj.BaseFee != nil | ||||||
| 	if _tmp1 { | 	_tmp2 := obj.WithdrawalsHash != nil | ||||||
|  | 	if _tmp1 || _tmp2 { | ||||||
| 		if obj.BaseFee == nil { | 		if obj.BaseFee == nil { | ||||||
| 			w.Write(rlp.EmptyString) | 			w.Write(rlp.EmptyString) | ||||||
| 		} else { | 		} else { | ||||||
| @ -51,6 +52,13 @@ func (obj *Header) EncodeRLP(_w io.Writer) error { | |||||||
| 			w.WriteBigInt(obj.BaseFee) | 			w.WriteBigInt(obj.BaseFee) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if _tmp2 { | ||||||
|  | 		if obj.WithdrawalsHash == nil { | ||||||
|  | 			w.Write([]byte{0x80}) | ||||||
|  | 		} else { | ||||||
|  | 			w.WriteBytes(obj.WithdrawalsHash[:]) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	w.ListEnd(_tmp0) | 	w.ListEnd(_tmp0) | ||||||
| 	return w.Flush() | 	return w.Flush() | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										55
									
								
								core/types/gen_withdrawal_json.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								core/types/gen_withdrawal_json.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | |||||||
|  | // Code generated by github.com/fjl/gencodec. DO NOT EDIT.
 | ||||||
|  | 
 | ||||||
|  | package types | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 
 | ||||||
|  | 	"github.com/ethereum/go-ethereum/common" | ||||||
|  | 	"github.com/ethereum/go-ethereum/common/hexutil" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var _ = (*withdrawalMarshaling)(nil) | ||||||
|  | 
 | ||||||
|  | // MarshalJSON marshals as JSON.
 | ||||||
|  | func (w Withdrawal) MarshalJSON() ([]byte, error) { | ||||||
|  | 	type Withdrawal struct { | ||||||
|  | 		Index     hexutil.Uint64 `json:"index"` | ||||||
|  | 		Validator hexutil.Uint64 `json:"validatorIndex"` | ||||||
|  | 		Address   common.Address `json:"address"` | ||||||
|  | 		Amount    hexutil.Uint64 `json:"amount"` | ||||||
|  | 	} | ||||||
|  | 	var enc Withdrawal | ||||||
|  | 	enc.Index = hexutil.Uint64(w.Index) | ||||||
|  | 	enc.Validator = hexutil.Uint64(w.Validator) | ||||||
|  | 	enc.Address = w.Address | ||||||
|  | 	enc.Amount = hexutil.Uint64(w.Amount) | ||||||
|  | 	return json.Marshal(&enc) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // UnmarshalJSON unmarshals from JSON.
 | ||||||
|  | func (w *Withdrawal) UnmarshalJSON(input []byte) error { | ||||||
|  | 	type Withdrawal struct { | ||||||
|  | 		Index     *hexutil.Uint64 `json:"index"` | ||||||
|  | 		Validator *hexutil.Uint64 `json:"validatorIndex"` | ||||||
|  | 		Address   *common.Address `json:"address"` | ||||||
|  | 		Amount    *hexutil.Uint64 `json:"amount"` | ||||||
|  | 	} | ||||||
|  | 	var dec Withdrawal | ||||||
|  | 	if err := json.Unmarshal(input, &dec); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if dec.Index != nil { | ||||||
|  | 		w.Index = uint64(*dec.Index) | ||||||
|  | 	} | ||||||
|  | 	if dec.Validator != nil { | ||||||
|  | 		w.Validator = uint64(*dec.Validator) | ||||||
|  | 	} | ||||||
|  | 	if dec.Address != nil { | ||||||
|  | 		w.Address = *dec.Address | ||||||
|  | 	} | ||||||
|  | 	if dec.Amount != nil { | ||||||
|  | 		w.Amount = uint64(*dec.Amount) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								core/types/gen_withdrawal_rlp.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								core/types/gen_withdrawal_rlp.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | // Code generated by rlpgen. DO NOT EDIT.
 | ||||||
|  | 
 | ||||||
|  | //go:build !norlpgen
 | ||||||
|  | // +build !norlpgen
 | ||||||
|  | 
 | ||||||
|  | package types | ||||||
|  | 
 | ||||||
|  | import "github.com/ethereum/go-ethereum/rlp" | ||||||
|  | import "io" | ||||||
|  | 
 | ||||||
|  | func (obj *Withdrawal) EncodeRLP(_w io.Writer) error { | ||||||
|  | 	w := rlp.NewEncoderBuffer(_w) | ||||||
|  | 	_tmp0 := w.List() | ||||||
|  | 	w.WriteUint64(obj.Index) | ||||||
|  | 	w.WriteUint64(obj.Validator) | ||||||
|  | 	w.WriteBytes(obj.Address[:]) | ||||||
|  | 	w.WriteUint64(obj.Amount) | ||||||
|  | 	w.ListEnd(_tmp0) | ||||||
|  | 	return w.Flush() | ||||||
|  | } | ||||||
							
								
								
									
										56
									
								
								core/types/withdrawal.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								core/types/withdrawal.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | // Copyright 2022 The go-ethereum Authors
 | ||||||
|  | // This file is part of the go-ethereum library.
 | ||||||
|  | //
 | ||||||
|  | // The go-ethereum library is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU Lesser General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | //
 | ||||||
|  | // The go-ethereum library is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||||
|  | // GNU Lesser General Public License for more details.
 | ||||||
|  | //
 | ||||||
|  | // You should have received a copy of the GNU Lesser General Public License
 | ||||||
|  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | package types | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 
 | ||||||
|  | 	"github.com/ethereum/go-ethereum/common" | ||||||
|  | 	"github.com/ethereum/go-ethereum/common/hexutil" | ||||||
|  | 	"github.com/ethereum/go-ethereum/rlp" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | //go:generate go run github.com/fjl/gencodec -type Withdrawal -field-override withdrawalMarshaling -out gen_withdrawal_json.go
 | ||||||
|  | //go:generate go run ../../rlp/rlpgen -type Withdrawal -out gen_withdrawal_rlp.go
 | ||||||
|  | 
 | ||||||
|  | // Withdrawal represents a validator withdrawal from the consensus layer.
 | ||||||
|  | type Withdrawal struct { | ||||||
|  | 	Index     uint64         `json:"index"`          // monotonically increasing identifier issued by consensus layer
 | ||||||
|  | 	Validator uint64         `json:"validatorIndex"` // index of validator associated with withdrawal
 | ||||||
|  | 	Address   common.Address `json:"address"`        // target address for withdrawn ether
 | ||||||
|  | 	Amount    uint64         `json:"amount"`         // value of withdrawal in Gwei
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // field type overrides for gencodec
 | ||||||
|  | type withdrawalMarshaling struct { | ||||||
|  | 	Index     hexutil.Uint64 | ||||||
|  | 	Validator hexutil.Uint64 | ||||||
|  | 	Amount    hexutil.Uint64 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Withdrawals implements DerivableList for withdrawals.
 | ||||||
|  | type Withdrawals []*Withdrawal | ||||||
|  | 
 | ||||||
|  | // Len returns the length of s.
 | ||||||
|  | func (s Withdrawals) Len() int { return len(s) } | ||||||
|  | 
 | ||||||
|  | // EncodeIndex encodes the i'th withdrawal to w. Note that this does not check for errors
 | ||||||
|  | // because we assume that *Withdrawal will only ever contain valid withdrawals that were either
 | ||||||
|  | // constructed by decoding or via public API in this package.
 | ||||||
|  | func (s Withdrawals) EncodeIndex(i int, w *bytes.Buffer) { | ||||||
|  | 	rlp.Encode(w, s[i]) | ||||||
|  | } | ||||||
| @ -119,7 +119,6 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { | |||||||
| 	// - prepare accessList(post-berlin)
 | 	// - prepare accessList(post-berlin)
 | ||||||
| 	// - reset transient storage(eip 1153)
 | 	// - reset transient storage(eip 1153)
 | ||||||
| 	cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil) | 	cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil) | ||||||
| 
 |  | ||||||
| 	cfg.State.CreateAccount(address) | 	cfg.State.CreateAccount(address) | ||||||
| 	// set the receiver's (the executing contract) code for execution.
 | 	// set the receiver's (the executing contract) code for execution.
 | ||||||
| 	cfg.State.SetCode(address, code) | 	cfg.State.SetCode(address, code) | ||||||
| @ -153,7 +152,6 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { | |||||||
| 	// - prepare accessList(post-berlin)
 | 	// - prepare accessList(post-berlin)
 | ||||||
| 	// - reset transient storage(eip 1153)
 | 	// - reset transient storage(eip 1153)
 | ||||||
| 	cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil) | 	cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil) | ||||||
| 
 |  | ||||||
| 	// Call the code with the given configuration.
 | 	// Call the code with the given configuration.
 | ||||||
| 	code, address, leftOverGas, err := vmenv.Create( | 	code, address, leftOverGas, err := vmenv.Create( | ||||||
| 		sender, | 		sender, | ||||||
|  | |||||||
| @ -155,7 +155,19 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { | |||||||
| //
 | //
 | ||||||
| // If there are payloadAttributes: we try to assemble a block with the payloadAttributes
 | // If there are payloadAttributes: we try to assemble a block with the payloadAttributes
 | ||||||
| // and return its payloadID.
 | // and return its payloadID.
 | ||||||
| func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributesV1) (beacon.ForkChoiceResponse, error) { | func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { | ||||||
|  | 	if payloadAttributes != nil && payloadAttributes.Withdrawals != nil { | ||||||
|  | 		return beacon.STATUS_INVALID, fmt.Errorf("withdrawals not supported in V1") | ||||||
|  | 	} | ||||||
|  | 	return api.forkchoiceUpdated(update, payloadAttributes) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload attributes.
 | ||||||
|  | func (api *ConsensusAPI) ForkchoiceUpdatedV2(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { | ||||||
|  | 	return api.forkchoiceUpdated(update, payloadAttributes) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { | ||||||
| 	api.forkchoiceLock.Lock() | 	api.forkchoiceLock.Lock() | ||||||
| 	defer api.forkchoiceLock.Unlock() | 	defer api.forkchoiceLock.Unlock() | ||||||
| 
 | 
 | ||||||
| @ -285,6 +297,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa | |||||||
| 			Timestamp:    payloadAttributes.Timestamp, | 			Timestamp:    payloadAttributes.Timestamp, | ||||||
| 			FeeRecipient: payloadAttributes.SuggestedFeeRecipient, | 			FeeRecipient: payloadAttributes.SuggestedFeeRecipient, | ||||||
| 			Random:       payloadAttributes.Random, | 			Random:       payloadAttributes.Random, | ||||||
|  | 			Withdrawals:  payloadAttributes.Withdrawals, | ||||||
| 		} | 		} | ||||||
| 		id := args.Id() | 		id := args.Id() | ||||||
| 		// If we already are busy generating this work, then we do not need
 | 		// If we already are busy generating this work, then we do not need
 | ||||||
| @ -334,7 +347,20 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.Transit | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // GetPayloadV1 returns a cached payload by id.
 | // GetPayloadV1 returns a cached payload by id.
 | ||||||
| func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableDataV1, error) { | func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableData, error) { | ||||||
|  | 	data, err := api.getPayload(payloadID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return data.ExecutionPayload, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetPayloadV2 returns a cached payload by id.
 | ||||||
|  | func (api *ConsensusAPI) GetPayloadV2(payloadID beacon.PayloadID) (*beacon.ExecutionPayloadEnvelope, error) { | ||||||
|  | 	return api.getPayload(payloadID) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (api *ConsensusAPI) getPayload(payloadID beacon.PayloadID) (*beacon.ExecutionPayloadEnvelope, error) { | ||||||
| 	log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID) | 	log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID) | ||||||
| 	data := api.localBlocks.get(payloadID) | 	data := api.localBlocks.get(payloadID) | ||||||
| 	if data == nil { | 	if data == nil { | ||||||
| @ -344,7 +370,19 @@ func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.Execu | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewPayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
 | // NewPayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
 | ||||||
| func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.PayloadStatusV1, error) { | func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) { | ||||||
|  | 	if params.Withdrawals != nil { | ||||||
|  | 		return beacon.PayloadStatusV1{Status: beacon.INVALID}, fmt.Errorf("withdrawals not supported in V1") | ||||||
|  | 	} | ||||||
|  | 	return api.newPayload(params) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
 | ||||||
|  | func (api *ConsensusAPI) NewPayloadV2(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) { | ||||||
|  | 	return api.newPayload(params) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (api *ConsensusAPI) newPayload(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) { | ||||||
| 	// The locking here is, strictly, not required. Without these locks, this can happen:
 | 	// The locking here is, strictly, not required. Without these locks, this can happen:
 | ||||||
| 	//
 | 	//
 | ||||||
| 	// 1. NewPayload( execdata-N ) is invoked from the CL. It goes all the way down to
 | 	// 1. NewPayload( execdata-N ) is invoked from the CL. It goes all the way down to
 | ||||||
| @ -361,7 +399,7 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa | |||||||
| 	api.newPayloadLock.Lock() | 	api.newPayloadLock.Lock() | ||||||
| 	defer api.newPayloadLock.Unlock() | 	defer api.newPayloadLock.Unlock() | ||||||
| 
 | 
 | ||||||
| 	log.Trace("Engine API request received", "method", "ExecutePayload", "number", params.Number, "hash", params.BlockHash) | 	log.Trace("Engine API request received", "method", "NewPayload", "number", params.Number, "hash", params.BlockHash) | ||||||
| 	block, err := beacon.ExecutableDataToBlock(params) | 	block, err := beacon.ExecutableDataToBlock(params) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Debug("Invalid NewPayload params", "params", params, "error", err) | 		log.Debug("Invalid NewPayload params", "params", params, "error", err) | ||||||
|  | |||||||
| @ -18,6 +18,7 @@ package catalyst | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
|  | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"math/big" | 	"math/big" | ||||||
| 	"sync" | 	"sync" | ||||||
| @ -26,6 +27,8 @@ import ( | |||||||
| 
 | 
 | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/common/hexutil" | 	"github.com/ethereum/go-ethereum/common/hexutil" | ||||||
|  | 	"github.com/ethereum/go-ethereum/consensus" | ||||||
|  | 	beaconConsensus "github.com/ethereum/go-ethereum/consensus/beacon" | ||||||
| 	"github.com/ethereum/go-ethereum/consensus/ethash" | 	"github.com/ethereum/go-ethereum/consensus/ethash" | ||||||
| 	"github.com/ethereum/go-ethereum/core" | 	"github.com/ethereum/go-ethereum/core" | ||||||
| 	"github.com/ethereum/go-ethereum/core/beacon" | 	"github.com/ethereum/go-ethereum/core/beacon" | ||||||
| @ -38,6 +41,7 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/node" | 	"github.com/ethereum/go-ethereum/node" | ||||||
| 	"github.com/ethereum/go-ethereum/p2p" | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
| 	"github.com/ethereum/go-ethereum/params" | 	"github.com/ethereum/go-ethereum/params" | ||||||
|  | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| 	"github.com/ethereum/go-ethereum/trie" | 	"github.com/ethereum/go-ethereum/trie" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -51,8 +55,14 @@ var ( | |||||||
| 	testBalance = big.NewInt(2e18) | 	testBalance = big.NewInt(2e18) | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) { | func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) { | ||||||
| 	config := *params.AllEthashProtocolChanges | 	config := *params.AllEthashProtocolChanges | ||||||
|  | 	engine := consensus.Engine(beaconConsensus.New(ethash.NewFaker())) | ||||||
|  | 	if merged { | ||||||
|  | 		config.TerminalTotalDifficulty = common.Big0 | ||||||
|  | 		config.TerminalTotalDifficultyPassed = true | ||||||
|  | 		engine = beaconConsensus.NewFaker() | ||||||
|  | 	} | ||||||
| 	genesis := &core.Genesis{ | 	genesis := &core.Genesis{ | ||||||
| 		Config:     &config, | 		Config:     &config, | ||||||
| 		Alloc:      core.GenesisAlloc{testAddr: {Balance: testBalance}}, | 		Alloc:      core.GenesisAlloc{testAddr: {Balance: testBalance}}, | ||||||
| @ -69,17 +79,21 @@ func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) { | |||||||
| 		g.AddTx(tx) | 		g.AddTx(tx) | ||||||
| 		testNonce++ | 		testNonce++ | ||||||
| 	} | 	} | ||||||
| 	_, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), n, generate) | 	_, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, n, generate) | ||||||
|  | 
 | ||||||
|  | 	if !merged { | ||||||
| 		totalDifficulty := big.NewInt(0) | 		totalDifficulty := big.NewInt(0) | ||||||
| 		for _, b := range blocks { | 		for _, b := range blocks { | ||||||
| 			totalDifficulty.Add(totalDifficulty, b.Difficulty()) | 			totalDifficulty.Add(totalDifficulty, b.Difficulty()) | ||||||
| 		} | 		} | ||||||
| 		config.TerminalTotalDifficulty = totalDifficulty | 		config.TerminalTotalDifficulty = totalDifficulty | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return genesis, blocks | 	return genesis, blocks | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestEth2AssembleBlock(t *testing.T) { | func TestEth2AssembleBlock(t *testing.T) { | ||||||
| 	genesis, blocks := generatePreMergeChain(10) | 	genesis, blocks := generateMergeChain(10, false) | ||||||
| 	n, ethservice := startEthService(t, genesis, blocks) | 	n, ethservice := startEthService(t, genesis, blocks) | ||||||
| 	defer n.Close() | 	defer n.Close() | ||||||
| 
 | 
 | ||||||
| @ -90,7 +104,7 @@ func TestEth2AssembleBlock(t *testing.T) { | |||||||
| 		t.Fatalf("error signing transaction, err=%v", err) | 		t.Fatalf("error signing transaction, err=%v", err) | ||||||
| 	} | 	} | ||||||
| 	ethservice.TxPool().AddLocal(tx) | 	ethservice.TxPool().AddLocal(tx) | ||||||
| 	blockParams := beacon.PayloadAttributesV1{ | 	blockParams := beacon.PayloadAttributes{ | ||||||
| 		Timestamp: blocks[9].Time() + 5, | 		Timestamp: blocks[9].Time() + 5, | ||||||
| 	} | 	} | ||||||
| 	// The miner needs to pick up on the txs in the pool, so a few retries might be
 | 	// The miner needs to pick up on the txs in the pool, so a few retries might be
 | ||||||
| @ -102,7 +116,7 @@ func TestEth2AssembleBlock(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| // assembleWithTransactions tries to assemble a block, retrying until it has 'want',
 | // assembleWithTransactions tries to assemble a block, retrying until it has 'want',
 | ||||||
| // number of transactions in it, or it has retried three times.
 | // number of transactions in it, or it has retried three times.
 | ||||||
| func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributesV1, want int) (execData *beacon.ExecutableDataV1, err error) { | func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributes, want int) (execData *beacon.ExecutableData, err error) { | ||||||
| 	for retries := 3; retries > 0; retries-- { | 	for retries := 3; retries > 0; retries-- { | ||||||
| 		execData, err = assembleBlock(api, parentHash, params) | 		execData, err = assembleBlock(api, parentHash, params) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @ -118,7 +132,7 @@ func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { | func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { | ||||||
| 	genesis, blocks := generatePreMergeChain(10) | 	genesis, blocks := generateMergeChain(10, false) | ||||||
| 	n, ethservice := startEthService(t, genesis, blocks[:9]) | 	n, ethservice := startEthService(t, genesis, blocks[:9]) | ||||||
| 	defer n.Close() | 	defer n.Close() | ||||||
| 
 | 
 | ||||||
| @ -126,7 +140,7 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	// Put the 10th block's tx in the pool and produce a new block
 | 	// Put the 10th block's tx in the pool and produce a new block
 | ||||||
| 	api.eth.TxPool().AddRemotesSync(blocks[9].Transactions()) | 	api.eth.TxPool().AddRemotesSync(blocks[9].Transactions()) | ||||||
| 	blockParams := beacon.PayloadAttributesV1{ | 	blockParams := beacon.PayloadAttributes{ | ||||||
| 		Timestamp: blocks[8].Time() + 5, | 		Timestamp: blocks[8].Time() + 5, | ||||||
| 	} | 	} | ||||||
| 	// The miner needs to pick up on the txs in the pool, so a few retries might be
 | 	// The miner needs to pick up on the txs in the pool, so a few retries might be
 | ||||||
| @ -137,7 +151,7 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestSetHeadBeforeTotalDifficulty(t *testing.T) { | func TestSetHeadBeforeTotalDifficulty(t *testing.T) { | ||||||
| 	genesis, blocks := generatePreMergeChain(10) | 	genesis, blocks := generateMergeChain(10, false) | ||||||
| 	n, ethservice := startEthService(t, genesis, blocks) | 	n, ethservice := startEthService(t, genesis, blocks) | ||||||
| 	defer n.Close() | 	defer n.Close() | ||||||
| 
 | 
 | ||||||
| @ -155,7 +169,7 @@ func TestSetHeadBeforeTotalDifficulty(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestEth2PrepareAndGetPayload(t *testing.T) { | func TestEth2PrepareAndGetPayload(t *testing.T) { | ||||||
| 	genesis, blocks := generatePreMergeChain(10) | 	genesis, blocks := generateMergeChain(10, false) | ||||||
| 	// We need to properly set the terminal total difficulty
 | 	// We need to properly set the terminal total difficulty
 | ||||||
| 	genesis.Config.TerminalTotalDifficulty.Sub(genesis.Config.TerminalTotalDifficulty, blocks[9].Difficulty()) | 	genesis.Config.TerminalTotalDifficulty.Sub(genesis.Config.TerminalTotalDifficulty, blocks[9].Difficulty()) | ||||||
| 	n, ethservice := startEthService(t, genesis, blocks[:9]) | 	n, ethservice := startEthService(t, genesis, blocks[:9]) | ||||||
| @ -165,7 +179,7 @@ func TestEth2PrepareAndGetPayload(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	// Put the 10th block's tx in the pool and produce a new block
 | 	// Put the 10th block's tx in the pool and produce a new block
 | ||||||
| 	ethservice.TxPool().AddLocals(blocks[9].Transactions()) | 	ethservice.TxPool().AddLocals(blocks[9].Transactions()) | ||||||
| 	blockParams := beacon.PayloadAttributesV1{ | 	blockParams := beacon.PayloadAttributes{ | ||||||
| 		Timestamp: blocks[8].Time() + 5, | 		Timestamp: blocks[8].Time() + 5, | ||||||
| 	} | 	} | ||||||
| 	fcState := beacon.ForkchoiceStateV1{ | 	fcState := beacon.ForkchoiceStateV1{ | ||||||
| @ -221,7 +235,7 @@ func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan co | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestInvalidPayloadTimestamp(t *testing.T) { | func TestInvalidPayloadTimestamp(t *testing.T) { | ||||||
| 	genesis, preMergeBlocks := generatePreMergeChain(10) | 	genesis, preMergeBlocks := generateMergeChain(10, false) | ||||||
| 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | ||||||
| 	defer n.Close() | 	defer n.Close() | ||||||
| 	var ( | 	var ( | ||||||
| @ -244,7 +258,7 @@ func TestInvalidPayloadTimestamp(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	for i, test := range tests { | 	for i, test := range tests { | ||||||
| 		t.Run(fmt.Sprintf("Timestamp test: %v", i), func(t *testing.T) { | 		t.Run(fmt.Sprintf("Timestamp test: %v", i), func(t *testing.T) { | ||||||
| 			params := beacon.PayloadAttributesV1{ | 			params := beacon.PayloadAttributes{ | ||||||
| 				Timestamp:             test.time, | 				Timestamp:             test.time, | ||||||
| 				Random:                crypto.Keccak256Hash([]byte{byte(123)}), | 				Random:                crypto.Keccak256Hash([]byte{byte(123)}), | ||||||
| 				SuggestedFeeRecipient: parent.Coinbase(), | 				SuggestedFeeRecipient: parent.Coinbase(), | ||||||
| @ -265,7 +279,7 @@ func TestInvalidPayloadTimestamp(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestEth2NewBlock(t *testing.T) { | func TestEth2NewBlock(t *testing.T) { | ||||||
| 	genesis, preMergeBlocks := generatePreMergeChain(10) | 	genesis, preMergeBlocks := generateMergeChain(10, false) | ||||||
| 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | ||||||
| 	defer n.Close() | 	defer n.Close() | ||||||
| 
 | 
 | ||||||
| @ -288,7 +302,7 @@ func TestEth2NewBlock(t *testing.T) { | |||||||
| 		tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) | 		tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) | ||||||
| 		ethservice.TxPool().AddLocal(tx) | 		ethservice.TxPool().AddLocal(tx) | ||||||
| 
 | 
 | ||||||
| 		execData, err := assembleWithTransactions(api, parent.Hash(), &beacon.PayloadAttributesV1{ | 		execData, err := assembleWithTransactions(api, parent.Hash(), &beacon.PayloadAttributes{ | ||||||
| 			Timestamp: parent.Time() + 5, | 			Timestamp: parent.Time() + 5, | ||||||
| 		}, 1) | 		}, 1) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @ -330,7 +344,7 @@ func TestEth2NewBlock(t *testing.T) { | |||||||
| 	) | 	) | ||||||
| 	parent = preMergeBlocks[len(preMergeBlocks)-1] | 	parent = preMergeBlocks[len(preMergeBlocks)-1] | ||||||
| 	for i := 0; i < 10; i++ { | 	for i := 0; i < 10; i++ { | ||||||
| 		execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{ | 		execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributes{ | ||||||
| 			Timestamp: parent.Time() + 6, | 			Timestamp: parent.Time() + 6, | ||||||
| 		}) | 		}) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @ -367,7 +381,7 @@ func TestEth2DeepReorg(t *testing.T) { | |||||||
| 	// TODO (MariusVanDerWijden) TestEth2DeepReorg is currently broken, because it tries to reorg
 | 	// TODO (MariusVanDerWijden) TestEth2DeepReorg is currently broken, because it tries to reorg
 | ||||||
| 	// before the totalTerminalDifficulty threshold
 | 	// before the totalTerminalDifficulty threshold
 | ||||||
| 	/* | 	/* | ||||||
| 		genesis, preMergeBlocks := generatePreMergeChain(core.TriesInMemory * 2) | 		genesis, preMergeBlocks := generateMergeChain(core.TriesInMemory * 2, false) | ||||||
| 		n, ethservice := startEthService(t, genesis, preMergeBlocks) | 		n, ethservice := startEthService(t, genesis, preMergeBlocks) | ||||||
| 		defer n.Close() | 		defer n.Close() | ||||||
| 
 | 
 | ||||||
| @ -442,7 +456,7 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestFullAPI(t *testing.T) { | func TestFullAPI(t *testing.T) { | ||||||
| 	genesis, preMergeBlocks := generatePreMergeChain(10) | 	genesis, preMergeBlocks := generateMergeChain(10, false) | ||||||
| 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | ||||||
| 	defer n.Close() | 	defer n.Close() | ||||||
| 	var ( | 	var ( | ||||||
| @ -494,7 +508,7 @@ func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Bl | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestExchangeTransitionConfig(t *testing.T) { | func TestExchangeTransitionConfig(t *testing.T) { | ||||||
| 	genesis, preMergeBlocks := generatePreMergeChain(10) | 	genesis, preMergeBlocks := generateMergeChain(10, false) | ||||||
| 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | ||||||
| 	defer n.Close() | 	defer n.Close() | ||||||
| 
 | 
 | ||||||
| @ -555,7 +569,7 @@ We expect | |||||||
| 	                └── P1'' | 	                └── P1'' | ||||||
| */ | */ | ||||||
| func TestNewPayloadOnInvalidChain(t *testing.T) { | func TestNewPayloadOnInvalidChain(t *testing.T) { | ||||||
| 	genesis, preMergeBlocks := generatePreMergeChain(10) | 	genesis, preMergeBlocks := generateMergeChain(10, false) | ||||||
| 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | ||||||
| 	defer n.Close() | 	defer n.Close() | ||||||
| 
 | 
 | ||||||
| @ -577,7 +591,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { | |||||||
| 		}) | 		}) | ||||||
| 		ethservice.TxPool().AddRemotesSync([]*types.Transaction{tx}) | 		ethservice.TxPool().AddRemotesSync([]*types.Transaction{tx}) | ||||||
| 		var ( | 		var ( | ||||||
| 			params = beacon.PayloadAttributesV1{ | 			params = beacon.PayloadAttributes{ | ||||||
| 				Timestamp:             parent.Time() + 1, | 				Timestamp:             parent.Time() + 1, | ||||||
| 				Random:                crypto.Keccak256Hash([]byte{byte(i)}), | 				Random:                crypto.Keccak256Hash([]byte{byte(i)}), | ||||||
| 				SuggestedFeeRecipient: parent.Coinbase(), | 				SuggestedFeeRecipient: parent.Coinbase(), | ||||||
| @ -587,7 +601,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { | |||||||
| 				SafeBlockHash:      common.Hash{}, | 				SafeBlockHash:      common.Hash{}, | ||||||
| 				FinalizedBlockHash: common.Hash{}, | 				FinalizedBlockHash: common.Hash{}, | ||||||
| 			} | 			} | ||||||
| 			payload *beacon.ExecutableDataV1 | 			payload *beacon.ExecutableData | ||||||
| 			resp    beacon.ForkChoiceResponse | 			resp    beacon.ForkChoiceResponse | ||||||
| 			err     error | 			err     error | ||||||
| 		) | 		) | ||||||
| @ -634,22 +648,23 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributesV1) (*beacon.ExecutableDataV1, error) { | func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributes) (*beacon.ExecutableData, error) { | ||||||
| 	args := &miner.BuildPayloadArgs{ | 	args := &miner.BuildPayloadArgs{ | ||||||
| 		Parent:       parentHash, | 		Parent:       parentHash, | ||||||
| 		Timestamp:    params.Timestamp, | 		Timestamp:    params.Timestamp, | ||||||
| 		FeeRecipient: params.SuggestedFeeRecipient, | 		FeeRecipient: params.SuggestedFeeRecipient, | ||||||
| 		Random:       params.Random, | 		Random:       params.Random, | ||||||
|  | 		Withdrawals:  params.Withdrawals, | ||||||
| 	} | 	} | ||||||
| 	payload, err := api.eth.Miner().BuildPayload(args) | 	payload, err := api.eth.Miner().BuildPayload(args) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	return payload.ResolveFull(), nil | 	return payload.ResolveFull().ExecutionPayload, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestEmptyBlocks(t *testing.T) { | func TestEmptyBlocks(t *testing.T) { | ||||||
| 	genesis, preMergeBlocks := generatePreMergeChain(10) | 	genesis, preMergeBlocks := generateMergeChain(10, false) | ||||||
| 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | ||||||
| 	defer n.Close() | 	defer n.Close() | ||||||
| 
 | 
 | ||||||
| @ -708,8 +723,8 @@ func TestEmptyBlocks(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon.ExecutableDataV1 { | func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon.ExecutableData { | ||||||
| 	params := beacon.PayloadAttributesV1{ | 	params := beacon.PayloadAttributes{ | ||||||
| 		Timestamp:             parent.Time() + 1, | 		Timestamp:             parent.Time() + 1, | ||||||
| 		Random:                crypto.Keccak256Hash([]byte{byte(1)}), | 		Random:                crypto.Keccak256Hash([]byte{byte(1)}), | ||||||
| 		SuggestedFeeRecipient: parent.Coinbase(), | 		SuggestedFeeRecipient: parent.Coinbase(), | ||||||
| @ -724,7 +739,7 @@ func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon | |||||||
| 
 | 
 | ||||||
| // setBlockhash sets the blockhash of a modified ExecutableData.
 | // setBlockhash sets the blockhash of a modified ExecutableData.
 | ||||||
| // Can be used to make modified payloads look valid.
 | // Can be used to make modified payloads look valid.
 | ||||||
| func setBlockhash(data *beacon.ExecutableDataV1) *beacon.ExecutableDataV1 { | func setBlockhash(data *beacon.ExecutableData) *beacon.ExecutableData { | ||||||
| 	txs, _ := decodeTransactions(data.Transactions) | 	txs, _ := decodeTransactions(data.Transactions) | ||||||
| 	number := big.NewInt(0) | 	number := big.NewInt(0) | ||||||
| 	number.SetUint64(data.Number) | 	number.SetUint64(data.Number) | ||||||
| @ -764,7 +779,7 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) { | |||||||
| 
 | 
 | ||||||
| func TestTrickRemoteBlockCache(t *testing.T) { | func TestTrickRemoteBlockCache(t *testing.T) { | ||||||
| 	// Setup two nodes
 | 	// Setup two nodes
 | ||||||
| 	genesis, preMergeBlocks := generatePreMergeChain(10) | 	genesis, preMergeBlocks := generateMergeChain(10, false) | ||||||
| 	nodeA, ethserviceA := startEthService(t, genesis, preMergeBlocks) | 	nodeA, ethserviceA := startEthService(t, genesis, preMergeBlocks) | ||||||
| 	nodeB, ethserviceB := startEthService(t, genesis, preMergeBlocks) | 	nodeB, ethserviceB := startEthService(t, genesis, preMergeBlocks) | ||||||
| 	defer nodeA.Close() | 	defer nodeA.Close() | ||||||
| @ -783,7 +798,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { | |||||||
| 	setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Block) {}) | 	setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Block) {}) | ||||||
| 	commonAncestor = ethserviceA.BlockChain().CurrentBlock() | 	commonAncestor = ethserviceA.BlockChain().CurrentBlock() | ||||||
| 
 | 
 | ||||||
| 	var invalidChain []*beacon.ExecutableDataV1 | 	var invalidChain []*beacon.ExecutableData | ||||||
| 	// create a valid payload (P1)
 | 	// create a valid payload (P1)
 | ||||||
| 	//payload1 := getNewPayload(t, apiA, commonAncestor)
 | 	//payload1 := getNewPayload(t, apiA, commonAncestor)
 | ||||||
| 	//invalidChain = append(invalidChain, payload1)
 | 	//invalidChain = append(invalidChain, payload1)
 | ||||||
| @ -827,7 +842,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestInvalidBloom(t *testing.T) { | func TestInvalidBloom(t *testing.T) { | ||||||
| 	genesis, preMergeBlocks := generatePreMergeChain(10) | 	genesis, preMergeBlocks := generateMergeChain(10, false) | ||||||
| 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | ||||||
| 	ethservice.Merger().ReachTTD() | 	ethservice.Merger().ReachTTD() | ||||||
| 	defer n.Close() | 	defer n.Close() | ||||||
| @ -851,12 +866,12 @@ func TestInvalidBloom(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { | func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { | ||||||
| 	genesis, preMergeBlocks := generatePreMergeChain(100) | 	genesis, preMergeBlocks := generateMergeChain(100, false) | ||||||
| 
 |  | ||||||
| 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | ||||||
| 	defer n.Close() | 	defer n.Close() | ||||||
| 
 | 
 | ||||||
| 	genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty())
 | 	genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty())
 | ||||||
|  | 
 | ||||||
| 	var ( | 	var ( | ||||||
| 		api    = NewConsensusAPI(ethservice) | 		api    = NewConsensusAPI(ethservice) | ||||||
| 		parent = preMergeBlocks[len(preMergeBlocks)-1] | 		parent = preMergeBlocks[len(preMergeBlocks)-1] | ||||||
| @ -887,7 +902,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("error preparing payload, err=%v", err) | 		t.Fatalf("error preparing payload, err=%v", err) | ||||||
| 	} | 	} | ||||||
| 	data := *payload.Resolve() | 	data := *payload.Resolve().ExecutionPayload | ||||||
| 	resp2, err := api.NewPayloadV1(data) | 	resp2, err := api.NewPayloadV1(data) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("error sending NewPayload, err=%v", err) | 		t.Fatalf("error sending NewPayload, err=%v", err) | ||||||
| @ -901,7 +916,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { | |||||||
| // newPayLoad and forkchoiceUpdate. This is to test that the api behaves
 | // newPayLoad and forkchoiceUpdate. This is to test that the api behaves
 | ||||||
| // well even of the caller is not being 'serial'.
 | // well even of the caller is not being 'serial'.
 | ||||||
| func TestSimultaneousNewBlock(t *testing.T) { | func TestSimultaneousNewBlock(t *testing.T) { | ||||||
| 	genesis, preMergeBlocks := generatePreMergeChain(10) | 	genesis, preMergeBlocks := generateMergeChain(10, false) | ||||||
| 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | 	n, ethservice := startEthService(t, genesis, preMergeBlocks) | ||||||
| 	defer n.Close() | 	defer n.Close() | ||||||
| 
 | 
 | ||||||
| @ -910,7 +925,7 @@ func TestSimultaneousNewBlock(t *testing.T) { | |||||||
| 		parent = preMergeBlocks[len(preMergeBlocks)-1] | 		parent = preMergeBlocks[len(preMergeBlocks)-1] | ||||||
| 	) | 	) | ||||||
| 	for i := 0; i < 10; i++ { | 	for i := 0; i < 10; i++ { | ||||||
| 		execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{ | 		execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributes{ | ||||||
| 			Timestamp: parent.Time() + 5, | 			Timestamp: parent.Time() + 5, | ||||||
| 		}) | 		}) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @ -984,3 +999,117 @@ func TestSimultaneousNewBlock(t *testing.T) { | |||||||
| 		parent = block | 		parent = block | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // TestWithdrawals creates and verifies two post-Shanghai blocks. The first
 | ||||||
|  | // includes zero withdrawals and the second includes two.
 | ||||||
|  | func TestWithdrawals(t *testing.T) { | ||||||
|  | 	genesis, blocks := generateMergeChain(10, true) | ||||||
|  | 	// Set shanghai time to last block + 5 seconds (first post-merge block)
 | ||||||
|  | 	time := blocks[len(blocks)-1].Time() + 5 | ||||||
|  | 	genesis.Config.ShanghaiTime = &time | ||||||
|  | 
 | ||||||
|  | 	n, ethservice := startEthService(t, genesis, blocks) | ||||||
|  | 	ethservice.Merger().ReachTTD() | ||||||
|  | 	defer n.Close() | ||||||
|  | 
 | ||||||
|  | 	api := NewConsensusAPI(ethservice) | ||||||
|  | 
 | ||||||
|  | 	// 10: Build Shanghai block with no withdrawals.
 | ||||||
|  | 	parent := ethservice.BlockChain().CurrentHeader() | ||||||
|  | 	blockParams := beacon.PayloadAttributes{ | ||||||
|  | 		Timestamp:   parent.Time + 5, | ||||||
|  | 		Withdrawals: make([]*types.Withdrawal, 0), | ||||||
|  | 	} | ||||||
|  | 	fcState := beacon.ForkchoiceStateV1{ | ||||||
|  | 		HeadBlockHash: parent.Hash(), | ||||||
|  | 	} | ||||||
|  | 	resp, err := api.ForkchoiceUpdatedV2(fcState, &blockParams) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("error preparing payload, err=%v", err) | ||||||
|  | 	} | ||||||
|  | 	if resp.PayloadStatus.Status != beacon.VALID { | ||||||
|  | 		t.Fatalf("unexpected status (got: %s, want: %s)", resp.PayloadStatus.Status, beacon.VALID) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// 10: verify state root is the same as parent
 | ||||||
|  | 	payloadID := (&miner.BuildPayloadArgs{ | ||||||
|  | 		Parent:       fcState.HeadBlockHash, | ||||||
|  | 		Timestamp:    blockParams.Timestamp, | ||||||
|  | 		FeeRecipient: blockParams.SuggestedFeeRecipient, | ||||||
|  | 		Random:       blockParams.Random, | ||||||
|  | 	}).Id() | ||||||
|  | 	execData, err := api.GetPayloadV2(payloadID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("error getting payload, err=%v", err) | ||||||
|  | 	} | ||||||
|  | 	if execData.ExecutionPayload.StateRoot != parent.Root { | ||||||
|  | 		t.Fatalf("mismatch state roots (got: %s, want: %s)", execData.ExecutionPayload.StateRoot, blocks[8].Root()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// 10: verify locally built block
 | ||||||
|  | 	if status, err := api.NewPayloadV2(*execData.ExecutionPayload); err != nil { | ||||||
|  | 		t.Fatalf("error validating payload: %v", err) | ||||||
|  | 	} else if status.Status != beacon.VALID { | ||||||
|  | 		t.Fatalf("invalid payload") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// 11: build shanghai block with withdrawal
 | ||||||
|  | 	aa := common.Address{0xaa} | ||||||
|  | 	bb := common.Address{0xbb} | ||||||
|  | 	blockParams = beacon.PayloadAttributes{ | ||||||
|  | 		Timestamp: execData.ExecutionPayload.Timestamp + 5, | ||||||
|  | 		Withdrawals: []*types.Withdrawal{ | ||||||
|  | 			{ | ||||||
|  | 				Index:   0, | ||||||
|  | 				Address: aa, | ||||||
|  | 				Amount:  32, | ||||||
|  | 			}, | ||||||
|  | 			{ | ||||||
|  | 				Index:   1, | ||||||
|  | 				Address: bb, | ||||||
|  | 				Amount:  33, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	fcState.HeadBlockHash = execData.ExecutionPayload.BlockHash | ||||||
|  | 	_, err = api.ForkchoiceUpdatedV2(fcState, &blockParams) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("error preparing payload, err=%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// 11: verify locally build block.
 | ||||||
|  | 	payloadID = (&miner.BuildPayloadArgs{ | ||||||
|  | 		Parent:       fcState.HeadBlockHash, | ||||||
|  | 		Timestamp:    blockParams.Timestamp, | ||||||
|  | 		FeeRecipient: blockParams.SuggestedFeeRecipient, | ||||||
|  | 		Random:       blockParams.Random, | ||||||
|  | 	}).Id() | ||||||
|  | 	execData, err = api.GetPayloadV2(payloadID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("error getting payload, err=%v", err) | ||||||
|  | 	} | ||||||
|  | 	if status, err := api.NewPayloadV2(*execData.ExecutionPayload); err != nil { | ||||||
|  | 		t.Fatalf("error validating payload: %v", err) | ||||||
|  | 	} else if status.Status != beacon.VALID { | ||||||
|  | 		t.Fatalf("invalid payload") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// 11: set block as head.
 | ||||||
|  | 	fcState.HeadBlockHash = execData.ExecutionPayload.BlockHash | ||||||
|  | 	_, err = api.ForkchoiceUpdatedV2(fcState, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("error preparing payload, err=%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// 11: verify withdrawals were processed.
 | ||||||
|  | 	db, _, err := ethservice.APIBackend.StateAndHeaderByNumber(context.Background(), rpc.BlockNumber(execData.ExecutionPayload.Number)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("unable to load db: %v", err) | ||||||
|  | 	} | ||||||
|  | 	for i, w := range blockParams.Withdrawals { | ||||||
|  | 		// w.Amount is in gwei, balance in wei
 | ||||||
|  | 		if db.GetBalance(w.Address).Uint64() != w.Amount*params.GWei { | ||||||
|  | 			t.Fatalf("failed to process withdrawal %d", i) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | |||||||
| @ -70,7 +70,7 @@ func (q *payloadQueue) put(id beacon.PayloadID, payload *miner.Payload) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // get retrieves a previously stored payload item or nil if it does not exist.
 | // get retrieves a previously stored payload item or nil if it does not exist.
 | ||||||
| func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutableDataV1 { | func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutionPayloadEnvelope { | ||||||
| 	q.lock.RLock() | 	q.lock.RLock() | ||||||
| 	defer q.lock.RUnlock() | 	defer q.lock.RUnlock() | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1548,7 +1548,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error { | |||||||
| 	) | 	) | ||||||
| 	blocks := make([]*types.Block, len(results)) | 	blocks := make([]*types.Block, len(results)) | ||||||
| 	for i, result := range results { | 	for i, result := range results { | ||||||
| 		blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) | 		blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals) | ||||||
| 	} | 	} | ||||||
| 	// Downloaded blocks are always regarded as trusted after the
 | 	// Downloaded blocks are always regarded as trusted after the
 | ||||||
| 	// transition. Because the downloaded chain is guided by the
 | 	// transition. Because the downloaded chain is guided by the
 | ||||||
| @ -1748,7 +1748,7 @@ func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *state | |||||||
| 	blocks := make([]*types.Block, len(results)) | 	blocks := make([]*types.Block, len(results)) | ||||||
| 	receipts := make([]types.Receipts, len(results)) | 	receipts := make([]types.Receipts, len(results)) | ||||||
| 	for i, result := range results { | 	for i, result := range results { | ||||||
| 		blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) | 		blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals) | ||||||
| 		receipts[i] = result.Receipts | 		receipts[i] = result.Receipts | ||||||
| 	} | 	} | ||||||
| 	if index, err := d.blockchain.InsertReceiptChain(blocks, receipts, d.ancientLimit); err != nil { | 	if index, err := d.blockchain.InsertReceiptChain(blocks, receipts, d.ancientLimit); err != nil { | ||||||
| @ -1759,7 +1759,7 @@ func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *state | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (d *Downloader) commitPivotBlock(result *fetchResult) error { | func (d *Downloader) commitPivotBlock(result *fetchResult) error { | ||||||
| 	block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) | 	block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals) | ||||||
| 	log.Debug("Committing snap sync pivot as new head", "number", block.Number(), "hash", block.Hash()) | 	log.Debug("Committing snap sync pivot as new head", "number", block.Number(), "hash", block.Hash()) | ||||||
| 
 | 
 | ||||||
| 	// Commit the pivot block as the new head, will require full sync from here on
 | 	// Commit the pivot block as the new head, will require full sync from here on
 | ||||||
|  | |||||||
| @ -275,6 +275,7 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et | |||||||
| 	var ( | 	var ( | ||||||
| 		txsHashes        = make([]common.Hash, len(bodies)) | 		txsHashes        = make([]common.Hash, len(bodies)) | ||||||
| 		uncleHashes      = make([]common.Hash, len(bodies)) | 		uncleHashes      = make([]common.Hash, len(bodies)) | ||||||
|  | 		withdrawalHashes = make([]common.Hash, len(bodies)) | ||||||
| 	) | 	) | ||||||
| 	hasher := trie.NewStackTrie(nil) | 	hasher := trie.NewStackTrie(nil) | ||||||
| 	for i, body := range bodies { | 	for i, body := range bodies { | ||||||
| @ -287,7 +288,7 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et | |||||||
| 	res := ð.Response{ | 	res := ð.Response{ | ||||||
| 		Req:  req, | 		Req:  req, | ||||||
| 		Res:  (*eth.BlockBodiesPacket)(&bodies), | 		Res:  (*eth.BlockBodiesPacket)(&bodies), | ||||||
| 		Meta: [][]common.Hash{txsHashes, uncleHashes}, | 		Meta: [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes}, | ||||||
| 		Time: 1, | 		Time: 1, | ||||||
| 		Done: make(chan error, 1), // Ignore the returned status
 | 		Done: make(chan error, 1), // Ignore the returned status
 | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -89,10 +89,10 @@ func (q *bodyQueue) request(peer *peerConnection, req *fetchRequest, resCh chan | |||||||
| // deliver is responsible for taking a generic response packet from the concurrent
 | // deliver is responsible for taking a generic response packet from the concurrent
 | ||||||
| // fetcher, unpacking the body data and delivering it to the downloader's queue.
 | // fetcher, unpacking the body data and delivering it to the downloader's queue.
 | ||||||
| func (q *bodyQueue) deliver(peer *peerConnection, packet *eth.Response) (int, error) { | func (q *bodyQueue) deliver(peer *peerConnection, packet *eth.Response) (int, error) { | ||||||
| 	txs, uncles := packet.Res.(*eth.BlockBodiesPacket).Unpack() | 	txs, uncles, withdrawals := packet.Res.(*eth.BlockBodiesPacket).Unpack() | ||||||
| 	hashsets := packet.Meta.([][]common.Hash) // {txs hashes, uncle hashes}
 | 	hashsets := packet.Meta.([][]common.Hash) // {txs hashes, uncle hashes, withdrawal hashes}
 | ||||||
| 
 | 
 | ||||||
| 	accepted, err := q.queue.DeliverBodies(peer.id, txs, hashsets[0], uncles, hashsets[1]) | 	accepted, err := q.queue.DeliverBodies(peer.id, txs, hashsets[0], uncles, hashsets[1], withdrawals, hashsets[2]) | ||||||
| 	switch { | 	switch { | ||||||
| 	case err == nil && len(txs) == 0: | 	case err == nil && len(txs) == 0: | ||||||
| 		peer.log.Trace("Requested bodies delivered") | 		peer.log.Trace("Requested bodies delivered") | ||||||
|  | |||||||
| @ -67,6 +67,7 @@ type fetchResult struct { | |||||||
| 	Uncles       []*types.Header | 	Uncles       []*types.Header | ||||||
| 	Transactions types.Transactions | 	Transactions types.Transactions | ||||||
| 	Receipts     types.Receipts | 	Receipts     types.Receipts | ||||||
|  | 	Withdrawals  types.Withdrawals | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func newFetchResult(header *types.Header, fastSync bool) *fetchResult { | func newFetchResult(header *types.Header, fastSync bool) *fetchResult { | ||||||
| @ -764,7 +765,9 @@ func (q *queue) DeliverHeaders(id string, headers []*types.Header, hashes []comm | |||||||
| // DeliverBodies injects a block body retrieval response into the results queue.
 | // DeliverBodies injects a block body retrieval response into the results queue.
 | ||||||
| // The method returns the number of blocks bodies accepted from the delivery and
 | // The method returns the number of blocks bodies accepted from the delivery and
 | ||||||
| // also wakes any threads waiting for data delivery.
 | // also wakes any threads waiting for data delivery.
 | ||||||
| func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListHashes []common.Hash, uncleLists [][]*types.Header, uncleListHashes []common.Hash) (int, error) { | func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListHashes []common.Hash, | ||||||
|  | 	uncleLists [][]*types.Header, uncleListHashes []common.Hash, | ||||||
|  | 	withdrawalLists [][]*types.Withdrawal, withdrawalListHashes []common.Hash) (int, error) { | ||||||
| 	q.lock.Lock() | 	q.lock.Lock() | ||||||
| 	defer q.lock.Unlock() | 	defer q.lock.Unlock() | ||||||
| 
 | 
 | ||||||
| @ -775,12 +778,19 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH | |||||||
| 		if uncleListHashes[index] != header.UncleHash { | 		if uncleListHashes[index] != header.UncleHash { | ||||||
| 			return errInvalidBody | 			return errInvalidBody | ||||||
| 		} | 		} | ||||||
|  | 		if header.WithdrawalsHash == nil { | ||||||
|  | 			// discard any withdrawals if we don't have a withdrawal hash set
 | ||||||
|  | 			withdrawalLists[index] = nil | ||||||
|  | 		} else if withdrawalListHashes[index] != *header.WithdrawalsHash { | ||||||
|  | 			return errInvalidBody | ||||||
|  | 		} | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	reconstruct := func(index int, result *fetchResult) { | 	reconstruct := func(index int, result *fetchResult) { | ||||||
| 		result.Transactions = txLists[index] | 		result.Transactions = txLists[index] | ||||||
| 		result.Uncles = uncleLists[index] | 		result.Uncles = uncleLists[index] | ||||||
|  | 		result.Withdrawals = withdrawalLists[index] | ||||||
| 		result.SetBodyDone() | 		result.SetBodyDone() | ||||||
| 	} | 	} | ||||||
| 	return q.deliver(id, q.blockTaskPool, q.blockTaskQueue, q.blockPendPool, | 	return q.deliver(id, q.blockTaskPool, q.blockTaskQueue, q.blockPendPool, | ||||||
|  | |||||||
| @ -339,7 +339,7 @@ func XTestDelivery(t *testing.T) { | |||||||
| 					uncleHashes[i] = types.CalcUncleHash(uncles) | 					uncleHashes[i] = types.CalcUncleHash(uncles) | ||||||
| 				} | 				} | ||||||
| 				time.Sleep(100 * time.Millisecond) | 				time.Sleep(100 * time.Millisecond) | ||||||
| 				_, err := q.DeliverBodies(peer.id, txset, txsHashes, uncleset, uncleHashes) | 				_, err := q.DeliverBodies(peer.id, txset, txsHashes, uncleset, uncleHashes, nil, nil) | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
| 					fmt.Printf("delivered %d bodies %v\n", len(txset), err) | 					fmt.Printf("delivered %d bodies %v\n", len(txset), err) | ||||||
| 				} | 				} | ||||||
|  | |||||||
| @ -540,8 +540,8 @@ func (f *BlockFetcher) loop() { | |||||||
| 					select { | 					select { | ||||||
| 					case res := <-resCh: | 					case res := <-resCh: | ||||||
| 						res.Done <- nil | 						res.Done <- nil | ||||||
| 
 | 						// Ignoring withdrawals here, since the block fetcher is not used post-merge.
 | ||||||
| 						txs, uncles := res.Res.(*eth.BlockBodiesPacket).Unpack() | 						txs, uncles, _ := res.Res.(*eth.BlockBodiesPacket).Unpack() | ||||||
| 						f.FilterBodies(peer, txs, uncles, time.Now()) | 						f.FilterBodies(peer, txs, uncles, time.Now()) | ||||||
| 
 | 
 | ||||||
| 					case <-timeout.C: | 					case <-timeout.C: | ||||||
|  | |||||||
| @ -23,6 +23,8 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
|  | 	"github.com/ethereum/go-ethereum/consensus" | ||||||
|  | 	"github.com/ethereum/go-ethereum/consensus/beacon" | ||||||
| 	"github.com/ethereum/go-ethereum/consensus/ethash" | 	"github.com/ethereum/go-ethereum/consensus/ethash" | ||||||
| 	"github.com/ethereum/go-ethereum/core" | 	"github.com/ethereum/go-ethereum/core" | ||||||
| 	"github.com/ethereum/go-ethereum/core/rawdb" | 	"github.com/ethereum/go-ethereum/core/rawdb" | ||||||
| @ -45,6 +47,8 @@ var ( | |||||||
| 	testAddr = crypto.PubkeyToAddress(testKey.PublicKey) | 	testAddr = crypto.PubkeyToAddress(testKey.PublicKey) | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | func u64(val uint64) *uint64 { return &val } | ||||||
|  | 
 | ||||||
| // testBackend is a mock implementation of the live Ethereum message handler. Its
 | // testBackend is a mock implementation of the live Ethereum message handler. Its
 | ||||||
| // purpose is to allow testing the request/reply workflows and wire serialization
 | // purpose is to allow testing the request/reply workflows and wire serialization
 | ||||||
| // in the `eth` protocol without actually doing any data processing.
 | // in the `eth` protocol without actually doing any data processing.
 | ||||||
| @ -56,21 +60,53 @@ type testBackend struct { | |||||||
| 
 | 
 | ||||||
| // newTestBackend creates an empty chain and wraps it into a mock backend.
 | // newTestBackend creates an empty chain and wraps it into a mock backend.
 | ||||||
| func newTestBackend(blocks int) *testBackend { | func newTestBackend(blocks int) *testBackend { | ||||||
| 	return newTestBackendWithGenerator(blocks, nil) | 	return newTestBackendWithGenerator(blocks, false, nil) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // newTestBackend creates a chain with a number of explicitly defined blocks and
 | // newTestBackend creates a chain with a number of explicitly defined blocks and
 | ||||||
| // wraps it into a mock backend.
 | // wraps it into a mock backend.
 | ||||||
| func newTestBackendWithGenerator(blocks int, generator func(int, *core.BlockGen)) *testBackend { | func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, *core.BlockGen)) *testBackend { | ||||||
|  | 	var ( | ||||||
| 		// Create a database pre-initialize with a genesis block
 | 		// Create a database pre-initialize with a genesis block
 | ||||||
| 	db := rawdb.NewMemoryDatabase() | 		db                      = rawdb.NewMemoryDatabase() | ||||||
|  | 		config                  = params.TestChainConfig | ||||||
|  | 		engine consensus.Engine = ethash.NewFaker() | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	if shanghai { | ||||||
|  | 		config = ¶ms.ChainConfig{ | ||||||
|  | 			ChainID:                       big.NewInt(1), | ||||||
|  | 			HomesteadBlock:                big.NewInt(0), | ||||||
|  | 			DAOForkBlock:                  nil, | ||||||
|  | 			DAOForkSupport:                true, | ||||||
|  | 			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), | ||||||
|  | 			BerlinBlock:                   big.NewInt(0), | ||||||
|  | 			LondonBlock:                   big.NewInt(0), | ||||||
|  | 			ArrowGlacierBlock:             big.NewInt(0), | ||||||
|  | 			GrayGlacierBlock:              big.NewInt(0), | ||||||
|  | 			MergeNetsplitBlock:            big.NewInt(0), | ||||||
|  | 			ShanghaiTime:                  u64(0), | ||||||
|  | 			TerminalTotalDifficulty:       big.NewInt(0), | ||||||
|  | 			TerminalTotalDifficultyPassed: true, | ||||||
|  | 			Ethash:                        new(params.EthashConfig), | ||||||
|  | 		} | ||||||
|  | 		engine = beacon.NewFaker() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	gspec := &core.Genesis{ | 	gspec := &core.Genesis{ | ||||||
| 		Config: params.TestChainConfig, | 		Config: config, | ||||||
| 		Alloc:  core.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}}, | 		Alloc:  core.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}}, | ||||||
| 	} | 	} | ||||||
| 	chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) | 	chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) | ||||||
| 
 | 
 | ||||||
| 	_, bs, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), blocks, generator) | 	_, bs, _ := core.GenerateChainWithGenesis(gspec, engine, blocks, generator) | ||||||
| 	if _, err := chain.InsertChain(bs); err != nil { | 	if _, err := chain.InsertChain(bs); err != nil { | ||||||
| 		panic(err) | 		panic(err) | ||||||
| 	} | 	} | ||||||
| @ -305,7 +341,17 @@ func TestGetBlockBodies68(t *testing.T) { testGetBlockBodies(t, ETH68) } | |||||||
| func testGetBlockBodies(t *testing.T, protocol uint) { | func testGetBlockBodies(t *testing.T, protocol uint) { | ||||||
| 	t.Parallel() | 	t.Parallel() | ||||||
| 
 | 
 | ||||||
| 	backend := newTestBackend(maxBodiesServe + 15) | 	gen := func(n int, g *core.BlockGen) { | ||||||
|  | 		if n%2 == 0 { | ||||||
|  | 			w := &types.Withdrawal{ | ||||||
|  | 				Address: common.Address{0xaa}, | ||||||
|  | 				Amount:  42, | ||||||
|  | 			} | ||||||
|  | 			g.AddWithdrawal(w) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	backend := newTestBackendWithGenerator(maxBodiesServe+15, true, gen) | ||||||
| 	defer backend.close() | 	defer backend.close() | ||||||
| 
 | 
 | ||||||
| 	peer, _ := newTestPeer("peer", protocol, backend) | 	peer, _ := newTestPeer("peer", protocol, backend) | ||||||
| @ -355,7 +401,7 @@ func testGetBlockBodies(t *testing.T, protocol uint) { | |||||||
| 					block := backend.chain.GetBlockByNumber(uint64(num)) | 					block := backend.chain.GetBlockByNumber(uint64(num)) | ||||||
| 					hashes = append(hashes, block.Hash()) | 					hashes = append(hashes, block.Hash()) | ||||||
| 					if len(bodies) < tt.expected { | 					if len(bodies) < tt.expected { | ||||||
| 						bodies = append(bodies, &BlockBody{Transactions: block.Transactions(), Uncles: block.Uncles()}) | 						bodies = append(bodies, &BlockBody{Transactions: block.Transactions(), Uncles: block.Uncles(), Withdrawals: block.Withdrawals()}) | ||||||
| 					} | 					} | ||||||
| 					break | 					break | ||||||
| 				} | 				} | ||||||
| @ -365,9 +411,10 @@ func testGetBlockBodies(t *testing.T, protocol uint) { | |||||||
| 			hashes = append(hashes, hash) | 			hashes = append(hashes, hash) | ||||||
| 			if tt.available[j] && len(bodies) < tt.expected { | 			if tt.available[j] && len(bodies) < tt.expected { | ||||||
| 				block := backend.chain.GetBlockByHash(hash) | 				block := backend.chain.GetBlockByHash(hash) | ||||||
| 				bodies = append(bodies, &BlockBody{Transactions: block.Transactions(), Uncles: block.Uncles()}) | 				bodies = append(bodies, &BlockBody{Transactions: block.Transactions(), Uncles: block.Uncles(), Withdrawals: block.Withdrawals()}) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
| 		// Send the hash request and verify the response
 | 		// Send the hash request and verify the response
 | ||||||
| 		p2p.Send(peer.app, GetBlockBodiesMsg, &GetBlockBodiesPacket66{ | 		p2p.Send(peer.app, GetBlockBodiesMsg, &GetBlockBodiesPacket66{ | ||||||
| 			RequestId:            123, | 			RequestId:            123, | ||||||
| @ -426,7 +473,7 @@ func testGetNodeData(t *testing.T, protocol uint, drop bool) { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	// Assemble the test environment
 | 	// Assemble the test environment
 | ||||||
| 	backend := newTestBackendWithGenerator(4, generator) | 	backend := newTestBackendWithGenerator(4, false, generator) | ||||||
| 	defer backend.close() | 	defer backend.close() | ||||||
| 
 | 
 | ||||||
| 	peer, _ := newTestPeer("peer", protocol, backend) | 	peer, _ := newTestPeer("peer", protocol, backend) | ||||||
| @ -544,7 +591,7 @@ func testGetBlockReceipts(t *testing.T, protocol uint) { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	// Assemble the test environment
 | 	// Assemble the test environment
 | ||||||
| 	backend := newTestBackendWithGenerator(4, generator) | 	backend := newTestBackendWithGenerator(4, false, generator) | ||||||
| 	defer backend.close() | 	defer backend.close() | ||||||
| 
 | 
 | ||||||
| 	peer, _ := newTestPeer("peer", protocol, backend) | 	peer, _ := newTestPeer("peer", protocol, backend) | ||||||
|  | |||||||
| @ -381,13 +381,17 @@ func handleBlockBodies66(backend Backend, msg Decoder, peer *Peer) error { | |||||||
| 		var ( | 		var ( | ||||||
| 			txsHashes        = make([]common.Hash, len(res.BlockBodiesPacket)) | 			txsHashes        = make([]common.Hash, len(res.BlockBodiesPacket)) | ||||||
| 			uncleHashes      = make([]common.Hash, len(res.BlockBodiesPacket)) | 			uncleHashes      = make([]common.Hash, len(res.BlockBodiesPacket)) | ||||||
|  | 			withdrawalHashes = make([]common.Hash, len(res.BlockBodiesPacket)) | ||||||
| 		) | 		) | ||||||
| 		hasher := trie.NewStackTrie(nil) | 		hasher := trie.NewStackTrie(nil) | ||||||
| 		for i, body := range res.BlockBodiesPacket { | 		for i, body := range res.BlockBodiesPacket { | ||||||
| 			txsHashes[i] = types.DeriveSha(types.Transactions(body.Transactions), hasher) | 			txsHashes[i] = types.DeriveSha(types.Transactions(body.Transactions), hasher) | ||||||
| 			uncleHashes[i] = types.CalcUncleHash(body.Uncles) | 			uncleHashes[i] = types.CalcUncleHash(body.Uncles) | ||||||
|  | 			if body.Withdrawals != nil { | ||||||
|  | 				withdrawalHashes[i] = types.DeriveSha(types.Withdrawals(body.Withdrawals), hasher) | ||||||
| 			} | 			} | ||||||
| 		return [][]common.Hash{txsHashes, uncleHashes} | 		} | ||||||
|  | 		return [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes} | ||||||
| 	} | 	} | ||||||
| 	return peer.dispatchResponse(&Response{ | 	return peer.dispatchResponse(&Response{ | ||||||
| 		id:   res.RequestId, | 		id:   res.RequestId, | ||||||
|  | |||||||
| @ -239,19 +239,22 @@ type BlockBodiesRLPPacket66 struct { | |||||||
| type BlockBody struct { | type BlockBody struct { | ||||||
| 	Transactions []*types.Transaction // Transactions contained within a block
 | 	Transactions []*types.Transaction // Transactions contained within a block
 | ||||||
| 	Uncles       []*types.Header      // Uncles contained within a block
 | 	Uncles       []*types.Header      // Uncles contained within a block
 | ||||||
|  | 	Withdrawals  []*types.Withdrawal  `rlp:"optional"` // Withdrawals contained within a block
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Unpack retrieves the transactions and uncles from the range packet and returns
 | // Unpack retrieves the transactions and uncles from the range packet and returns
 | ||||||
| // them in a split flat format that's more consistent with the internal data structures.
 | // them in a split flat format that's more consistent with the internal data structures.
 | ||||||
| func (p *BlockBodiesPacket) Unpack() ([][]*types.Transaction, [][]*types.Header) { | func (p *BlockBodiesPacket) Unpack() ([][]*types.Transaction, [][]*types.Header, [][]*types.Withdrawal) { | ||||||
|  | 	// TODO(matt): add support for withdrawals to fetchers
 | ||||||
| 	var ( | 	var ( | ||||||
| 		txset         = make([][]*types.Transaction, len(*p)) | 		txset         = make([][]*types.Transaction, len(*p)) | ||||||
| 		uncleset      = make([][]*types.Header, len(*p)) | 		uncleset      = make([][]*types.Header, len(*p)) | ||||||
|  | 		withdrawalset = make([][]*types.Withdrawal, len(*p)) | ||||||
| 	) | 	) | ||||||
| 	for i, body := range *p { | 	for i, body := range *p { | ||||||
| 		txset[i], uncleset[i] = body.Transactions, body.Uncles | 		txset[i], uncleset[i], withdrawalset[i] = body.Transactions, body.Uncles, body.Withdrawals | ||||||
| 	} | 	} | ||||||
| 	return txset, uncleset | 	return txset, uncleset, withdrawalset | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // GetNodeDataPacket represents a trie node data query.
 | // GetNodeDataPacket represents a trie node data query.
 | ||||||
|  | |||||||
| @ -1214,6 +1214,10 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { | |||||||
| 		result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee) | 		result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if head.WithdrawalsHash != nil { | ||||||
|  | 		result["withdrawalsRoot"] = head.WithdrawalsHash | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return result | 	return result | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -1242,6 +1246,8 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		fields["transactions"] = transactions | 		fields["transactions"] = transactions | ||||||
|  | 		// inclTx also expands withdrawals
 | ||||||
|  | 		fields["withdrawals"] = block.Withdrawals() | ||||||
| 	} | 	} | ||||||
| 	uncles := block.Uncles() | 	uncles := block.Uncles() | ||||||
| 	uncleHashes := make([]common.Hash, len(uncles)) | 	uncleHashes := make([]common.Hash, len(uncles)) | ||||||
|  | |||||||
| @ -70,7 +70,7 @@ func NewConsensusAPI(les *les.LightEthereum) *ConsensusAPI { | |||||||
| //
 | //
 | ||||||
| // If there are payloadAttributes: we return an error since block creation is not
 | // If there are payloadAttributes: we return an error since block creation is not
 | ||||||
| // supported in les mode.
 | // supported in les mode.
 | ||||||
| func (api *ConsensusAPI) ForkchoiceUpdatedV1(heads beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributesV1) (beacon.ForkChoiceResponse, error) { | func (api *ConsensusAPI) ForkchoiceUpdatedV1(heads beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { | ||||||
| 	if heads.HeadBlockHash == (common.Hash{}) { | 	if heads.HeadBlockHash == (common.Hash{}) { | ||||||
| 		log.Warn("Forkchoice requested update to zero hash") | 		log.Warn("Forkchoice requested update to zero hash") | ||||||
| 		return beacon.STATUS_INVALID, nil // TODO(karalabe): Why does someone send us this?
 | 		return beacon.STATUS_INVALID, nil // TODO(karalabe): Why does someone send us this?
 | ||||||
| @ -100,12 +100,12 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(heads beacon.ForkchoiceStateV1, pay | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // GetPayloadV1 returns a cached payload by id. It's not supported in les mode.
 | // GetPayloadV1 returns a cached payload by id. It's not supported in les mode.
 | ||||||
| func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableDataV1, error) { | func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableData, error) { | ||||||
| 	return nil, beacon.GenericServerError.With(errors.New("not supported in light client mode")) | 	return nil, beacon.GenericServerError.With(errors.New("not supported in light client mode")) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ExecutePayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
 | // ExecutePayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
 | ||||||
| func (api *ConsensusAPI) ExecutePayloadV1(params beacon.ExecutableDataV1) (beacon.PayloadStatusV1, error) { | func (api *ConsensusAPI) ExecutePayloadV1(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) { | ||||||
| 	block, err := beacon.ExecutableDataToBlock(params) | 	block, err := beacon.ExecutableDataToBlock(params) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return api.invalid(), err | 		return api.invalid(), err | ||||||
|  | |||||||
| @ -130,7 +130,7 @@ func TestExecutePayloadV1(t *testing.T) { | |||||||
| 		BaseFee:     block.BaseFee(), | 		BaseFee:     block.BaseFee(), | ||||||
| 	}, nil, nil, nil, trie.NewStackTrie(nil)) | 	}, nil, nil, nil, trie.NewStackTrie(nil)) | ||||||
| 
 | 
 | ||||||
| 	_, err := api.ExecutePayloadV1(beacon.ExecutableDataV1{ | 	_, err := api.ExecutePayloadV1(beacon.ExecutableData{ | ||||||
| 		ParentHash:    fakeBlock.ParentHash(), | 		ParentHash:    fakeBlock.ParentHash(), | ||||||
| 		FeeRecipient:  fakeBlock.Coinbase(), | 		FeeRecipient:  fakeBlock.Coinbase(), | ||||||
| 		StateRoot:     fakeBlock.Root(), | 		StateRoot:     fakeBlock.Root(), | ||||||
|  | |||||||
| @ -38,6 +38,7 @@ type BuildPayloadArgs struct { | |||||||
| 	Timestamp    uint64            // The provided timestamp of generated payload
 | 	Timestamp    uint64            // The provided timestamp of generated payload
 | ||||||
| 	FeeRecipient common.Address    // The provided recipient address for collecting transaction fee
 | 	FeeRecipient common.Address    // The provided recipient address for collecting transaction fee
 | ||||||
| 	Random       common.Hash       // The provided randomness value
 | 	Random       common.Hash       // The provided randomness value
 | ||||||
|  | 	Withdrawals  types.Withdrawals // The provided withdrawals
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Id computes an 8-byte identifier by hashing the components of the payload arguments.
 | // Id computes an 8-byte identifier by hashing the components of the payload arguments.
 | ||||||
| @ -107,7 +108,7 @@ func (payload *Payload) update(block *types.Block, fees *big.Int, elapsed time.D | |||||||
| 
 | 
 | ||||||
| // Resolve returns the latest built payload and also terminates the background
 | // Resolve returns the latest built payload and also terminates the background
 | ||||||
| // thread for updating payload. It's safe to be called multiple times.
 | // thread for updating payload. It's safe to be called multiple times.
 | ||||||
| func (payload *Payload) Resolve() *beacon.ExecutableDataV1 { | func (payload *Payload) Resolve() *beacon.ExecutionPayloadEnvelope { | ||||||
| 	payload.lock.Lock() | 	payload.lock.Lock() | ||||||
| 	defer payload.lock.Unlock() | 	defer payload.lock.Unlock() | ||||||
| 
 | 
 | ||||||
| @ -117,23 +118,23 @@ func (payload *Payload) Resolve() *beacon.ExecutableDataV1 { | |||||||
| 		close(payload.stop) | 		close(payload.stop) | ||||||
| 	} | 	} | ||||||
| 	if payload.full != nil { | 	if payload.full != nil { | ||||||
| 		return beacon.BlockToExecutableData(payload.full) | 		return beacon.BlockToExecutableData(payload.full, payload.fullFees) | ||||||
| 	} | 	} | ||||||
| 	return beacon.BlockToExecutableData(payload.empty) | 	return beacon.BlockToExecutableData(payload.empty, big.NewInt(0)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ResolveEmpty is basically identical to Resolve, but it expects empty block only.
 | // ResolveEmpty is basically identical to Resolve, but it expects empty block only.
 | ||||||
| // It's only used in tests.
 | // It's only used in tests.
 | ||||||
| func (payload *Payload) ResolveEmpty() *beacon.ExecutableDataV1 { | func (payload *Payload) ResolveEmpty() *beacon.ExecutionPayloadEnvelope { | ||||||
| 	payload.lock.Lock() | 	payload.lock.Lock() | ||||||
| 	defer payload.lock.Unlock() | 	defer payload.lock.Unlock() | ||||||
| 
 | 
 | ||||||
| 	return beacon.BlockToExecutableData(payload.empty) | 	return beacon.BlockToExecutableData(payload.empty, big.NewInt(0)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ResolveFull is basically identical to Resolve, but it expects full block only.
 | // ResolveFull is basically identical to Resolve, but it expects full block only.
 | ||||||
| // It's only used in tests.
 | // It's only used in tests.
 | ||||||
| func (payload *Payload) ResolveFull() *beacon.ExecutableDataV1 { | func (payload *Payload) ResolveFull() *beacon.ExecutionPayloadEnvelope { | ||||||
| 	payload.lock.Lock() | 	payload.lock.Lock() | ||||||
| 	defer payload.lock.Unlock() | 	defer payload.lock.Unlock() | ||||||
| 
 | 
 | ||||||
| @ -145,7 +146,7 @@ func (payload *Payload) ResolveFull() *beacon.ExecutableDataV1 { | |||||||
| 		} | 		} | ||||||
| 		payload.cond.Wait() | 		payload.cond.Wait() | ||||||
| 	} | 	} | ||||||
| 	return beacon.BlockToExecutableData(payload.full) | 	return beacon.BlockToExecutableData(payload.full, payload.fullFees) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // buildPayload builds the payload according to the provided parameters.
 | // buildPayload builds the payload according to the provided parameters.
 | ||||||
| @ -153,7 +154,7 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { | |||||||
| 	// Build the initial version with no transaction included. It should be fast
 | 	// Build the initial version with no transaction included. It should be fast
 | ||||||
| 	// enough to run. The empty payload can at least make sure there is something
 | 	// enough to run. The empty payload can at least make sure there is something
 | ||||||
| 	// to deliver for not missing slot.
 | 	// to deliver for not missing slot.
 | ||||||
| 	empty, _, err := w.getSealingBlock(args.Parent, args.Timestamp, args.FeeRecipient, args.Random, true) | 	empty, _, err := w.getSealingBlock(args.Parent, args.Timestamp, args.FeeRecipient, args.Random, args.Withdrawals, true) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @ -177,7 +178,7 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { | |||||||
| 			select { | 			select { | ||||||
| 			case <-timer.C: | 			case <-timer.C: | ||||||
| 				start := time.Now() | 				start := time.Now() | ||||||
| 				block, fees, err := w.getSealingBlock(args.Parent, args.Timestamp, args.FeeRecipient, args.Random, false) | 				block, fees, err := w.getSealingBlock(args.Parent, args.Timestamp, args.FeeRecipient, args.Random, args.Withdrawals, false) | ||||||
| 				if err == nil { | 				if err == nil { | ||||||
| 					payload.update(block, fees, time.Since(start)) | 					payload.update(block, fees, time.Since(start)) | ||||||
| 				} | 				} | ||||||
|  | |||||||
| @ -47,20 +47,21 @@ func TestBuildPayload(t *testing.T) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("Failed to build payload %v", err) | 		t.Fatalf("Failed to build payload %v", err) | ||||||
| 	} | 	} | ||||||
| 	verify := func(data *beacon.ExecutableDataV1, txs int) { | 	verify := func(outer *beacon.ExecutionPayloadEnvelope, txs int) { | ||||||
| 		if data.ParentHash != b.chain.CurrentBlock().Hash() { | 		payload := outer.ExecutionPayload | ||||||
|  | 		if payload.ParentHash != b.chain.CurrentBlock().Hash() { | ||||||
| 			t.Fatal("Unexpect parent hash") | 			t.Fatal("Unexpect parent hash") | ||||||
| 		} | 		} | ||||||
| 		if data.Random != (common.Hash{}) { | 		if payload.Random != (common.Hash{}) { | ||||||
| 			t.Fatal("Unexpect random value") | 			t.Fatal("Unexpect random value") | ||||||
| 		} | 		} | ||||||
| 		if data.Timestamp != timestamp { | 		if payload.Timestamp != timestamp { | ||||||
| 			t.Fatal("Unexpect timestamp") | 			t.Fatal("Unexpect timestamp") | ||||||
| 		} | 		} | ||||||
| 		if data.FeeRecipient != recipient { | 		if payload.FeeRecipient != recipient { | ||||||
| 			t.Fatal("Unexpect fee recipient") | 			t.Fatal("Unexpect fee recipient") | ||||||
| 		} | 		} | ||||||
| 		if len(data.Transactions) != txs { | 		if len(payload.Transactions) != txs { | ||||||
| 			t.Fatal("Unexpect transaction set") | 			t.Fatal("Unexpect transaction set") | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -142,7 +142,7 @@ func newNode(typ nodetype, genesis *core.Genesis, enodes []*enode.Node) *ethNode | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) (*beacon.ExecutableDataV1, error) { | func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) (*beacon.ExecutableData, error) { | ||||||
| 	if n.typ != eth2MiningNode { | 	if n.typ != eth2MiningNode { | ||||||
| 		return nil, errors.New("invalid node type") | 		return nil, errors.New("invalid node type") | ||||||
| 	} | 	} | ||||||
| @ -150,7 +150,7 @@ func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) | |||||||
| 	if timestamp <= parentTimestamp { | 	if timestamp <= parentTimestamp { | ||||||
| 		timestamp = parentTimestamp + 1 | 		timestamp = parentTimestamp + 1 | ||||||
| 	} | 	} | ||||||
| 	payloadAttribute := beacon.PayloadAttributesV1{ | 	payloadAttribute := beacon.PayloadAttributes{ | ||||||
| 		Timestamp:             timestamp, | 		Timestamp:             timestamp, | ||||||
| 		Random:                common.Hash{}, | 		Random:                common.Hash{}, | ||||||
| 		SuggestedFeeRecipient: common.HexToAddress("0xdeadbeef"), | 		SuggestedFeeRecipient: common.HexToAddress("0xdeadbeef"), | ||||||
| @ -168,7 +168,7 @@ func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) | |||||||
| 	return n.api.GetPayloadV1(*payload.PayloadID) | 	return n.api.GetPayloadV1(*payload.PayloadID) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (n *ethNode) insertBlock(eb beacon.ExecutableDataV1) error { | func (n *ethNode) insertBlock(eb beacon.ExecutableData) error { | ||||||
| 	if !eth2types(n.typ) { | 	if !eth2types(n.typ) { | ||||||
| 		return errors.New("invalid node type") | 		return errors.New("invalid node type") | ||||||
| 	} | 	} | ||||||
| @ -194,7 +194,7 @@ func (n *ethNode) insertBlock(eb beacon.ExecutableDataV1) error { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (n *ethNode) insertBlockAndSetHead(parent *types.Header, ed beacon.ExecutableDataV1) error { | func (n *ethNode) insertBlockAndSetHead(parent *types.Header, ed beacon.ExecutableData) error { | ||||||
| 	if !eth2types(n.typ) { | 	if !eth2types(n.typ) { | ||||||
| 		return errors.New("invalid node type") | 		return errors.New("invalid node type") | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -968,11 +968,12 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP | |||||||
| 
 | 
 | ||||||
| // generateParams wraps various of settings for generating sealing task.
 | // generateParams wraps various of settings for generating sealing task.
 | ||||||
| type generateParams struct { | type generateParams struct { | ||||||
| 	timestamp  uint64         // The timestamp for sealing task
 | 	timestamp   uint64            // The timstamp for sealing task
 | ||||||
| 	forceTime   bool              // Flag whether the given timestamp is immutable or not
 | 	forceTime   bool              // Flag whether the given timestamp is immutable or not
 | ||||||
| 	parentHash  common.Hash       // Parent block hash, empty means the latest chain head
 | 	parentHash  common.Hash       // Parent block hash, empty means the latest chain head
 | ||||||
| 	coinbase    common.Address    // The fee recipient address for including transaction
 | 	coinbase    common.Address    // The fee recipient address for including transaction
 | ||||||
| 	random      common.Hash       // The randomness generated by beacon chain, empty before the merge
 | 	random      common.Hash       // The randomness generated by beacon chain, empty before the merge
 | ||||||
|  | 	withdrawals types.Withdrawals // List of withdrawals to include in block.
 | ||||||
| 	noUncle     bool              // Flag whether the uncle block inclusion is allowed
 | 	noUncle     bool              // Flag whether the uncle block inclusion is allowed
 | ||||||
| 	noTxs       bool              // Flag whether an empty block without any transaction is expected
 | 	noTxs       bool              // Flag whether an empty block without any transaction is expected
 | ||||||
| } | } | ||||||
| @ -1108,7 +1109,7 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, *big.Int, e | |||||||
| 			log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(w.newpayloadTimeout)) | 			log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(w.newpayloadTimeout)) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	block, err := w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, work.txs, work.unclelist(), work.receipts) | 	block, err := w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, work.txs, work.unclelist(), work.receipts, params.withdrawals) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, nil, err | 		return nil, nil, err | ||||||
| 	} | 	} | ||||||
| @ -1193,7 +1194,8 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti | |||||||
| 		// Create a local environment copy, avoid the data race with snapshot state.
 | 		// Create a local environment copy, avoid the data race with snapshot state.
 | ||||||
| 		// https://github.com/ethereum/go-ethereum/issues/24299
 | 		// https://github.com/ethereum/go-ethereum/issues/24299
 | ||||||
| 		env := env.copy() | 		env := env.copy() | ||||||
| 		block, err := w.engine.FinalizeAndAssemble(w.chain, env.header, env.state, env.txs, env.unclelist(), env.receipts) | 		// Withdrawals are set to nil here, because this is only called in PoW.
 | ||||||
|  | 		block, err := w.engine.FinalizeAndAssemble(w.chain, env.header, env.state, env.txs, env.unclelist(), env.receipts, nil) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| @ -1224,7 +1226,7 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti | |||||||
| // getSealingBlock generates the sealing block based on the given parameters.
 | // getSealingBlock generates the sealing block based on the given parameters.
 | ||||||
| // The generation result will be passed back via the given channel no matter
 | // The generation result will be passed back via the given channel no matter
 | ||||||
| // the generation itself succeeds or not.
 | // the generation itself succeeds or not.
 | ||||||
| func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, noTxs bool) (*types.Block, *big.Int, error) { | func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, withdrawals types.Withdrawals, noTxs bool) (*types.Block, *big.Int, error) { | ||||||
| 	req := &getWorkReq{ | 	req := &getWorkReq{ | ||||||
| 		params: &generateParams{ | 		params: &generateParams{ | ||||||
| 			timestamp:   timestamp, | 			timestamp:   timestamp, | ||||||
| @ -1232,6 +1234,7 @@ func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase | |||||||
| 			parentHash:  parent, | 			parentHash:  parent, | ||||||
| 			coinbase:    coinbase, | 			coinbase:    coinbase, | ||||||
| 			random:      random, | 			random:      random, | ||||||
|  | 			withdrawals: withdrawals, | ||||||
| 			noUncle:     true, | 			noUncle:     true, | ||||||
| 			noTxs:       noTxs, | 			noTxs:       noTxs, | ||||||
| 		}, | 		}, | ||||||
|  | |||||||
| @ -637,7 +637,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co | |||||||
| 
 | 
 | ||||||
| 	// This API should work even when the automatic sealing is not enabled
 | 	// This API should work even when the automatic sealing is not enabled
 | ||||||
| 	for _, c := range cases { | 	for _, c := range cases { | ||||||
| 		block, _, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random, false) | 		block, _, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random, nil, false) | ||||||
| 		if c.expectErr { | 		if c.expectErr { | ||||||
| 			if err == nil { | 			if err == nil { | ||||||
| 				t.Error("Expect error but get nil") | 				t.Error("Expect error but get nil") | ||||||
| @ -653,7 +653,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co | |||||||
| 	// This API should work even when the automatic sealing is enabled
 | 	// This API should work even when the automatic sealing is enabled
 | ||||||
| 	w.start() | 	w.start() | ||||||
| 	for _, c := range cases { | 	for _, c := range cases { | ||||||
| 		block, _, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random, false) | 		block, _, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random, nil, false) | ||||||
| 		if c.expectErr { | 		if c.expectErr { | ||||||
| 			if err == nil { | 			if err == nil { | ||||||
| 				t.Error("Expect error but get nil") | 				t.Error("Expect error but get nil") | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user