eth/catalyst: error on nil withdrawals post-shanghai (#26549)
This adds explicit checks for the presence of withdrawals in the engine API. Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
parent
55f41d198c
commit
245cff0a1a
@ -164,6 +164,18 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa
|
|||||||
|
|
||||||
// ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload attributes.
|
// 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) {
|
func (api *ConsensusAPI) ForkchoiceUpdatedV2(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) {
|
||||||
|
if !api.eth.BlockChain().Config().IsShanghai(payloadAttributes.Timestamp) {
|
||||||
|
// Reject payload attributes with withdrawals before shanghai
|
||||||
|
if payloadAttributes != nil && payloadAttributes.Withdrawals != nil {
|
||||||
|
return beacon.STATUS_INVALID, beacon.InvalidPayloadAttributes.With(errors.New("withdrawals before shanghai"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Reject payload attributes with nil withdrawals after shanghai
|
||||||
|
if payloadAttributes != nil && payloadAttributes.Withdrawals == nil {
|
||||||
|
return beacon.STATUS_INVALID, beacon.InvalidPayloadAttributes.With(errors.New("missing withdrawals list"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return api.forkchoiceUpdated(update, payloadAttributes)
|
return api.forkchoiceUpdated(update, payloadAttributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1113,3 +1113,115 @@ func TestWithdrawals(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNilWithdrawals(t *testing.T) {
|
||||||
|
genesis, blocks := generateMergeChain(10, true)
|
||||||
|
// Set shanghai time to last block + 4 seconds (first post-merge block)
|
||||||
|
time := blocks[len(blocks)-1].Time() + 4
|
||||||
|
genesis.Config.ShanghaiTime = &time
|
||||||
|
|
||||||
|
n, ethservice := startEthService(t, genesis, blocks)
|
||||||
|
ethservice.Merger().ReachTTD()
|
||||||
|
defer n.Close()
|
||||||
|
|
||||||
|
api := NewConsensusAPI(ethservice)
|
||||||
|
parent := ethservice.BlockChain().CurrentHeader()
|
||||||
|
aa := common.Address{0xaa}
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
blockParams beacon.PayloadAttributes
|
||||||
|
wantErr bool
|
||||||
|
}
|
||||||
|
tests := []test{
|
||||||
|
// Before Shanghai
|
||||||
|
{
|
||||||
|
blockParams: beacon.PayloadAttributes{
|
||||||
|
Timestamp: parent.Time + 2,
|
||||||
|
Withdrawals: nil,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blockParams: beacon.PayloadAttributes{
|
||||||
|
Timestamp: parent.Time + 2,
|
||||||
|
Withdrawals: make([]*types.Withdrawal, 0),
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blockParams: beacon.PayloadAttributes{
|
||||||
|
Timestamp: parent.Time + 2,
|
||||||
|
Withdrawals: []*types.Withdrawal{
|
||||||
|
{
|
||||||
|
Index: 0,
|
||||||
|
Address: aa,
|
||||||
|
Amount: 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
// After Shanghai
|
||||||
|
{
|
||||||
|
blockParams: beacon.PayloadAttributes{
|
||||||
|
Timestamp: parent.Time + 5,
|
||||||
|
Withdrawals: nil,
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blockParams: beacon.PayloadAttributes{
|
||||||
|
Timestamp: parent.Time + 5,
|
||||||
|
Withdrawals: make([]*types.Withdrawal, 0),
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blockParams: beacon.PayloadAttributes{
|
||||||
|
Timestamp: parent.Time + 5,
|
||||||
|
Withdrawals: []*types.Withdrawal{
|
||||||
|
{
|
||||||
|
Index: 0,
|
||||||
|
Address: aa,
|
||||||
|
Amount: 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fcState := beacon.ForkchoiceStateV1{
|
||||||
|
HeadBlockHash: parent.Hash(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
_, err := api.ForkchoiceUpdatedV2(fcState, &test.blockParams)
|
||||||
|
if test.wantErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("wanted error on fcuv2 with invalid withdrawals")
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error preparing payload, err=%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 11: verify locally build block.
|
||||||
|
payloadID := (&miner.BuildPayloadArgs{
|
||||||
|
Parent: fcState.HeadBlockHash,
|
||||||
|
Timestamp: test.blockParams.Timestamp,
|
||||||
|
FeeRecipient: test.blockParams.SuggestedFeeRecipient,
|
||||||
|
Random: test.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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user