Wallet keeps track of nonces

This commit is contained in:
Mark Spanbroek 2021-04-14 12:57:14 +02:00
parent 04beab5b91
commit 76cc0a9bcc
6 changed files with 95 additions and 0 deletions

View File

@ -1,3 +1,4 @@
import std/hashes
import pkg/questionable
import pkg/questionable/results
import pkg/stew/byteutils
@ -19,3 +20,4 @@ func parse*(_: type EthAddress, hex: string): ?EthAddress =
EthAddress(array[20, byte].fromHex(hex)).catch.option
proc `==`*(a, b: EthAddress): bool {.borrow.}
proc `hash`*(a: EthAddress): Hash {.borrow.}

34
nitro/wallet/nonces.nim Normal file
View File

@ -0,0 +1,34 @@
import std/tables
import std/sets
import std/hashes
import ../basics
push: {.upraises: [].}
type
Nonces* = object
next: Table[NonceKey, UInt48]
NonceKey = object
chainId: UInt256
participants: HashSet[EthAddress]
func hash(key: NonceKey): Hash =
var h: Hash
h = h !& key.chainId.hash
h = h !& key.participants.hash
!$h
func key(chainId: UInt256, participants: openArray[EthAddress]): NonceKey =
NonceKey(chainId: chainId, participants: participants.toHashSet)
func getNonce*(nonces: var Nonces,
chainId: UInt256,
participants: varargs[EthAddress]): UInt48 =
nonces.next.?[key(chainId, participants)] |? 0
func incNonce*(nonces: var Nonces,
oldNonce: UInt48,
chainId: UInt256,
participants: varargs[EthAddress]) =
let next = max(oldNonce, nonces.getNonce(chainId, participants)) + 1
nonces.next[key(chainId, participants)] = next

View File

@ -5,6 +5,7 @@ import ../protocol
import ./signedstate
import ./ledger
import ./balances
import ./nonces
push: {.upraises:[].}
@ -17,6 +18,7 @@ type
Wallet* = object
key: EthPrivateKey
channels: Table[ChannelId, SignedState]
nonces: Nonces
ChannelId* = Destination
Payment* = tuple
destination: Destination
@ -39,11 +41,16 @@ func sign(wallet: Wallet, state: SignedState): SignedState =
signed.signatures &= wallet.key.sign(state.state)
signed
func incNonce(wallet: var Wallet, state: SignedState) =
let channel = state.state.channel
wallet.nonces.incNonce(channel.nonce, channel.chainId, channel.participants)
func createChannel(wallet: var Wallet, state: SignedState): ?!ChannelId =
let id = getChannelId(state.state.channel)
if wallet.channels.contains(id):
return ChannelId.failure("channel with id " & $id & " already exists")
wallet.channels[id] = wallet.sign(state)
wallet.incNonce(state)
ok id
func updateChannel(wallet: var Wallet, state: SignedState) =
@ -60,6 +67,14 @@ func openLedgerChannel*(wallet: var Wallet,
let state = startLedger(wallet.address, hub, chainId, nonce, asset, amount)
wallet.createChannel(state)
func openLedgerChannel*(wallet: var Wallet,
hub: EthAddress,
chainId: UInt256,
asset: EthAddress,
amount: UInt256): ?!ChannelId =
let nonce = wallet.nonces.getNonce(chainId, wallet.address, hub)
openLedgerChannel(wallet, hub, chainId, nonce, asset, amount)
func acceptChannel*(wallet: var Wallet, signed: SignedState): ?!ChannelId =
if not signed.hasParticipant(wallet.address):
return ChannelId.failure "wallet owner is not a participant"

View File

@ -31,6 +31,12 @@ suite "wallet: opening ledger channel":
check definition.nonce == nonce
check definition.participants == @[wallet.address, hub]
test "uses consecutive nonces when none is provided":
channel = wallet.openLedgerChannel(hub, chainId, asset, amount).get
check wallet.state(channel).get.channel.nonce == nonce + 1
channel = wallet.openLedgerChannel(hub, chainId, asset, amount).get
check wallet.state(channel).get.channel.nonce == nonce + 2
test "provides correct outcome":
let outcome = wallet.state(channel).get.outcome
check outcome == Outcome.init(asset, {wallet.destination: amount})

View File

@ -0,0 +1,37 @@
import ../basics
import pkg/nitro/wallet/nonces
suite "nonces":
let chainId = UInt256.example
let participants = seq[EthAddress].example
var nonces: Nonces
setup:
nonces = Nonces()
test "nonces start at 0":
check nonces.getNonce(chainId, participants) == 0
test "nonces increase by 1":
nonces.incNonce(0, chainId, participants)
check nonces.getNonce(chainId, participants) == 1
nonces.incNonce(1, chainId, participants)
check nonces.getNonce(chainId, participants) == 2
test "nonces do not decrease":
nonces.incNonce(100, chainId, participants)
check nonces.getNonce(chainId, participants) == 101
nonces.incNonce(0, chainId, participants)
check nonces.getNonce(chainId, participants) == 102
test "nonces are different when participants differ":
let otherParticipants = seq[EthAddress].example
nonces.incNonce(0, chainId, participants)
check nonces.getNonce(chainId, otherParticipants) == 0
test "nonces are different when chain ids differ":
let otherChainId = UInt256.example
nonces.incNonce(0, chainId, participants)
check nonces.getNonce(otherChainId, participants) == 0

View File

@ -3,6 +3,7 @@ import ./nitro/protocol/testChannel
import ./nitro/protocol/testOutcome
import ./nitro/protocol/testState
import ./nitro/protocol/testSignature
import ./nitro/wallet/testNonces
import ./nitro/testWallet
import ./nitro/testJson