Skip to content

Commit

Permalink
Correct nonce values when sending multiple transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
zah committed Aug 1, 2020
1 parent 9fb271b commit 0361338
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 30 deletions.
6 changes: 0 additions & 6 deletions tests/test_rng.nim

This file was deleted.

5 changes: 3 additions & 2 deletions tests/test_signed_tx.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import ../web3
import chronos, options, json, stint, eth/keys
import test_utils, test_rng

import test_utils

#[ Contract NumberStorage
pragma solidity ^0.4.18;
Expand All @@ -25,6 +24,8 @@ contract(NumberStorage):
const NumberStorageCode = "6060604052341561000f57600080fd5b60bb8061001d6000396000f30060606040526004361060485763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416633fb5c1cb8114604d578063f2c9ecd8146062575b600080fd5b3415605757600080fd5b60606004356084565b005b3415606c57600080fd5b60726089565b60405190815260200160405180910390f35b600055565b600054905600a165627a7a7230582023e722f35009f12d5698a4ab22fb9d55a6c0f479fc43875c65be46fbdd8db4310029"

proc test() {.async.} =
let theRNG = newRng()

let web3 = await newWeb3("ws://127.0.0.1:8545/")
let accounts = await web3.provider.eth_accounts()
web3.defaultAccount = accounts[0]
Expand Down
56 changes: 36 additions & 20 deletions web3.nim
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type
subscriptions*: Table[string, Subscription]
defaultAccount*: Address
privateKey*: Option[PrivateKey]
lastKnownNonce*: Option[Nonce]
onDisconnect*: proc() {.gcsafe.}

Sender*[T] = ref object
Expand All @@ -44,13 +45,13 @@ type
historicalEventsProcessed: bool
removed: bool

ContractCallBase = object of RootObj
ContractCallBase = ref object of RootObj
web3: Web3
data: string
to: Address
value: Uint256

ContractCall*[T] = object of ContractCallBase
ContractCall*[T] = ref object of ContractCallBase

proc handleSubscriptionNotification(w: Web3, j: JsonNode) =
let s = w.subscriptions.getOrDefault(j{"subscription"}.getStr())
Expand Down Expand Up @@ -246,9 +247,7 @@ template typeSignature(T: typedesc): string =
unknownType(T)

proc initContractCall[T](web3: Web3, data: string, to: Address): ContractCall[T] {.inline.} =
result.web3 = web3
result.data = data
result.to = to
ContractCall[T](web3: web3, data: data, to: to)

macro makeTypeEnum(): untyped =
## This macro creates all the various types of Solidity contracts and maps
Expand Down Expand Up @@ -743,29 +742,46 @@ proc getJsonLogs*(s: Sender,

s.web3.provider.eth_getLogs(options)

proc nextNonce*(web3: Web3): Future[Nonce] {.async.} =
if web3.lastKnownNonce.isSome:
inc web3.lastKnownNonce.get
return web3.lastKnownNonce.get
else:
let fromAddress = web3.privateKey.get().toPublicKey().toCanonicalAddress.Address
result = int(await web3.provider.eth_getTransactionCount(fromAddress, "latest"))
web3.lastKnownNonce = some result

proc send*(web3: Web3, c: EthSend): Future[TxHash] {.async.} =
if web3.privateKey.isSome():
var cc = c
if not cc.nonce.isSome:
let fromAddress = web3.privateKey.get().toPublicKey().toCanonicalAddress.Address
cc.nonce = some(int(await web3.provider.eth_getTransactionCount(fromAddress, "latest")))
if cc.nonce.isNone:
cc.nonce = some(await web3.nextNonce())
let t = "0x" & encodeTransaction(cc, web3.privateKey.get())
return await web3.provider.eth_sendRawTransaction(t)
else:
return await web3.provider.eth_sendTransaction(c)

proc send*(c: ContractCallBase, value = 0.u256, gas = 3000000'u64, gasPrice = 0): Future[TxHash] =
let web3 = c.web3
var cc: EthSend
cc.data = "0x" & c.data
cc.source = web3.defaultAccount
cc.to = some(c.to)
cc.gas = some(Quantity(gas))
cc.value = some(value)

if web3.privateKey.isSome() or gasPrice != 0:
cc.gasPrice = some(gasPrice)
web3.send(cc)
proc send*(c: ContractCallBase,
value = 0.u256,
gas = 3000000'u64,
gasPrice = 0): Future[TxHash] {.async.} =
let
web3 = c.web3
gasPrice = if web3.privateKey.isSome() or gasPrice != 0: some(gasPrice)
else: none(int)
nonce = if web3.privateKey.isSome(): some(await web3.nextNonce())
else: none(Nonce)

cc = EthSend(
data: "0x" & c.data,
source: web3.defaultAccount,
to: some(c.to),
gas: some(Quantity(gas)),
value: some(value),
nonce: nonce,
gasPrice: gasPrice)

return await web3.send(cc)

proc call*[T](c: ContractCall[T],
value = 0.u256,
Expand Down
6 changes: 4 additions & 2 deletions web3/ethtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type
BlockHash* = FixedBytes[32]
BlockNumber* = uint64
BlockIdentifier* = string|BlockNumber|RtBlockIdentifier
Nonce* = int

BlockIdentifierKind* = enum
bidNumber
Expand All @@ -37,7 +38,8 @@ type
gasPrice*: Option[int] # (optional, default: To-Be-Determined) integer of the gasPrice used for each paid gas.
value*: Option[Uint256] # (optional) integer of the value sent with this transaction.
data*: string # the compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see Ethereum Contract ABI.
nonce*: Option[int] # (optional) integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce
nonce*: Option[Nonce] # (optional) integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce

#EthSend* = object
# source*: Address # the address the transaction is send from.
# to*: Address # (optional when creating new contract) the address the transaction is directed to.
Expand Down Expand Up @@ -129,7 +131,7 @@ type
contractAddress*: Option[Address] # the contract address created, if the transaction was a contract creation, otherwise null.
logs*: seq[LogObject] # TODO: See Wiki for details. list of log objects, which this transaction generated.
logsBloom*: Option[FixedBytes[256]] # bloom filter for light clients to quickly retrieve related logs.
# TODO:
# TODO:
#case kind*: ReceiptKind
#of rkRoot: root*: UInt256 # post-transaction stateroot (pre Byzantium).
#of rkStatus: status*: int # 1 = success, 0 = failure.
Expand Down

0 comments on commit 0361338

Please sign in to comment.