@@ -7,26 +7,36 @@ import (
77 "github.com/ethpandaops/go-eth-engine-client/spec/prague"
88 "github.com/ethpandaops/go-eth2-client/spec/bellatrix"
99 "github.com/ethpandaops/go-eth2-client/spec/electra"
10+ "github.com/ethpandaops/go-eth2-client/spec/gloas"
1011 "github.com/ethpandaops/go-eth2-client/spec/phase0"
12+ "github.com/ethpandaops/go-eth2-client/spec/version"
13+
14+ eth2all "github.com/ethpandaops/go-eth2-client/spec/all"
1115)
1216
1317const (
14- depositRequestType = 0x00
15- withdrawalRequestType = 0x01
16- consolidationRequestType = 0x02
17-
18- depositRequestSize = 192 // 48 + 32 + 8 + 96 + 8
19- withdrawalRequestSize = 76 // 20 + 48 + 8
20- consolidationRequestSize = 116 // 20 + 48 + 48
18+ depositRequestType = 0x00
19+ withdrawalRequestType = 0x01
20+ consolidationRequestType = 0x02
21+ builderDepositRequestType = 0x03 // EIP-8282, Gloas+
22+ builderExitRequestType = 0x04 // EIP-8282, Gloas+
23+
24+ depositRequestSize = 192 // 48 + 32 + 8 + 96 + 8
25+ withdrawalRequestSize = 76 // 20 + 48 + 8
26+ consolidationRequestSize = 116 // 20 + 48 + 48
27+ builderDepositRequestSize = 184 // 48 + 32 + 8 + 96
28+ builderExitRequestSize = 68 // 20 + 48
2129)
2230
2331// ParseExecutionRequests decodes raw EIP-7685 execution request bytes from the
24- // Engine API into typed electra .ExecutionRequests.
32+ // Engine API into a versioned eth2all .ExecutionRequests.
2533//
2634// Each element in raw is: [type_prefix_byte || request_1 || request_2 || ...]
2735// where all requests of the same type are concatenated after a single prefix byte.
28- func ParseExecutionRequests (raw []prague.ExecutionRequest ) (* electra.ExecutionRequests , error ) {
29- result := & electra.ExecutionRequests {
36+ // Builder deposit (0x03) and builder exit (0x04) requests are only valid from Gloas onwards.
37+ func ParseExecutionRequests (raw []prague.ExecutionRequest , dataVersion version.DataVersion ) (* eth2all.ExecutionRequests , error ) {
38+ result := & eth2all.ExecutionRequests {
39+ Version : dataVersion ,
3040 Deposits : make ([]* electra.DepositRequest , 0 ),
3141 Withdrawals : make ([]* electra.WithdrawalRequest , 0 ),
3242 Consolidations : make ([]* electra.ConsolidationRequest , 0 ),
@@ -68,6 +78,26 @@ func ParseExecutionRequests(raw []prague.ExecutionRequest) (*electra.ExecutionRe
6878 }
6979 result .Consolidations = consolidations
7080
81+ case builderDepositRequestType :
82+ if dataVersion < version .DataVersionGloas {
83+ return nil , fmt .Errorf ("execution request %d: builder deposit request not valid before Gloas" , i )
84+ }
85+ builderDeposits , err := parseBuilderDepositRequests (data )
86+ if err != nil {
87+ return nil , fmt .Errorf ("execution request %d: %w" , i , err )
88+ }
89+ result .BuilderDeposits = builderDeposits
90+
91+ case builderExitRequestType :
92+ if dataVersion < version .DataVersionGloas {
93+ return nil , fmt .Errorf ("execution request %d: builder exit request not valid before Gloas" , i )
94+ }
95+ builderExits , err := parseBuilderExitRequests (data )
96+ if err != nil {
97+ return nil , fmt .Errorf ("execution request %d: %w" , i , err )
98+ }
99+ result .BuilderExits = builderExits
100+
71101 default :
72102 return nil , fmt .Errorf ("execution request %d: unknown type 0x%02x" , i , reqType )
73103 }
@@ -170,3 +200,62 @@ func parseConsolidationRequests(data []byte) ([]*electra.ConsolidationRequest, e
170200
171201 return consolidations , nil
172202}
203+
204+ func parseBuilderDepositRequests (data []byte ) ([]* gloas.BuilderDepositRequest , error ) {
205+ if len (data )% builderDepositRequestSize != 0 {
206+ return nil , fmt .Errorf ("builder deposit requests: length %d not divisible by %d" , len (data ), builderDepositRequestSize )
207+ }
208+
209+ count := len (data ) / builderDepositRequestSize
210+ deposits := make ([]* gloas.BuilderDepositRequest , count )
211+
212+ for i := range count {
213+ d := data [i * builderDepositRequestSize : (i + 1 )* builderDepositRequestSize ]
214+
215+ var pubkey phase0.BLSPubKey
216+ copy (pubkey [:], d [0 :48 ])
217+
218+ withdrawalCreds := make ([]byte , 32 )
219+ copy (withdrawalCreds , d [48 :80 ])
220+
221+ amount := phase0 .Gwei (binary .LittleEndian .Uint64 (d [80 :88 ]))
222+
223+ var sig phase0.BLSSignature
224+ copy (sig [:], d [88 :184 ])
225+
226+ deposits [i ] = & gloas.BuilderDepositRequest {
227+ Pubkey : pubkey ,
228+ WithdrawalCredentials : withdrawalCreds ,
229+ Amount : amount ,
230+ Signature : sig ,
231+ }
232+ }
233+
234+ return deposits , nil
235+ }
236+
237+ func parseBuilderExitRequests (data []byte ) ([]* gloas.BuilderExitRequest , error ) {
238+ if len (data )% builderExitRequestSize != 0 {
239+ return nil , fmt .Errorf ("builder exit requests: length %d not divisible by %d" , len (data ), builderExitRequestSize )
240+ }
241+
242+ count := len (data ) / builderExitRequestSize
243+ exits := make ([]* gloas.BuilderExitRequest , count )
244+
245+ for i := range count {
246+ d := data [i * builderExitRequestSize : (i + 1 )* builderExitRequestSize ]
247+
248+ var addr bellatrix.ExecutionAddress
249+ copy (addr [:], d [0 :20 ])
250+
251+ var pubkey phase0.BLSPubKey
252+ copy (pubkey [:], d [20 :68 ])
253+
254+ exits [i ] = & gloas.BuilderExitRequest {
255+ SourceAddress : addr ,
256+ Pubkey : pubkey ,
257+ }
258+ }
259+
260+ return exits , nil
261+ }
0 commit comments