eth/catalyst: implement kintsugi-spec v3 (#24067)

This commit is contained in:
Marius van der Wijden
2021-12-17 15:38:58 +01:00
committed by GitHub
parent f5f5c0855a
commit 2295640ebd
8 changed files with 97 additions and 59 deletions

View File

@@ -43,13 +43,14 @@ import (
)
var (
VALID = GenericStringResponse{"VALID"}
SUCCESS = GenericStringResponse{"SUCCESS"}
INVALID = ForkChoiceResponse{Status: "INVALID", PayloadID: nil}
SYNCING = ForkChoiceResponse{Status: "INVALID", PayloadID: nil}
UnknownHeader = rpc.CustomError{Code: -32000, Message: "unknown header"}
UnknownPayload = rpc.CustomError{Code: -32001, Message: "unknown payload"}
InvalidPayloadID = rpc.CustomError{Code: 1, Message: "invalid payload id"}
VALID = GenericStringResponse{"VALID"}
SUCCESS = GenericStringResponse{"SUCCESS"}
INVALID = ForkChoiceResponse{Status: "INVALID", PayloadID: nil}
SYNCING = ForkChoiceResponse{Status: "SYNCING", PayloadID: nil}
GenericServerError = rpc.CustomError{Code: -32000, ValidationError: "Server error"}
UnknownPayload = rpc.CustomError{Code: -32001, ValidationError: "Unknown payload"}
InvalidTB = rpc.CustomError{Code: -32002, ValidationError: "Invalid terminal block"}
InvalidPayloadID = rpc.CustomError{Code: 1, ValidationError: "invalid payload id"}
)
// Register adds catalyst APIs to the full node.
@@ -232,7 +233,7 @@ func computePayloadId(headBlockHash common.Hash, params *PayloadAttributesV1) []
hasher.Write(headBlockHash[:])
binary.Write(hasher, binary.BigEndian, params.Timestamp)
hasher.Write(params.Random[:])
hasher.Write(params.FeeRecipient[:])
hasher.Write(params.SuggestedFeeRecipient[:])
return hasher.Sum([]byte{})[:8]
}
@@ -308,7 +309,7 @@ func (api *ConsensusAPI) assembleBlock(parentHash common.Hash, params *PayloadAt
log.Warn("Producing block too far in the future", "diff", common.PrettyDuration(diff))
}
pending := api.eth.TxPool().Pending(true)
coinbase := params.FeeRecipient
coinbase := params.SuggestedFeeRecipient
num := parent.Number()
header := &types.Header{
ParentHash: parent.Hash(),
@@ -419,10 +420,10 @@ func ExecutableDataToBlock(params ExecutableDataV1) (*types.Block, error) {
header := &types.Header{
ParentHash: params.ParentHash,
UncleHash: types.EmptyUncleHash,
Coinbase: params.Coinbase,
Coinbase: params.FeeRecipient,
Root: params.StateRoot,
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
ReceiptHash: params.ReceiptRoot,
ReceiptHash: params.ReceiptsRoot,
Bloom: types.BytesToBloom(params.LogsBloom),
Difficulty: common.Big0,
Number: number,
@@ -444,14 +445,14 @@ func BlockToExecutableData(block *types.Block, random common.Hash) *ExecutableDa
return &ExecutableDataV1{
BlockHash: block.Hash(),
ParentHash: block.ParentHash(),
Coinbase: block.Coinbase(),
FeeRecipient: block.Coinbase(),
StateRoot: block.Root(),
Number: block.NumberU64(),
GasLimit: block.GasLimit(),
GasUsed: block.GasUsed(),
BaseFeePerGas: block.BaseFee(),
Timestamp: block.Time(),
ReceiptRoot: block.ReceiptHash(),
ReceiptsRoot: block.ReceiptHash(),
LogsBloom: block.Bloom().Bytes(),
Transactions: encodeTransactions(block.Transactions()),
Random: random,
@@ -475,11 +476,11 @@ func (api *ConsensusAPI) checkTerminalTotalDifficulty(head common.Hash) error {
// make sure the parent has enough terminal total difficulty
newHeadBlock := api.eth.BlockChain().GetBlockByHash(head)
if newHeadBlock == nil {
return &UnknownHeader
return &GenericServerError
}
td := api.eth.BlockChain().GetTd(newHeadBlock.Hash(), newHeadBlock.NumberU64())
if td != nil && td.Cmp(api.eth.BlockChain().Config().TerminalTotalDifficulty) < 0 {
return errors.New("total difficulty not reached yet")
return &InvalidTB
}
return nil
}
@@ -494,7 +495,7 @@ func (api *ConsensusAPI) setHead(newHead common.Hash) error {
}
newHeadHeader := api.les.BlockChain().GetHeaderByHash(newHead)
if newHeadHeader == nil {
return &UnknownHeader
return &GenericServerError
}
if err := api.les.BlockChain().SetChainHead(newHeadHeader); err != nil {
return err
@@ -508,15 +509,11 @@ func (api *ConsensusAPI) setHead(newHead common.Hash) error {
}
headBlock := api.eth.BlockChain().CurrentBlock()
if headBlock.Hash() == newHead {
// Trigger the transition if it's the first `NewHead` event.
if merger := api.merger(); !merger.PoSFinalized() {
merger.FinalizePoS()
}
return nil
}
newHeadBlock := api.eth.BlockChain().GetBlockByHash(newHead)
if newHeadBlock == nil {
return &UnknownHeader
return &GenericServerError
}
if err := api.eth.BlockChain().SetChainHead(newHeadBlock); err != nil {
return err

View File

@@ -374,9 +374,9 @@ func TestFullAPI(t *testing.T) {
ethservice.TxPool().AddLocal(tx)
params := PayloadAttributesV1{
Timestamp: parent.Time() + 1,
Random: crypto.Keccak256Hash([]byte{byte(i)}),
FeeRecipient: parent.Coinbase(),
Timestamp: parent.Time() + 1,
Random: crypto.Keccak256Hash([]byte{byte(i)}),
SuggestedFeeRecipient: parent.Coinbase(),
}
fcState := ForkchoiceStateV1{
HeadBlockHash: parent.Hash(),

View File

@@ -27,9 +27,9 @@ import (
// Structure described at https://github.com/ethereum/execution-apis/pull/74
type PayloadAttributesV1 struct {
Timestamp uint64 `json:"timestamp" gencodec:"required"`
Random common.Hash `json:"random" gencodec:"required"`
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
Timestamp uint64 `json:"timestamp" gencodec:"required"`
Random common.Hash `json:"random" gencodec:"required"`
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
}
// JSON type overrides for PayloadAttributesV1.
@@ -42,9 +42,9 @@ type payloadAttributesMarshaling struct {
// Structure described at https://github.com/ethereum/execution-apis/src/engine/specification.md
type ExecutableDataV1 struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
Coinbase common.Address `json:"coinbase" gencodec:"required"`
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
ReceiptRoot common.Hash `json:"receiptRoot" gencodec:"required"`
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
LogsBloom []byte `json:"logsBloom" gencodec:"required"`
Random common.Hash `json:"random" gencodec:"required"`
Number uint64 `json:"blockNumber" gencodec:"required"`

View File

@@ -15,23 +15,23 @@ var _ = (*payloadAttributesMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (p PayloadAttributesV1) MarshalJSON() ([]byte, error) {
type PayloadAttributesV1 struct {
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
Random common.Hash `json:"random" gencodec:"required"`
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
Random common.Hash `json:"random" gencodec:"required"`
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
}
var enc PayloadAttributesV1
enc.Timestamp = hexutil.Uint64(p.Timestamp)
enc.Random = p.Random
enc.FeeRecipient = p.FeeRecipient
enc.SuggestedFeeRecipient = p.SuggestedFeeRecipient
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (p *PayloadAttributesV1) UnmarshalJSON(input []byte) error {
type PayloadAttributesV1 struct {
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
Random *common.Hash `json:"random" gencodec:"required"`
FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"`
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
Random *common.Hash `json:"random" gencodec:"required"`
SuggestedFeeRecipient *common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
}
var dec PayloadAttributesV1
if err := json.Unmarshal(input, &dec); err != nil {
@@ -45,9 +45,9 @@ func (p *PayloadAttributesV1) UnmarshalJSON(input []byte) error {
return errors.New("missing required field 'random' for PayloadAttributesV1")
}
p.Random = *dec.Random
if dec.FeeRecipient == nil {
return errors.New("missing required field 'feeRecipient' for PayloadAttributesV1")
if dec.SuggestedFeeRecipient == nil {
return errors.New("missing required field 'suggestedFeeRecipient' for PayloadAttributesV1")
}
p.FeeRecipient = *dec.FeeRecipient
p.SuggestedFeeRecipient = *dec.SuggestedFeeRecipient
return nil
}

View File

@@ -17,9 +17,9 @@ var _ = (*executableDataMarshaling)(nil)
func (e ExecutableDataV1) MarshalJSON() ([]byte, error) {
type ExecutableDataV1 struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
Coinbase common.Address `json:"coinbase" gencodec:"required"`
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
ReceiptRoot common.Hash `json:"receiptRoot" gencodec:"required"`
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"`
Random common.Hash `json:"random" gencodec:"required"`
Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
@@ -33,9 +33,9 @@ func (e ExecutableDataV1) MarshalJSON() ([]byte, error) {
}
var enc ExecutableDataV1
enc.ParentHash = e.ParentHash
enc.Coinbase = e.Coinbase
enc.FeeRecipient = e.FeeRecipient
enc.StateRoot = e.StateRoot
enc.ReceiptRoot = e.ReceiptRoot
enc.ReceiptsRoot = e.ReceiptsRoot
enc.LogsBloom = e.LogsBloom
enc.Random = e.Random
enc.Number = hexutil.Uint64(e.Number)
@@ -58,9 +58,9 @@ func (e ExecutableDataV1) MarshalJSON() ([]byte, error) {
func (e *ExecutableDataV1) UnmarshalJSON(input []byte) error {
type ExecutableDataV1 struct {
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
Coinbase *common.Address `json:"coinbase" gencodec:"required"`
FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"`
StateRoot *common.Hash `json:"stateRoot" gencodec:"required"`
ReceiptRoot *common.Hash `json:"receiptRoot" gencodec:"required"`
ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"`
LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"`
Random *common.Hash `json:"random" gencodec:"required"`
Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
@@ -80,18 +80,18 @@ func (e *ExecutableDataV1) UnmarshalJSON(input []byte) error {
return errors.New("missing required field 'parentHash' for ExecutableDataV1")
}
e.ParentHash = *dec.ParentHash
if dec.Coinbase == nil {
return errors.New("missing required field 'coinbase' for ExecutableDataV1")
if dec.FeeRecipient == nil {
return errors.New("missing required field 'feeRecipient' for ExecutableDataV1")
}
e.Coinbase = *dec.Coinbase
e.FeeRecipient = *dec.FeeRecipient
if dec.StateRoot == nil {
return errors.New("missing required field 'stateRoot' for ExecutableDataV1")
}
e.StateRoot = *dec.StateRoot
if dec.ReceiptRoot == nil {
return errors.New("missing required field 'receiptRoot' for ExecutableDataV1")
if dec.ReceiptsRoot == nil {
return errors.New("missing required field 'receiptsRoot' for ExecutableDataV1")
}
e.ReceiptRoot = *dec.ReceiptRoot
e.ReceiptsRoot = *dec.ReceiptsRoot
if dec.LogsBloom == nil {
return errors.New("missing required field 'logsBloom' for ExecutableDataV1")
}