Increment nonce count when populating transaction (#54)

Increment nonce count when populating transaction

Co-authored-by: markspanbroek <mark@spanbroek.net>
This commit is contained in:
Eric 2023-09-15 09:54:08 +10:00 committed by GitHub
parent 8fff63102a
commit f0303473f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 5 deletions

View File

@ -240,6 +240,7 @@ method signMessage*(signer: JsonRpcSigner,
method sendTransaction*(signer: JsonRpcSigner, method sendTransaction*(signer: JsonRpcSigner,
transaction: Transaction): Future[TransactionResponse] {.async.} = transaction: Transaction): Future[TransactionResponse] {.async.} =
convertError: convertError:
signer.updateNonce(transaction.nonce)
let let
client = await signer.provider.client client = await signer.provider.client
hash = await client.eth_sendTransaction(transaction) hash = await client.eth_sendTransaction(transaction)

View File

@ -3,7 +3,10 @@ import ./provider
export basics export basics
type Signer* = ref object of RootObj type
Signer* = ref object of RootObj
lastSeenNonce: ?UInt256
type SignerError* = object of EthersError type SignerError* = object of EthersError
template raiseSignerError(message: string) = template raiseSignerError(message: string) =
@ -41,6 +44,26 @@ method estimateGas*(signer: Signer,
method getChainId*(signer: Signer): Future[UInt256] {.base, gcsafe.} = method getChainId*(signer: Signer): Future[UInt256] {.base, gcsafe.} =
signer.provider.getChainId() signer.provider.getChainId()
method getNonce(signer: Signer): Future[UInt256] {.base, gcsafe, async.} =
var nonce = await signer.getTransactionCount(BlockTag.pending)
if lastSeen =? signer.lastSeenNonce and lastSeen >= nonce:
nonce = (lastSeen + 1.u256)
signer.lastSeenNonce = some nonce
return nonce
method updateNonce*(signer: Signer, nonce: ?UInt256) {.base, gcsafe.} =
without nonce =? nonce:
return
without lastSeen =? signer.lastSeenNonce:
signer.lastSeenNonce = some nonce
return
if nonce > lastSeen:
signer.lastSeenNonce = some nonce
method populateTransaction*(signer: Signer, method populateTransaction*(signer: Signer,
transaction: Transaction): transaction: Transaction):
Future[Transaction] {.base, async.} = Future[Transaction] {.base, async.} =
@ -55,7 +78,7 @@ method populateTransaction*(signer: Signer,
if transaction.sender.isNone: if transaction.sender.isNone:
populated.sender = some(await signer.getAddress()) populated.sender = some(await signer.getAddress())
if transaction.nonce.isNone: if transaction.nonce.isNone:
populated.nonce = some(await signer.getTransactionCount(BlockTag.pending)) populated.nonce = some(await signer.getNonce())
if transaction.chainId.isNone: if transaction.chainId.isNone:
populated.chainId = some(await signer.getChainId()) populated.chainId = some(await signer.getChainId())
if transaction.gasPrice.isNone and (transaction.maxFee.isNone or transaction.maxPriorityFee.isNone): if transaction.gasPrice.isNone and (transaction.maxFee.isNone or transaction.maxPriorityFee.isNone):

View File

@ -21,11 +21,11 @@ func `$`*(transaction: Transaction): string =
result &= "value: " & $transaction.value & ", " result &= "value: " & $transaction.value & ", "
result &= "data: 0x" & $transaction.data.toHex result &= "data: 0x" & $transaction.data.toHex
if nonce =? transaction.nonce: if nonce =? transaction.nonce:
result &= ", nonce: 0x" & $nonce.toHex result &= ", nonce: " & $nonce
if chainId =? transaction.chainId: if chainId =? transaction.chainId:
result &= ", chainId: " & $chainId result &= ", chainId: " & $chainId
if gasPrice =? transaction.gasPrice: if gasPrice =? transaction.gasPrice:
result &= ", gasPrice: 0x" & $gasPrice.toHex result &= ", gasPrice: " & $gasPrice
if gasLimit =? transaction.gasLimit: if gasLimit =? transaction.gasLimit:
result &= ", gasLimit: 0x" & $gasLimit.toHex result &= ", gasLimit: " & $gasLimit
result &= ")" result &= ")"

View File

@ -70,4 +70,5 @@ proc signTransaction*(wallet: Wallet,
method sendTransaction*(wallet: Wallet, transaction: Transaction): Future[TransactionResponse] {.async.} = method sendTransaction*(wallet: Wallet, transaction: Transaction): Future[TransactionResponse] {.async.} =
let signed = await signTransaction(wallet, transaction) let signed = await signTransaction(wallet, transaction)
wallet.updateNonce(transaction.nonce)
return await provider(wallet).sendTransaction(signed) return await provider(wallet).sendTransaction(signed)

View File

@ -82,3 +82,24 @@ suite "JsonRpcSigner":
transaction.chainId = 0xdeadbeef.u256.some transaction.chainId = 0xdeadbeef.u256.some
expect SignerError: expect SignerError:
discard await signer.populateTransaction(transaction) discard await signer.populateTransaction(transaction)
test "concurrent populate calls increment nonce":
let signer = provider.getSigner()
let count = await signer.getTransactionCount(BlockTag.pending)
var transaction1 = Transaction.example
var transaction2 = Transaction.example
var transaction3 = Transaction.example
let populated = await allFinished(
signer.populateTransaction(transaction1),
signer.populateTransaction(transaction2),
signer.populateTransaction(transaction3)
)
transaction1 = await populated[0]
transaction2 = await populated[1]
transaction3 = await populated[2]
check !transaction1.nonce == count
check !transaction2.nonce == count + 1.u256
check !transaction3.nonce == count + 2.u256