You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

604 lines
19 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. package coordinator
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "math/big"
  7. "time"
  8. "github.com/ethereum/go-ethereum"
  9. "github.com/ethereum/go-ethereum/accounts"
  10. "github.com/ethereum/go-ethereum/accounts/abi/bind"
  11. "github.com/ethereum/go-ethereum/core"
  12. "github.com/ethereum/go-ethereum/core/types"
  13. "github.com/hermeznetwork/hermez-node/common"
  14. "github.com/hermeznetwork/hermez-node/db/l2db"
  15. "github.com/hermeznetwork/hermez-node/eth"
  16. "github.com/hermeznetwork/hermez-node/log"
  17. "github.com/hermeznetwork/hermez-node/synchronizer"
  18. "github.com/hermeznetwork/tracerr"
  19. )
  20. // TxManager handles everything related to ethereum transactions: It makes the
  21. // call to forge, waits for transaction confirmation, and keeps checking them
  22. // until a number of confirmed blocks have passed.
  23. type TxManager struct {
  24. cfg Config
  25. ethClient eth.ClientInterface
  26. l2DB *l2db.L2DB // Used only to mark forged txs as forged in the L2DB
  27. coord *Coordinator // Used only to send messages to stop the pipeline
  28. batchCh chan *BatchInfo
  29. chainID *big.Int
  30. account accounts.Account
  31. consts synchronizer.SCConsts
  32. stats synchronizer.Stats
  33. vars synchronizer.SCVariables
  34. statsVarsCh chan statsVars
  35. discardPipelineCh chan int // int refers to the pipelineNum
  36. minPipelineNum int
  37. queue Queue
  38. // lastSuccessBatch stores the last BatchNum that who's forge call was confirmed
  39. lastSuccessBatch common.BatchNum
  40. // lastPendingBatch common.BatchNum
  41. // accNonce is the account nonce in the last mined block (due to mined txs)
  42. accNonce uint64
  43. // accNextNonce is the nonce that we should use to send the next tx.
  44. // In some cases this will be a reused nonce of an already pending tx.
  45. accNextNonce uint64
  46. // accPendingNonce is the pending nonce of the account due to pending txs
  47. // accPendingNonce uint64
  48. lastSentL1BatchBlockNum int64
  49. }
  50. // NewTxManager creates a new TxManager
  51. func NewTxManager(ctx context.Context, cfg *Config, ethClient eth.ClientInterface, l2DB *l2db.L2DB,
  52. coord *Coordinator, scConsts *synchronizer.SCConsts, initSCVars *synchronizer.SCVariables) (*TxManager, error) {
  53. chainID, err := ethClient.EthChainID()
  54. if err != nil {
  55. return nil, tracerr.Wrap(err)
  56. }
  57. address, err := ethClient.EthAddress()
  58. if err != nil {
  59. return nil, tracerr.Wrap(err)
  60. }
  61. accNonce, err := ethClient.EthNonceAt(ctx, *address, nil)
  62. if err != nil {
  63. return nil, err
  64. }
  65. // accPendingNonce, err := ethClient.EthPendingNonceAt(ctx, *address)
  66. // if err != nil {
  67. // return nil, err
  68. // }
  69. // if accNonce != accPendingNonce {
  70. // return nil, tracerr.Wrap(fmt.Errorf("currentNonce (%v) != accPendingNonce (%v)",
  71. // accNonce, accPendingNonce))
  72. // }
  73. log.Infow("TxManager started", "nonce", accNonce)
  74. return &TxManager{
  75. cfg: *cfg,
  76. ethClient: ethClient,
  77. l2DB: l2DB,
  78. coord: coord,
  79. batchCh: make(chan *BatchInfo, queueLen),
  80. statsVarsCh: make(chan statsVars, queueLen),
  81. discardPipelineCh: make(chan int, queueLen),
  82. account: accounts.Account{
  83. Address: *address,
  84. },
  85. chainID: chainID,
  86. consts: *scConsts,
  87. vars: *initSCVars,
  88. minPipelineNum: 0,
  89. queue: NewQueue(),
  90. accNonce: accNonce,
  91. accNextNonce: accNonce,
  92. // accPendingNonce: accPendingNonce,
  93. }, nil
  94. }
  95. // AddBatch is a thread safe method to pass a new batch TxManager to be sent to
  96. // the smart contract via the forge call
  97. func (t *TxManager) AddBatch(ctx context.Context, batchInfo *BatchInfo) {
  98. select {
  99. case t.batchCh <- batchInfo:
  100. case <-ctx.Done():
  101. }
  102. }
  103. // SetSyncStatsVars is a thread safe method to sets the synchronizer Stats
  104. func (t *TxManager) SetSyncStatsVars(ctx context.Context, stats *synchronizer.Stats, vars *synchronizer.SCVariablesPtr) {
  105. select {
  106. case t.statsVarsCh <- statsVars{Stats: *stats, Vars: *vars}:
  107. case <-ctx.Done():
  108. }
  109. }
  110. // DiscardPipeline is a thread safe method to notify about a discarded pipeline
  111. // due to a reorg
  112. func (t *TxManager) DiscardPipeline(ctx context.Context, pipelineNum int) {
  113. select {
  114. case t.discardPipelineCh <- pipelineNum:
  115. case <-ctx.Done():
  116. }
  117. }
  118. func (t *TxManager) syncSCVars(vars synchronizer.SCVariablesPtr) {
  119. updateSCVars(&t.vars, vars)
  120. }
  121. // NewAuth generates a new auth object for an ethereum transaction
  122. func (t *TxManager) NewAuth(ctx context.Context) (*bind.TransactOpts, error) {
  123. gasPrice, err := t.ethClient.EthSuggestGasPrice(ctx)
  124. if err != nil {
  125. return nil, tracerr.Wrap(err)
  126. }
  127. inc := new(big.Int).Set(gasPrice)
  128. // TODO: Replace this by a value of percentage
  129. const gasPriceDiv = 100
  130. inc.Div(inc, new(big.Int).SetUint64(gasPriceDiv))
  131. gasPrice.Add(gasPrice, inc)
  132. // log.Debugw("TxManager: transaction metadata", "gasPrice", gasPrice)
  133. auth, err := bind.NewKeyStoreTransactorWithChainID(t.ethClient.EthKeyStore(), t.account, t.chainID)
  134. if err != nil {
  135. return nil, tracerr.Wrap(err)
  136. }
  137. auth.Value = big.NewInt(0) // in wei
  138. // TODO: Calculate GasLimit based on the contents of the ForgeBatchArgs
  139. auth.GasLimit = 1000000
  140. auth.GasPrice = gasPrice
  141. auth.Nonce = nil
  142. return auth, nil
  143. }
  144. func (t *TxManager) shouldSendRollupForgeBatch(batchInfo *BatchInfo) error {
  145. nextBlock := t.stats.Eth.LastBlock.Num + 1
  146. if !t.canForgeAt(nextBlock) {
  147. return tracerr.Wrap(fmt.Errorf("can't forge in the next block: %v", nextBlock))
  148. }
  149. if t.mustL1L2Batch(nextBlock) && !batchInfo.L1Batch {
  150. return tracerr.Wrap(fmt.Errorf("can't forge non-L1Batch in the next block: %v", nextBlock))
  151. }
  152. margin := t.cfg.SendBatchBlocksMarginCheck
  153. if margin != 0 {
  154. if !t.canForgeAt(nextBlock + margin) {
  155. return tracerr.Wrap(fmt.Errorf("can't forge after %v blocks: %v",
  156. margin, nextBlock))
  157. }
  158. if t.mustL1L2Batch(nextBlock+margin) && !batchInfo.L1Batch {
  159. return tracerr.Wrap(fmt.Errorf("can't forge non-L1Batch after %v blocks: %v",
  160. margin, nextBlock))
  161. }
  162. }
  163. return nil
  164. }
  165. func addPerc(v *big.Int, p int64) *big.Int {
  166. r := new(big.Int).Set(v)
  167. r.Mul(r, big.NewInt(p))
  168. // nolint reason: to calculate percetnages we divide by 100
  169. r.Div(r, big.NewInt(100)) //nolit:gomnd
  170. return r.Add(v, r)
  171. }
  172. func (t *TxManager) sendRollupForgeBatch(ctx context.Context, batchInfo *BatchInfo, resend bool) error {
  173. var ethTx *types.Transaction
  174. var err error
  175. auth, err := t.NewAuth(ctx)
  176. if err != nil {
  177. return tracerr.Wrap(err)
  178. }
  179. auth.Nonce = big.NewInt(int64(t.accNextNonce))
  180. if resend {
  181. auth.Nonce = big.NewInt(int64(batchInfo.EthTx.Nonce()))
  182. }
  183. for attempt := 0; attempt < t.cfg.EthClientAttempts; attempt++ {
  184. if auth.GasPrice.Cmp(t.cfg.MaxGasPrice) > 0 {
  185. return tracerr.Wrap(fmt.Errorf("calculated gasPrice (%v) > maxGasPrice (%v)",
  186. auth.GasPrice, t.cfg.MaxGasPrice))
  187. }
  188. // RollupForgeBatch() calls ethclient.SendTransaction()
  189. ethTx, err = t.ethClient.RollupForgeBatch(batchInfo.ForgeBatchArgs, auth)
  190. if errors.Is(err, core.ErrNonceTooLow) {
  191. log.Warnw("TxManager ethClient.RollupForgeBatch incrementing nonce",
  192. "err", err, "nonce", auth.Nonce, "batchNum", batchInfo.BatchNum)
  193. auth.Nonce.Add(auth.Nonce, big.NewInt(1))
  194. attempt--
  195. } else if errors.Is(err, core.ErrNonceTooHigh) {
  196. log.Warnw("TxManager ethClient.RollupForgeBatch decrementing nonce",
  197. "err", err, "nonce", auth.Nonce, "batchNum", batchInfo.BatchNum)
  198. auth.Nonce.Sub(auth.Nonce, big.NewInt(1))
  199. attempt--
  200. } else if errors.Is(err, core.ErrUnderpriced) {
  201. log.Warnw("TxManager ethClient.RollupForgeBatch incrementing gasPrice",
  202. "err", err, "gasPrice", auth.GasPrice, "batchNum", batchInfo.BatchNum)
  203. auth.GasPrice = addPerc(auth.GasPrice, 10)
  204. attempt--
  205. } else if errors.Is(err, core.ErrReplaceUnderpriced) {
  206. log.Warnw("TxManager ethClient.RollupForgeBatch incrementing gasPrice",
  207. "err", err, "gasPrice", auth.GasPrice, "batchNum", batchInfo.BatchNum)
  208. auth.GasPrice = addPerc(auth.GasPrice, 10)
  209. attempt--
  210. } else if err != nil {
  211. log.Errorw("TxManager ethClient.RollupForgeBatch",
  212. "attempt", attempt, "err", err, "block", t.stats.Eth.LastBlock.Num+1,
  213. "batchNum", batchInfo.BatchNum)
  214. } else {
  215. break
  216. }
  217. select {
  218. case <-ctx.Done():
  219. return tracerr.Wrap(common.ErrDone)
  220. case <-time.After(t.cfg.EthClientAttemptsDelay):
  221. }
  222. }
  223. if err != nil {
  224. return tracerr.Wrap(fmt.Errorf("reached max attempts for ethClient.RollupForgeBatch: %w", err))
  225. }
  226. if !resend {
  227. t.accNextNonce = auth.Nonce.Uint64() + 1
  228. }
  229. batchInfo.EthTx = ethTx
  230. log.Infow("TxManager ethClient.RollupForgeBatch", "batch", batchInfo.BatchNum, "tx", ethTx.Hash())
  231. now := time.Now()
  232. batchInfo.SendTimestamp = now
  233. if resend {
  234. batchInfo.Debug.ResendNum++
  235. }
  236. batchInfo.Debug.Status = StatusSent
  237. batchInfo.Debug.SendBlockNum = t.stats.Eth.LastBlock.Num + 1
  238. batchInfo.Debug.SendTimestamp = batchInfo.SendTimestamp
  239. batchInfo.Debug.StartToSendDelay = batchInfo.Debug.SendTimestamp.Sub(
  240. batchInfo.Debug.StartTimestamp).Seconds()
  241. t.cfg.debugBatchStore(batchInfo)
  242. // t.lastPendingBatch = batchInfo.BatchNum
  243. if !resend {
  244. if batchInfo.L1Batch {
  245. t.lastSentL1BatchBlockNum = t.stats.Eth.LastBlock.Num + 1
  246. }
  247. }
  248. if err := t.l2DB.DoneForging(common.TxIDsFromL2Txs(batchInfo.L2Txs), batchInfo.BatchNum); err != nil {
  249. return tracerr.Wrap(err)
  250. }
  251. return nil
  252. }
  253. // checkEthTransactionReceipt takes the txHash from the BatchInfo and stores
  254. // the corresponding receipt if found
  255. func (t *TxManager) checkEthTransactionReceipt(ctx context.Context, batchInfo *BatchInfo) error {
  256. txHash := batchInfo.EthTx.Hash()
  257. var receipt *types.Receipt
  258. var err error
  259. for attempt := 0; attempt < t.cfg.EthClientAttempts; attempt++ {
  260. receipt, err = t.ethClient.EthTransactionReceipt(ctx, txHash)
  261. if ctx.Err() != nil {
  262. continue
  263. } else if tracerr.Unwrap(err) == ethereum.NotFound {
  264. err = nil
  265. break
  266. } else if err != nil {
  267. log.Errorw("TxManager ethClient.EthTransactionReceipt",
  268. "attempt", attempt, "err", err)
  269. } else {
  270. break
  271. }
  272. select {
  273. case <-ctx.Done():
  274. return tracerr.Wrap(common.ErrDone)
  275. case <-time.After(t.cfg.EthClientAttemptsDelay):
  276. }
  277. }
  278. if err != nil {
  279. return tracerr.Wrap(fmt.Errorf("reached max attempts for ethClient.EthTransactionReceipt: %w", err))
  280. }
  281. batchInfo.Receipt = receipt
  282. t.cfg.debugBatchStore(batchInfo)
  283. return nil
  284. }
  285. func (t *TxManager) handleReceipt(ctx context.Context, batchInfo *BatchInfo) (*int64, error) {
  286. receipt := batchInfo.Receipt
  287. if receipt != nil {
  288. if batchInfo.EthTx.Nonce()+1 > t.accNonce {
  289. t.accNonce = batchInfo.EthTx.Nonce() + 1
  290. }
  291. if receipt.Status == types.ReceiptStatusFailed {
  292. batchInfo.Debug.Status = StatusFailed
  293. t.cfg.debugBatchStore(batchInfo)
  294. _, err := t.ethClient.EthCall(ctx, batchInfo.EthTx, receipt.BlockNumber)
  295. log.Warnw("TxManager receipt status is failed", "tx", receipt.TxHash,
  296. "batch", batchInfo.BatchNum, "block", receipt.BlockNumber.Int64(),
  297. "err", err)
  298. if batchInfo.BatchNum <= t.lastSuccessBatch {
  299. t.lastSuccessBatch = batchInfo.BatchNum - 1
  300. }
  301. return nil, tracerr.Wrap(fmt.Errorf(
  302. "ethereum transaction receipt status is failed: %w", err))
  303. } else if receipt.Status == types.ReceiptStatusSuccessful {
  304. batchInfo.Debug.Status = StatusMined
  305. batchInfo.Debug.MineBlockNum = receipt.BlockNumber.Int64()
  306. batchInfo.Debug.StartToMineBlocksDelay = batchInfo.Debug.MineBlockNum -
  307. batchInfo.Debug.StartBlockNum
  308. if batchInfo.Debug.StartToMineDelay == 0 {
  309. if block, err := t.ethClient.EthBlockByNumber(ctx,
  310. receipt.BlockNumber.Int64()); err != nil {
  311. log.Warnw("TxManager: ethClient.EthBlockByNumber", "err", err)
  312. } else {
  313. batchInfo.Debug.SendToMineDelay = block.Timestamp.Sub(
  314. batchInfo.Debug.SendTimestamp).Seconds()
  315. batchInfo.Debug.StartToMineDelay = block.Timestamp.Sub(
  316. batchInfo.Debug.StartTimestamp).Seconds()
  317. }
  318. }
  319. t.cfg.debugBatchStore(batchInfo)
  320. if batchInfo.BatchNum > t.lastSuccessBatch {
  321. t.lastSuccessBatch = batchInfo.BatchNum
  322. }
  323. confirm := t.stats.Eth.LastBlock.Num - receipt.BlockNumber.Int64()
  324. return &confirm, nil
  325. }
  326. }
  327. return nil, nil
  328. }
  329. // TODO:
  330. // - After sending a message: CancelPipeline, stop all consecutive pending Batches (transactions)
  331. // Queue of BatchInfos
  332. type Queue struct {
  333. list []*BatchInfo
  334. // nonceByBatchNum map[common.BatchNum]uint64
  335. next int
  336. }
  337. // NewQueue returns a new queue
  338. func NewQueue() Queue {
  339. return Queue{
  340. list: make([]*BatchInfo, 0),
  341. // nonceByBatchNum: make(map[common.BatchNum]uint64),
  342. next: 0,
  343. }
  344. }
  345. // Len is the length of the queue
  346. func (q *Queue) Len() int {
  347. return len(q.list)
  348. }
  349. // At returns the BatchInfo at position (or nil if position is out of bounds)
  350. func (q *Queue) At(position int) *BatchInfo {
  351. if position >= len(q.list) {
  352. return nil
  353. }
  354. return q.list[position]
  355. }
  356. // Next returns the next BatchInfo (or nil if queue is empty)
  357. func (q *Queue) Next() (int, *BatchInfo) {
  358. if len(q.list) == 0 {
  359. return 0, nil
  360. }
  361. defer func() { q.next = (q.next + 1) % len(q.list) }()
  362. return q.next, q.list[q.next]
  363. }
  364. // Remove removes the BatchInfo at position
  365. func (q *Queue) Remove(position int) {
  366. // batchInfo := q.list[position]
  367. // delete(q.nonceByBatchNum, batchInfo.BatchNum)
  368. q.list = append(q.list[:position], q.list[position+1:]...)
  369. if len(q.list) == 0 {
  370. q.next = 0
  371. } else {
  372. q.next = position % len(q.list)
  373. }
  374. }
  375. // Push adds a new BatchInfo
  376. func (q *Queue) Push(batchInfo *BatchInfo) {
  377. q.list = append(q.list, batchInfo)
  378. // q.nonceByBatchNum[batchInfo.BatchNum] = batchInfo.EthTx.Nonce()
  379. }
  380. // func (q *Queue) NonceByBatchNum(batchNum common.BatchNum) (uint64, bool) {
  381. // nonce, ok := q.nonceByBatchNum[batchNum]
  382. // return nonce, ok
  383. // }
  384. // Run the TxManager
  385. func (t *TxManager) Run(ctx context.Context) {
  386. waitDuration := longWaitDuration
  387. var statsVars statsVars
  388. select {
  389. case statsVars = <-t.statsVarsCh:
  390. case <-ctx.Done():
  391. }
  392. t.stats = statsVars.Stats
  393. t.syncSCVars(statsVars.Vars)
  394. log.Infow("TxManager: received initial statsVars",
  395. "block", t.stats.Eth.LastBlock.Num, "batch", t.stats.Eth.LastBatchNum)
  396. for {
  397. select {
  398. case <-ctx.Done():
  399. log.Info("TxManager done")
  400. return
  401. case statsVars := <-t.statsVarsCh:
  402. t.stats = statsVars.Stats
  403. t.syncSCVars(statsVars.Vars)
  404. case pipelineNum := <-t.discardPipelineCh:
  405. t.minPipelineNum = pipelineNum + 1
  406. if err := t.removeBadBatchInfos(ctx); ctx.Err() != nil {
  407. continue
  408. } else if err != nil {
  409. log.Errorw("TxManager: removeBadBatchInfos", "err", err)
  410. continue
  411. }
  412. case batchInfo := <-t.batchCh:
  413. if batchInfo.PipelineNum < t.minPipelineNum {
  414. log.Warnw("TxManager: batchInfo received pipelineNum < minPipelineNum",
  415. "num", batchInfo.PipelineNum, "minNum", t.minPipelineNum)
  416. }
  417. if err := t.shouldSendRollupForgeBatch(batchInfo); err != nil {
  418. log.Warnw("TxManager: shouldSend", "err", err,
  419. "batch", batchInfo.BatchNum)
  420. t.coord.SendMsg(ctx, MsgStopPipeline{
  421. Reason: fmt.Sprintf("forgeBatch shouldSend: %v", err)})
  422. continue
  423. }
  424. if err := t.sendRollupForgeBatch(ctx, batchInfo, false); ctx.Err() != nil {
  425. continue
  426. } else if err != nil {
  427. // If we reach here it's because our ethNode has
  428. // been unable to send the transaction to
  429. // ethereum. This could be due to the ethNode
  430. // failure, or an invalid transaction (that
  431. // can't be mined)
  432. log.Warnw("TxManager: forgeBatch send failed", "err", err,
  433. "batch", batchInfo.BatchNum)
  434. t.coord.SendMsg(ctx, MsgStopPipeline{
  435. Reason: fmt.Sprintf("forgeBatch send: %v", err)})
  436. continue
  437. }
  438. t.queue.Push(batchInfo)
  439. waitDuration = t.cfg.TxManagerCheckInterval
  440. case <-time.After(waitDuration):
  441. queuePosition, batchInfo := t.queue.Next()
  442. if batchInfo == nil {
  443. waitDuration = longWaitDuration
  444. continue
  445. }
  446. if err := t.checkEthTransactionReceipt(ctx, batchInfo); ctx.Err() != nil {
  447. continue
  448. } else if err != nil { //nolint:staticcheck
  449. // Our ethNode is giving an error different
  450. // than "not found" when getting the receipt
  451. // for the transaction, so we can't figure out
  452. // if it was not mined, mined and succesfull or
  453. // mined and failed. This could be due to the
  454. // ethNode failure.
  455. t.coord.SendMsg(ctx, MsgStopPipeline{
  456. Reason: fmt.Sprintf("forgeBatch receipt: %v", err)})
  457. }
  458. confirm, err := t.handleReceipt(ctx, batchInfo)
  459. if ctx.Err() != nil {
  460. continue
  461. } else if err != nil { //nolint:staticcheck
  462. // Transaction was rejected
  463. if err := t.removeBadBatchInfos(ctx); ctx.Err() != nil {
  464. continue
  465. } else if err != nil {
  466. log.Errorw("TxManager: removeBadBatchInfos", "err", err)
  467. continue
  468. }
  469. t.coord.SendMsg(ctx, MsgStopPipeline{
  470. Reason: fmt.Sprintf("forgeBatch reject: %v", err)})
  471. continue
  472. }
  473. now := time.Now()
  474. if !t.cfg.EthNoReuseNonce && confirm == nil &&
  475. now.Sub(batchInfo.SendTimestamp) > t.cfg.EthTxResendTimeout {
  476. log.Infow("TxManager: forgeBatch tx not been mined timeout, resending",
  477. "tx", batchInfo.EthTx.Hash(), "batch", batchInfo.BatchNum)
  478. if err := t.sendRollupForgeBatch(ctx, batchInfo, true); ctx.Err() != nil {
  479. continue
  480. } else if err != nil {
  481. // If we reach here it's because our ethNode has
  482. // been unable to send the transaction to
  483. // ethereum. This could be due to the ethNode
  484. // failure, or an invalid transaction (that
  485. // can't be mined)
  486. log.Warnw("TxManager: forgeBatch resend failed", "err", err,
  487. "batch", batchInfo.BatchNum)
  488. t.coord.SendMsg(ctx, MsgStopPipeline{
  489. Reason: fmt.Sprintf("forgeBatch resend: %v", err)})
  490. continue
  491. }
  492. }
  493. if confirm != nil && *confirm >= t.cfg.ConfirmBlocks {
  494. log.Debugw("TxManager: forgeBatch tx confirmed",
  495. "tx", batchInfo.EthTx.Hash(), "batch", batchInfo.BatchNum)
  496. t.queue.Remove(queuePosition)
  497. }
  498. }
  499. }
  500. }
  501. func (t *TxManager) removeBadBatchInfos(ctx context.Context) error {
  502. next := 0
  503. // batchNum := 0
  504. for {
  505. batchInfo := t.queue.At(next)
  506. if batchInfo == nil {
  507. break
  508. }
  509. if err := t.checkEthTransactionReceipt(ctx, batchInfo); ctx.Err() != nil {
  510. return nil
  511. } else if err != nil {
  512. // Our ethNode is giving an error different
  513. // than "not found" when getting the receipt
  514. // for the transaction, so we can't figure out
  515. // if it was not mined, mined and succesfull or
  516. // mined and failed. This could be due to the
  517. // ethNode failure.
  518. next++
  519. continue
  520. }
  521. confirm, err := t.handleReceipt(ctx, batchInfo)
  522. if ctx.Err() != nil {
  523. return nil
  524. } else if err != nil {
  525. // Transaction was rejected
  526. if t.minPipelineNum <= batchInfo.PipelineNum {
  527. t.minPipelineNum = batchInfo.PipelineNum + 1
  528. }
  529. t.queue.Remove(next)
  530. continue
  531. }
  532. // If tx is pending but is from a cancelled pipeline, remove it
  533. // from the queue
  534. if confirm == nil {
  535. if batchInfo.PipelineNum < t.minPipelineNum {
  536. // batchNum++
  537. t.queue.Remove(next)
  538. continue
  539. }
  540. }
  541. next++
  542. }
  543. accNonce, err := t.ethClient.EthNonceAt(ctx, t.account.Address, nil)
  544. if err != nil {
  545. return err
  546. }
  547. if !t.cfg.EthNoReuseNonce {
  548. t.accNextNonce = accNonce
  549. }
  550. return nil
  551. }
  552. func (t *TxManager) canForgeAt(blockNum int64) bool {
  553. return canForge(&t.consts.Auction, &t.vars.Auction,
  554. &t.stats.Sync.Auction.CurrentSlot, &t.stats.Sync.Auction.NextSlot,
  555. t.cfg.ForgerAddress, blockNum)
  556. }
  557. func (t *TxManager) mustL1L2Batch(blockNum int64) bool {
  558. lastL1BatchBlockNum := t.lastSentL1BatchBlockNum
  559. if t.stats.Sync.LastL1BatchBlock > lastL1BatchBlockNum {
  560. lastL1BatchBlockNum = t.stats.Sync.LastL1BatchBlock
  561. }
  562. return blockNum-lastL1BatchBlockNum >= t.vars.Rollup.ForgeL1L2BatchTimeout-1
  563. }