From ea093591f7201df374d710ea3af8275f28db8f04 Mon Sep 17 00:00:00 2001 From: istae <14264581+istae@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:29:22 +0300 Subject: [PATCH] fix(transaction): swallow estimate gas error --- pkg/storageincentives/agent.go | 10 +-- pkg/transaction/transaction.go | 3 +- pkg/transaction/transaction_test.go | 121 ++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 6 deletions(-) diff --git a/pkg/storageincentives/agent.go b/pkg/storageincentives/agent.go index 16e7770c859..51a62393a8c 100644 --- a/pkg/storageincentives/agent.go +++ b/pkg/storageincentives/agent.go @@ -131,7 +131,7 @@ func (a *Agent) start(blockTime time.Duration, blocksPerRound, blocksPerPhase ui phaseEvents := newEvents() defer phaseEvents.Close() - logPhaseResult := func(phase PhaseType, round uint64, err error) { + logErr := func(phase PhaseType, round uint64, err error) { if err != nil { a.logger.Error(err, "phase failed", "phase", phase, "round", round) } @@ -142,13 +142,13 @@ func (a *Agent) start(blockTime time.Duration, blocksPerRound, blocksPerPhase ui round, _ := a.state.currentRoundAndPhase() err := a.handleCommit(ctx, round) - logPhaseResult(commit, round, err) + logErr(commit, round, err) }) phaseEvents.On(reveal, func(ctx context.Context) { phaseEvents.Cancel(commit, sample) round, _ := a.state.currentRoundAndPhase() - logPhaseResult(reveal, round, a.handleReveal(ctx, round)) + logErr(reveal, round, a.handleReveal(ctx, round)) }) phaseEvents.On(claim, func(ctx context.Context) { @@ -156,13 +156,13 @@ func (a *Agent) start(blockTime time.Duration, blocksPerRound, blocksPerPhase ui phaseEvents.Publish(sample) round, _ := a.state.currentRoundAndPhase() - logPhaseResult(claim, round, a.handleClaim(ctx, round)) + logErr(claim, round, a.handleClaim(ctx, round)) }) phaseEvents.On(sample, func(ctx context.Context) { round, _ := a.state.currentRoundAndPhase() isPhasePlayed, err := a.handleSample(ctx, round) - logPhaseResult(sample, round, err) + logErr(sample, round, err) // Sample handled could potentially take long time, therefore it could overlap with commit // phase of next round. When that case happens commit event needs to be triggered once more diff --git a/pkg/transaction/transaction.go b/pkg/transaction/transaction.go index c4246631023..05a07fbf461 100644 --- a/pkg/transaction/transaction.go +++ b/pkg/transaction/transaction.go @@ -282,7 +282,8 @@ func (t *transactionService) prepareTransaction(ctx context.Context, request *Tx Data: request.Data, }) if err != nil { - return nil, err + t.logger.Debug("estimage gas failed", "error", err) + gasLimit = request.MinEstimatedGasLimit } gasLimit += gasLimit / 4 // add 25% on top diff --git a/pkg/transaction/transaction_test.go b/pkg/transaction/transaction_test.go index 60e0989a8a0..8794fd33281 100644 --- a/pkg/transaction/transaction_test.go +++ b/pkg/transaction/transaction_test.go @@ -7,6 +7,7 @@ package transaction_test import ( "bytes" "context" + "errors" "fmt" "math/big" "testing" @@ -213,6 +214,126 @@ func TestTransactionSend(t *testing.T) { } }) + t.Run("send with estimate error", func(t *testing.T) { + t.Parallel() + + signedTx := types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + To: &recipient, + Value: value, + Gas: estimatedGasLimit, + GasFeeCap: defaultGasFee, + GasTipCap: suggestedGasTip, + Data: txData, + }) + request := &transaction.TxRequest{ + To: &recipient, + Data: txData, + Value: value, + MinEstimatedGasLimit: estimatedGasLimit, + } + store := storemock.NewStateStore() + err := store.Put(nonceKey(sender), nonce) + if err != nil { + t.Fatal(err) + } + + transactionService, err := transaction.NewService(logger, + backendmock.New( + backendmock.WithSendTransactionFunc(func(ctx context.Context, tx *types.Transaction) error { + if tx != signedTx { + t.Fatal("not sending signed transaction") + } + return nil + }), + backendmock.WithEstimateGasFunc(func(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) { + return 0, errors.New("estimate failure") + }), + backendmock.WithSuggestGasPriceFunc(func(ctx context.Context) (*big.Int, error) { + return suggestedGasPrice, nil + }), + backendmock.WithPendingNonceAtFunc(func(ctx context.Context, account common.Address) (uint64, error) { + return nonce - 1, nil + }), + backendmock.WithSuggestGasTipCapFunc(func(ctx context.Context) (*big.Int, error) { + return suggestedGasTip, nil + }), + ), + signerMockForTransaction(t, signedTx, sender, chainID), + store, + chainID, + monitormock.New( + monitormock.WithWatchTransactionFunc(func(txHash common.Hash, nonce uint64) (<-chan types.Receipt, <-chan error, error) { + return nil, nil, nil + }), + ), + ) + if err != nil { + t.Fatal(err) + } + testutil.CleanupCloser(t, transactionService) + + txHash, err := transactionService.Send(context.Background(), request, 0) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(txHash.Bytes(), signedTx.Hash().Bytes()) { + t.Fatal("returning wrong transaction hash") + } + + var storedNonce uint64 + err = store.Get(nonceKey(sender), &storedNonce) + if err != nil { + t.Fatal(err) + } + if storedNonce != nonce+1 { + t.Fatalf("nonce not stored correctly: want %d, got %d", nonce+1, storedNonce) + } + + storedTransaction, err := transactionService.StoredTransaction(txHash) + if err != nil { + t.Fatal(err) + } + + if storedTransaction.To == nil || *storedTransaction.To != recipient { + t.Fatalf("got wrong recipient in stored transaction. wanted %x, got %x", recipient, storedTransaction.To) + } + + if !bytes.Equal(storedTransaction.Data, request.Data) { + t.Fatalf("got wrong data in stored transaction. wanted %x, got %x", request.Data, storedTransaction.Data) + } + + if storedTransaction.Description != request.Description { + t.Fatalf("got wrong description in stored transaction. wanted %x, got %x", request.Description, storedTransaction.Description) + } + + if storedTransaction.GasLimit != estimatedGasLimit { + t.Fatalf("got wrong gas limit in stored transaction. wanted %d, got %d", estimatedGasLimit, storedTransaction.GasLimit) + } + + if defaultGasFee.Cmp(storedTransaction.GasPrice) != 0 { + t.Fatalf("got wrong gas price in stored transaction. wanted %d, got %d", defaultGasFee, storedTransaction.GasPrice) + } + + if storedTransaction.Nonce != nonce { + t.Fatalf("got wrong nonce in stored transaction. wanted %d, got %d", nonce, storedTransaction.Nonce) + } + + pending, err := transactionService.PendingTransactions() + if err != nil { + t.Fatal(err) + } + if len(pending) != 1 { + t.Fatalf("expected one pending transaction, got %d", len(pending)) + } + + if pending[0] != txHash { + t.Fatalf("got wrong pending transaction. wanted %x, got %x", txHash, pending[0]) + } + }) + t.Run("sendWithBoost", func(t *testing.T) { t.Parallel()