@@ -13,50 +13,63 @@ import (
1313 flowGo "github.com/onflow/flow-go/model/flow"
1414 "github.com/rs/zerolog"
1515 "github.com/sethvargo/go-retry"
16- "golang.org/x/sync/errgroup"
1716
1817 "github.com/onflow/flow-evm-gateway/config"
1918 "github.com/onflow/flow-evm-gateway/metrics"
2019 "github.com/onflow/flow-evm-gateway/models"
2120 "github.com/onflow/flow-evm-gateway/services/requester/keystore"
2221)
2322
23+ var blockHeaderUpdateFrequency = time .Second * 5
24+
2425// SingleTxPool is a simple implementation of the `TxPool` interface that submits
2526// transactions as soon as they arrive, without any delays or batching strategies.
2627type SingleTxPool struct {
27- logger zerolog.Logger
28- client * CrossSporkClient
29- pool * sync.Map
30- txPublisher * models.Publisher [* gethTypes.Transaction ]
31- config config.Config
32- mux sync.Mutex
33- keystore * keystore.KeyStore
34- collector metrics.Collector
28+ logger zerolog.Logger
29+ client * CrossSporkClient
30+ pool * sync.Map
31+ txPublisher * models.Publisher [* gethTypes.Transaction ]
32+ config config.Config
33+ mux sync.Mutex
34+ keystore * keystore.KeyStore
35+ collector metrics.Collector
36+ latestBlockHeader * flow.BlockHeader
3537 // todo add methods to inspect transaction pool state
3638}
3739
3840var _ TxPool = & SingleTxPool {}
3941
4042func NewSingleTxPool (
43+ ctx context.Context ,
4144 client * CrossSporkClient ,
4245 transactionsPublisher * models.Publisher [* gethTypes.Transaction ],
4346 logger zerolog.Logger ,
4447 config config.Config ,
4548 collector metrics.Collector ,
4649 keystore * keystore.KeyStore ,
47- ) * SingleTxPool {
50+ ) (* SingleTxPool , error ) {
51+ latestBlockHeader , err := client .GetLatestBlockHeader (ctx , false )
52+ if err != nil {
53+ return nil , err
54+ }
55+
4856 // initialize the available keys metric since it is only updated when sending a tx
4957 collector .AvailableSigningKeys (keystore .AvailableKeys ())
5058
51- return & SingleTxPool {
52- logger : logger .With ().Str ("component" , "tx-pool" ).Logger (),
53- client : client ,
54- txPublisher : transactionsPublisher ,
55- pool : & sync.Map {},
56- config : config ,
57- collector : collector ,
58- keystore : keystore ,
59+ singleTxPool := & SingleTxPool {
60+ logger : logger .With ().Str ("component" , "tx-pool" ).Logger (),
61+ client : client ,
62+ txPublisher : transactionsPublisher ,
63+ pool : & sync.Map {},
64+ config : config ,
65+ collector : collector ,
66+ keystore : keystore ,
67+ latestBlockHeader : latestBlockHeader ,
5968 }
69+
70+ go singleTxPool .trackLatestBlockHeader (ctx )
71+
72+ return singleTxPool , nil
6073}
6174
6275// Add creates a Cadence transaction that wraps the given EVM transaction in
@@ -93,14 +106,14 @@ func (t *SingleTxPool) Add(
93106 return err
94107 }
95108
96- latestBlock , account , err := t .fetchFlowLatestBlockAndCOA (ctx )
109+ account , err := t .client . GetAccount (ctx , t . config . COAAddress )
97110 if err != nil {
98111 return err
99112 }
100113
101114 script := replaceAddresses (runTxScript , t .config .FlowNetworkID )
102115 flowTx , err := t .buildTransaction (
103- latestBlock ,
116+ t . latestBlockHeader ,
104117 account ,
105118 script ,
106119 hexEncodedTx ,
@@ -157,7 +170,7 @@ func (t *SingleTxPool) Add(
157170// buildTransaction creates a Cadence transaction from the provided script,
158171// with the given arguments and signs it with the configured COA account.
159172func (t * SingleTxPool ) buildTransaction (
160- latestBlock * flow.Block ,
173+ latestBlockHeader * flow.BlockHeader ,
161174 account * flow.Account ,
162175 script []byte ,
163176 args ... cadence.Value ,
@@ -168,7 +181,7 @@ func (t *SingleTxPool) buildTransaction(
168181
169182 flowTx := flow .NewTransaction ().
170183 SetScript (script ).
171- SetReferenceBlockID (latestBlock .ID ).
184+ SetReferenceBlockID (latestBlockHeader .ID ).
172185 SetComputeLimit (flowGo .DefaultMaxTransactionGasLimit )
173186
174187 for _ , arg := range args {
@@ -193,37 +206,30 @@ func (t *SingleTxPool) buildTransaction(
193206 }
194207
195208 // now that the transaction is prepared, store the transaction's metadata
196- accKey .SetLockMetadata (flowTx .ID (), latestBlock .Height )
209+ accKey .SetLockMetadata (flowTx .ID (), latestBlockHeader .Height )
197210
198211 t .collector .OperatorBalance (account )
199212
200213 return flowTx , nil
201214}
202215
203- func (t * SingleTxPool ) fetchFlowLatestBlockAndCOA (ctx context.Context ) (
204- * flow.Block ,
205- * flow.Account ,
206- error ,
207- ) {
208- var (
209- g = errgroup.Group {}
210- err1 , err2 error
211- latestBlock * flow.Block
212- account * flow.Account
213- )
216+ func (t * SingleTxPool ) trackLatestBlockHeader (ctx context.Context ) {
217+ ticker := time .NewTicker (blockHeaderUpdateFrequency )
218+ defer ticker .Stop ()
214219
215- // execute concurrently so we can speed up all the information we need for tx
216- g .Go (func () error {
217- latestBlock , err1 = t .client .GetLatestBlock (ctx , true )
218- return err1
219- })
220- g .Go (func () error {
221- account , err2 = t .client .GetAccount (ctx , t .config .COAAddress )
222- return err2
223- })
224- if err := g .Wait (); err != nil {
225- return nil , nil , err
220+ for {
221+ select {
222+ case <- ctx .Done ():
223+ return
224+ case <- ticker .C :
225+ blockHeader , err := t .client .GetLatestBlockHeader (ctx , false )
226+ if err != nil {
227+ t .logger .Error ().Err (err ).Msg (
228+ "failed to update latest Flow block header" ,
229+ )
230+ continue
231+ }
232+ t .latestBlockHeader = blockHeader
233+ }
226234 }
227-
228- return latestBlock , account , nil
229235}
0 commit comments