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.
 | ||||
| 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) | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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