From 6bfc1bed08908a9d981483a0c734f226d1cedb68 Mon Sep 17 00:00:00 2001 From: Sale Djenic Date: Tue, 19 Dec 2023 14:38:01 +0100 Subject: [PATCH] chore: read and use nonce from network instead from the local cache when sending tx Reading the Nonce from the local cache may be incorrect if the tx is made out of the Status app or if Status app sends a tx prepared by the dapp (via WalletConnect). A submitted tx with a wrong Nonce results in a failing tx, that's why we need to read the Nonce from the network. --- services/wallet/bridge/bridge.go | 2 +- services/wallet/bridge/cbridge.go | 5 +- services/wallet/bridge/erc721_transfer.go | 21 ++-- services/wallet/bridge/hop.go | 21 ++-- services/wallet/bridge/transfer.go | 2 +- .../wallet/transfer/transaction_manager.go | 17 +--- .../transaction_manager_multitransaction.go | 11 +-- transactions/nonce.go | 73 -------------- transactions/transactor.go | 66 +++++-------- transactions/transactor_test.go | 95 +++---------------- 10 files changed, 58 insertions(+), 255 deletions(-) delete mode 100644 transactions/nonce.go diff --git a/services/wallet/bridge/bridge.go b/services/wallet/bridge/bridge.go index 7539d4007..057e45ab6 100644 --- a/services/wallet/bridge/bridge.go +++ b/services/wallet/bridge/bridge.go @@ -96,5 +96,5 @@ type Bridge interface { CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (types.Hash, error) GetContractAddress(network *params.Network, token *token.Token) *common.Address - BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, transactions.UnlockNonceFunc, error) + BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, error) } diff --git a/services/wallet/bridge/cbridge.go b/services/wallet/bridge/cbridge.go index 25397e312..c86f33464 100644 --- a/services/wallet/bridge/cbridge.go +++ b/services/wallet/bridge/cbridge.go @@ -362,9 +362,8 @@ func (s *CBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.Sel return types.Hash(tx.Hash()), nil } -func (s *CBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, transactions.UnlockNonceFunc, error) { - tx, err := s.sendOrBuild(sendArgs, nil) - return tx, nil, err +func (s *CBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, error) { + return s.sendOrBuild(sendArgs, nil) } func (s *CBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) { diff --git a/services/wallet/bridge/erc721_transfer.go b/services/wallet/bridge/erc721_transfer.go index a5a52fe05..1616f6992 100644 --- a/services/wallet/bridge/erc721_transfer.go +++ b/services/wallet/bridge/erc721_transfer.go @@ -98,20 +98,20 @@ func (s *ERC721TransferBridge) EstimateGas(fromNetwork *params.Network, toNetwor return uint64(increasedEstimation), nil } -func (s *ERC721TransferBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn bind.SignerFn) (tx *ethTypes.Transaction, unlock transactions.UnlockNonceFunc, err error) { +func (s *ERC721TransferBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn bind.SignerFn) (tx *ethTypes.Transaction, err error) { ethClient, err := s.rpcClient.EthClient(sendArgs.ChainID) if err != nil { - return tx, nil, err + return tx, err } contract, err := collectibles.NewCollectibles(common.Address(*sendArgs.ERC721TransferTx.To), ethClient) if err != nil { - return tx, nil, err + return tx, err } - nonce, unlock, err := s.transactor.NextNonce(s.rpcClient, sendArgs.ChainID, sendArgs.ERC721TransferTx.From) + nonce, err := s.transactor.NextNonce(s.rpcClient, sendArgs.ChainID, sendArgs.ERC721TransferTx.From) if err != nil { - return tx, nil, err + return tx, err } argNonce := hexutil.Uint64(nonce) @@ -120,23 +120,18 @@ func (s *ERC721TransferBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn tx, err = contract.SafeTransferFrom(txOpts, common.Address(sendArgs.ERC721TransferTx.From), sendArgs.ERC721TransferTx.Recipient, sendArgs.ERC721TransferTx.TokenID.ToInt()) - return tx, unlock, err + return tx, err } func (s *ERC721TransferBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { - tx, unlock, err := s.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.ERC721TransferTx.From, verifiedAccount)) - defer func() { - if unlock != nil { - unlock(err == nil, tx.Nonce()) - } - }() + tx, err := s.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.ERC721TransferTx.From, verifiedAccount)) if err != nil { return hash, err } return types.Hash(tx.Hash()), nil } -func (s *ERC721TransferBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, transactions.UnlockNonceFunc, error) { +func (s *ERC721TransferBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, error) { return s.sendOrBuild(sendArgs, nil) } diff --git a/services/wallet/bridge/hop.go b/services/wallet/bridge/hop.go index 394e07a6e..c3e33ef63 100644 --- a/services/wallet/bridge/hop.go +++ b/services/wallet/bridge/hop.go @@ -226,15 +226,15 @@ func (h *HopBridge) GetContractAddress(network *params.Network, token *token.Tok return &address } -func (h *HopBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn bind.SignerFn) (tx *ethTypes.Transaction, unlock transactions.UnlockNonceFunc, err error) { +func (h *HopBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn bind.SignerFn) (tx *ethTypes.Transaction, err error) { fromNetwork := h.contractMaker.RPCClient.NetworkManager.Find(sendArgs.ChainID) if fromNetwork == nil { - return tx, nil, err + return tx, err } - nonce, unlock, err := h.transactor.NextNonce(h.contractMaker.RPCClient, sendArgs.ChainID, sendArgs.HopTx.From) + nonce, err := h.transactor.NextNonce(h.contractMaker.RPCClient, sendArgs.ChainID, sendArgs.HopTx.From) if err != nil { - return tx, nil, err + return tx, err } argNonce := hexutil.Uint64(nonce) @@ -243,26 +243,21 @@ func (h *HopBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn bind.Signe token := h.tokenManager.FindToken(fromNetwork, sendArgs.HopTx.Symbol) if fromNetwork.Layer == 1 { tx, err = h.sendToL2(sendArgs.ChainID, sendArgs.HopTx, signerFn, token) - return tx, unlock, err + return tx, err } tx, err = h.swapAndSend(sendArgs.ChainID, sendArgs.HopTx, signerFn, token) - return tx, unlock, err + return tx, err } func (h *HopBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { - tx, unlock, err := h.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.HopTx.From, verifiedAccount)) - defer func() { - if unlock != nil { - unlock(err == nil, tx.Nonce()) - } - }() + tx, err := h.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.HopTx.From, verifiedAccount)) if err != nil { return types.Hash{}, err } return types.Hash(tx.Hash()), nil } -func (h *HopBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, transactions.UnlockNonceFunc, error) { +func (h *HopBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, error) { return h.sendOrBuild(sendArgs, nil) } diff --git a/services/wallet/bridge/transfer.go b/services/wallet/bridge/transfer.go index 62193a82e..078879365 100644 --- a/services/wallet/bridge/transfer.go +++ b/services/wallet/bridge/transfer.go @@ -88,7 +88,7 @@ func (s *TransferBridge) Send(sendArgs *TransactionBridge, verifiedAccount *acco return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, verifiedAccount) } -func (s *TransferBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, transactions.UnlockNonceFunc, error) { +func (s *TransferBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, error) { return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx) } diff --git a/services/wallet/transfer/transaction_manager.go b/services/wallet/transfer/transaction_manager.go index 8220eacdd..4ef3df355 100644 --- a/services/wallet/transfer/transaction_manager.go +++ b/services/wallet/transfer/transaction_manager.go @@ -40,7 +40,6 @@ type TransactionDescription struct { chainID uint64 builtTx *ethTypes.Transaction signature []byte - unlock transactions.UnlockNonceFunc } type TransactionManager struct { @@ -160,13 +159,7 @@ func (tm *TransactionManager) BuildTransaction(chainID uint64, sendArgs transact return nil, err } - txBeingSigned, unlock, err := tm.transactor.ValidateAndBuildTransaction(chainID, sendArgs) - // We have to unlock the nonce, cause we don't know what will happen on the client side (will user accept/reject) an action. - if unlock != nil { - defer func() { - unlock(false, 0) - }() - } + txBeingSigned, err := tm.transactor.ValidateAndBuildTransaction(chainID, sendArgs) if err != nil { return nil, err } @@ -214,13 +207,7 @@ func (tm *TransactionManager) BuildTransaction(chainID uint64, sendArgs transact } func (tm *TransactionManager) BuildRawTransaction(chainID uint64, sendArgs transactions.SendTxArgs, signature []byte) (response *TxResponse, err error) { - tx, unlock, err := tm.transactor.BuildTransactionWithSignature(chainID, sendArgs, signature) - // We have to unlock the nonce, cause we don't know what will happen on the client side (will user accept/reject) an action. - if unlock != nil { - defer func() { - unlock(false, 0) - }() - } + tx, err := tm.transactor.BuildTransactionWithSignature(chainID, sendArgs, signature) if err != nil { return nil, err } diff --git a/services/wallet/transfer/transaction_manager_multitransaction.go b/services/wallet/transfer/transaction_manager_multitransaction.go index 809972c64..729e5010a 100644 --- a/services/wallet/transfer/transaction_manager_multitransaction.go +++ b/services/wallet/transfer/transaction_manager_multitransaction.go @@ -293,11 +293,6 @@ func (tm *TransactionManager) ProceedWithTransactionsSignatures(ctx context.Cont hashes := make(map[uint64][]types.Hash) for _, desc := range tm.transactionsForKeycardSingning { hash, err := tm.transactor.AddSignatureToTransactionAndSend(desc.chainID, desc.builtTx, desc.signature) - if desc.unlock != nil { - defer func() { - desc.unlock(err == nil, desc.builtTx.Nonce()) - }() - } if err != nil { return nil, err } @@ -376,11 +371,8 @@ func (tm *TransactionManager) buildTransactions(bridges map[string]bridge.Bridge tm.transactionsForKeycardSingning = make(map[common.Hash]*TransactionDescription) var hashes []string for _, bridgeTx := range tm.transactionsBridgeData { - builtTx, unlock, err := bridges[bridgeTx.BridgeName].BuildTransaction(bridgeTx) + builtTx, err := bridges[bridgeTx.BridgeName].BuildTransaction(bridgeTx) if err != nil { - if unlock != nil { - unlock(false, 0) // unlock nonce in case of an error, otherwise keep it locked, until the transaction is sent - } return hashes, err } @@ -390,7 +382,6 @@ func (tm *TransactionManager) buildTransactions(bridges map[string]bridge.Bridge tm.transactionsForKeycardSingning[txHash] = &TransactionDescription{ chainID: bridgeTx.ChainID, builtTx: builtTx, - unlock: unlock, } hashes = append(hashes, txHash.String()) diff --git a/transactions/nonce.go b/transactions/nonce.go deleted file mode 100644 index f54da49cd..000000000 --- a/transactions/nonce.go +++ /dev/null @@ -1,73 +0,0 @@ -package transactions - -import ( - "context" - "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/status-im/status-go/eth-node/types" -) - -type UnlockNonceFunc func(inc bool, n uint64) - -type Nonce struct { - addrLock *AddrLocker - localNonce map[uint64]*sync.Map -} - -func NewNonce() *Nonce { - return &Nonce{ - addrLock: &AddrLocker{}, - localNonce: make(map[uint64]*sync.Map), - } -} - -func (n *Nonce) Next(rpcWrapper *rpcWrapper, from types.Address) (uint64, UnlockNonceFunc, error) { - n.addrLock.LockAddr(from) - current, err := n.GetCurrent(rpcWrapper, from) - if err != nil { - return 0, nil, err - } - - unlock := func(inc bool, nonce uint64) { - if inc { - if _, ok := n.localNonce[rpcWrapper.chainID]; !ok { - n.localNonce[rpcWrapper.chainID] = &sync.Map{} - } - - n.localNonce[rpcWrapper.chainID].Store(from, nonce+1) - } - n.addrLock.UnlockAddr(from) - } - - return current, unlock, nil -} - -func (n *Nonce) GetCurrent(rpcWrapper *rpcWrapper, from types.Address) (uint64, error) { - var ( - localNonce uint64 - remoteNonce uint64 - ) - if _, ok := n.localNonce[rpcWrapper.chainID]; !ok { - n.localNonce[rpcWrapper.chainID] = &sync.Map{} - } - - // get the local nonce - if val, ok := n.localNonce[rpcWrapper.chainID].Load(from); ok { - localNonce = val.(uint64) - } - - // get the remote nonce - ctx := context.Background() - remoteNonce, err := rpcWrapper.PendingNonceAt(ctx, common.Address(from)) - if err != nil { - return 0, err - } - - // if upstream node returned nonce higher than ours we will use it, as it probably means - // that another client was used for sending transactions - if remoteNonce > localNonce { - return remoteNonce, nil - } - return localNonce, nil -} diff --git a/transactions/transactor.go b/transactions/transactor.go index 78b361e56..2cb9c9a0c 100644 --- a/transactions/transactor.go +++ b/transactions/transactor.go @@ -49,7 +49,6 @@ type Transactor struct { sendTxTimeout time.Duration rpcCallTimeout time.Duration networkID uint64 - nonce *Nonce log log.Logger } @@ -57,7 +56,6 @@ type Transactor struct { func NewTransactor() *Transactor { return &Transactor{ sendTxTimeout: sendTxTimeout, - nonce: NewNonce(), log: log.New("package", "status-go/transactions.Manager"), } } @@ -77,9 +75,10 @@ func (t *Transactor) SetRPC(rpcClient *rpc.Client, timeout time.Duration) { t.rpcCallTimeout = timeout } -func (t *Transactor) NextNonce(rpcClient *rpc.Client, chainID uint64, from types.Address) (uint64, UnlockNonceFunc, error) { +func (t *Transactor) NextNonce(rpcClient *rpc.Client, chainID uint64, from types.Address) (uint64, error) { wrapper := newRPCWrapper(rpcClient, chainID) - return t.nonce.Next(wrapper, from) + ctx := context.Background() + return wrapper.PendingNonceAt(ctx, common.Address(from)) } func (t *Transactor) EstimateGas(network *params.Network, from common.Address, to common.Address, value *big.Int, input []byte) (uint64, error) { @@ -110,9 +109,9 @@ func (t *Transactor) SendTransactionWithChainID(chainID uint64, sendArgs SendTxA return } -func (t *Transactor) ValidateAndBuildTransaction(chainID uint64, sendArgs SendTxArgs) (tx *gethtypes.Transaction, unlock UnlockNonceFunc, err error) { +func (t *Transactor) ValidateAndBuildTransaction(chainID uint64, sendArgs SendTxArgs) (tx *gethtypes.Transaction, err error) { wrapper := newRPCWrapper(t.rpcWrapper.RPCClient, chainID) - tx, unlock, err = t.validateAndBuildTransaction(wrapper, sendArgs) + tx, err = t.validateAndBuildTransaction(wrapper, sendArgs) return } @@ -167,16 +166,7 @@ func (t *Transactor) AddSignatureToTransactionAndSend(chainID uint64, tx *gethty // It's different from eth_sendRawTransaction because it receives a signature and not a serialized transaction with signature. // Since the transactions is already signed, we assume it was validated and used the right nonce. func (t *Transactor) BuildTransactionAndSendWithSignature(chainID uint64, args SendTxArgs, sig []byte) (hash types.Hash, err error) { - txWithSignature, unlock, err := t.BuildTransactionWithSignature(chainID, args, sig) - if unlock != nil { - defer func() { - var nonce uint64 - if txWithSignature != nil { - nonce = txWithSignature.Nonce() - } - unlock(err == nil, nonce) - }() - } + txWithSignature, err := t.BuildTransactionWithSignature(chainID, args, sig) if err != nil { return hash, err } @@ -185,32 +175,31 @@ func (t *Transactor) BuildTransactionAndSendWithSignature(chainID uint64, args S return hash, err } -func (t *Transactor) BuildTransactionWithSignature(chainID uint64, args SendTxArgs, sig []byte) (*gethtypes.Transaction, UnlockNonceFunc, error) { +func (t *Transactor) BuildTransactionWithSignature(chainID uint64, args SendTxArgs, sig []byte) (*gethtypes.Transaction, error) { if !args.Valid() { - return nil, nil, ErrInvalidSendTxArgs + return nil, ErrInvalidSendTxArgs } if len(sig) != ValidSignatureSize { - return nil, nil, ErrInvalidSignatureSize + return nil, ErrInvalidSignatureSize } tx := t.buildTransaction(args) - rpcWrapper := newRPCWrapper(t.rpcWrapper.RPCClient, chainID) - expectedNonce, unlock, err := t.nonce.Next(rpcWrapper, args.From) + expectedNonce, err := t.NextNonce(t.rpcWrapper.RPCClient, chainID, args.From) if err != nil { - return nil, nil, err + return nil, err } if tx.Nonce() != expectedNonce { - return nil, unlock, &ErrBadNonce{tx.Nonce(), expectedNonce} + return nil, &ErrBadNonce{tx.Nonce(), expectedNonce} } txWithSignature, err := t.AddSignatureToTransaction(chainID, tx, sig) if err != nil { - return nil, unlock, err + return nil, err } - return txWithSignature, unlock, nil + return txWithSignature, nil } func (t *Transactor) HashTransaction(args SendTxArgs) (validatedArgs SendTxArgs, hash types.Hash, err error) { @@ -220,13 +209,10 @@ func (t *Transactor) HashTransaction(args SendTxArgs) (validatedArgs SendTxArgs, validatedArgs = args - nonce, unlock, err := t.nonce.Next(t.rpcWrapper, args.From) + nonce, err := t.NextNonce(t.rpcWrapper.RPCClient, t.rpcWrapper.chainID, args.From) if err != nil { return validatedArgs, hash, err } - if unlock != nil { - defer unlock(false, 0) - } gasPrice := (*big.Int)(args.GasPrice) gasFeeCap := (*big.Int)(args.MaxFeePerGas) @@ -315,18 +301,18 @@ func (t *Transactor) validateAccount(args SendTxArgs, selectedAccount *account.S return nil } -func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args SendTxArgs) (tx *gethtypes.Transaction, unlock UnlockNonceFunc, err error) { +func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args SendTxArgs) (tx *gethtypes.Transaction, err error) { if !args.Valid() { - return tx, nil, ErrInvalidSendTxArgs + return tx, ErrInvalidSendTxArgs } var nonce uint64 if args.Nonce != nil { nonce = uint64(*args.Nonce) } else { - nonce, unlock, err = t.nonce.Next(rpcWrapper, args.From) + nonce, err = t.NextNonce(rpcWrapper.RPCClient, rpcWrapper.chainID, args.From) if err != nil { - return tx, nil, err + return tx, err } } @@ -337,7 +323,7 @@ func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args Se if !args.IsDynamicFeeTx() && args.GasPrice == nil { gasPrice, err = rpcWrapper.SuggestGasPrice(ctx) if err != nil { - return tx, unlock, err + return tx, err } } @@ -365,15 +351,16 @@ func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args Se Data: args.GetInput(), }) if err != nil { - return tx, unlock, err + return tx, err } if gas < defaultGas { t.log.Info("default gas will be used because estimated is lower", "estimated", gas, "default", defaultGas) gas = defaultGas } } + tx = t.buildTransactionWithOverrides(nonce, value, gas, gasPrice, args) - return tx, unlock, nil + return tx, nil } func (t *Transactor) validateAndPropagate(rpcWrapper *rpcWrapper, selectedAccount *account.SelectedExtKey, args SendTxArgs) (hash types.Hash, err error) { @@ -381,12 +368,7 @@ func (t *Transactor) validateAndPropagate(rpcWrapper *rpcWrapper, selectedAccoun return hash, err } - tx, unlock, err := t.validateAndBuildTransaction(rpcWrapper, args) - defer func() { - if unlock != nil { - unlock(err == nil, tx.Nonce()) - } - }() + tx, err := t.validateAndBuildTransaction(rpcWrapper, args) if err != nil { return hash, err } diff --git a/transactions/transactor_test.go b/transactions/transactor_test.go index 46eb103c6..e3f432c7d 100644 --- a/transactions/transactor_test.go +++ b/transactions/transactor_test.go @@ -1,11 +1,9 @@ package transactions import ( - "errors" "fmt" "math/big" "reflect" - "sync" "testing" "time" @@ -246,92 +244,30 @@ func (s *TransactorSuite) TestAccountMismatch() { s.EqualError(err, ErrInvalidTxSender.Error()) } -// TestLocalNonce verifies that local nonce will be used unless -// upstream nonce is updated and higher than a local -// in test we will run 3 transaction with nonce zero returned by upstream -// node, after each call local nonce will be incremented -// then, we return higher nonce, as if another node was used to send 2 transactions -// upstream nonce will be equal to 5, we update our local counter to 5+1 -// as the last step, we verify that if tx failed nonce is not updated -func (s *TransactorSuite) TestLocalNonce() { - txCount := 3 - chainID := s.nodeConfig.NetworkID - key, _ := gethcrypto.GenerateKey() - selectedAccount := &account.SelectedExtKey{ - Address: account.FromAddress(utils.TestConfig.Account1.WalletAddress), - AccountKey: &types.Key{PrivateKey: key}, - } - nonce := hexutil.Uint64(0) - - for i := 0; i < txCount; i++ { - args := SendTxArgs{ - From: account.FromAddress(utils.TestConfig.Account1.WalletAddress), - To: account.ToAddress(utils.TestConfig.Account2.WalletAddress), - } - s.setupTransactionPoolAPI(args, nonce, hexutil.Uint64(i), selectedAccount, nil) - - _, err := s.manager.SendTransaction(args, selectedAccount) - s.NoError(err) - resultNonce, _ := s.manager.nonce.localNonce[chainID].Load(args.From) - s.Equal(uint64(i)+1, resultNonce.(uint64)) - } - - nonce = hexutil.Uint64(5) - args := SendTxArgs{ - From: account.FromAddress(utils.TestConfig.Account1.WalletAddress), - To: account.ToAddress(utils.TestConfig.Account2.WalletAddress), - } - - s.setupTransactionPoolAPI(args, nonce, nonce, selectedAccount, nil) - - _, err := s.manager.SendTransaction(args, selectedAccount) - s.NoError(err) - - resultNonce, _ := s.manager.nonce.localNonce[chainID].Load(args.From) - s.Equal(uint64(nonce)+1, resultNonce.(uint64)) - - testErr := errors.New("test") - s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), gomock.Eq(common.Address(selectedAccount.Address)), gethrpc.PendingBlockNumber).Return(nil, testErr) - args = SendTxArgs{ - From: account.FromAddress(utils.TestConfig.Account1.WalletAddress), - To: account.ToAddress(utils.TestConfig.Account2.WalletAddress), - } - - _, err = s.manager.SendTransaction(args, selectedAccount) - s.EqualError(err, testErr.Error()) - resultNonce, _ = s.manager.nonce.localNonce[chainID].Load(args.From) - s.Equal(uint64(nonce)+1, resultNonce.(uint64)) -} - func (s *TransactorSuite) TestSendTransactionWithSignature() { privKey, err := crypto.GenerateKey() s.Require().NoError(err) address := crypto.PubkeyToAddress(privKey.PublicKey) scenarios := []struct { - localNonce hexutil.Uint64 - txNonce hexutil.Uint64 - expectError bool + nonceFromNetwork hexutil.Uint64 + txNonce hexutil.Uint64 + expectError bool }{ { - localNonce: hexutil.Uint64(0), - txNonce: hexutil.Uint64(0), - expectError: false, + nonceFromNetwork: hexutil.Uint64(0), + txNonce: hexutil.Uint64(0), + expectError: false, }, { - localNonce: hexutil.Uint64(1), - txNonce: hexutil.Uint64(0), - expectError: true, - }, - { - localNonce: hexutil.Uint64(0), - txNonce: hexutil.Uint64(1), - expectError: true, + nonceFromNetwork: hexutil.Uint64(0), + txNonce: hexutil.Uint64(1), + expectError: true, }, } for _, scenario := range scenarios { - desc := fmt.Sprintf("local nonce: %d, tx nonce: %d, expect error: %v", scenario.localNonce, scenario.txNonce, scenario.expectError) + desc := fmt.Sprintf("nonceFromNetwork: %d, tx nonce: %d, expect error: %v", scenario.nonceFromNetwork, scenario.txNonce, scenario.expectError) s.T().Run(desc, func(t *testing.T) { nonce := scenario.txNonce from := address @@ -341,8 +277,6 @@ func (s *TransactorSuite) TestSendTransactionWithSignature() { gasPrice := (*hexutil.Big)(big.NewInt(2000000000)) data := []byte{} chainID := big.NewInt(int64(s.nodeConfig.NetworkID)) - s.manager.nonce.localNonce[s.nodeConfig.NetworkID] = &sync.Map{} - s.manager.nonce.localNonce[s.nodeConfig.NetworkID].Store(address, uint64(scenario.localNonce)) args := SendTxArgs{ From: from, To: &to, @@ -366,7 +300,7 @@ func (s *TransactorSuite) TestSendTransactionWithSignature() { s.txServiceMock.EXPECT(). GetTransactionCount(gomock.Any(), common.Address(address), gethrpc.PendingBlockNumber). - Return(&scenario.localNonce, nil) + Return(&scenario.nonceFromNetwork, nil) if !scenario.expectError { s.txServiceMock.EXPECT(). @@ -377,15 +311,8 @@ func (s *TransactorSuite) TestSendTransactionWithSignature() { _, err = s.manager.BuildTransactionAndSendWithSignature(s.nodeConfig.NetworkID, args, sig) if scenario.expectError { s.Error(err) - // local nonce should not be incremented - resultNonce, _ := s.manager.nonce.localNonce[s.nodeConfig.NetworkID].Load(args.From) - s.Equal(uint64(scenario.localNonce), resultNonce.(uint64)) } else { s.NoError(err) - // local nonce should be incremented - resultNonce, _ := s.manager.nonce.localNonce[s.nodeConfig.NetworkID].Load(args.From) - - s.Equal(uint64(nonce)+1, resultNonce.(uint64)) } }) }