@@ -219,6 +219,48 @@ func (t *Task) Execute(ctx context.Context) error {
219219 return nil
220220}
221221
222+ // isFuluActive checks whether the Fulu fork is active by comparing the
223+ // current wallclock epoch against FULU_FORK_EPOCH from the consensus specs.
224+ func (t * Task ) isFuluActive () bool {
225+ blockCache := t .ctx .Scheduler .GetServices ().ClientPool ().
226+ GetConsensusPool ().GetBlockCache ()
227+
228+ specValues := blockCache .GetSpecValues ()
229+ if specValues == nil {
230+ return false
231+ }
232+
233+ fuluEpochVal , ok := specValues ["FULU_FORK_EPOCH" ]
234+ if ! ok {
235+ return false
236+ }
237+
238+ var fuluEpoch uint64
239+
240+ switch v := fuluEpochVal .(type ) {
241+ case uint64 :
242+ fuluEpoch = v
243+ case string :
244+ if _ , err := fmt .Sscanf (v , "%d" , & fuluEpoch ); err != nil {
245+ return false
246+ }
247+ default :
248+ return false
249+ }
250+
251+ wallclock := blockCache .GetWallclock ()
252+ if wallclock == nil {
253+ return false
254+ }
255+
256+ _ , currentEpoch , err := wallclock .Now ()
257+ if err != nil {
258+ return false
259+ }
260+
261+ return currentEpoch .Number () >= fuluEpoch
262+ }
263+
222264func (t * Task ) generateTransaction (ctx context.Context , transactionIdx uint64 , completeFn spamoor.TxCompleteFn ) error {
223265 txWallet := t .wallet
224266 if t .wallet == nil {
@@ -307,6 +349,13 @@ func (t *Task) generateTransaction(ctx context.Context, transactionIdx uint64, c
307349 }
308350 }
309351
352+ walletMgr := t .ctx .Scheduler .GetServices ().WalletManager ()
353+ spamoorClients := make ([]* spamoor.Client , len (clients ))
354+
355+ for i , c := range clients {
356+ spamoorClients [i ] = walletMgr .GetClient (c )
357+ }
358+
310359 blobTx , err := txbuilder .BuildBlobTx (& txbuilder.TxMetadata {
311360 GasFeeCap : uint256 .MustFromBig (t .config .FeeCap ),
312361 GasTipCap : uint256 .MustFromBig (t .config .TipCap ),
@@ -325,11 +374,13 @@ func (t *Task) generateTransaction(ctx context.Context, transactionIdx uint64, c
325374 return fmt .Errorf ("cannot build blob transaction: %w" , err )
326375 }
327376
328- walletMgr := t .ctx .Scheduler .GetServices ().WalletManager ()
329- client := walletMgr .GetClient (clients [transactionIdx % uint64 (len (clients ))])
377+ // Check if Fulu is active to determine blob sidecar version.
378+ // After Fulu, blob sidecars must use v1 format (cell proofs).
379+ useBlobV1 := t .isFuluActive ()
330380
331- err = walletMgr .GetTxPool ().SendTransaction (ctx , txWallet , tx , & spamoor.SendTransactionOptions {
332- Client : client ,
381+ sendOpts := & spamoor.SendTransactionOptions {
382+ Client : spamoorClients [transactionIdx % uint64 (len (spamoorClients ))],
383+ ClientList : spamoorClients ,
333384 Rebroadcast : true ,
334385 OnComplete : completeFn ,
335386 LogFn : func (client * spamoor.Client , retry int , rebroadcast int , err error ) {
@@ -351,7 +402,25 @@ func (t *Task) generateTransaction(ctx context.Context, transactionIdx uint64, c
351402
352403 logEntry .Infof ("submitted blob transaction %v (nonce: %v, attempt: %v)" , transactionIdx , tx .Nonce (), retry )
353404 },
354- })
405+ }
406+
407+ if useBlobV1 {
408+ convertedToV1 := false
409+
410+ sendOpts .OnEncode = func (tx * ethtypes.Transaction ) ([]byte , error ) {
411+ if ! convertedToV1 {
412+ if convErr := tx .BlobTxSidecar ().ToV1 (); convErr != nil {
413+ return nil , fmt .Errorf ("cannot convert blob sidecar to v1: %w" , convErr )
414+ }
415+
416+ convertedToV1 = true
417+ }
418+
419+ return nil , nil
420+ }
421+ }
422+
423+ err = walletMgr .GetTxPool ().SendTransaction (ctx , txWallet , tx , sendOpts )
355424 if err != nil {
356425 txWallet .MarkSkippedNonce (tx .Nonce ())
357426 return err
0 commit comments