mirror of https://github.com/status-im/nim-eth.git
use bearssl rng throughout (#265)
* use bearssl rng throughout * seeder can fail * imports and exports * modules, sigh * one more try * move var * even fewer thread vars * remove out-of-date genrated files
This commit is contained in:
parent
4f533eb5e6
commit
484fbcab1b
|
@ -15,3 +15,4 @@ build/
|
||||||
*.la
|
*.la
|
||||||
*.exe
|
*.exe
|
||||||
*.dll
|
*.dll
|
||||||
|
*.generated.nim
|
||||||
|
|
53
eth/keys.nim
53
eth/keys.nim
|
@ -15,13 +15,13 @@
|
||||||
{.push raises: [Defect].}
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
import
|
import
|
||||||
secp256k1,
|
secp256k1, bearssl,
|
||||||
nimcrypto/hash, nimcrypto/keccak,
|
nimcrypto/hash, nimcrypto/keccak,
|
||||||
stew/[byteutils, objects, results], strformat
|
stew/[byteutils, objects, results], strformat
|
||||||
|
|
||||||
from nimcrypto/utils import burnMem
|
from nimcrypto/utils import burnMem
|
||||||
|
|
||||||
export secp256k1, results
|
export secp256k1, results, bearssl
|
||||||
|
|
||||||
const
|
const
|
||||||
KeyLength* = SkEcdhRawSecretSize - 1
|
KeyLength* = SkEcdhRawSecretSize - 1
|
||||||
|
@ -46,12 +46,31 @@ type
|
||||||
SharedSecret* = object
|
SharedSecret* = object
|
||||||
data*: array[KeyLength, byte]
|
data*: array[KeyLength, byte]
|
||||||
|
|
||||||
KeyPair* = object
|
KeyPair* = distinct SkKeyPair
|
||||||
seckey*: PrivateKey
|
|
||||||
pubkey*: PublicKey
|
|
||||||
|
|
||||||
proc random*(T: type PrivateKey): SkResult[T] =
|
template pubkey*(v: KeyPair): PublicKey = PublicKey(SkKeyPair(v).pubkey)
|
||||||
SkSecretKey.random().mapConvert(T)
|
template seckey*(v: KeyPair): PrivateKey = PrivateKey(SkKeyPair(v).seckey)
|
||||||
|
|
||||||
|
proc newRng*(): ref BrHmacDrbgContext =
|
||||||
|
# You should only create one instance of the RNG per application / library
|
||||||
|
# Ref is used so that it can be shared between components
|
||||||
|
# TODO consider moving to bearssl
|
||||||
|
var seeder = brPrngSeederSystem(nil)
|
||||||
|
if seeder == nil:
|
||||||
|
return nil
|
||||||
|
|
||||||
|
var rng = (ref BrHmacDrbgContext)()
|
||||||
|
brHmacDrbgInit(addr rng[], addr sha256Vtable, nil, 0)
|
||||||
|
if seeder(addr rng.vtable) == 0:
|
||||||
|
return nil
|
||||||
|
rng
|
||||||
|
|
||||||
|
proc random*(T: type PrivateKey, rng: var BrHmacDrbgContext): T =
|
||||||
|
let rngPtr = unsafeAddr rng # doesn't escape
|
||||||
|
proc callRng(data: var openArray[byte]) =
|
||||||
|
brHmacDrbgGenerate(rngPtr[], data)
|
||||||
|
|
||||||
|
T(SkSecretKey.random(callRng))
|
||||||
|
|
||||||
func fromRaw*(T: type PrivateKey, data: openArray[byte]): SkResult[T] =
|
func fromRaw*(T: type PrivateKey, data: openArray[byte]): SkResult[T] =
|
||||||
SkSecretKey.fromRaw(data).mapConvert(T)
|
SkSecretKey.fromRaw(data).mapConvert(T)
|
||||||
|
@ -87,12 +106,16 @@ func toRaw*(pubkey: PublicKey): array[RawPublicKeySize, byte] =
|
||||||
|
|
||||||
func toRawCompressed*(pubkey: PublicKey): array[33, byte] {.borrow.}
|
func toRawCompressed*(pubkey: PublicKey): array[33, byte] {.borrow.}
|
||||||
|
|
||||||
proc random*(T: type KeyPair): SkResult[T] =
|
proc random*(T: type KeyPair, rng: var BrHmacDrbgContext): T =
|
||||||
let tmp = ? SkKeypair.random()
|
let seckey = SkSecretKey(PrivateKey.random(rng))
|
||||||
ok(T(seckey: PrivateKey(tmp.seckey), pubkey: PublicKey(tmp.pubkey)))
|
KeyPair(SkKeyPair(
|
||||||
|
seckey: seckey,
|
||||||
|
pubkey: seckey.toPublicKey()
|
||||||
|
))
|
||||||
|
|
||||||
func toKeyPair*(seckey: PrivateKey): KeyPair =
|
func toKeyPair*(seckey: PrivateKey): KeyPair =
|
||||||
KeyPair(seckey: seckey, pubkey: seckey.toPublicKey())
|
KeyPair(SkKeyPair(
|
||||||
|
seckey: SkSecretKey(seckey), pubkey: SkSecretKey(seckey).toPublicKey()))
|
||||||
|
|
||||||
func fromRaw*(T: type Signature, data: openArray[byte]): SkResult[T] =
|
func fromRaw*(T: type Signature, data: openArray[byte]): SkResult[T] =
|
||||||
SkRecoverableSignature.fromRaw(data).mapConvert(T)
|
SkRecoverableSignature.fromRaw(data).mapConvert(T)
|
||||||
|
@ -192,28 +215,28 @@ func sign*(seckey: PrivateKey, msg: SkMessage): Signature =
|
||||||
|
|
||||||
func sign*(seckey: PrivateKey, msg: openArray[byte]): Signature =
|
func sign*(seckey: PrivateKey, msg: openArray[byte]): Signature =
|
||||||
let hash = keccak256.digest(msg)
|
let hash = keccak256.digest(msg)
|
||||||
sign(seckey, hash)
|
sign(seckey, SkMessage(hash.data))
|
||||||
|
|
||||||
func signNR*(seckey: PrivateKey, msg: SkMessage): SignatureNR =
|
func signNR*(seckey: PrivateKey, msg: SkMessage): SignatureNR =
|
||||||
SignatureNR(sign(SkSecretKey(seckey), msg))
|
SignatureNR(sign(SkSecretKey(seckey), msg))
|
||||||
|
|
||||||
func signNR*(seckey: PrivateKey, msg: openArray[byte]): SignatureNR =
|
func signNR*(seckey: PrivateKey, msg: openArray[byte]): SignatureNR =
|
||||||
let hash = keccak256.digest(msg)
|
let hash = keccak256.digest(msg)
|
||||||
signNR(seckey, hash)
|
signNR(seckey, SkMessage(hash.data))
|
||||||
|
|
||||||
func recover*(sig: Signature, msg: SkMessage): SkResult[PublicKey] =
|
func recover*(sig: Signature, msg: SkMessage): SkResult[PublicKey] =
|
||||||
recover(SkRecoverableSignature(sig), msg).mapConvert(PublicKey)
|
recover(SkRecoverableSignature(sig), msg).mapConvert(PublicKey)
|
||||||
|
|
||||||
func recover*(sig: Signature, msg: openArray[byte]): SkResult[PublicKey] =
|
func recover*(sig: Signature, msg: openArray[byte]): SkResult[PublicKey] =
|
||||||
let hash = keccak256.digest(msg)
|
let hash = keccak256.digest(msg)
|
||||||
recover(sig, hash)
|
recover(sig, SkMessage(hash.data))
|
||||||
|
|
||||||
func verify*(sig: SignatureNR, msg: SkMessage, key: PublicKey): bool =
|
func verify*(sig: SignatureNR, msg: SkMessage, key: PublicKey): bool =
|
||||||
verify(SkSignature(sig), msg, SkPublicKey(key))
|
verify(SkSignature(sig), msg, SkPublicKey(key))
|
||||||
|
|
||||||
func verify*(sig: SignatureNR, msg: openArray[byte], key: PublicKey): bool =
|
func verify*(sig: SignatureNR, msg: openArray[byte], key: PublicKey): bool =
|
||||||
let hash = keccak256.digest(msg)
|
let hash = keccak256.digest(msg)
|
||||||
verify(sig, hash, key)
|
verify(sig, SkMessage(hash.data), key)
|
||||||
|
|
||||||
func ecdhRaw*(seckey: PrivateKey, pubkey: PublicKey): SharedSecret =
|
func ecdhRaw*(seckey: PrivateKey, pubkey: PublicKey): SharedSecret =
|
||||||
let tmp = ecdhRaw(SkSecretKey(seckey), SkPublicKey(pubkey))
|
let tmp = ecdhRaw(SkSecretKey(seckey), SkPublicKey(pubkey))
|
||||||
|
|
10
eth/p2p.nim
10
eth/p2p.nim
|
@ -9,7 +9,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import
|
import
|
||||||
tables, algorithm, random,
|
tables, algorithm, random, bearssl,
|
||||||
chronos, chronos/timer, chronicles,
|
chronos, chronos/timer, chronicles,
|
||||||
eth/keys, eth/common/eth_types,
|
eth/keys, eth/common/eth_types,
|
||||||
eth/p2p/[kademlia, discovery, enode, peer_pool, rlpx],
|
eth/p2p/[kademlia, discovery, enode, peer_pool, rlpx],
|
||||||
|
@ -38,7 +38,12 @@ proc newEthereumNode*(keys: KeyPair,
|
||||||
clientId = "nim-eth-p2p/0.2.0", # TODO: read this value from nimble somehow
|
clientId = "nim-eth-p2p/0.2.0", # TODO: read this value from nimble somehow
|
||||||
addAllCapabilities = true,
|
addAllCapabilities = true,
|
||||||
useCompression: bool = false,
|
useCompression: bool = false,
|
||||||
minPeers = 10): EthereumNode =
|
minPeers = 10,
|
||||||
|
rng = newRng()): EthereumNode =
|
||||||
|
|
||||||
|
if rng == nil: # newRng could fail
|
||||||
|
raise (ref CatchableError)(msg: "Cannot initialize RNG")
|
||||||
|
|
||||||
new result
|
new result
|
||||||
result.keys = keys
|
result.keys = keys
|
||||||
result.networkId = networkId
|
result.networkId = networkId
|
||||||
|
@ -47,6 +52,7 @@ proc newEthereumNode*(keys: KeyPair,
|
||||||
result.capabilities.newSeq 0
|
result.capabilities.newSeq 0
|
||||||
result.address = address
|
result.address = address
|
||||||
result.connectionState = ConnectionState.None
|
result.connectionState = ConnectionState.None
|
||||||
|
result.rng = rng
|
||||||
|
|
||||||
when useSnappy:
|
when useSnappy:
|
||||||
result.protocolVersion = if useCompression: devp2pSnappyVersion
|
result.protocolVersion = if useCompression: devp2pSnappyVersion
|
||||||
|
|
108
eth/p2p/auth.nim
108
eth/p2p/auth.nim
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
{.push raises: [Defect].}
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
import eth/[keys, rlp], nimcrypto
|
import eth/[keys, rlp], nimcrypto/[rijndael, keccak, utils], bearssl
|
||||||
import ecies
|
import ecies
|
||||||
import stew/[byteutils, endians2, objects, results]
|
import stew/[byteutils, endians2, objects, results]
|
||||||
|
|
||||||
|
@ -54,7 +54,6 @@ type
|
||||||
Eip8 ## Flag indicates that EIP-8 handshake is used
|
Eip8 ## Flag indicates that EIP-8 handshake is used
|
||||||
|
|
||||||
AuthError* = enum
|
AuthError* = enum
|
||||||
RandomError = "auth: could not obtain random data"
|
|
||||||
EcdhError = "auth: ECDH shared secret could not be calculated"
|
EcdhError = "auth: ECDH shared secret could not be calculated"
|
||||||
BufferOverrun = "auth: buffer overrun"
|
BufferOverrun = "auth: buffer overrun"
|
||||||
SignatureError = "auth: signature could not be obtained"
|
SignatureError = "auth: signature could not be obtained"
|
||||||
|
@ -95,7 +94,8 @@ proc mapErrTo[T, E](r: Result[T, E], v: static AuthError): AuthResult[T] =
|
||||||
r.mapErr(proc (e: E): AuthError = v)
|
r.mapErr(proc (e: E): AuthError = v)
|
||||||
|
|
||||||
proc tryInit*(
|
proc tryInit*(
|
||||||
T: type Handshake, host: KeyPair, flags: set[HandshakeFlag] = {Initiator},
|
T: type Handshake, rng: var BrHmacDrbgContext, host: KeyPair,
|
||||||
|
flags: set[HandshakeFlag] = {Initiator},
|
||||||
version: uint8 = SupportedRlpxVersion): AuthResult[T] =
|
version: uint8 = SupportedRlpxVersion): AuthResult[T] =
|
||||||
## Create new `Handshake` object.
|
## Create new `Handshake` object.
|
||||||
|
|
||||||
|
@ -103,16 +103,14 @@ proc tryInit*(
|
||||||
initiatorNonce: Nonce
|
initiatorNonce: Nonce
|
||||||
responderNonce: Nonce
|
responderNonce: Nonce
|
||||||
expectedLength: int
|
expectedLength: int
|
||||||
ephemeral = ? KeyPair.random().mapErrTo(RandomError)
|
ephemeral = KeyPair.random(rng)
|
||||||
|
|
||||||
if Initiator in flags:
|
if Initiator in flags:
|
||||||
expectedLength = AckMessageV4Length
|
expectedLength = AckMessageV4Length
|
||||||
if randomBytes(initiatorNonce) != len(initiatorNonce):
|
brHmacDrbgGenerate(rng, initiatorNonce)
|
||||||
return err(RandomError)
|
|
||||||
else:
|
else:
|
||||||
expectedLength = AuthMessageV4Length
|
expectedLength = AuthMessageV4Length
|
||||||
if randomBytes(responderNonce) != len(responderNonce):
|
brHmacDrbgGenerate(rng, responderNonce)
|
||||||
return err(RandomError)
|
|
||||||
|
|
||||||
return ok(T(
|
return ok(T(
|
||||||
version: version,
|
version: version,
|
||||||
|
@ -125,6 +123,7 @@ proc tryInit*(
|
||||||
))
|
))
|
||||||
|
|
||||||
proc authMessagePreEIP8(h: var Handshake,
|
proc authMessagePreEIP8(h: var Handshake,
|
||||||
|
rng: var BrHmacDrbgContext,
|
||||||
pubkey: PublicKey,
|
pubkey: PublicKey,
|
||||||
output: var openarray[byte],
|
output: var openarray[byte],
|
||||||
outlen: var int,
|
outlen: var int,
|
||||||
|
@ -137,12 +136,11 @@ proc authMessagePreEIP8(h: var Handshake,
|
||||||
let header = cast[ptr AuthMessageV4](addr buffer[0])
|
let header = cast[ptr AuthMessageV4](addr buffer[0])
|
||||||
|
|
||||||
var secret = ecdhRaw(h.host.seckey, pubkey)
|
var secret = ecdhRaw(h.host.seckey, pubkey)
|
||||||
let xornonce = secret.data xor h.initiatorNonce
|
secret.data = secret.data xor h.initiatorNonce
|
||||||
|
|
||||||
|
let signature = sign(h.ephemeral.seckey, SkMessage(secret.data))
|
||||||
secret.clear()
|
secret.clear()
|
||||||
|
|
||||||
let signature = sign(h.ephemeral.seckey, SkMessage(data: xornonce))
|
|
||||||
|
|
||||||
h.remoteHPubkey = pubkey
|
h.remoteHPubkey = pubkey
|
||||||
header.signature = signature.toRaw()
|
header.signature = signature.toRaw()
|
||||||
header.keyhash = keccak256.digest(h.ephemeral.pubkey.toRaw()).data
|
header.keyhash = keccak256.digest(h.ephemeral.pubkey.toRaw()).data
|
||||||
|
@ -152,7 +150,7 @@ proc authMessagePreEIP8(h: var Handshake,
|
||||||
if encrypt:
|
if encrypt:
|
||||||
if len(output) < AuthMessageV4Length:
|
if len(output) < AuthMessageV4Length:
|
||||||
return err(BufferOverrun)
|
return err(BufferOverrun)
|
||||||
if eciesEncrypt(buffer, output, h.remoteHPubkey).isErr:
|
if eciesEncrypt(rng, buffer, output, h.remoteHPubkey).isErr:
|
||||||
return err(EciesError)
|
return err(EciesError)
|
||||||
outlen = AuthMessageV4Length
|
outlen = AuthMessageV4Length
|
||||||
else:
|
else:
|
||||||
|
@ -164,6 +162,7 @@ proc authMessagePreEIP8(h: var Handshake,
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
proc authMessageEIP8(h: var Handshake,
|
proc authMessageEIP8(h: var Handshake,
|
||||||
|
rng: var BrHmacDrbgContext,
|
||||||
pubkey: PublicKey,
|
pubkey: PublicKey,
|
||||||
output: var openarray[byte],
|
output: var openarray[byte],
|
||||||
outlen: var int,
|
outlen: var int,
|
||||||
|
@ -172,50 +171,49 @@ proc authMessageEIP8(h: var Handshake,
|
||||||
## Create EIP8 authentication message.
|
## Create EIP8 authentication message.
|
||||||
var
|
var
|
||||||
buffer: array[PlainAuthMessageMaxEIP8, byte]
|
buffer: array[PlainAuthMessageMaxEIP8, byte]
|
||||||
padsize: byte
|
padsize: array[1, byte]
|
||||||
|
|
||||||
doAssert(EIP8 in h.flags)
|
doAssert(EIP8 in h.flags)
|
||||||
outlen = 0
|
outlen = 0
|
||||||
var
|
|
||||||
secret = ecdhRaw(h.host.seckey, pubkey)
|
|
||||||
xornonce = secret.data xor h.initiatorNonce
|
|
||||||
|
|
||||||
|
var secret = ecdhRaw(h.host.seckey, pubkey)
|
||||||
|
secret.data = secret.data xor h.initiatorNonce
|
||||||
|
|
||||||
|
let signature = sign(h.ephemeral.seckey, SkMessage(secret.data))
|
||||||
secret.clear()
|
secret.clear()
|
||||||
|
|
||||||
let signature = sign(h.ephemeral.seckey, SkMessage(data: xornonce))
|
|
||||||
|
|
||||||
h.remoteHPubkey = pubkey
|
h.remoteHPubkey = pubkey
|
||||||
var payload = rlp.encodeList(signature.toRaw(),
|
var payload = rlp.encodeList(signature.toRaw(),
|
||||||
h.host.pubkey.toRaw(),
|
h.host.pubkey.toRaw(),
|
||||||
h.initiatorNonce,
|
h.initiatorNonce,
|
||||||
[byte(h.version)])
|
[byte(h.version)])
|
||||||
doAssert(len(payload) == PlainAuthMessageEIP8Length)
|
doAssert(len(payload) == PlainAuthMessageEIP8Length)
|
||||||
let pencsize = eciesEncryptedLength(len(payload))
|
let
|
||||||
|
pencsize = eciesEncryptedLength(len(payload))
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
if randomBytes(addr padsize, 1) != 1:
|
brHmacDrbgGenerate(rng, padsize)
|
||||||
return err(RandomError)
|
if int(padsize[0]) > (AuthMessageV4Length - (pencsize + 2)):
|
||||||
if int(padsize) > (AuthMessageV4Length - (pencsize + 2)):
|
|
||||||
break
|
break
|
||||||
# It is possible to make packet size constant by uncommenting this line
|
# It is possible to make packet size constant by uncommenting this line
|
||||||
# padsize = 24
|
# padsize = 24
|
||||||
let wosize = pencsize + int(padsize)
|
let wosize = pencsize + int(padsize[0])
|
||||||
let fullsize = wosize + 2
|
let fullsize = wosize + 2
|
||||||
if randomBytes(toa(buffer, PlainAuthMessageEIP8Length,
|
brHmacDrbgGenerate(
|
||||||
int(padsize))) != int(padsize):
|
rng, toa(buffer, PlainAuthMessageEIP8Length, int(padsize[0])))
|
||||||
return err(RandomError)
|
|
||||||
if encrypt:
|
if encrypt:
|
||||||
copyMem(addr buffer[0], addr payload[0], len(payload))
|
copyMem(addr buffer[0], addr payload[0], len(payload))
|
||||||
if len(output) < fullsize:
|
if len(output) < fullsize:
|
||||||
return err(BufferOverrun)
|
return err(BufferOverrun)
|
||||||
let wosizeBE = uint16(wosize).toBytesBE()
|
let wosizeBE = uint16(wosize).toBytesBE()
|
||||||
output[0..<2] = wosizeBE
|
output[0..<2] = wosizeBE
|
||||||
if eciesEncrypt(toa(buffer, 0, len(payload) + int(padsize)),
|
if eciesEncrypt(rng, toa(buffer, 0, len(payload) + int(padsize[0])),
|
||||||
toa(output, 2, wosize), pubkey,
|
toa(output, 2, wosize), pubkey,
|
||||||
toa(output, 0, 2)).isErr:
|
toa(output, 0, 2)).isErr:
|
||||||
return err(EciesError)
|
return err(EciesError)
|
||||||
outlen = fullsize
|
outlen = fullsize
|
||||||
else:
|
else:
|
||||||
let plainsize = len(payload) + int(padsize)
|
let plainsize = len(payload) + int(padsize[0])
|
||||||
if len(output) < plainsize:
|
if len(output) < plainsize:
|
||||||
return err(BufferOverrun)
|
return err(BufferOverrun)
|
||||||
copyMem(addr output[0], addr buffer[0], plainsize)
|
copyMem(addr output[0], addr buffer[0], plainsize)
|
||||||
|
@ -224,6 +222,7 @@ proc authMessageEIP8(h: var Handshake,
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
proc ackMessagePreEIP8(h: var Handshake,
|
proc ackMessagePreEIP8(h: var Handshake,
|
||||||
|
rng: var BrHmacDrbgContext,
|
||||||
output: var openarray[byte],
|
output: var openarray[byte],
|
||||||
outlen: var int,
|
outlen: var int,
|
||||||
flag: byte = 0,
|
flag: byte = 0,
|
||||||
|
@ -238,7 +237,7 @@ proc ackMessagePreEIP8(h: var Handshake,
|
||||||
if encrypt:
|
if encrypt:
|
||||||
if len(output) < AckMessageV4Length:
|
if len(output) < AckMessageV4Length:
|
||||||
return err(BufferOverrun)
|
return err(BufferOverrun)
|
||||||
if eciesEncrypt(buffer, output, h.remoteHPubkey).isErr:
|
if eciesEncrypt(rng, buffer, output, h.remoteHPubkey).isErr:
|
||||||
return err(EciesError)
|
return err(EciesError)
|
||||||
outlen = AckMessageV4Length
|
outlen = AckMessageV4Length
|
||||||
else:
|
else:
|
||||||
|
@ -250,6 +249,7 @@ proc ackMessagePreEIP8(h: var Handshake,
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
proc ackMessageEIP8(h: var Handshake,
|
proc ackMessageEIP8(h: var Handshake,
|
||||||
|
rng: var BrHmacDrbgContext,
|
||||||
output: var openarray[byte],
|
output: var openarray[byte],
|
||||||
outlen: var int,
|
outlen: var int,
|
||||||
flag: byte = 0,
|
flag: byte = 0,
|
||||||
|
@ -257,7 +257,7 @@ proc ackMessageEIP8(h: var Handshake,
|
||||||
## Create EIP8 authentication ack message.
|
## Create EIP8 authentication ack message.
|
||||||
var
|
var
|
||||||
buffer: array[PlainAckMessageMaxEIP8, byte]
|
buffer: array[PlainAckMessageMaxEIP8, byte]
|
||||||
padsize: byte
|
padsize: array[1, byte]
|
||||||
doAssert(EIP8 in h.flags)
|
doAssert(EIP8 in h.flags)
|
||||||
var payload = rlp.encodeList(h.ephemeral.pubkey.toRaw(),
|
var payload = rlp.encodeList(h.ephemeral.pubkey.toRaw(),
|
||||||
h.responderNonce,
|
h.responderNonce,
|
||||||
|
@ -266,30 +266,29 @@ proc ackMessageEIP8(h: var Handshake,
|
||||||
outlen = 0
|
outlen = 0
|
||||||
let pencsize = eciesEncryptedLength(len(payload))
|
let pencsize = eciesEncryptedLength(len(payload))
|
||||||
while true:
|
while true:
|
||||||
if randomBytes(addr padsize, 1) != 1:
|
brHmacDrbgGenerate(rng, padsize)
|
||||||
return err(RandomError)
|
if int(padsize[0]) > (AckMessageV4Length - (pencsize + 2)):
|
||||||
if int(padsize) > (AckMessageV4Length - (pencsize + 2)):
|
|
||||||
break
|
break
|
||||||
# It is possible to make packet size constant by uncommenting this line
|
# It is possible to make packet size constant by uncommenting this line
|
||||||
# padsize = 0
|
# padsize = 0
|
||||||
let wosize = pencsize + int(padsize)
|
let wosize = pencsize + int(padsize[0])
|
||||||
let fullsize = wosize + 2
|
let fullsize = wosize + 2
|
||||||
if int(padsize) > 0:
|
if int(padsize[0]) > 0:
|
||||||
if randomBytes(toa(buffer, PlainAckMessageEIP8Length,
|
brHmacDrbgGenerate(
|
||||||
int(padsize))) != int(padsize):
|
rng, toa(buffer, PlainAckMessageEIP8Length, int(padsize[0])))
|
||||||
return err(RandomError)
|
|
||||||
copyMem(addr buffer[0], addr payload[0], len(payload))
|
copyMem(addr buffer[0], addr payload[0], len(payload))
|
||||||
if encrypt:
|
if encrypt:
|
||||||
if len(output) < fullsize:
|
if len(output) < fullsize:
|
||||||
return err(BufferOverrun)
|
return err(BufferOverrun)
|
||||||
output[0..<2] = uint16(wosize).toBytesBE()
|
output[0..<2] = uint16(wosize).toBytesBE()
|
||||||
if eciesEncrypt(toa(buffer, 0, len(payload) + int(padsize)),
|
if eciesEncrypt(rng, toa(buffer, 0, len(payload) + int(padsize[0])),
|
||||||
toa(output, 2, wosize), h.remoteHPubkey,
|
toa(output, 2, wosize), h.remoteHPubkey,
|
||||||
toa(output, 0, 2)).isErr:
|
toa(output, 0, 2)).isErr:
|
||||||
return err(EciesError)
|
return err(EciesError)
|
||||||
outlen = fullsize
|
outlen = fullsize
|
||||||
else:
|
else:
|
||||||
let plainsize = len(payload) + int(padsize)
|
let plainsize = len(payload) + int(padsize[0])
|
||||||
if len(output) < plainsize:
|
if len(output) < plainsize:
|
||||||
return err(BufferOverrun)
|
return err(BufferOverrun)
|
||||||
copyMem(addr output[0], addr buffer[0], plainsize)
|
copyMem(addr output[0], addr buffer[0], plainsize)
|
||||||
|
@ -311,26 +310,28 @@ template ackSize*(h: Handshake, encrypt: bool = true): int =
|
||||||
else:
|
else:
|
||||||
if encrypt: (AckMessageV4Length) else: (PlainAckMessageV4Length)
|
if encrypt: (AckMessageV4Length) else: (PlainAckMessageV4Length)
|
||||||
|
|
||||||
proc authMessage*(h: var Handshake, pubkey: PublicKey,
|
proc authMessage*(h: var Handshake, rng: var BrHmacDrbgContext,
|
||||||
|
pubkey: PublicKey,
|
||||||
output: var openarray[byte],
|
output: var openarray[byte],
|
||||||
outlen: var int, flag: byte = 0,
|
outlen: var int, flag: byte = 0,
|
||||||
encrypt: bool = true): AuthResult[void] =
|
encrypt: bool = true): AuthResult[void] =
|
||||||
## Create new AuthMessage for specified `pubkey` and store it inside
|
## Create new AuthMessage for specified `pubkey` and store it inside
|
||||||
## of `output`, size of generated AuthMessage will stored in `outlen`.
|
## of `output`, size of generated AuthMessage will stored in `outlen`.
|
||||||
if EIP8 in h.flags:
|
if EIP8 in h.flags:
|
||||||
authMessageEIP8(h, pubkey, output, outlen, flag, encrypt)
|
authMessageEIP8(h, rng, pubkey, output, outlen, flag, encrypt)
|
||||||
else:
|
else:
|
||||||
authMessagePreEIP8(h, pubkey, output, outlen, flag, encrypt)
|
authMessagePreEIP8(h, rng, pubkey, output, outlen, flag, encrypt)
|
||||||
|
|
||||||
proc ackMessage*(h: var Handshake, output: var openarray[byte],
|
proc ackMessage*(h: var Handshake, rng: var BrHmacDrbgContext,
|
||||||
|
output: var openarray[byte],
|
||||||
outlen: var int, flag: byte = 0,
|
outlen: var int, flag: byte = 0,
|
||||||
encrypt: bool = true): AuthResult[void] =
|
encrypt: bool = true): AuthResult[void] =
|
||||||
## Create new AckMessage and store it inside of `output`, size of generated
|
## Create new AckMessage and store it inside of `output`, size of generated
|
||||||
## AckMessage will stored in `outlen`.
|
## AckMessage will stored in `outlen`.
|
||||||
if EIP8 in h.flags:
|
if EIP8 in h.flags:
|
||||||
ackMessageEIP8(h, output, outlen, flag, encrypt)
|
ackMessageEIP8(h, rng, output, outlen, flag, encrypt)
|
||||||
else:
|
else:
|
||||||
ackMessagePreEIP8(h, output, outlen, flag, encrypt)
|
ackMessagePreEIP8(h, rng, output, outlen, flag, encrypt)
|
||||||
|
|
||||||
proc decodeAuthMessageV4(h: var Handshake, m: openarray[byte]): AuthResult[void] =
|
proc decodeAuthMessageV4(h: var Handshake, m: openarray[byte]): AuthResult[void] =
|
||||||
## Decodes V4 AuthMessage.
|
## Decodes V4 AuthMessage.
|
||||||
|
@ -347,12 +348,12 @@ proc decodeAuthMessageV4(h: var Handshake, m: openarray[byte]): AuthResult[void]
|
||||||
signature = ? Signature.fromRaw(header.signature).mapErrTo(SignatureError)
|
signature = ? Signature.fromRaw(header.signature).mapErrTo(SignatureError)
|
||||||
|
|
||||||
var secret = ecdhRaw(h.host.seckey, pubkey)
|
var secret = ecdhRaw(h.host.seckey, pubkey)
|
||||||
let xornonce = secret.data xor header.nonce
|
secret.data = secret.data xor header.nonce
|
||||||
|
|
||||||
|
var recovered = recover(signature, SkMessage(secret.data))
|
||||||
secret.clear()
|
secret.clear()
|
||||||
|
|
||||||
h.remoteEPubkey =
|
h.remoteEPubkey = ? recovered.mapErrTo(SignatureError)
|
||||||
? recover(signature, SkMessage(data: xornonce)).mapErrTo(SignatureError)
|
|
||||||
h.initiatorNonce = header.nonce
|
h.initiatorNonce = header.nonce
|
||||||
h.remoteHPubkey = pubkey
|
h.remoteHPubkey = pubkey
|
||||||
|
|
||||||
|
@ -392,13 +393,12 @@ proc decodeAuthMessageEip8(h: var Handshake, m: openarray[byte]): AuthResult[voi
|
||||||
nonce = toArray(KeyLength, nonceBr)
|
nonce = toArray(KeyLength, nonceBr)
|
||||||
|
|
||||||
var secret = ecdhRaw(h.host.seckey, pubkey)
|
var secret = ecdhRaw(h.host.seckey, pubkey)
|
||||||
|
secret.data = secret.data xor nonce
|
||||||
|
|
||||||
let xornonce = nonce xor secret.data
|
let recovered = recover(signature, SkMessage(secret.data))
|
||||||
secret.clear()
|
secret.clear()
|
||||||
|
|
||||||
h.remoteEPubkey =
|
h.remoteEPubkey = ? recovered.mapErrTo(SignatureError)
|
||||||
? recover(signature, SkMessage(data: xornonce)).mapErrTo(SignatureError)
|
|
||||||
|
|
||||||
h.initiatorNonce = nonce
|
h.initiatorNonce = nonce
|
||||||
h.remoteHPubkey = pubkey
|
h.remoteHPubkey = pubkey
|
||||||
h.version = versionBr[0]
|
h.version = versionBr[0]
|
||||||
|
@ -520,7 +520,7 @@ proc getSecrets*(
|
||||||
mac1 = ctx0.finish()
|
mac1 = ctx0.finish()
|
||||||
secret.macKey = mac1.data
|
secret.macKey = mac1.data
|
||||||
|
|
||||||
burnMem(shsec)
|
clear(shsec)
|
||||||
|
|
||||||
# egress-mac = keccak256(mac-secret ^ recipient-nonce || auth-sent-init)
|
# egress-mac = keccak256(mac-secret ^ recipient-nonce || auth-sent-init)
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
times,
|
times,
|
||||||
chronos, stint, nimcrypto, chronicles,
|
chronos, stint, nimcrypto/keccak, chronicles, bearssl,
|
||||||
eth/[keys, rlp],
|
eth/[keys, rlp],
|
||||||
kademlia, enode,
|
kademlia, enode,
|
||||||
stew/[objects, results]
|
stew/[objects, results]
|
||||||
|
@ -155,7 +155,7 @@ proc sendNeighbours*(d: DiscoveryProtocol, node: Node, neighbours: seq[Node]) =
|
||||||
if nodes.len != 0: flush()
|
if nodes.len != 0: flush()
|
||||||
|
|
||||||
proc newDiscoveryProtocol*(privKey: PrivateKey, address: Address,
|
proc newDiscoveryProtocol*(privKey: PrivateKey, address: Address,
|
||||||
bootstrapNodes: openarray[ENode]
|
bootstrapNodes: openarray[ENode], rng = newRng()
|
||||||
): DiscoveryProtocol =
|
): DiscoveryProtocol =
|
||||||
result.new()
|
result.new()
|
||||||
result.privKey = privKey
|
result.privKey = privKey
|
||||||
|
@ -163,7 +163,7 @@ proc newDiscoveryProtocol*(privKey: PrivateKey, address: Address,
|
||||||
result.bootstrapNodes = newSeqOfCap[Node](bootstrapNodes.len)
|
result.bootstrapNodes = newSeqOfCap[Node](bootstrapNodes.len)
|
||||||
for n in bootstrapNodes: result.bootstrapNodes.add(newNode(n))
|
for n in bootstrapNodes: result.bootstrapNodes.add(newNode(n))
|
||||||
result.thisNode = newNode(privKey.toPublicKey(), address)
|
result.thisNode = newNode(privKey.toPublicKey(), address)
|
||||||
result.kademlia = newKademliaProtocol(result.thisNode, result)
|
result.kademlia = newKademliaProtocol(result.thisNode, result, rng = rng)
|
||||||
|
|
||||||
proc recvPing(d: DiscoveryProtocol, node: Node,
|
proc recvPing(d: DiscoveryProtocol, node: Node,
|
||||||
msgHash: MDigest[256]) {.inline.} =
|
msgHash: MDigest[256]) {.inline.} =
|
||||||
|
|
|
@ -28,7 +28,7 @@ proc makeKey(id: NodeId, address: Address): array[keySize, byte] =
|
||||||
of IpAddressFamily.IpV4:
|
of IpAddressFamily.IpV4:
|
||||||
result[pos ..< pos+sizeof(address.ip.address_v4)] = address.ip.address_v4
|
result[pos ..< pos+sizeof(address.ip.address_v4)] = address.ip.address_v4
|
||||||
of IpAddressFamily.IpV6:
|
of IpAddressFamily.IpV6:
|
||||||
result[pos..< pos+sizeof(address.ip.address_v6)] = address.ip.address_v6
|
result[pos ..< pos+sizeof(address.ip.address_v6)] = address.ip.address_v6
|
||||||
pos.inc(sizeof(address.ip.address_v6))
|
pos.inc(sizeof(address.ip.address_v6))
|
||||||
result[pos ..< pos+sizeof(address.port)] = toBytes(address.port.uint16)
|
result[pos ..< pos+sizeof(address.port)] = toBytes(address.port.uint16)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import
|
import
|
||||||
std/[tables, options], nimcrypto, stint, chronicles, stew/results,
|
std/[tables, options], nimcrypto, stint, chronicles, stew/results,
|
||||||
types, node, enr, hkdf, eth/[rlp, keys]
|
types, node, enr, hkdf, eth/[rlp, keys], bearssl
|
||||||
|
|
||||||
export keys
|
export keys
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ proc idNonceHash(nonce, ephkey: openarray[byte]): MDigest[256] =
|
||||||
|
|
||||||
proc signIDNonce*(privKey: PrivateKey, idNonce, ephKey: openarray[byte]):
|
proc signIDNonce*(privKey: PrivateKey, idNonce, ephKey: openarray[byte]):
|
||||||
SignatureNR =
|
SignatureNR =
|
||||||
signNR(privKey, idNonceHash(idNonce, ephKey))
|
signNR(privKey, SkMessage(idNonceHash(idNonce, ephKey).data))
|
||||||
|
|
||||||
proc deriveKeys(n1, n2: NodeID, priv: PrivateKey, pub: PublicKey,
|
proc deriveKeys(n1, n2: NodeID, priv: PrivateKey, pub: PublicKey,
|
||||||
idNonce: openarray[byte]): HandshakeSecrets =
|
idNonce: openarray[byte]): HandshakeSecrets =
|
||||||
|
@ -89,11 +89,12 @@ proc encryptGCM*(key, nonce, pt, authData: openarray[byte]): seq[byte] =
|
||||||
ectx.getTag(result.toOpenArray(pt.len, result.high))
|
ectx.getTag(result.toOpenArray(pt.len, result.high))
|
||||||
ectx.clear()
|
ectx.clear()
|
||||||
|
|
||||||
proc encodeAuthHeader*(c: Codec,
|
proc encodeAuthHeader*(rng: var BrHmacDrbgContext,
|
||||||
|
c: Codec,
|
||||||
toId: NodeID,
|
toId: NodeID,
|
||||||
nonce: array[gcmNonceSize, byte],
|
nonce: array[gcmNonceSize, byte],
|
||||||
challenge: Whoareyou):
|
challenge: Whoareyou):
|
||||||
EncodeResult[(seq[byte], HandshakeSecrets)] =
|
(seq[byte], HandshakeSecrets) =
|
||||||
var resp = AuthResponse(version: 5)
|
var resp = AuthResponse(version: 5)
|
||||||
let ln = c.localNode
|
let ln = c.localNode
|
||||||
|
|
||||||
|
@ -101,7 +102,7 @@ proc encodeAuthHeader*(c: Codec,
|
||||||
if challenge.recordSeq < ln.record.seqNum:
|
if challenge.recordSeq < ln.record.seqNum:
|
||||||
resp.record = ln.record
|
resp.record = ln.record
|
||||||
|
|
||||||
let ephKeys = ? KeyPair.random()
|
let ephKeys = KeyPair.random(rng)
|
||||||
let signature = signIDNonce(c.privKey, challenge.idNonce,
|
let signature = signIDNonce(c.privKey, challenge.idNonce,
|
||||||
ephKeys.pubkey.toRaw)
|
ephKeys.pubkey.toRaw)
|
||||||
resp.signature = signature.toRaw
|
resp.signature = signature.toRaw
|
||||||
|
@ -117,7 +118,7 @@ proc encodeAuthHeader*(c: Codec,
|
||||||
let header = AuthHeader(auth: nonce, idNonce: challenge.idNonce,
|
let header = AuthHeader(auth: nonce, idNonce: challenge.idNonce,
|
||||||
scheme: authSchemeName, ephemeralKey: ephKeys.pubkey.toRaw,
|
scheme: authSchemeName, ephemeralKey: ephKeys.pubkey.toRaw,
|
||||||
response: respEnc)
|
response: respEnc)
|
||||||
ok((rlp.encode(header), secrets))
|
(rlp.encode(header), secrets)
|
||||||
|
|
||||||
proc `xor`[N: static[int], T](a, b: array[N, T]): array[N, T] =
|
proc `xor`[N: static[int], T](a, b: array[N, T]): array[N, T] =
|
||||||
for i in 0 .. a.high:
|
for i in 0 .. a.high:
|
||||||
|
@ -130,15 +131,16 @@ proc packetTag(destNode, srcNode: NodeID): PacketTag =
|
||||||
destidHash = sha256.digest(destId)
|
destidHash = sha256.digest(destId)
|
||||||
result = srcId xor destidHash.data
|
result = srcId xor destidHash.data
|
||||||
|
|
||||||
proc encodePacket*(c: Codec,
|
proc encodePacket*(
|
||||||
toId: NodeID,
|
rng: var BrHmacDrbgContext,
|
||||||
toAddr: Address,
|
c: Codec,
|
||||||
message: openarray[byte],
|
toId: NodeID,
|
||||||
challenge: Whoareyou):
|
toAddr: Address,
|
||||||
EncodeResult[(seq[byte], array[gcmNonceSize, byte])] =
|
message: openarray[byte],
|
||||||
|
challenge: Whoareyou):
|
||||||
|
(seq[byte], array[gcmNonceSize, byte]) =
|
||||||
var nonce: array[gcmNonceSize, byte]
|
var nonce: array[gcmNonceSize, byte]
|
||||||
if randomBytes(nonce) != nonce.len:
|
brHmacDrbgGenerate(rng, nonce)
|
||||||
return err("Could not randomize bytes")
|
|
||||||
|
|
||||||
var headEnc: seq[byte]
|
var headEnc: seq[byte]
|
||||||
|
|
||||||
|
@ -153,7 +155,7 @@ proc encodePacket*(c: Codec,
|
||||||
discard c.db.loadKeys(toId, toAddr, readKey, writeKey)
|
discard c.db.loadKeys(toId, toAddr, readKey, writeKey)
|
||||||
else:
|
else:
|
||||||
var secrets: HandshakeSecrets
|
var secrets: HandshakeSecrets
|
||||||
(headEnc, secrets) = ? c.encodeAuthHeader(toId, nonce, challenge)
|
(headEnc, secrets) = encodeAuthHeader(rng, c, toId, nonce, challenge)
|
||||||
|
|
||||||
writeKey = secrets.writeKey
|
writeKey = secrets.writeKey
|
||||||
# TODO: is it safe to ignore the error here?
|
# TODO: is it safe to ignore the error here?
|
||||||
|
@ -165,7 +167,7 @@ proc encodePacket*(c: Codec,
|
||||||
packet.add(tag)
|
packet.add(tag)
|
||||||
packet.add(headEnc)
|
packet.add(headEnc)
|
||||||
packet.add(encryptGCM(writeKey, nonce, message, tag))
|
packet.add(encryptGCM(writeKey, nonce, message, tag))
|
||||||
ok((packet, nonce))
|
(packet, nonce)
|
||||||
|
|
||||||
proc decryptGCM*(key: AesKey, nonce, ct, authData: openarray[byte]):
|
proc decryptGCM*(key: AesKey, nonce, ct, authData: openarray[byte]):
|
||||||
Option[seq[byte]] =
|
Option[seq[byte]] =
|
||||||
|
@ -260,7 +262,7 @@ proc decodeAuthResp*(c: Codec, fromId: NodeId, head: AuthHeader,
|
||||||
# Verify the id-nonce-sig
|
# Verify the id-nonce-sig
|
||||||
let sig = ? SignatureNR.fromRaw(authResp.signature).mapErrTo(HandshakeError)
|
let sig = ? SignatureNR.fromRaw(authResp.signature).mapErrTo(HandshakeError)
|
||||||
let h = idNonceHash(head.idNonce, head.ephemeralKey)
|
let h = idNonceHash(head.idNonce, head.ephemeralKey)
|
||||||
if verify(sig, h, newNode.pubkey):
|
if verify(sig, SkMessage(h.data), newNode.pubkey):
|
||||||
ok(secrets)
|
ok(secrets)
|
||||||
else:
|
else:
|
||||||
err(HandshakeError)
|
err(HandshakeError)
|
||||||
|
@ -332,12 +334,12 @@ proc decodePacket*(c: var Codec,
|
||||||
|
|
||||||
decodeMessage(message.get())
|
decodeMessage(message.get())
|
||||||
|
|
||||||
proc newRequestId*(): Result[RequestId, cstring] =
|
proc init*(T: type RequestId, rng: var BrHmacDrbgContext): T =
|
||||||
var id: RequestId
|
var buf: array[sizeof(T), byte]
|
||||||
if randomBytes(addr id, sizeof(id)) != sizeof(id):
|
brHmacDrbgGenerate(rng, buf)
|
||||||
err("Could not randomize bytes")
|
var id: T
|
||||||
else:
|
copyMem(addr id, addr buf[0], sizeof(id))
|
||||||
ok(id)
|
id
|
||||||
|
|
||||||
proc numFields(T: typedesc): int =
|
proc numFields(T: typedesc): int =
|
||||||
for k, v in fieldPairs(default(T)): inc result
|
for k, v in fieldPairs(default(T)): inc result
|
||||||
|
|
|
@ -232,7 +232,7 @@ proc verifySignatureV4(r: Record, sigData: openarray[byte], content: seq[byte]):
|
||||||
let sig = SignatureNR.fromRaw(sigData)
|
let sig = SignatureNR.fromRaw(sigData)
|
||||||
if sig.isOk:
|
if sig.isOk:
|
||||||
var h = keccak256.digest(content)
|
var h = keccak256.digest(content)
|
||||||
return verify(sig[], h, publicKey.get)
|
return verify(sig[], SkMessage(h.data), publicKey.get)
|
||||||
|
|
||||||
proc verifySignature(r: Record): bool {.raises: [RlpError, Defect].} =
|
proc verifySignature(r: Record): bool {.raises: [RlpError, Defect].} =
|
||||||
var rlp = rlpFromBytes(r.raw)
|
var rlp = rlpFromBytes(r.raw)
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
## This might be a concern for mobile devices.
|
## This might be a concern for mobile devices.
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[tables, sets, options, math, random],
|
std/[tables, sets, options, math, random], bearssl,
|
||||||
stew/shims/net as stewNet, json_serialization/std/net,
|
stew/shims/net as stewNet, json_serialization/std/net,
|
||||||
stew/[byteutils, endians2], chronicles, chronos, stint,
|
stew/[byteutils, endians2], chronicles, chronos, stint,
|
||||||
eth/[rlp, keys, async_utils], types, encoding, node, routing_table, enr
|
eth/[rlp, keys, async_utils], types, encoding, node, routing_table, enr
|
||||||
|
@ -120,6 +120,7 @@ type
|
||||||
lookupLoop: Future[void]
|
lookupLoop: Future[void]
|
||||||
revalidateLoop: Future[void]
|
revalidateLoop: Future[void]
|
||||||
bootstrapRecords*: seq[Record]
|
bootstrapRecords*: seq[Record]
|
||||||
|
rng*: ref BrHmacDrbgContext
|
||||||
|
|
||||||
PendingRequest = object
|
PendingRequest = object
|
||||||
node: Node
|
node: Node
|
||||||
|
@ -222,9 +223,7 @@ proc sendWhoareyou(d: Protocol, address: Address, toNode: NodeId,
|
||||||
authTag: AuthTag): DiscResult[void] {.raises: [Exception, Defect].} =
|
authTag: AuthTag): DiscResult[void] {.raises: [Exception, Defect].} =
|
||||||
trace "sending who are you", to = $toNode, toAddress = $address
|
trace "sending who are you", to = $toNode, toAddress = $address
|
||||||
let challenge = Whoareyou(authTag: authTag, recordSeq: 0)
|
let challenge = Whoareyou(authTag: authTag, recordSeq: 0)
|
||||||
|
brHmacDrbgGenerate(d.rng[], challenge.idNonce)
|
||||||
if randomBytes(challenge.idNonce) != challenge.idNonce.len:
|
|
||||||
return err("Could not randomize bytes")
|
|
||||||
|
|
||||||
# If there is already a handshake going on for this nodeid then we drop this
|
# If there is already a handshake going on for this nodeid then we drop this
|
||||||
# new one. Handshake will get cleaned up after `handshakeTimeout`.
|
# new one. Handshake will get cleaned up after `handshakeTimeout`.
|
||||||
|
@ -250,17 +249,18 @@ proc sendWhoareyou(d: Protocol, address: Address, toNode: NodeId,
|
||||||
err("NodeId already has ongoing handshake")
|
err("NodeId already has ongoing handshake")
|
||||||
|
|
||||||
proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address, reqId: RequestId,
|
proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address, reqId: RequestId,
|
||||||
nodes: openarray[Node]): DiscResult[void] =
|
nodes: openarray[Node]) =
|
||||||
proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address,
|
proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address,
|
||||||
message: NodesMessage, reqId: RequestId): DiscResult[void] {.nimcall.} =
|
message: NodesMessage, reqId: RequestId) {.nimcall.} =
|
||||||
let (data, _) = ? d.codec.encodePacket(toId, toAddr,
|
let (data, _) = encodePacket(
|
||||||
|
d.rng[], d.codec, toId, toAddr,
|
||||||
encodeMessage(message, reqId), challenge = nil)
|
encodeMessage(message, reqId), challenge = nil)
|
||||||
d.send(toAddr, data)
|
d.send(toAddr, data)
|
||||||
ok()
|
|
||||||
|
|
||||||
if nodes.len == 0:
|
if nodes.len == 0:
|
||||||
# In case of 0 nodes, a reply is still needed
|
# In case of 0 nodes, a reply is still needed
|
||||||
return d.sendNodes(toId, toAddr, NodesMessage(total: 1, enrs: @[]), reqId)
|
d.sendNodes(toId, toAddr, NodesMessage(total: 1, enrs: @[]), reqId)
|
||||||
|
return
|
||||||
|
|
||||||
var message: NodesMessage
|
var message: NodesMessage
|
||||||
# TODO: Do the total calculation based on the max UDP packet size we want to
|
# TODO: Do the total calculation based on the max UDP packet size we want to
|
||||||
|
@ -271,19 +271,14 @@ proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address, reqId: RequestId,
|
||||||
for i in 0 ..< nodes.len:
|
for i in 0 ..< nodes.len:
|
||||||
message.enrs.add(nodes[i].record)
|
message.enrs.add(nodes[i].record)
|
||||||
if message.enrs.len == maxNodesPerMessage:
|
if message.enrs.len == maxNodesPerMessage:
|
||||||
let res = d.sendNodes(toId, toAddr, message, reqId)
|
d.sendNodes(toId, toAddr, message, reqId)
|
||||||
if res.isErr: # TODO: is there something nicer for this?
|
|
||||||
return res
|
|
||||||
message.enrs.setLen(0)
|
message.enrs.setLen(0)
|
||||||
|
|
||||||
if message.enrs.len != 0:
|
if message.enrs.len != 0:
|
||||||
let res = d.sendNodes(toId, toAddr, message, reqId)
|
d.sendNodes(toId, toAddr, message, reqId)
|
||||||
if res.isErr: # TODO: is there something nicer for this?
|
|
||||||
return res
|
|
||||||
ok()
|
|
||||||
|
|
||||||
proc handlePing(d: Protocol, fromId: NodeId, fromAddr: Address,
|
proc handlePing(d: Protocol, fromId: NodeId, fromAddr: Address,
|
||||||
ping: PingMessage, reqId: RequestId): DiscResult[void] =
|
ping: PingMessage, reqId: RequestId) =
|
||||||
let a = fromAddr
|
let a = fromAddr
|
||||||
var pong: PongMessage
|
var pong: PongMessage
|
||||||
pong.enrSeq = ping.enrSeq
|
pong.enrSeq = ping.enrSeq
|
||||||
|
@ -292,14 +287,13 @@ proc handlePing(d: Protocol, fromId: NodeId, fromAddr: Address,
|
||||||
of IpAddressFamily.IPv6: @(a.ip.address_v6)
|
of IpAddressFamily.IPv6: @(a.ip.address_v6)
|
||||||
pong.port = a.port.uint16
|
pong.port = a.port.uint16
|
||||||
|
|
||||||
let (data, _) = ? d.codec.encodePacket(fromId, fromAddr,
|
let (data, _) = encodePacket(d.rng[], d.codec, fromId, fromAddr,
|
||||||
encodeMessage(pong, reqId), challenge = nil)
|
encodeMessage(pong, reqId), challenge = nil)
|
||||||
|
|
||||||
d.send(fromAddr, data)
|
d.send(fromAddr, data)
|
||||||
ok()
|
|
||||||
|
|
||||||
proc handleFindNode(d: Protocol, fromId: NodeId, fromAddr: Address,
|
proc handleFindNode(d: Protocol, fromId: NodeId, fromAddr: Address,
|
||||||
fn: FindNodeMessage, reqId: RequestId): DiscResult[void] =
|
fn: FindNodeMessage, reqId: RequestId) =
|
||||||
if fn.distance == 0:
|
if fn.distance == 0:
|
||||||
d.sendNodes(fromId, fromAddr, reqId, [d.localNode])
|
d.sendNodes(fromId, fromAddr, reqId, [d.localNode])
|
||||||
else:
|
else:
|
||||||
|
@ -333,14 +327,8 @@ proc receive*(d: Protocol, a: Address, packet: openArray[byte]) {.gcsafe,
|
||||||
let toNode = pr.node
|
let toNode = pr.node
|
||||||
whoareyou.pubKey = toNode.pubkey # TODO: Yeah, rather ugly this.
|
whoareyou.pubKey = toNode.pubkey # TODO: Yeah, rather ugly this.
|
||||||
doAssert(toNode.address.isSome())
|
doAssert(toNode.address.isSome())
|
||||||
let encoded = d.codec.encodePacket(toNode.id, toNode.address.get(),
|
let (data, _) = encodePacket(d.rng[], d.codec, toNode.id, toNode.address.get(),
|
||||||
pr.message, challenge = whoareyou)
|
pr.message, challenge = whoareyou)
|
||||||
# TODO: Perhaps just expect here? Or raise Defect in `encodePacket`?
|
|
||||||
# if this occurs there is an issue with the system anyhow?
|
|
||||||
if encoded.isErr:
|
|
||||||
warn "Not enough randomness to encode packet"
|
|
||||||
return
|
|
||||||
let (data, _) = encoded[]
|
|
||||||
d.send(toNode, data)
|
d.send(toNode, data)
|
||||||
else:
|
else:
|
||||||
debug "Timed out or unrequested WhoAreYou packet"
|
debug "Timed out or unrequested WhoAreYou packet"
|
||||||
|
@ -366,11 +354,9 @@ proc receive*(d: Protocol, a: Address, packet: openArray[byte]) {.gcsafe,
|
||||||
|
|
||||||
case message.kind
|
case message.kind
|
||||||
of ping:
|
of ping:
|
||||||
if d.handlePing(sender, a, message.ping, message.reqId).isErr:
|
d.handlePing(sender, a, message.ping, message.reqId)
|
||||||
debug "Sending Pong message failed"
|
|
||||||
of findNode:
|
of findNode:
|
||||||
if d.handleFindNode(sender, a, message.findNode, message.reqId).isErr:
|
d.handleFindNode(sender, a, message.findNode, message.reqId)
|
||||||
debug "Sending Nodes message failed"
|
|
||||||
else:
|
else:
|
||||||
var waiter: Future[Option[Message]]
|
var waiter: Future[Option[Message]]
|
||||||
if d.awaitedMessages.take((sender, message.reqId), waiter):
|
if d.awaitedMessages.take((sender, message.reqId), waiter):
|
||||||
|
@ -518,24 +504,22 @@ proc waitNodes(d: Protocol, fromNode: Node, reqId: RequestId):
|
||||||
return err("Nodes message not received in time")
|
return err("Nodes message not received in time")
|
||||||
|
|
||||||
proc sendMessage*[T: SomeMessage](d: Protocol, toNode: Node, m: T):
|
proc sendMessage*[T: SomeMessage](d: Protocol, toNode: Node, m: T):
|
||||||
DiscResult[RequestId] {.raises: [Exception, Defect].} =
|
RequestId {.raises: [Exception, Defect].} =
|
||||||
doAssert(toNode.address.isSome())
|
doAssert(toNode.address.isSome())
|
||||||
let
|
let
|
||||||
reqId = ? newRequestId()
|
reqId = RequestId.init(d.rng[])
|
||||||
message = encodeMessage(m, reqId)
|
message = encodeMessage(m, reqId)
|
||||||
(data, nonce) = ? d.codec.encodePacket(toNode.id, toNode.address.get(),
|
(data, nonce) = encodePacket(d.rng[], d.codec, toNode.id, toNode.address.get(),
|
||||||
message, challenge = nil)
|
message, challenge = nil)
|
||||||
d.registerRequest(toNode, message, nonce)
|
d.registerRequest(toNode, message, nonce)
|
||||||
d.send(toNode, data)
|
d.send(toNode, data)
|
||||||
return ok(reqId)
|
return reqId
|
||||||
|
|
||||||
proc ping*(d: Protocol, toNode: Node):
|
proc ping*(d: Protocol, toNode: Node):
|
||||||
Future[DiscResult[PongMessage]] {.async, raises: [Exception, Defect].} =
|
Future[DiscResult[PongMessage]] {.async, raises: [Exception, Defect].} =
|
||||||
let reqId = d.sendMessage(toNode,
|
let reqId = d.sendMessage(toNode,
|
||||||
PingMessage(enrSeq: d.localNode.record.seqNum))
|
PingMessage(enrSeq: d.localNode.record.seqNum))
|
||||||
if reqId.isErr:
|
let resp = await d.waitMessage(toNode, reqId)
|
||||||
return err(reqId.error)
|
|
||||||
let resp = await d.waitMessage(toNode, reqId[])
|
|
||||||
|
|
||||||
if resp.isSome() and resp.get().kind == pong:
|
if resp.isSome() and resp.get().kind == pong:
|
||||||
d.routingTable.setJustSeen(toNode)
|
d.routingTable.setJustSeen(toNode)
|
||||||
|
@ -547,9 +531,7 @@ proc ping*(d: Protocol, toNode: Node):
|
||||||
proc findNode*(d: Protocol, toNode: Node, distance: uint32):
|
proc findNode*(d: Protocol, toNode: Node, distance: uint32):
|
||||||
Future[DiscResult[seq[Node]]] {.async, raises: [Exception, Defect].} =
|
Future[DiscResult[seq[Node]]] {.async, raises: [Exception, Defect].} =
|
||||||
let reqId = d.sendMessage(toNode, FindNodeMessage(distance: distance))
|
let reqId = d.sendMessage(toNode, FindNodeMessage(distance: distance))
|
||||||
if reqId.isErr:
|
let nodes = await d.waitNodes(toNode, reqId)
|
||||||
return err(reqId.error)
|
|
||||||
let nodes = await d.waitNodes(toNode, reqId[])
|
|
||||||
|
|
||||||
if nodes.isOk:
|
if nodes.isOk:
|
||||||
var res = newSeq[Node]()
|
var res = newSeq[Node]()
|
||||||
|
@ -632,15 +614,16 @@ proc lookup*(d: Protocol, target: NodeId): Future[seq[Node]]
|
||||||
if result.len < BUCKET_SIZE:
|
if result.len < BUCKET_SIZE:
|
||||||
result.add(n)
|
result.add(n)
|
||||||
|
|
||||||
proc lookupRandom*(d: Protocol): Future[DiscResult[seq[Node]]]
|
proc lookupRandom*(d: Protocol): Future[seq[Node]]
|
||||||
{.async, raises:[Exception, Defect].} =
|
{.async, raises:[Exception, Defect].} =
|
||||||
## Perform a lookup for a random target, return the closest n nodes to the
|
## Perform a lookup for a random target, return the closest n nodes to the
|
||||||
## target. Maximum value for n is `BUCKET_SIZE`.
|
## target. Maximum value for n is `BUCKET_SIZE`.
|
||||||
var id: NodeId
|
var id: NodeId
|
||||||
if randomBytes(addr id, sizeof(id)) != sizeof(id):
|
var buf: array[sizeof(id), byte]
|
||||||
return err("Could not randomize bytes")
|
brHmacDrbgGenerate(d.rng[], buf)
|
||||||
|
copyMem(addr id, addr buf[0], sizeof(id))
|
||||||
|
|
||||||
return ok(await d.lookup(id))
|
return await d.lookup(id)
|
||||||
|
|
||||||
proc resolve*(d: Protocol, id: NodeId): Future[Option[Node]]
|
proc resolve*(d: Protocol, id: NodeId): Future[Option[Node]]
|
||||||
{.async, raises: [Exception, Defect].} =
|
{.async, raises: [Exception, Defect].} =
|
||||||
|
@ -700,11 +683,8 @@ proc lookupLoop(d: Protocol) {.async, raises: [Exception, Defect].} =
|
||||||
trace "Discovered nodes in self lookup", nodes = $selfLookup
|
trace "Discovered nodes in self lookup", nodes = $selfLookup
|
||||||
while true:
|
while true:
|
||||||
let randomLookup = await d.lookupRandom()
|
let randomLookup = await d.lookupRandom()
|
||||||
if randomLookup.isOK:
|
trace "Discovered nodes in random lookup", nodes = $randomLookup
|
||||||
trace "Discovered nodes in random lookup", nodes = $randomLookup[]
|
trace "Total nodes in routing table", total = d.routingTable.len()
|
||||||
trace "Total nodes in routing table", total = d.routingTable.len()
|
|
||||||
else:
|
|
||||||
trace "random lookup failed", err = randomLookup.error
|
|
||||||
await sleepAsync(lookupInterval)
|
await sleepAsync(lookupInterval)
|
||||||
except CancelledError:
|
except CancelledError:
|
||||||
trace "lookupLoop canceled"
|
trace "lookupLoop canceled"
|
||||||
|
@ -713,7 +693,7 @@ proc newProtocol*(privKey: PrivateKey, db: Database,
|
||||||
externalIp: Option[ValidIpAddress], tcpPort, udpPort: Port,
|
externalIp: Option[ValidIpAddress], tcpPort, udpPort: Port,
|
||||||
localEnrFields: openarray[FieldPair] = [],
|
localEnrFields: openarray[FieldPair] = [],
|
||||||
bootstrapRecords: openarray[Record] = [],
|
bootstrapRecords: openarray[Record] = [],
|
||||||
bindIp = IPv4_any()):
|
bindIp = IPv4_any(), rng = newRng()):
|
||||||
Protocol {.raises: [Defect].} =
|
Protocol {.raises: [Defect].} =
|
||||||
# TODO: Tried adding bindPort = udpPort as parameter but that gave
|
# TODO: Tried adding bindPort = udpPort as parameter but that gave
|
||||||
# "Error: internal error: environment misses: udpPort" in nim-beacon-chain.
|
# "Error: internal error: environment misses: udpPort" in nim-beacon-chain.
|
||||||
|
@ -725,6 +705,9 @@ proc newProtocol*(privKey: PrivateKey, db: Database,
|
||||||
localEnrFields).expect("Properly intialized private key")
|
localEnrFields).expect("Properly intialized private key")
|
||||||
node = newNode(enrRec).expect("Properly initialized node")
|
node = newNode(enrRec).expect("Properly initialized node")
|
||||||
|
|
||||||
|
# TODO Consider whether this should be a Defect
|
||||||
|
doAssert rng != nil, "RNG initialization failed"
|
||||||
|
|
||||||
result = Protocol(
|
result = Protocol(
|
||||||
privateKey: privKey,
|
privateKey: privKey,
|
||||||
db: db,
|
db: db,
|
||||||
|
@ -733,7 +716,8 @@ proc newProtocol*(privKey: PrivateKey, db: Database,
|
||||||
whoareyouMagic: whoareyouMagic(node.id),
|
whoareyouMagic: whoareyouMagic(node.id),
|
||||||
idHash: sha256.digest(node.id.toByteArrayBE).data,
|
idHash: sha256.digest(node.id.toByteArrayBE).data,
|
||||||
codec: Codec(localNode: node, privKey: privKey, db: db),
|
codec: Codec(localNode: node, privKey: privKey, db: db),
|
||||||
bootstrapRecords: @bootstrapRecords)
|
bootstrapRecords: @bootstrapRecords,
|
||||||
|
rng: rng)
|
||||||
|
|
||||||
result.routingTable.init(node, 5)
|
result.routingTable.init(node, 5)
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
|
|
||||||
{.push raises: [Defect].}
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
import eth/keys, nimcrypto/[rijndael, bcmode, hash, hmac, sysrand, sha2, utils]
|
import bearssl
|
||||||
|
import eth/keys, nimcrypto/[rijndael, bcmode, hash, hmac, sha2, utils]
|
||||||
import stew/results
|
import stew/results
|
||||||
|
|
||||||
export results
|
export results
|
||||||
|
@ -23,7 +24,6 @@ const
|
||||||
type
|
type
|
||||||
EciesError* = enum
|
EciesError* = enum
|
||||||
BufferOverrun = "ecies: output buffer size is too small"
|
BufferOverrun = "ecies: output buffer size is too small"
|
||||||
RandomError = "ecies: could not obtain random data"
|
|
||||||
EcdhError = "ecies: ECDH shared secret could not be calculated"
|
EcdhError = "ecies: ECDH shared secret could not be calculated"
|
||||||
WrongHeader = "ecies: header is incorrect"
|
WrongHeader = "ecies: header is incorrect"
|
||||||
IncorrectKey = "ecies: recovered public key is invalid"
|
IncorrectKey = "ecies: recovered public key is invalid"
|
||||||
|
@ -92,8 +92,8 @@ proc kdf*(data: openarray[byte]): array[KeyLength, byte] {.noInit.} =
|
||||||
ctx.clear() # clean ctx
|
ctx.clear() # clean ctx
|
||||||
copyMem(addr result[0], addr storage[0], KeyLength)
|
copyMem(addr result[0], addr storage[0], KeyLength)
|
||||||
|
|
||||||
proc eciesEncrypt*(input: openarray[byte], output: var openarray[byte],
|
proc eciesEncrypt*(rng: var BrHmacDrbgContext, input: openarray[byte],
|
||||||
pubkey: PublicKey,
|
output: var openarray[byte], pubkey: PublicKey,
|
||||||
sharedmac: openarray[byte] = emptyMac): EciesResult[void] =
|
sharedmac: openarray[byte] = emptyMac): EciesResult[void] =
|
||||||
## Encrypt data with ECIES method using given public key `pubkey`.
|
## Encrypt data with ECIES method using given public key `pubkey`.
|
||||||
## ``input`` - input data
|
## ``input`` - input data
|
||||||
|
@ -110,11 +110,11 @@ proc eciesEncrypt*(input: openarray[byte], output: var openarray[byte],
|
||||||
|
|
||||||
if len(output) < eciesEncryptedLength(len(input)):
|
if len(output) < eciesEncryptedLength(len(input)):
|
||||||
return err(BufferOverrun)
|
return err(BufferOverrun)
|
||||||
if randomBytes(iv) != aes128.sizeBlock:
|
|
||||||
return err(RandomError)
|
brHmacDrbgGenerate(rng, iv)
|
||||||
|
|
||||||
var
|
var
|
||||||
ephemeral = ? KeyPair.random().mapErrTo(RandomError)
|
ephemeral = KeyPair.random(rng)
|
||||||
secret = ecdhRaw(ephemeral.seckey, pubkey)
|
secret = ecdhRaw(ephemeral.seckey, pubkey)
|
||||||
material = kdf(secret.data)
|
material = kdf(secret.data)
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import
|
import
|
||||||
tables, hashes, times, algorithm, sets, sequtils, random,
|
tables, hashes, times, algorithm, sets, sequtils, bearssl, random,
|
||||||
chronos, eth/keys, chronicles, stint, nimcrypto,
|
chronos, eth/keys, chronicles, stint, nimcrypto/keccak,
|
||||||
enode
|
enode
|
||||||
|
|
||||||
export sets # TODO: This should not be needed, but compilation fails otherwise
|
export sets # TODO: This should not be needed, but compilation fails otherwise
|
||||||
|
@ -26,6 +26,7 @@ type
|
||||||
pongFutures: Table[seq[byte], Future[bool]]
|
pongFutures: Table[seq[byte], Future[bool]]
|
||||||
pingFutures: Table[Node, Future[bool]]
|
pingFutures: Table[Node, Future[bool]]
|
||||||
neighboursCallbacks: Table[Node, proc(n: seq[Node]) {.gcsafe.}]
|
neighboursCallbacks: Table[Node, proc(n: seq[Node]) {.gcsafe.}]
|
||||||
|
rng: ref BrHmacDrbgContext
|
||||||
|
|
||||||
NodeId* = UInt256
|
NodeId* = UInt256
|
||||||
|
|
||||||
|
@ -231,12 +232,15 @@ proc neighbours(r: RoutingTable, id: NodeId, k: int = BUCKET_SIZE): seq[Node] =
|
||||||
proc len(r: RoutingTable): int =
|
proc len(r: RoutingTable): int =
|
||||||
for b in r.buckets: result += b.len
|
for b in r.buckets: result += b.len
|
||||||
|
|
||||||
proc newKademliaProtocol*[Wire](thisNode: Node,
|
proc newKademliaProtocol*[Wire](
|
||||||
wire: Wire): KademliaProtocol[Wire] =
|
thisNode: Node, wire: Wire, rng = newRng()): KademliaProtocol[Wire] =
|
||||||
|
if rng == nil: raiseAssert "Need an RNG" # doAssert gives compile error on mac
|
||||||
|
|
||||||
result.new()
|
result.new()
|
||||||
result.thisNode = thisNode
|
result.thisNode = thisNode
|
||||||
result.wire = wire
|
result.wire = wire
|
||||||
result.routing.init(thisNode)
|
result.routing.init(thisNode)
|
||||||
|
result.rng = rng
|
||||||
|
|
||||||
proc bond(k: KademliaProtocol, n: Node): Future[bool] {.async, gcsafe.}
|
proc bond(k: KademliaProtocol, n: Node): Future[bool] {.async, gcsafe.}
|
||||||
|
|
||||||
|
@ -408,7 +412,10 @@ proc lookup*(k: KademliaProtocol, nodeId: NodeId): Future[seq[Node]] {.async.} =
|
||||||
|
|
||||||
proc lookupRandom*(k: KademliaProtocol): Future[seq[Node]] =
|
proc lookupRandom*(k: KademliaProtocol): Future[seq[Node]] =
|
||||||
var id: NodeId
|
var id: NodeId
|
||||||
discard randomBytes(addr id, id.sizeof)
|
var buf: array[sizeof(id), byte]
|
||||||
|
brHmacDrbgGenerate(k.rng[], buf)
|
||||||
|
copyMem(addr id, addr buf[0], sizeof(id))
|
||||||
|
|
||||||
k.lookup(id)
|
k.lookup(id)
|
||||||
|
|
||||||
proc resolve*(k: KademliaProtocol, id: NodeId): Future[Node] {.async.} =
|
proc resolve*(k: KademliaProtocol, id: NodeId): Future[Node] {.async.} =
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import
|
import
|
||||||
deques, tables,
|
deques, tables, bearssl,
|
||||||
eth/[rlp, keys], chronos, eth/common/eth_types,
|
eth/[rlp, keys], chronos, eth/common/eth_types,
|
||||||
../enode, ../kademlia, ../discovery, ../rlpxcrypt
|
../enode, ../kademlia, ../discovery, ../rlpxcrypt
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ type
|
||||||
discovery*: DiscoveryProtocol
|
discovery*: DiscoveryProtocol
|
||||||
when useSnappy:
|
when useSnappy:
|
||||||
protocolVersion*: uint
|
protocolVersion*: uint
|
||||||
|
rng*: ref BrHmacDrbgContext
|
||||||
|
|
||||||
Peer* = ref object
|
Peer* = ref object
|
||||||
remote*: Node
|
remote*: Node
|
||||||
|
|
|
@ -461,7 +461,7 @@ proc waitSingleMsg(peer: Peer, MsgType: type): Future[MsgType] {.async.} =
|
||||||
result = checkedRlpRead(peer, nextMsgData, MsgType)
|
result = checkedRlpRead(peer, nextMsgData, MsgType)
|
||||||
logReceivedMsg(peer, result)
|
logReceivedMsg(peer, result)
|
||||||
return
|
return
|
||||||
except RlpError:
|
except rlp.RlpError:
|
||||||
await peer.disconnectAndRaise(BreachOfProtocol,
|
await peer.disconnectAndRaise(BreachOfProtocol,
|
||||||
"Invalid RLPx message body")
|
"Invalid RLPx message body")
|
||||||
|
|
||||||
|
@ -969,11 +969,12 @@ proc rlpxConnect*(node: EthereumNode, remote: Node): Future[Peer] {.async.} =
|
||||||
try:
|
try:
|
||||||
result.transport = await connect(ta)
|
result.transport = await connect(ta)
|
||||||
var handshake = Handshake.tryInit(
|
var handshake = Handshake.tryInit(
|
||||||
node.keys, {Initiator, EIP8}, node.baseProtocolVersion).tryGet()
|
node.rng[], node.keys, {Initiator, EIP8}, node.baseProtocolVersion).tryGet()
|
||||||
|
|
||||||
var authMsg: array[AuthMessageMaxEIP8, byte]
|
var authMsg: array[AuthMessageMaxEIP8, byte]
|
||||||
var authMsgLen = 0
|
var authMsgLen = 0
|
||||||
authMessage(handshake, remote.node.pubkey, authMsg, authMsgLen).tryGet()
|
authMessage(
|
||||||
|
handshake, node.rng[], remote.node.pubkey, authMsg, authMsgLen).tryGet()
|
||||||
var res = await result.transport.write(addr authMsg[0], authMsgLen)
|
var res = await result.transport.write(addr authMsg[0], authMsgLen)
|
||||||
if res != authMsgLen:
|
if res != authMsgLen:
|
||||||
raisePeerDisconnected("Unexpected disconnect while authenticating",
|
raisePeerDisconnected("Unexpected disconnect while authenticating",
|
||||||
|
@ -1055,7 +1056,8 @@ proc rlpxAccept*(node: EthereumNode,
|
||||||
result.transport = transport
|
result.transport = transport
|
||||||
result.network = node
|
result.network = node
|
||||||
|
|
||||||
var handshake = HandShake.tryInit(node.keys, {auth.Responder}).tryGet
|
var handshake =
|
||||||
|
HandShake.tryInit(node.rng[], node.keys, {auth.Responder}).tryGet
|
||||||
|
|
||||||
var ok = false
|
var ok = false
|
||||||
try:
|
try:
|
||||||
|
@ -1078,7 +1080,7 @@ proc rlpxAccept*(node: EthereumNode,
|
||||||
|
|
||||||
var ackMsg: array[AckMessageMaxEIP8, byte]
|
var ackMsg: array[AckMessageMaxEIP8, byte]
|
||||||
var ackMsgLen: int
|
var ackMsgLen: int
|
||||||
handshake.ackMessage(ackMsg, ackMsgLen).tryGet()
|
handshake.ackMessage(node.rng[], ackMsg, ackMsgLen).tryGet()
|
||||||
var res = await transport.write(addr ackMsg[0], ackMsgLen)
|
var res = await transport.write(addr ackMsg[0], ackMsgLen)
|
||||||
if res != ackMsgLen:
|
if res != ackMsgLen:
|
||||||
raisePeerDisconnected("Unexpected disconnect while authenticating",
|
raisePeerDisconnected("Unexpected disconnect while authenticating",
|
||||||
|
|
|
@ -1,196 +0,0 @@
|
||||||
|
|
||||||
## Generated at line 781
|
|
||||||
type
|
|
||||||
DevP2P* = object
|
|
||||||
type
|
|
||||||
helloObj* = object
|
|
||||||
version*: uint
|
|
||||||
clientId*: string
|
|
||||||
capabilities*: seq[Capability]
|
|
||||||
listenPort*: uint
|
|
||||||
nodeId*: array[RawPublicKeySize, byte]
|
|
||||||
|
|
||||||
template hello*(PROTO: type DevP2P): type =
|
|
||||||
helloObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type helloObj): type =
|
|
||||||
DevP2P
|
|
||||||
|
|
||||||
template RecType*(MSG: type helloObj): untyped =
|
|
||||||
helloObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type helloObj): int =
|
|
||||||
0
|
|
||||||
|
|
||||||
type
|
|
||||||
sendDisconnectMsgObj* = object
|
|
||||||
reason*: DisconnectionReasonList
|
|
||||||
|
|
||||||
template sendDisconnectMsg*(PROTO: type DevP2P): type =
|
|
||||||
sendDisconnectMsgObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type sendDisconnectMsgObj): type =
|
|
||||||
DevP2P
|
|
||||||
|
|
||||||
template RecType*(MSG: type sendDisconnectMsgObj): untyped =
|
|
||||||
sendDisconnectMsgObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type sendDisconnectMsgObj): int =
|
|
||||||
1
|
|
||||||
|
|
||||||
type
|
|
||||||
pingObj* = object
|
|
||||||
emptyList*: EmptyList
|
|
||||||
|
|
||||||
template ping*(PROTO: type DevP2P): type =
|
|
||||||
pingObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type pingObj): type =
|
|
||||||
DevP2P
|
|
||||||
|
|
||||||
template RecType*(MSG: type pingObj): untyped =
|
|
||||||
pingObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type pingObj): int =
|
|
||||||
2
|
|
||||||
|
|
||||||
type
|
|
||||||
pongObj* = object
|
|
||||||
emptyList*: EmptyList
|
|
||||||
|
|
||||||
template pong*(PROTO: type DevP2P): type =
|
|
||||||
pongObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type pongObj): type =
|
|
||||||
DevP2P
|
|
||||||
|
|
||||||
template RecType*(MSG: type pongObj): untyped =
|
|
||||||
pongObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type pongObj): int =
|
|
||||||
3
|
|
||||||
|
|
||||||
var DevP2PProtocolObj = initProtocol("p2p", 5, nil, nil)
|
|
||||||
var DevP2PProtocol = addr DevP2PProtocolObj
|
|
||||||
template protocolInfo*(P`gensym75730262: type DevP2P): auto =
|
|
||||||
DevP2PProtocol
|
|
||||||
|
|
||||||
proc hello*(peerOrResponder: Peer; version: uint; clientId: string;
|
|
||||||
capabilities: seq[Capability]; listenPort: uint;
|
|
||||||
nodeId: array[RawPublicKeySize, byte]): Future[void] {.gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 0
|
|
||||||
let perPeerMsgId = 0
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
startList(writer, 5)
|
|
||||||
append(writer, version)
|
|
||||||
append(writer, clientId)
|
|
||||||
append(writer, capabilities)
|
|
||||||
append(writer, listenPort)
|
|
||||||
append(writer, nodeId)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
proc sendDisconnectMsg*(peerOrResponder: Peer; reason: DisconnectionReasonList): Future[
|
|
||||||
void] {.gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 1
|
|
||||||
let perPeerMsgId = 1
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
append(writer, reason)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
proc ping*(peerOrResponder: Peer; emptyList: EmptyList): Future[void] {.gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 2
|
|
||||||
let perPeerMsgId = 2
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
append(writer, emptyList)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
proc pong*(peerOrResponder: Peer; emptyList: EmptyList): Future[void] {.gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 3
|
|
||||||
let perPeerMsgId = 3
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
append(writer, emptyList)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
proc sendDisconnectMsgUserHandler(peer: Peer; reason: DisconnectionReasonList) {.
|
|
||||||
gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = DevP2P
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 1
|
|
||||||
trace "disconnect message received", reason = reason.value, peer
|
|
||||||
await peer.disconnect(reason.value, false)
|
|
||||||
|
|
||||||
proc pingUserHandler(peer: Peer; emptyList: EmptyList) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = DevP2P
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 2
|
|
||||||
discard peer.pong(EmptyList())
|
|
||||||
|
|
||||||
proc pongUserHandler(peer: Peer; emptyList: EmptyList) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = DevP2P
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 3
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc helloThunk(peer: Peer; _`gensym75730215: int; data`gensym75730216: Rlp) {.async,
|
|
||||||
gcsafe.} =
|
|
||||||
var rlp = data`gensym75730216
|
|
||||||
var msg {.noinit.}: helloObj
|
|
||||||
tryEnterList(rlp)
|
|
||||||
msg.version = checkedRlpRead(peer, rlp, uint)
|
|
||||||
msg.clientId = checkedRlpRead(peer, rlp, string)
|
|
||||||
msg.capabilities = checkedRlpRead(peer, rlp, seq[Capability])
|
|
||||||
msg.listenPort = checkedRlpRead(peer, rlp, uint)
|
|
||||||
msg.nodeId = checkedRlpRead(peer, rlp, array[RawPublicKeySize, byte])
|
|
||||||
|
|
||||||
proc sendDisconnectMsgThunk(peer: Peer; _`gensym75730250: int;
|
|
||||||
data`gensym75730251: Rlp) {.async, gcsafe.} =
|
|
||||||
var rlp = data`gensym75730251
|
|
||||||
var msg {.noinit.}: sendDisconnectMsgObj
|
|
||||||
msg.reason = checkedRlpRead(peer, rlp, DisconnectionReasonList)
|
|
||||||
await(sendDisconnectMsgUserHandler(peer, msg.reason))
|
|
||||||
|
|
||||||
proc pingThunk(peer: Peer; _`gensym75730252: int; data`gensym75730253: Rlp) {.async,
|
|
||||||
gcsafe.} =
|
|
||||||
var rlp = data`gensym75730253
|
|
||||||
var msg {.noinit.}: pingObj
|
|
||||||
msg.emptyList = checkedRlpRead(peer, rlp, EmptyList)
|
|
||||||
await(pingUserHandler(peer, msg.emptyList))
|
|
||||||
|
|
||||||
proc pongThunk(peer: Peer; _`gensym75730254: int; data`gensym75730255: Rlp) {.async,
|
|
||||||
gcsafe.} =
|
|
||||||
var rlp = data`gensym75730255
|
|
||||||
var msg {.noinit.}: pongObj
|
|
||||||
msg.emptyList = checkedRlpRead(peer, rlp, EmptyList)
|
|
||||||
await(pongUserHandler(peer, msg.emptyList))
|
|
||||||
|
|
||||||
registerMsg(DevP2PProtocol, 0, "hello", helloThunk, messagePrinter[helloObj],
|
|
||||||
requestResolver[helloObj], nextMsgResolver[helloObj])
|
|
||||||
registerMsg(DevP2PProtocol, 1, "sendDisconnectMsg", sendDisconnectMsgThunk,
|
|
||||||
messagePrinter[sendDisconnectMsgObj],
|
|
||||||
requestResolver[sendDisconnectMsgObj],
|
|
||||||
nextMsgResolver[sendDisconnectMsgObj])
|
|
||||||
registerMsg(DevP2PProtocol, 2, "ping", pingThunk, messagePrinter[pingObj],
|
|
||||||
requestResolver[pingObj], nextMsgResolver[pingObj])
|
|
||||||
registerMsg(DevP2PProtocol, 3, "pong", pongThunk, messagePrinter[pongObj],
|
|
||||||
requestResolver[pongObj], nextMsgResolver[pongObj])
|
|
||||||
setEventHandlers(DevP2PProtocol, nil, nil)
|
|
||||||
registerProtocol(DevP2PProtocol)
|
|
|
@ -9,9 +9,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import
|
import
|
||||||
algorithm, bitops, math, options, tables, times, chronicles, hashes, strutils,
|
algorithm, bitops, math, options, tables, times, chronicles, hashes,
|
||||||
stew/[byteutils, endians2], metrics,
|
stew/[byteutils, endians2], metrics, bearssl,
|
||||||
nimcrypto/[bcmode, hash, keccak, rijndael, sysrand],
|
nimcrypto/[bcmode, hash, keccak, rijndael],
|
||||||
eth/[keys, rlp, p2p], eth/p2p/ecies
|
eth/[keys, rlp, p2p], eth/p2p/ecies
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
|
@ -158,12 +158,10 @@ proc topicBloom*(topic: Topic): Bloom =
|
||||||
doAssert idx <= 511
|
doAssert idx <= 511
|
||||||
result[idx div 8] = result[idx div 8] or byte(1 shl (idx and 7'u16))
|
result[idx div 8] = result[idx div 8] or byte(1 shl (idx and 7'u16))
|
||||||
|
|
||||||
proc generateRandomID*(): string =
|
proc generateRandomID*(rng: var BrHmacDrbgContext): string =
|
||||||
var bytes: array[256 div 8, byte]
|
var bytes: array[256 div 8, byte]
|
||||||
while true: # XXX: error instead of looping?
|
brHmacDrbgGenerate(rng, bytes)
|
||||||
if randomBytes(bytes) == 256 div 8:
|
toHex(bytes)
|
||||||
result = toHex(bytes)
|
|
||||||
break
|
|
||||||
|
|
||||||
proc `or`(a, b: Bloom): Bloom =
|
proc `or`(a, b: Bloom): Bloom =
|
||||||
for i in 0..<a.len:
|
for i in 0..<a.len:
|
||||||
|
@ -231,7 +229,7 @@ proc decryptAesGcm(cipher: openarray[byte], key: SymKey): Option[seq[byte]] =
|
||||||
# simply because that makes it closer to EIP 627 - see also:
|
# simply because that makes it closer to EIP 627 - see also:
|
||||||
# https://github.com/paritytech/parity-ethereum/issues/9652
|
# https://github.com/paritytech/parity-ethereum/issues/9652
|
||||||
|
|
||||||
proc encode*(self: Payload): Option[seq[byte]] =
|
proc encode*(rng: var BrHmacDrbgContext, self: Payload): Option[seq[byte]] =
|
||||||
## Encode a payload according so as to make it suitable to put in an Envelope
|
## Encode a payload according so as to make it suitable to put in an Envelope
|
||||||
## The format follows EIP 627 - https://eips.ethereum.org/EIPS/eip-627
|
## The format follows EIP 627 - https://eips.ethereum.org/EIPS/eip-627
|
||||||
|
|
||||||
|
@ -284,9 +282,7 @@ proc encode*(self: Payload): Option[seq[byte]] =
|
||||||
plain.add self.padding.get()
|
plain.add self.padding.get()
|
||||||
else:
|
else:
|
||||||
var padding = newSeq[byte](padLen)
|
var padding = newSeq[byte](padLen)
|
||||||
if randomBytes(padding) != padLen:
|
brHmacDrbgGenerate(rng, padding)
|
||||||
notice "Generation of random padding failed"
|
|
||||||
return
|
|
||||||
|
|
||||||
plain.add padding
|
plain.add padding
|
||||||
|
|
||||||
|
@ -297,7 +293,7 @@ proc encode*(self: Payload): Option[seq[byte]] =
|
||||||
|
|
||||||
if self.dst.isSome(): # Asymmetric key present - encryption requested
|
if self.dst.isSome(): # Asymmetric key present - encryption requested
|
||||||
var res = newSeq[byte](eciesEncryptedLength(plain.len))
|
var res = newSeq[byte](eciesEncryptedLength(plain.len))
|
||||||
let err = eciesEncrypt(plain, res, self.dst.get())
|
let err = eciesEncrypt(rng, plain, res, self.dst.get())
|
||||||
if err.isErr:
|
if err.isErr:
|
||||||
notice "Encryption failed", err = err.error
|
notice "Encryption failed", err = err.error
|
||||||
return
|
return
|
||||||
|
@ -305,9 +301,7 @@ proc encode*(self: Payload): Option[seq[byte]] =
|
||||||
|
|
||||||
if self.symKey.isSome(): # Symmetric key present - encryption requested
|
if self.symKey.isSome(): # Symmetric key present - encryption requested
|
||||||
var iv: array[gcmIVLen, byte]
|
var iv: array[gcmIVLen, byte]
|
||||||
if randomBytes(iv) != gcmIVLen:
|
brHmacDrbgGenerate(rng, iv)
|
||||||
notice "Generation of random IV failed"
|
|
||||||
return
|
|
||||||
|
|
||||||
return some(encryptAesGcm(plain, self.symKey.get(), iv))
|
return some(encryptAesGcm(plain, self.symKey.get(), iv))
|
||||||
|
|
||||||
|
@ -582,11 +576,12 @@ proc initFilter*(src = none[PublicKey](), privateKey = none[PrivateKey](),
|
||||||
Filter(src: src, privateKey: privateKey, symKey: symKey, topics: topics,
|
Filter(src: src, privateKey: privateKey, symKey: symKey, topics: topics,
|
||||||
powReq: powReq, allowP2P: allowP2P, bloom: toBloom(topics))
|
powReq: powReq, allowP2P: allowP2P, bloom: toBloom(topics))
|
||||||
|
|
||||||
proc subscribeFilter*(filters: var Filters, filter: Filter,
|
proc subscribeFilter*(
|
||||||
handler:FilterMsgHandler = nil): string =
|
rng: var BrHmacDrbgContext, filters: var Filters, filter: Filter,
|
||||||
|
handler: FilterMsgHandler = nil): string =
|
||||||
# NOTE: Should we allow a filter without a key? Encryption is mandatory in v6?
|
# NOTE: Should we allow a filter without a key? Encryption is mandatory in v6?
|
||||||
# Check if asymmetric _and_ symmetric key? Now asymmetric just has precedence.
|
# Check if asymmetric _and_ symmetric key? Now asymmetric just has precedence.
|
||||||
let id = generateRandomID()
|
let id = generateRandomID(rng)
|
||||||
var filter = filter
|
var filter = filter
|
||||||
if handler.isNil():
|
if handler.isNil():
|
||||||
filter.queue = newSeqOfCap[ReceivedMessage](defaultFilterQueueCapacity)
|
filter.queue = newSeqOfCap[ReceivedMessage](defaultFilterQueueCapacity)
|
||||||
|
|
|
@ -343,8 +343,8 @@ proc postMessage*(node: EthereumNode, pubKey = none[PublicKey](),
|
||||||
##
|
##
|
||||||
## NOTE: This call allows a post without encryption. If encryption is
|
## NOTE: This call allows a post without encryption. If encryption is
|
||||||
## mandatory it should be enforced a layer up
|
## mandatory it should be enforced a layer up
|
||||||
let payload = encode(Payload(payload: payload, src: src, dst: pubKey,
|
let payload = encode(node.rng[], Payload(
|
||||||
symKey: symKey, padding: padding))
|
payload: payload, src: src, dst: pubKey, symKey: symKey, padding: padding))
|
||||||
if payload.isSome():
|
if payload.isSome():
|
||||||
var env = Envelope(expiry:epochTime().uint32 + ttl,
|
var env = Envelope(expiry:epochTime().uint32 + ttl,
|
||||||
ttl: ttl, topic: topic, data: payload.get(), nonce: 0)
|
ttl: ttl, topic: topic, data: payload.get(), nonce: 0)
|
||||||
|
@ -387,7 +387,8 @@ proc subscribeFilter*(node: EthereumNode, filter: Filter,
|
||||||
##
|
##
|
||||||
## NOTE: This call allows for a filter without decryption. If encryption is
|
## NOTE: This call allows for a filter without decryption. If encryption is
|
||||||
## mandatory it should be enforced a layer up.
|
## mandatory it should be enforced a layer up.
|
||||||
return node.protocolState(Whisper).filters.subscribeFilter(filter, handler)
|
return subscribeFilter(
|
||||||
|
node.rng[], node.protocolState(Whisper).filters, filter, handler)
|
||||||
|
|
||||||
proc unsubscribeFilter*(node: EthereumNode, filterId: string): bool =
|
proc unsubscribeFilter*(node: EthereumNode, filterId: string): bool =
|
||||||
## Remove a previously subscribed filter.
|
## Remove a previously subscribed filter.
|
||||||
|
|
|
@ -1,662 +0,0 @@
|
||||||
|
|
||||||
## Generated at line 119
|
|
||||||
type
|
|
||||||
Whisper* = object
|
|
||||||
template State*(PROTO: type Whisper): type =
|
|
||||||
ref[WhisperPeer:ObjectType]
|
|
||||||
|
|
||||||
template NetworkState*(PROTO: type Whisper): type =
|
|
||||||
ref[WhisperNetwork:ObjectType]
|
|
||||||
|
|
||||||
type
|
|
||||||
statusObj* = object
|
|
||||||
protocolVersion*: uint
|
|
||||||
powConverted*: uint64
|
|
||||||
bloom*: seq[byte]
|
|
||||||
isLightNode*: bool
|
|
||||||
|
|
||||||
template status*(PROTO: type Whisper): type =
|
|
||||||
statusObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type statusObj): type =
|
|
||||||
Whisper
|
|
||||||
|
|
||||||
template RecType*(MSG: type statusObj): untyped =
|
|
||||||
statusObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type statusObj): int =
|
|
||||||
0
|
|
||||||
|
|
||||||
type
|
|
||||||
messagesObj* = object
|
|
||||||
envelopes*: seq[Envelope]
|
|
||||||
|
|
||||||
template messages*(PROTO: type Whisper): type =
|
|
||||||
messagesObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type messagesObj): type =
|
|
||||||
Whisper
|
|
||||||
|
|
||||||
template RecType*(MSG: type messagesObj): untyped =
|
|
||||||
messagesObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type messagesObj): int =
|
|
||||||
1
|
|
||||||
|
|
||||||
type
|
|
||||||
powRequirementObj* = object
|
|
||||||
value*: uint64
|
|
||||||
|
|
||||||
template powRequirement*(PROTO: type Whisper): type =
|
|
||||||
powRequirementObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type powRequirementObj): type =
|
|
||||||
Whisper
|
|
||||||
|
|
||||||
template RecType*(MSG: type powRequirementObj): untyped =
|
|
||||||
powRequirementObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type powRequirementObj): int =
|
|
||||||
2
|
|
||||||
|
|
||||||
type
|
|
||||||
bloomFilterExchangeObj* = object
|
|
||||||
bloom*: seq[byte]
|
|
||||||
|
|
||||||
template bloomFilterExchange*(PROTO: type Whisper): type =
|
|
||||||
bloomFilterExchangeObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type bloomFilterExchangeObj): type =
|
|
||||||
Whisper
|
|
||||||
|
|
||||||
template RecType*(MSG: type bloomFilterExchangeObj): untyped =
|
|
||||||
bloomFilterExchangeObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type bloomFilterExchangeObj): int =
|
|
||||||
3
|
|
||||||
|
|
||||||
type
|
|
||||||
p2pRequestObj* = object
|
|
||||||
envelope*: Envelope
|
|
||||||
|
|
||||||
template p2pRequest*(PROTO: type Whisper): type =
|
|
||||||
p2pRequestObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type p2pRequestObj): type =
|
|
||||||
Whisper
|
|
||||||
|
|
||||||
template RecType*(MSG: type p2pRequestObj): untyped =
|
|
||||||
p2pRequestObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type p2pRequestObj): int =
|
|
||||||
126
|
|
||||||
|
|
||||||
type
|
|
||||||
p2pMessageObj* = object
|
|
||||||
envelope*: Envelope
|
|
||||||
|
|
||||||
template p2pMessage*(PROTO: type Whisper): type =
|
|
||||||
p2pMessageObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type p2pMessageObj): type =
|
|
||||||
Whisper
|
|
||||||
|
|
||||||
template RecType*(MSG: type p2pMessageObj): untyped =
|
|
||||||
p2pMessageObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type p2pMessageObj): int =
|
|
||||||
127
|
|
||||||
|
|
||||||
type
|
|
||||||
batchAcknowledgedObj* = object
|
|
||||||
|
|
||||||
template batchAcknowledged*(PROTO: type Whisper): type =
|
|
||||||
batchAcknowledgedObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type batchAcknowledgedObj): type =
|
|
||||||
Whisper
|
|
||||||
|
|
||||||
template RecType*(MSG: type batchAcknowledgedObj): untyped =
|
|
||||||
batchAcknowledgedObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type batchAcknowledgedObj): int =
|
|
||||||
11
|
|
||||||
|
|
||||||
type
|
|
||||||
messageResponseObj* = object
|
|
||||||
|
|
||||||
template messageResponse*(PROTO: type Whisper): type =
|
|
||||||
messageResponseObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type messageResponseObj): type =
|
|
||||||
Whisper
|
|
||||||
|
|
||||||
template RecType*(MSG: type messageResponseObj): untyped =
|
|
||||||
messageResponseObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type messageResponseObj): int =
|
|
||||||
12
|
|
||||||
|
|
||||||
type
|
|
||||||
p2pSyncResponseObj* = object
|
|
||||||
|
|
||||||
template p2pSyncResponse*(PROTO: type Whisper): type =
|
|
||||||
p2pSyncResponseObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type p2pSyncResponseObj): type =
|
|
||||||
Whisper
|
|
||||||
|
|
||||||
template RecType*(MSG: type p2pSyncResponseObj): untyped =
|
|
||||||
p2pSyncResponseObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type p2pSyncResponseObj): int =
|
|
||||||
124
|
|
||||||
|
|
||||||
type
|
|
||||||
p2pSyncRequestObj* = object
|
|
||||||
|
|
||||||
template p2pSyncRequest*(PROTO: type Whisper): type =
|
|
||||||
p2pSyncRequestObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type p2pSyncRequestObj): type =
|
|
||||||
Whisper
|
|
||||||
|
|
||||||
template RecType*(MSG: type p2pSyncRequestObj): untyped =
|
|
||||||
p2pSyncRequestObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type p2pSyncRequestObj): int =
|
|
||||||
123
|
|
||||||
|
|
||||||
type
|
|
||||||
p2pRequestCompleteObj* = object
|
|
||||||
|
|
||||||
template p2pRequestComplete*(PROTO: type Whisper): type =
|
|
||||||
p2pRequestCompleteObj
|
|
||||||
|
|
||||||
template msgProtocol*(MSG: type p2pRequestCompleteObj): type =
|
|
||||||
Whisper
|
|
||||||
|
|
||||||
template RecType*(MSG: type p2pRequestCompleteObj): untyped =
|
|
||||||
p2pRequestCompleteObj
|
|
||||||
|
|
||||||
template msgId*(MSG: type p2pRequestCompleteObj): int =
|
|
||||||
125
|
|
||||||
|
|
||||||
var WhisperProtocolObj = initProtocol("shh", 6, createPeerState[Peer,
|
|
||||||
ref[WhisperPeer:ObjectType]], createNetworkState[EthereumNode,
|
|
||||||
ref[WhisperNetwork:ObjectType]])
|
|
||||||
var WhisperProtocol = addr WhisperProtocolObj
|
|
||||||
template protocolInfo*(P`gensym85175079: type Whisper): auto =
|
|
||||||
WhisperProtocol
|
|
||||||
|
|
||||||
proc statusRawSender(peerOrResponder: Peer; protocolVersion: uint;
|
|
||||||
powConverted: uint64; bloom: seq[byte]; isLightNode: bool;
|
|
||||||
timeout: Duration = milliseconds(10000'i64)): Future[void] {.
|
|
||||||
gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 0
|
|
||||||
let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 0)
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
startList(writer, 4)
|
|
||||||
append(writer, protocolVersion)
|
|
||||||
append(writer, powConverted)
|
|
||||||
append(writer, bloom)
|
|
||||||
append(writer, isLightNode)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
template status*(peerOrResponder: Peer; protocolVersion: uint; powConverted: uint64;
|
|
||||||
bloom: seq[byte]; isLightNode: bool;
|
|
||||||
timeout: Duration = milliseconds(10000'i64)): Future[statusObj] =
|
|
||||||
let peer = peerOrResponder
|
|
||||||
let sendingFuture`gensym85175056 = statusRawSender(peer, protocolVersion,
|
|
||||||
powConverted, bloom, isLightNode)
|
|
||||||
handshakeImpl(peer, sendingFuture`gensym85175056, nextMsg(peer, statusObj),
|
|
||||||
timeout)
|
|
||||||
|
|
||||||
proc messages*(peerOrResponder: Peer; envelopes: openarray[Envelope]): Future[void] {.
|
|
||||||
gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 1
|
|
||||||
let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 1)
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
append(writer, envelopes)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
proc powRequirement*(peerOrResponder: Peer; value: uint64): Future[void] {.gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 2
|
|
||||||
let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 2)
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
append(writer, value)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
proc bloomFilterExchange*(peerOrResponder: Peer; bloom: openArray[byte]): Future[void] {.
|
|
||||||
gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 3
|
|
||||||
let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 3)
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
append(writer, bloom)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
proc p2pRequest*(peerOrResponder: Peer; envelope: Envelope): Future[void] {.gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 126
|
|
||||||
let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 126)
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
append(writer, envelope)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
proc p2pMessage*(peerOrResponder: Peer; envelope: Envelope): Future[void] {.gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 127
|
|
||||||
let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 127)
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
append(writer, envelope)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
proc batchAcknowledged*(peerOrResponder: Peer): Future[void] {.gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 11
|
|
||||||
let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 11)
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
proc messageResponse*(peerOrResponder: Peer): Future[void] {.gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 12
|
|
||||||
let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 12)
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
proc p2pSyncResponse*(peerOrResponder: ResponderWithId[p2pSyncResponseObj]): Future[
|
|
||||||
void] {.gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 124
|
|
||||||
let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 124)
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
append(writer, peerOrResponder.reqId)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
template send*(r`gensym85175073: ResponderWithId[p2pSyncResponseObj];
|
|
||||||
args`gensym85175074: varargs[untyped]): auto =
|
|
||||||
p2pSyncResponse(r`gensym85175073, args`gensym85175074)
|
|
||||||
|
|
||||||
proc p2pSyncRequest*(peerOrResponder: Peer;
|
|
||||||
timeout: Duration = milliseconds(10000'i64)): Future[
|
|
||||||
Option[p2pSyncResponseObj]] {.gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 123
|
|
||||||
let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 123)
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
initFuture result
|
|
||||||
let reqId = registerRequest(peer, timeout, result, perPeerMsgId + 1)
|
|
||||||
append(writer, reqId)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
linkSendFailureToReqFuture(sendMsg(peer, msgBytes), result)
|
|
||||||
|
|
||||||
proc p2pRequestComplete*(peerOrResponder: Peer): Future[void] {.gcsafe.} =
|
|
||||||
let peer = getPeer(peerOrResponder)
|
|
||||||
var writer = initRlpWriter()
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 125
|
|
||||||
let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 125)
|
|
||||||
append(writer, perPeerMsgId)
|
|
||||||
let msgBytes = finish(writer)
|
|
||||||
return sendMsg(peer, msgBytes)
|
|
||||||
|
|
||||||
proc messagesUserHandler(peer: Peer; envelopes: seq[Envelope]) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = Whisper
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 1
|
|
||||||
template state(peer: Peer): ref[WhisperPeer:ObjectType] =
|
|
||||||
cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol))
|
|
||||||
|
|
||||||
template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] =
|
|
||||||
cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network,
|
|
||||||
WhisperProtocol))
|
|
||||||
|
|
||||||
if not peer.state.initialized:
|
|
||||||
warn "Handshake not completed yet, discarding messages"
|
|
||||||
return
|
|
||||||
for envelope in envelopes:
|
|
||||||
if not envelope.valid():
|
|
||||||
warn "Expired or future timed envelope", peer
|
|
||||||
continue
|
|
||||||
let msg = initMessage(envelope)
|
|
||||||
if not msg.allowed(peer.networkState.config):
|
|
||||||
continue
|
|
||||||
if peer.state.received.containsOrIncl(msg.hash):
|
|
||||||
dropped_duplicate_envelopes.inc()
|
|
||||||
trace "Peer sending duplicate messages", peer, hash = $msg.hash
|
|
||||||
continue
|
|
||||||
if peer.networkState.queue[].add(msg):
|
|
||||||
peer.networkState.filters.notify(msg)
|
|
||||||
|
|
||||||
proc powRequirementUserHandler(peer: Peer; value: uint64) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = Whisper
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 2
|
|
||||||
template state(peer: Peer): ref[WhisperPeer:ObjectType] =
|
|
||||||
cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol))
|
|
||||||
|
|
||||||
template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] =
|
|
||||||
cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network,
|
|
||||||
WhisperProtocol))
|
|
||||||
|
|
||||||
if not peer.state.initialized:
|
|
||||||
warn "Handshake not completed yet, discarding powRequirement"
|
|
||||||
return
|
|
||||||
peer.state.powRequirement = cast[float64](value)
|
|
||||||
|
|
||||||
proc bloomFilterExchangeUserHandler(peer: Peer; bloom: seq[byte]) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = Whisper
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 3
|
|
||||||
template state(peer: Peer): ref[WhisperPeer:ObjectType] =
|
|
||||||
cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol))
|
|
||||||
|
|
||||||
template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] =
|
|
||||||
cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network,
|
|
||||||
WhisperProtocol))
|
|
||||||
|
|
||||||
if not peer.state.initialized:
|
|
||||||
warn "Handshake not completed yet, discarding bloomFilterExchange"
|
|
||||||
return
|
|
||||||
if bloom.len == bloomSize:
|
|
||||||
peer.state.bloom.bytesCopy(bloom)
|
|
||||||
|
|
||||||
proc p2pRequestUserHandler(peer: Peer; envelope: Envelope) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = Whisper
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 126
|
|
||||||
template state(peer: Peer): ref[WhisperPeer:ObjectType] =
|
|
||||||
cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol))
|
|
||||||
|
|
||||||
template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] =
|
|
||||||
cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network,
|
|
||||||
WhisperProtocol))
|
|
||||||
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc p2pMessageUserHandler(peer: Peer; envelope: Envelope) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = Whisper
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 127
|
|
||||||
template state(peer: Peer): ref[WhisperPeer:ObjectType] =
|
|
||||||
cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol))
|
|
||||||
|
|
||||||
template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] =
|
|
||||||
cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network,
|
|
||||||
WhisperProtocol))
|
|
||||||
|
|
||||||
if peer.state.trusted:
|
|
||||||
let msg = Message(env: envelope, isP2P: true)
|
|
||||||
peer.networkState.filters.notify(msg)
|
|
||||||
|
|
||||||
proc batchAcknowledgedUserHandler(peer: Peer) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = Whisper
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 11
|
|
||||||
template state(peer: Peer): ref[WhisperPeer:ObjectType] =
|
|
||||||
cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol))
|
|
||||||
|
|
||||||
template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] =
|
|
||||||
cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network,
|
|
||||||
WhisperProtocol))
|
|
||||||
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc messageResponseUserHandler(peer: Peer) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = Whisper
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 12
|
|
||||||
template state(peer: Peer): ref[WhisperPeer:ObjectType] =
|
|
||||||
cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol))
|
|
||||||
|
|
||||||
template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] =
|
|
||||||
cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network,
|
|
||||||
WhisperProtocol))
|
|
||||||
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc p2pSyncResponseUserHandler(peer: Peer; reqId: int) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = Whisper
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 124
|
|
||||||
template state(peer: Peer): ref[WhisperPeer:ObjectType] =
|
|
||||||
cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol))
|
|
||||||
|
|
||||||
template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] =
|
|
||||||
cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network,
|
|
||||||
WhisperProtocol))
|
|
||||||
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc p2pSyncRequestUserHandler(peer: Peer; reqId: int) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = Whisper
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 123
|
|
||||||
template state(peer: Peer): ref[WhisperPeer:ObjectType] =
|
|
||||||
cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol))
|
|
||||||
|
|
||||||
template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] =
|
|
||||||
cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network,
|
|
||||||
WhisperProtocol))
|
|
||||||
|
|
||||||
var response = init(ResponderWithId[p2pSyncResponseObj], peer, reqId)
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc p2pRequestCompleteUserHandler(peer: Peer) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = Whisper
|
|
||||||
const
|
|
||||||
perProtocolMsgId = 125
|
|
||||||
template state(peer: Peer): ref[WhisperPeer:ObjectType] =
|
|
||||||
cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol))
|
|
||||||
|
|
||||||
template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] =
|
|
||||||
cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network,
|
|
||||||
WhisperProtocol))
|
|
||||||
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc statusThunk(peer: Peer; _`gensym85175033: int; data`gensym85175034: Rlp) {.async,
|
|
||||||
gcsafe.} =
|
|
||||||
var rlp = data`gensym85175034
|
|
||||||
var msg {.noinit.}: statusObj
|
|
||||||
tryEnterList(rlp)
|
|
||||||
msg.protocolVersion = checkedRlpRead(peer, rlp, uint)
|
|
||||||
msg.powConverted = checkedRlpRead(peer, rlp, uint64)
|
|
||||||
msg.bloom = checkedRlpRead(peer, rlp, seq[byte])
|
|
||||||
msg.isLightNode = checkedRlpRead(peer, rlp, bool)
|
|
||||||
|
|
||||||
proc messagesThunk(peer: Peer; _`gensym85175057: int; data`gensym85175058: Rlp) {.
|
|
||||||
async, gcsafe.} =
|
|
||||||
var rlp = data`gensym85175058
|
|
||||||
var msg {.noinit.}: messagesObj
|
|
||||||
msg.envelopes = checkedRlpRead(peer, rlp, openarray[Envelope])
|
|
||||||
await(messagesUserHandler(peer, msg.envelopes))
|
|
||||||
|
|
||||||
proc powRequirementThunk(peer: Peer; _`gensym85175059: int; data`gensym85175060: Rlp) {.
|
|
||||||
async, gcsafe.} =
|
|
||||||
var rlp = data`gensym85175060
|
|
||||||
var msg {.noinit.}: powRequirementObj
|
|
||||||
msg.value = checkedRlpRead(peer, rlp, uint64)
|
|
||||||
await(powRequirementUserHandler(peer, msg.value))
|
|
||||||
|
|
||||||
proc bloomFilterExchangeThunk(peer: Peer; _`gensym85175061: int;
|
|
||||||
data`gensym85175062: Rlp) {.async, gcsafe.} =
|
|
||||||
var rlp = data`gensym85175062
|
|
||||||
var msg {.noinit.}: bloomFilterExchangeObj
|
|
||||||
msg.bloom = checkedRlpRead(peer, rlp, openArray[byte])
|
|
||||||
await(bloomFilterExchangeUserHandler(peer, msg.bloom))
|
|
||||||
|
|
||||||
proc p2pRequestThunk(peer: Peer; _`gensym85175063: int; data`gensym85175064: Rlp) {.
|
|
||||||
async, gcsafe.} =
|
|
||||||
var rlp = data`gensym85175064
|
|
||||||
var msg {.noinit.}: p2pRequestObj
|
|
||||||
msg.envelope = checkedRlpRead(peer, rlp, Envelope)
|
|
||||||
await(p2pRequestUserHandler(peer, msg.envelope))
|
|
||||||
|
|
||||||
proc p2pMessageThunk(peer: Peer; _`gensym85175065: int; data`gensym85175066: Rlp) {.
|
|
||||||
async, gcsafe.} =
|
|
||||||
var rlp = data`gensym85175066
|
|
||||||
var msg {.noinit.}: p2pMessageObj
|
|
||||||
msg.envelope = checkedRlpRead(peer, rlp, Envelope)
|
|
||||||
await(p2pMessageUserHandler(peer, msg.envelope))
|
|
||||||
|
|
||||||
proc batchAcknowledgedThunk(peer: Peer; _`gensym85175067: int;
|
|
||||||
data`gensym85175068: Rlp) {.async, gcsafe.} =
|
|
||||||
var rlp = data`gensym85175068
|
|
||||||
var msg {.noinit.}: batchAcknowledgedObj
|
|
||||||
await(batchAcknowledgedUserHandler(peer))
|
|
||||||
|
|
||||||
proc messageResponseThunk(peer: Peer; _`gensym85175069: int; data`gensym85175070: Rlp) {.
|
|
||||||
async, gcsafe.} =
|
|
||||||
var rlp = data`gensym85175070
|
|
||||||
var msg {.noinit.}: messageResponseObj
|
|
||||||
await(messageResponseUserHandler(peer))
|
|
||||||
|
|
||||||
proc p2pSyncResponseThunk(peer: Peer; _`gensym85175071: int; data`gensym85175072: Rlp) {.
|
|
||||||
async, gcsafe.} =
|
|
||||||
var rlp = data`gensym85175072
|
|
||||||
var msg {.noinit.}: p2pSyncResponseObj
|
|
||||||
let reqId = read(rlp, int)
|
|
||||||
await(p2pSyncResponseUserHandler(peer, reqId))
|
|
||||||
resolveResponseFuture(peer, perPeerMsgId(peer, p2pSyncResponseObj), addr(msg),
|
|
||||||
reqId)
|
|
||||||
|
|
||||||
proc p2pSyncRequestThunk(peer: Peer; _`gensym85175075: int; data`gensym85175076: Rlp) {.
|
|
||||||
async, gcsafe.} =
|
|
||||||
var rlp = data`gensym85175076
|
|
||||||
var msg {.noinit.}: p2pSyncRequestObj
|
|
||||||
let reqId = read(rlp, int)
|
|
||||||
await(p2pSyncRequestUserHandler(peer, reqId))
|
|
||||||
|
|
||||||
proc p2pRequestCompleteThunk(peer: Peer; _`gensym85175077: int;
|
|
||||||
data`gensym85175078: Rlp) {.async, gcsafe.} =
|
|
||||||
var rlp = data`gensym85175078
|
|
||||||
var msg {.noinit.}: p2pRequestCompleteObj
|
|
||||||
await(p2pRequestCompleteUserHandler(peer))
|
|
||||||
|
|
||||||
registerMsg(WhisperProtocol, 0, "status", statusThunk, messagePrinter[statusObj],
|
|
||||||
requestResolver[statusObj], nextMsgResolver[statusObj])
|
|
||||||
registerMsg(WhisperProtocol, 1, "messages", messagesThunk,
|
|
||||||
messagePrinter[messagesObj], requestResolver[messagesObj],
|
|
||||||
nextMsgResolver[messagesObj])
|
|
||||||
registerMsg(WhisperProtocol, 2, "powRequirement", powRequirementThunk,
|
|
||||||
messagePrinter[powRequirementObj],
|
|
||||||
requestResolver[powRequirementObj],
|
|
||||||
nextMsgResolver[powRequirementObj])
|
|
||||||
registerMsg(WhisperProtocol, 3, "bloomFilterExchange", bloomFilterExchangeThunk,
|
|
||||||
messagePrinter[bloomFilterExchangeObj],
|
|
||||||
requestResolver[bloomFilterExchangeObj],
|
|
||||||
nextMsgResolver[bloomFilterExchangeObj])
|
|
||||||
registerMsg(WhisperProtocol, 126, "p2pRequest", p2pRequestThunk,
|
|
||||||
messagePrinter[p2pRequestObj], requestResolver[p2pRequestObj],
|
|
||||||
nextMsgResolver[p2pRequestObj])
|
|
||||||
registerMsg(WhisperProtocol, 127, "p2pMessage", p2pMessageThunk,
|
|
||||||
messagePrinter[p2pMessageObj], requestResolver[p2pMessageObj],
|
|
||||||
nextMsgResolver[p2pMessageObj])
|
|
||||||
registerMsg(WhisperProtocol, 11, "batchAcknowledged", batchAcknowledgedThunk,
|
|
||||||
messagePrinter[batchAcknowledgedObj],
|
|
||||||
requestResolver[batchAcknowledgedObj],
|
|
||||||
nextMsgResolver[batchAcknowledgedObj])
|
|
||||||
registerMsg(WhisperProtocol, 12, "messageResponse", messageResponseThunk,
|
|
||||||
messagePrinter[messageResponseObj],
|
|
||||||
requestResolver[messageResponseObj],
|
|
||||||
nextMsgResolver[messageResponseObj])
|
|
||||||
registerMsg(WhisperProtocol, 124, "p2pSyncResponse", p2pSyncResponseThunk,
|
|
||||||
messagePrinter[p2pSyncResponseObj],
|
|
||||||
requestResolver[p2pSyncResponseObj],
|
|
||||||
nextMsgResolver[p2pSyncResponseObj])
|
|
||||||
registerMsg(WhisperProtocol, 123, "p2pSyncRequest", p2pSyncRequestThunk,
|
|
||||||
messagePrinter[p2pSyncRequestObj],
|
|
||||||
requestResolver[p2pSyncRequestObj],
|
|
||||||
nextMsgResolver[p2pSyncRequestObj])
|
|
||||||
registerMsg(WhisperProtocol, 125, "p2pRequestComplete", p2pRequestCompleteThunk,
|
|
||||||
messagePrinter[p2pRequestCompleteObj],
|
|
||||||
requestResolver[p2pRequestCompleteObj],
|
|
||||||
nextMsgResolver[p2pRequestCompleteObj])
|
|
||||||
proc WhisperPeerConnected(peer: Peer) {.gcsafe, async.} =
|
|
||||||
type
|
|
||||||
CurrentProtocol = Whisper
|
|
||||||
template state(peer: Peer): ref[WhisperPeer:ObjectType] =
|
|
||||||
cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol))
|
|
||||||
|
|
||||||
template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] =
|
|
||||||
cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network,
|
|
||||||
WhisperProtocol))
|
|
||||||
|
|
||||||
trace "onPeerConnected Whisper"
|
|
||||||
let
|
|
||||||
whisperNet = peer.networkState
|
|
||||||
whisperPeer = peer.state
|
|
||||||
let m = await peer.status(whisperVersion,
|
|
||||||
cast[uint64](whisperNet.config.powRequirement),
|
|
||||||
@(whisperNet.config.bloom),
|
|
||||||
whisperNet.config.isLightNode,
|
|
||||||
timeout = chronos.milliseconds(5000))
|
|
||||||
if m.protocolVersion == whisperVersion:
|
|
||||||
debug "Whisper peer", peer, whisperVersion
|
|
||||||
else:
|
|
||||||
raise newException(UselessPeerError, "Incompatible Whisper version")
|
|
||||||
whisperPeer.powRequirement = cast[float64](m.powConverted)
|
|
||||||
if m.bloom.len > 0:
|
|
||||||
if m.bloom.len != bloomSize:
|
|
||||||
raise newException(UselessPeerError, "Bloomfilter size mismatch")
|
|
||||||
else:
|
|
||||||
whisperPeer.bloom.bytesCopy(m.bloom)
|
|
||||||
else:
|
|
||||||
whisperPeer.bloom = fullBloom()
|
|
||||||
whisperPeer.isLightNode = m.isLightNode
|
|
||||||
if whisperPeer.isLightNode and whisperNet.config.isLightNode:
|
|
||||||
raise newException(UselessPeerError, "Two light nodes connected")
|
|
||||||
whisperPeer.received.init()
|
|
||||||
whisperPeer.trusted = false
|
|
||||||
whisperPeer.initialized = true
|
|
||||||
if not whisperNet.config.isLightNode:
|
|
||||||
traceAsyncErrors peer.run()
|
|
||||||
debug "Whisper peer initialized", peer
|
|
||||||
|
|
||||||
setEventHandlers(WhisperProtocol, WhisperPeerConnected, nil)
|
|
||||||
registerProtocol(WhisperProtocol)
|
|
|
@ -9,12 +9,13 @@ var
|
||||||
node2: EthereumNode
|
node2: EthereumNode
|
||||||
peer: Peer
|
peer: Peer
|
||||||
|
|
||||||
|
let rng = newRng()
|
||||||
# This is not a good example of a fuzzing test and it would be much better
|
# This is not a good example of a fuzzing test and it would be much better
|
||||||
# to mock more to get rid of anything sockets, async, etc.
|
# to mock more to get rid of anything sockets, async, etc.
|
||||||
# However, it can and has provided reasonably quick results anyhow.
|
# However, it can and has provided reasonably quick results anyhow.
|
||||||
init:
|
init:
|
||||||
node1 = setupTestNode(eth, Whisper)
|
node1 = setupTestNode(rng, eth, Whisper)
|
||||||
node2 = setupTestNode(eth, Whisper)
|
node2 = setupTestNode(rng, eth, Whisper)
|
||||||
|
|
||||||
node2.startListening()
|
node2.startListening()
|
||||||
peer = waitFor node1.rlpxConnect(newNode(node2.toENode()))
|
peer = waitFor node1.rlpxConnect(newNode(node2.toENode()))
|
||||||
|
|
|
@ -14,6 +14,8 @@ import eth/keys, eth/keyfile/[keyfile], json, os, unittest
|
||||||
# Test vectors copied from
|
# Test vectors copied from
|
||||||
# https://github.com/ethereum/tests/blob/develop/KeyStoreTests/basic_tests.json
|
# https://github.com/ethereum/tests/blob/develop/KeyStoreTests/basic_tests.json
|
||||||
|
|
||||||
|
let rng = newRng()
|
||||||
|
|
||||||
var TestVectors = [
|
var TestVectors = [
|
||||||
%*{
|
%*{
|
||||||
"keyfile": {
|
"keyfile": {
|
||||||
|
@ -114,7 +116,7 @@ suite "KeyFile test suite":
|
||||||
check:
|
check:
|
||||||
seckey.error == KeyFileError.IncorrectMac
|
seckey.error == KeyFileError.IncorrectMac
|
||||||
test "Create/Save/Load test":
|
test "Create/Save/Load test":
|
||||||
var seckey0 = PrivateKey.random()[]
|
var seckey0 = PrivateKey.random(rng[])
|
||||||
let jobject = createKeyFileJson(seckey0, "randompassword")[]
|
let jobject = createKeyFileJson(seckey0, "randompassword")[]
|
||||||
|
|
||||||
check:
|
check:
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import eth/keys
|
import eth/keys, bearssl
|
||||||
import nimcrypto/hash, nimcrypto/keccak, nimcrypto/utils
|
import nimcrypto/hash, nimcrypto/keccak, nimcrypto/utils
|
||||||
from strutils import toLowerAscii
|
from strutils import toLowerAscii
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ proc compare(x: openarray[byte], y: openarray[byte]): bool =
|
||||||
break
|
break
|
||||||
|
|
||||||
let message = "message".toBytes()
|
let message = "message".toBytes()
|
||||||
|
let rng = newRng()
|
||||||
|
|
||||||
const
|
const
|
||||||
pkbytes = "58d23b55bc9cdce1f18c2500f40ff4ab7245df9a89505e9b1fa4851f623d241d"
|
pkbytes = "58d23b55bc9cdce1f18c2500f40ff4ab7245df9a89505e9b1fa4851f623d241d"
|
||||||
|
@ -80,7 +81,7 @@ suite "ECC/ECDSA/ECDHE tests suite":
|
||||||
var s = PrivateKey.fromHex(pkbytes)[]
|
var s = PrivateKey.fromHex(pkbytes)[]
|
||||||
var mhash = keccak256.digest(message)
|
var mhash = keccak256.digest(message)
|
||||||
var signature = s.sign(message)
|
var signature = s.sign(message)
|
||||||
var p = recover(signature, mhash)[]
|
var p = recover(signature, SkMessage(mhash.data))[]
|
||||||
check:
|
check:
|
||||||
s.toPublicKey() == p
|
s.toPublicKey() == p
|
||||||
|
|
||||||
|
@ -130,7 +131,7 @@ suite "ECC/ECDSA/ECDHE tests suite":
|
||||||
|
|
||||||
test "EIP-55 100 addresses":
|
test "EIP-55 100 addresses":
|
||||||
for i in 1..100:
|
for i in 1..100:
|
||||||
var kp = KeyPair.random()[]
|
var kp = KeyPair.random(rng[])
|
||||||
var chaddress = kp.pubkey.toChecksumAddress()
|
var chaddress = kp.pubkey.toChecksumAddress()
|
||||||
var noaddress = kp.pubkey.toAddress()
|
var noaddress = kp.pubkey.toAddress()
|
||||||
if noaddress != chaddress:
|
if noaddress != chaddress:
|
||||||
|
@ -206,9 +207,9 @@ suite "ECC/ECDSA/ECDHE tests suite":
|
||||||
|
|
||||||
var s = PrivateKey.fromRaw(keccak256.digest("sec").data)[]
|
var s = PrivateKey.fromRaw(keccak256.digest("sec").data)[]
|
||||||
var m = keccak256.digest("msg")
|
var m = keccak256.digest("msg")
|
||||||
var sig = sign(s, m)
|
var sig = sign(s, SkMessage(m.data))
|
||||||
var sersig = sig.toRaw()
|
var sersig = sig.toRaw()
|
||||||
var key = recover(sig, m)[]
|
var key = recover(sig, SkMessage(m.data))[]
|
||||||
var serkey = key.toRaw()
|
var serkey = key.toRaw()
|
||||||
check:
|
check:
|
||||||
compare(sersig, check1) == true
|
compare(sersig, check1) == true
|
||||||
|
@ -217,18 +218,19 @@ suite "ECC/ECDSA/ECDHE tests suite":
|
||||||
test "ECDSA/100 signatures":
|
test "ECDSA/100 signatures":
|
||||||
# signature test
|
# signature test
|
||||||
for i in 1..100:
|
for i in 1..100:
|
||||||
var m = PrivateKey.random()[].toRaw
|
var m: array[32, byte]
|
||||||
var s = PrivateKey.random()[]
|
brHmacDrbgGenerate(rng[], m)
|
||||||
|
var s = PrivateKey.random(rng[])
|
||||||
var key = s.toPublicKey()
|
var key = s.toPublicKey()
|
||||||
let sig = sign(s, m)
|
let sig = sign(s, SkMessage(m))
|
||||||
let rkey = recover(sig, m)[]
|
let rkey = recover(sig, SkMessage(m))[]
|
||||||
check:
|
check:
|
||||||
key == rkey
|
key == rkey
|
||||||
|
|
||||||
test "KEYS/100 create/recovery keys":
|
test "KEYS/100 create/recovery keys":
|
||||||
# key create/recovery test
|
# key create/recovery test
|
||||||
for i in 1..100:
|
for i in 1..100:
|
||||||
var s = PrivateKey.random()[]
|
var s = PrivateKey.random(rng[])
|
||||||
var key = s.toPublicKey()
|
var key = s.toPublicKey()
|
||||||
let rkey = PublicKey.fromRaw(key.toRaw())[]
|
let rkey = PublicKey.fromRaw(key.toRaw())[]
|
||||||
check:
|
check:
|
||||||
|
@ -237,9 +239,9 @@ suite "ECC/ECDSA/ECDHE tests suite":
|
||||||
test "ECDHE/100 shared secrets":
|
test "ECDHE/100 shared secrets":
|
||||||
# ECDHE shared secret test
|
# ECDHE shared secret test
|
||||||
for i in 1..100:
|
for i in 1..100:
|
||||||
var aliceSecret = PrivateKey.random()[]
|
var aliceSecret = PrivateKey.random(rng[])
|
||||||
var alicePublic = aliceSecret.toPublicKey()
|
var alicePublic = aliceSecret.toPublicKey()
|
||||||
var bobSecret = PrivateKey.random()[]
|
var bobSecret = PrivateKey.random(rng[])
|
||||||
var bobPublic = bobSecret.toPublicKey()
|
var bobPublic = bobSecret.toPublicKey()
|
||||||
var secret1 = ecdhRaw(aliceSecret, bobPublic)
|
var secret1 = ecdhRaw(aliceSecret, bobPublic)
|
||||||
var secret2 = ecdhRaw(bobSecret, alicePublic)
|
var secret2 = ecdhRaw(bobSecret, alicePublic)
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
import
|
import
|
||||||
testutils/unittests, stew/shims/net, nimcrypto,
|
testutils/unittests, stew/shims/net, bearssl,
|
||||||
eth/[keys, rlp, trie/db],
|
eth/[keys, rlp, trie/db],
|
||||||
eth/p2p/discoveryv5/[discovery_db, enr, node, types, routing_table, encoding],
|
eth/p2p/discoveryv5/[discovery_db, enr, node, types, routing_table, encoding],
|
||||||
eth/p2p/discoveryv5/protocol as discv5_protocol
|
eth/p2p/discoveryv5/protocol as discv5_protocol
|
||||||
|
|
||||||
|
|
||||||
proc localAddress*(port: int): Address =
|
proc localAddress*(port: int): Address =
|
||||||
Address(ip: ValidIpAddress.init("127.0.0.1"), port: Port(port))
|
Address(ip: ValidIpAddress.init("127.0.0.1"), port: Port(port))
|
||||||
|
|
||||||
proc initDiscoveryNode*(privKey: PrivateKey, address: Address,
|
proc initDiscoveryNode*(rng: ref BrHmacDrbgContext, privKey: PrivateKey, address: Address,
|
||||||
bootstrapRecords: openarray[Record] = [],
|
bootstrapRecords: openarray[Record] = [],
|
||||||
localEnrFields: openarray[FieldPair] = []):
|
localEnrFields: openarray[FieldPair] = []):
|
||||||
discv5_protocol.Protocol =
|
discv5_protocol.Protocol =
|
||||||
|
@ -17,7 +16,7 @@ proc initDiscoveryNode*(privKey: PrivateKey, address: Address,
|
||||||
some(address.ip),
|
some(address.ip),
|
||||||
address.port, address.port,
|
address.port, address.port,
|
||||||
bootstrapRecords = bootstrapRecords,
|
bootstrapRecords = bootstrapRecords,
|
||||||
localEnrFields = localEnrFields)
|
localEnrFields = localEnrFields, rng = rng)
|
||||||
|
|
||||||
result.open()
|
result.open()
|
||||||
|
|
||||||
|
@ -26,33 +25,34 @@ proc nodeIdInNodes*(id: NodeId, nodes: openarray[Node]): bool =
|
||||||
if id == n.id: return true
|
if id == n.id: return true
|
||||||
|
|
||||||
# Creating a random packet with specific nodeid each time
|
# Creating a random packet with specific nodeid each time
|
||||||
proc randomPacket*(tag: PacketTag): seq[byte] =
|
proc randomPacket*(rng: var BrHmacDrbgContext, tag: PacketTag): seq[byte] =
|
||||||
var
|
var
|
||||||
authTag: AuthTag
|
authTag: AuthTag
|
||||||
msg: array[44, byte]
|
msg: array[44, byte]
|
||||||
|
|
||||||
check randomBytes(authTag) == authTag.len
|
brHmacDrbgGenerate(rng, authTag)
|
||||||
check randomBytes(msg) == msg.len
|
brHmacDrbgGenerate(rng, msg)
|
||||||
result.add(tag)
|
result.add(tag)
|
||||||
result.add(rlp.encode(authTag))
|
result.add(rlp.encode(authTag))
|
||||||
result.add(msg)
|
result.add(msg)
|
||||||
|
|
||||||
proc generateNode*(privKey = PrivateKey.random()[], port: int = 20302,
|
proc generateNode*(privKey: PrivateKey, port: int = 20302,
|
||||||
localEnrFields: openarray[FieldPair] = []): Node =
|
localEnrFields: openarray[FieldPair] = []): Node =
|
||||||
let port = Port(port)
|
let port = Port(port)
|
||||||
let enr = enr.Record.init(1, privKey, some(ValidIpAddress.init("127.0.0.1")),
|
let enr = enr.Record.init(1, privKey, some(ValidIpAddress.init("127.0.0.1")),
|
||||||
port, port, localEnrFields).expect("Properly intialized private key")
|
port, port, localEnrFields).expect("Properly intialized private key")
|
||||||
result = newNode(enr).expect("Properly initialized node")
|
result = newNode(enr).expect("Properly initialized node")
|
||||||
|
|
||||||
proc nodeAtDistance*(n: Node, d: uint32): Node =
|
proc nodeAtDistance*(n: Node, rng: var BrHmacDrbgContext, d: uint32): Node =
|
||||||
while true:
|
while true:
|
||||||
let node = generateNode()
|
let node = generateNode(PrivateKey.random(rng))
|
||||||
if logDist(n.id, node.id) == d:
|
if logDist(n.id, node.id) == d:
|
||||||
return node
|
return node
|
||||||
|
|
||||||
proc nodesAtDistance*(n: Node, d: uint32, amount: int): seq[Node] =
|
proc nodesAtDistance*(
|
||||||
|
n: Node, rng: var BrHmacDrbgContext, d: uint32, amount: int): seq[Node] =
|
||||||
for i in 0..<amount:
|
for i in 0..<amount:
|
||||||
result.add(nodeAtDistance(n, d))
|
result.add(nodeAtDistance(n, rng, d))
|
||||||
|
|
||||||
proc addSeenNode*(d: discv5_protocol.Protocol, n: Node): bool =
|
proc addSeenNode*(d: discv5_protocol.Protocol, n: Node): bool =
|
||||||
# Add it as a seen node, warning: for testing convenience only!
|
# Add it as a seen node, warning: for testing convenience only!
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import
|
import
|
||||||
unittest, chronos, nimcrypto, strutils,
|
unittest, chronos, nimcrypto, strutils, bearssl,
|
||||||
eth/[keys, p2p], eth/p2p/[discovery, enode]
|
eth/[keys, p2p], eth/p2p/[discovery, enode]
|
||||||
|
|
||||||
var nextPort = 30303
|
var nextPort = 30303
|
||||||
|
@ -15,17 +15,13 @@ proc startDiscoveryNode*(privKey: PrivateKey, address: Address,
|
||||||
result.open()
|
result.open()
|
||||||
await result.bootstrap()
|
await result.bootstrap()
|
||||||
|
|
||||||
proc setupBootNode*(): Future[ENode] {.async.} =
|
proc setupTestNode*(
|
||||||
let
|
rng: ref BrHmacDrbgContext,
|
||||||
bootNodeKey = KeyPair.random()[]
|
capabilities: varargs[ProtocolInfo, `protocolInfo`]): EthereumNode {.gcsafe.} =
|
||||||
bootNodeAddr = localAddress(30301)
|
# Don't create new RNG every time in production code!
|
||||||
bootNode = await startDiscoveryNode(bootNodeKey.seckey, bootNodeAddr, @[])
|
let keys1 = KeyPair.random(rng[])
|
||||||
result = ENode(pubkey: bootNodeKey.pubkey, address: bootNodeAddr)
|
|
||||||
|
|
||||||
proc setupTestNode*(capabilities: varargs[ProtocolInfo, `protocolInfo`]): EthereumNode =
|
|
||||||
let keys1 = KeyPair.random()[]
|
|
||||||
result = newEthereumNode(keys1, localAddress(nextPort), 1, nil,
|
result = newEthereumNode(keys1, localAddress(nextPort), 1, nil,
|
||||||
addAllCapabilities = false)
|
addAllCapabilities = false, rng = rng)
|
||||||
nextPort.inc
|
nextPort.inc
|
||||||
for capability in capabilities:
|
for capability in capabilities:
|
||||||
result.addCapability capability
|
result.addCapability capability
|
||||||
|
|
|
@ -199,6 +199,8 @@ const eip8data = [
|
||||||
"0c7ec6340062cc46f5e9f1e3cf86f8c8c403c5a0964f5df0ebd34a75ddc86db5")
|
"0c7ec6340062cc46f5e9f1e3cf86f8c8c403c5a0964f5df0ebd34a75ddc86db5")
|
||||||
]
|
]
|
||||||
|
|
||||||
|
let rng = newRng()
|
||||||
|
|
||||||
proc testValue(s: string): string =
|
proc testValue(s: string): string =
|
||||||
for item in data:
|
for item in data:
|
||||||
if item[0] == s:
|
if item[0] == s:
|
||||||
|
@ -212,26 +214,21 @@ proc testE8Value(s: string): string =
|
||||||
break
|
break
|
||||||
|
|
||||||
suite "Ethereum P2P handshake test suite":
|
suite "Ethereum P2P handshake test suite":
|
||||||
|
|
||||||
block:
|
block:
|
||||||
proc newTestHandshake(flags: set[HandshakeFlag]): Handshake =
|
proc newTestHandshake(flags: set[HandshakeFlag]): Handshake =
|
||||||
if Initiator in flags:
|
if Initiator in flags:
|
||||||
let pk = PrivateKey.fromHex(testValue("initiator_private_key"))[]
|
let pk = PrivateKey.fromHex(testValue("initiator_private_key"))[]
|
||||||
let kp = KeyPair(seckey: pk, pubkey: pk.toPublicKey())
|
result = Handshake.tryInit(rng[], pk.toKeyPair(), flags)[]
|
||||||
result = Handshake.tryInit(kp, flags)[]
|
|
||||||
|
|
||||||
let epki = testValue("initiator_ephemeral_private_key")
|
let epki = testValue("initiator_ephemeral_private_key")
|
||||||
result.ephemeral.seckey = PrivateKey.fromHex(epki)[]
|
result.ephemeral = PrivateKey.fromHex(epki)[].toKeyPair()
|
||||||
result.ephemeral.pubkey = result.ephemeral.seckey.toPublicKey()
|
|
||||||
let nonce = fromHex(stripSpaces(testValue("initiator_nonce")))
|
let nonce = fromHex(stripSpaces(testValue("initiator_nonce")))
|
||||||
result.initiatorNonce[0..^1] = nonce[0..^1]
|
result.initiatorNonce[0..^1] = nonce[0..^1]
|
||||||
elif Responder in flags:
|
elif Responder in flags:
|
||||||
let pk = PrivateKey.fromHex(testValue("receiver_private_key"))[]
|
let pk = PrivateKey.fromHex(testValue("receiver_private_key"))[]
|
||||||
let kp = KeyPair(seckey: pk, pubkey: pk.toPublicKey())
|
result = Handshake.tryInit(rng[], pk.toKeyPair(), flags)[]
|
||||||
result = Handshake.tryInit(kp, flags)[]
|
|
||||||
let epkr = testValue("receiver_ephemeral_private_key")
|
let epkr = testValue("receiver_ephemeral_private_key")
|
||||||
result.ephemeral.seckey = PrivateKey.fromHex(epkr)[]
|
result.ephemeral = PrivateKey.fromHex(epkr)[].toKeyPair()
|
||||||
result.ephemeral.pubkey = result.ephemeral.seckey.toPublicKey()
|
|
||||||
let nonce = fromHex(stripSpaces(testValue("receiver_nonce")))
|
let nonce = fromHex(stripSpaces(testValue("receiver_nonce")))
|
||||||
result.responderNonce[0..^1] = nonce[0..^1]
|
result.responderNonce[0..^1] = nonce[0..^1]
|
||||||
|
|
||||||
|
@ -241,7 +238,7 @@ suite "Ethereum P2P handshake test suite":
|
||||||
var m0 = newSeq[byte](initiator.authSize(false))
|
var m0 = newSeq[byte](initiator.authSize(false))
|
||||||
var k0 = 0
|
var k0 = 0
|
||||||
initiator.authMessage(
|
initiator.authMessage(
|
||||||
responder.host.pubkey, m0, k0, 0, false).expect("auth success")
|
rng[], responder.host.pubkey, m0, k0, 0, false).expect("auth success")
|
||||||
var expect1 = fromHex(stripSpaces(testValue("auth_plaintext")))
|
var expect1 = fromHex(stripSpaces(testValue("auth_plaintext")))
|
||||||
var expect2 = fromHex(stripSpaces(pyevmAuth))
|
var expect2 = fromHex(stripSpaces(pyevmAuth))
|
||||||
check:
|
check:
|
||||||
|
@ -257,7 +254,7 @@ suite "Ethereum P2P handshake test suite":
|
||||||
let remoteHPubkey0 = initiator.host.pubkey
|
let remoteHPubkey0 = initiator.host.pubkey
|
||||||
|
|
||||||
initiator.authMessage(
|
initiator.authMessage(
|
||||||
responder.host.pubkey, m0, k0).expect("auth success")
|
rng[], responder.host.pubkey, m0, k0).expect("auth success")
|
||||||
responder.decodeAuthMessage(m0).expect("decode success")
|
responder.decodeAuthMessage(m0).expect("decode success")
|
||||||
check:
|
check:
|
||||||
responder.initiatorNonce[0..^1] == initiator.initiatorNonce[0..^1]
|
responder.initiatorNonce[0..^1] == initiator.initiatorNonce[0..^1]
|
||||||
|
@ -273,9 +270,9 @@ suite "Ethereum P2P handshake test suite":
|
||||||
var k1 = 0
|
var k1 = 0
|
||||||
var expect0 = fromHex(stripSpaces(testValue("authresp_plaintext")))
|
var expect0 = fromHex(stripSpaces(testValue("authresp_plaintext")))
|
||||||
initiator.authMessage(
|
initiator.authMessage(
|
||||||
responder.host.pubkey, m0, k0).expect("auth success")
|
rng[], responder.host.pubkey, m0, k0).expect("auth success")
|
||||||
responder.decodeAuthMessage(m0).expect("decode success")
|
responder.decodeAuthMessage(m0).expect("decode success")
|
||||||
responder.ackMessage(m1, k1, 0, false).expect("ack success")
|
responder.ackMessage(rng[], m1, k1, 0, false).expect("ack success")
|
||||||
check:
|
check:
|
||||||
m1 == expect0
|
m1 == expect0
|
||||||
responder.initiatorNonce == initiator.initiatorNonce
|
responder.initiatorNonce == initiator.initiatorNonce
|
||||||
|
@ -289,9 +286,9 @@ suite "Ethereum P2P handshake test suite":
|
||||||
var k1 = 0
|
var k1 = 0
|
||||||
|
|
||||||
initiator.authMessage(
|
initiator.authMessage(
|
||||||
responder.host.pubkey, m0, k0).expect("auth success")
|
rng[], responder.host.pubkey, m0, k0).expect("auth success")
|
||||||
responder.decodeAuthMessage(m0).expect("decode success")
|
responder.decodeAuthMessage(m0).expect("decode success")
|
||||||
responder.ackMessage(m1, k1).expect("ack success")
|
responder.ackMessage(rng[], m1, k1).expect("ack success")
|
||||||
initiator.decodeAckMessage(m1).expect("decode success")
|
initiator.decodeAckMessage(m1).expect("decode success")
|
||||||
let remoteEPubkey0 = responder.ephemeral.pubkey
|
let remoteEPubkey0 = responder.ephemeral.pubkey
|
||||||
let remoteHPubkey0 = responder.host.pubkey
|
let remoteHPubkey0 = responder.host.pubkey
|
||||||
|
@ -333,23 +330,18 @@ suite "Ethereum P2P handshake test suite":
|
||||||
proc newTestHandshake(flags: set[HandshakeFlag]): Handshake =
|
proc newTestHandshake(flags: set[HandshakeFlag]): Handshake =
|
||||||
if Initiator in flags:
|
if Initiator in flags:
|
||||||
let pk = PrivateKey.fromHex(testE8Value("initiator_private_key"))[]
|
let pk = PrivateKey.fromHex(testE8Value("initiator_private_key"))[]
|
||||||
let kp = KeyPair(seckey: pk, pubkey: pk.toPublicKey())
|
result = Handshake.tryInit(rng[], pk.toKeyPair(), flags)[]
|
||||||
result = Handshake.tryInit(kp, flags)[]
|
|
||||||
|
|
||||||
result.host.pubkey = result.host.seckey.toPublicKey()
|
|
||||||
let esec = testE8Value("initiator_ephemeral_private_key")
|
let esec = testE8Value("initiator_ephemeral_private_key")
|
||||||
result.ephemeral.seckey = PrivateKey.fromHex(esec)[]
|
result.ephemeral = PrivateKey.fromHex(esec)[].toKeyPair()
|
||||||
result.ephemeral.pubkey = result.ephemeral.seckey.toPublicKey()
|
|
||||||
let nonce = fromHex(stripSpaces(testE8Value("initiator_nonce")))
|
let nonce = fromHex(stripSpaces(testE8Value("initiator_nonce")))
|
||||||
result.initiatorNonce[0..^1] = nonce[0..^1]
|
result.initiatorNonce[0..^1] = nonce[0..^1]
|
||||||
elif Responder in flags:
|
elif Responder in flags:
|
||||||
let pk = PrivateKey.fromHex(testE8Value("receiver_private_key"))[]
|
let pk = PrivateKey.fromHex(testE8Value("receiver_private_key"))[]
|
||||||
let kp = KeyPair(seckey: pk, pubkey: pk.toPublicKey())
|
result = Handshake.tryInit(rng[], pk.toKeyPair(), flags)[]
|
||||||
result = Handshake.tryInit(kp, flags)[]
|
|
||||||
|
|
||||||
let esec = testE8Value("receiver_ephemeral_private_key")
|
let esec = testE8Value("receiver_ephemeral_private_key")
|
||||||
result.ephemeral.seckey = PrivateKey.fromHex(esec)[]
|
result.ephemeral = PrivateKey.fromHex(esec)[].toKeyPair()
|
||||||
result.ephemeral.pubkey = result.ephemeral.seckey.toPublicKey()
|
|
||||||
let nonce = fromHex(stripSpaces(testE8Value("receiver_nonce")))
|
let nonce = fromHex(stripSpaces(testE8Value("receiver_nonce")))
|
||||||
result.responderNonce[0..^1] = nonce[0..^1]
|
result.responderNonce[0..^1] = nonce[0..^1]
|
||||||
|
|
||||||
|
@ -436,12 +428,12 @@ suite "Ethereum P2P handshake test suite":
|
||||||
var k0 = 0
|
var k0 = 0
|
||||||
var k1 = 0
|
var k1 = 0
|
||||||
initiator.authMessage(
|
initiator.authMessage(
|
||||||
responder.host.pubkey, m0, k0).expect("auth success")
|
rng[], responder.host.pubkey, m0, k0).expect("auth success")
|
||||||
m0.setLen(k0)
|
m0.setLen(k0)
|
||||||
responder.decodeAuthMessage(m0).expect("decode success")
|
responder.decodeAuthMessage(m0).expect("decode success")
|
||||||
check (EIP8 in responder.flags) == true
|
check (EIP8 in responder.flags) == true
|
||||||
var m1 = newSeq[byte](responder.ackSize())
|
var m1 = newSeq[byte](responder.ackSize())
|
||||||
responder.ackMessage(m1, k1).expect("ack success")
|
responder.ackMessage(rng[], m1, k1).expect("ack success")
|
||||||
m1.setLen(k1)
|
m1.setLen(k1)
|
||||||
initiator.decodeAckMessage(m1).expect("decode success")
|
initiator.decodeAckMessage(m1).expect("decode success")
|
||||||
var csecInitiator = initiator.getSecrets(m0, m1).expect("secrets")
|
var csecInitiator = initiator.getSecrets(m0, m1).expect("secrets")
|
||||||
|
@ -458,11 +450,11 @@ suite "Ethereum P2P handshake test suite":
|
||||||
var k0 = 0
|
var k0 = 0
|
||||||
var k1 = 0
|
var k1 = 0
|
||||||
initiator.authMessage(
|
initiator.authMessage(
|
||||||
responder.host.pubkey, m0, k0).expect("auth success")
|
rng[], responder.host.pubkey, m0, k0).expect("auth success")
|
||||||
m0.setLen(k0)
|
m0.setLen(k0)
|
||||||
responder.decodeAuthMessage(m0).expect("auth success")
|
responder.decodeAuthMessage(m0).expect("auth success")
|
||||||
var m1 = newSeq[byte](responder.ackSize())
|
var m1 = newSeq[byte](responder.ackSize())
|
||||||
responder.ackMessage(m1, k1).expect("ack success")
|
responder.ackMessage(rng[], m1, k1).expect("ack success")
|
||||||
m1.setLen(k1)
|
m1.setLen(k1)
|
||||||
initiator.decodeAckMessage(m1).expect("ack success")
|
initiator.decodeAckMessage(m1).expect("ack success")
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,8 @@ const data = [
|
||||||
e7c301a0c05559f4c25db65e36820b4b909a226171a60ac6cb7beea09376d6d8""")
|
e7c301a0c05559f4c25db65e36820b4b909a226171a60ac6cb7beea09376d6d8""")
|
||||||
]
|
]
|
||||||
|
|
||||||
|
let rng = newRng()
|
||||||
|
|
||||||
proc testValue(s: string): string =
|
proc testValue(s: string): string =
|
||||||
for item in data:
|
for item in data:
|
||||||
if item[0] == s:
|
if item[0] == s:
|
||||||
|
@ -90,20 +92,16 @@ suite "Ethereum RLPx encryption/decryption test suite":
|
||||||
proc newTestHandshake(flags: set[HandshakeFlag]): Handshake =
|
proc newTestHandshake(flags: set[HandshakeFlag]): Handshake =
|
||||||
if Initiator in flags:
|
if Initiator in flags:
|
||||||
let pk = PrivateKey.fromHex(testValue("initiator_private_key"))[]
|
let pk = PrivateKey.fromHex(testValue("initiator_private_key"))[]
|
||||||
let kp = KeyPair(seckey: pk, pubkey: pk.toPublicKey())
|
result = Handshake.tryInit(rng[], pk.toKeyPair(), flags)[]
|
||||||
result = Handshake.tryInit(kp, flags)[]
|
|
||||||
let epki = testValue("initiator_ephemeral_private_key")
|
let epki = testValue("initiator_ephemeral_private_key")
|
||||||
result.ephemeral.seckey = PrivateKey.fromHex(epki)[]
|
result.ephemeral = PrivateKey.fromHex(epki)[].toKeyPair()
|
||||||
result.ephemeral.pubkey = result.ephemeral.seckey.toPublicKey()
|
|
||||||
let nonce = fromHex(stripSpaces(testValue("initiator_nonce")))
|
let nonce = fromHex(stripSpaces(testValue("initiator_nonce")))
|
||||||
result.initiatorNonce[0..^1] = nonce[0..^1]
|
result.initiatorNonce[0..^1] = nonce[0..^1]
|
||||||
elif Responder in flags:
|
elif Responder in flags:
|
||||||
let pk = PrivateKey.fromHex(testValue("receiver_private_key"))[]
|
let pk = PrivateKey.fromHex(testValue("receiver_private_key"))[]
|
||||||
let kp = KeyPair(seckey: pk, pubkey: pk.toPublicKey())
|
result = Handshake.tryInit(rng[], pk.toKeyPair(), flags)[]
|
||||||
result = Handshake.tryInit(kp, flags)[]
|
|
||||||
let epkr = testValue("receiver_ephemeral_private_key")
|
let epkr = testValue("receiver_ephemeral_private_key")
|
||||||
result.ephemeral.seckey = PrivateKey.fromHex(epkr)[]
|
result.ephemeral = PrivateKey.fromHex(epkr)[].toKeyPair()
|
||||||
result.ephemeral.pubkey = result.ephemeral.seckey.toPublicKey()
|
|
||||||
let nonce = fromHex(stripSpaces(testValue("receiver_nonce")))
|
let nonce = fromHex(stripSpaces(testValue("receiver_nonce")))
|
||||||
result.responderNonce[0..^1] = nonce[0..^1]
|
result.responderNonce[0..^1] = nonce[0..^1]
|
||||||
|
|
||||||
|
@ -174,12 +172,12 @@ suite "Ethereum RLPx encryption/decryption test suite":
|
||||||
var m0 = newSeq[byte](initiator.authSize())
|
var m0 = newSeq[byte](initiator.authSize())
|
||||||
var k0 = 0
|
var k0 = 0
|
||||||
var k1 = 0
|
var k1 = 0
|
||||||
check initiator.authMessage(responder.host.pubkey,
|
check initiator.authMessage(rng[], responder.host.pubkey,
|
||||||
m0, k0).isOk
|
m0, k0).isOk
|
||||||
m0.setLen(k0)
|
m0.setLen(k0)
|
||||||
check responder.decodeAuthMessage(m0).isOk
|
check responder.decodeAuthMessage(m0).isOk
|
||||||
var m1 = newSeq[byte](responder.ackSize())
|
var m1 = newSeq[byte](responder.ackSize())
|
||||||
check responder.ackMessage(m1, k1).isOk
|
check responder.ackMessage(rng[], m1, k1).isOk
|
||||||
m1.setLen(k1)
|
m1.setLen(k1)
|
||||||
check initiator.decodeAckMessage(m1).isOk
|
check initiator.decodeAckMessage(m1).isOk
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
import
|
import
|
||||||
chronos, chronicles, tables, stint, nimcrypto, testutils/unittests,
|
chronos, chronicles, tables, stint, testutils/unittests,
|
||||||
stew/shims/net, eth/keys,
|
stew/shims/net, eth/keys, bearssl,
|
||||||
eth/p2p/discoveryv5/[enr, node, types, routing_table, encoding],
|
eth/p2p/discoveryv5/[enr, node, types, routing_table, encoding],
|
||||||
eth/p2p/discoveryv5/protocol as discv5_protocol,
|
eth/p2p/discoveryv5/protocol as discv5_protocol,
|
||||||
./discv5_test_helper
|
./discv5_test_helper
|
||||||
|
|
||||||
procSuite "Discovery v5 Tests":
|
procSuite "Discovery v5 Tests":
|
||||||
|
let rng = newRng()
|
||||||
|
|
||||||
asyncTest "GetNode":
|
asyncTest "GetNode":
|
||||||
# TODO: This could be tested in just a routing table only context
|
# TODO: This could be tested in just a routing table only context
|
||||||
let
|
let
|
||||||
node = initDiscoveryNode(PrivateKey.random()[], localAddress(20302))
|
node = initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(20302))
|
||||||
targetNode = generateNode()
|
targetNode = generateNode(PrivateKey.random(rng[]))
|
||||||
|
|
||||||
check node.addNode(targetNode)
|
check node.addNode(targetNode)
|
||||||
|
|
||||||
for i in 0..<1000:
|
for i in 0..<1000:
|
||||||
discard node.addNode(generateNode())
|
discard node.addNode(generateNode(PrivateKey.random(rng[])))
|
||||||
|
|
||||||
let n = node.getNode(targetNode.id)
|
let n = node.getNode(targetNode.id)
|
||||||
check n.isSome()
|
check n.isSome()
|
||||||
|
@ -25,10 +27,13 @@ procSuite "Discovery v5 Tests":
|
||||||
|
|
||||||
asyncTest "Node deletion":
|
asyncTest "Node deletion":
|
||||||
let
|
let
|
||||||
bootnode = initDiscoveryNode(PrivateKey.random()[], localAddress(20301))
|
bootnode = initDiscoveryNode(
|
||||||
node1 = initDiscoveryNode(PrivateKey.random()[], localAddress(20302),
|
rng, PrivateKey.random(rng[]), localAddress(20301))
|
||||||
|
node1 = initDiscoveryNode(
|
||||||
|
rng, PrivateKey.random(rng[]), localAddress(20302),
|
||||||
@[bootnode.localNode.record])
|
@[bootnode.localNode.record])
|
||||||
node2 = initDiscoveryNode(PrivateKey.random()[], localAddress(20303),
|
node2 = initDiscoveryNode(
|
||||||
|
rng, PrivateKey.random(rng[]), localAddress(20303),
|
||||||
@[bootnode.localNode.record])
|
@[bootnode.localNode.record])
|
||||||
pong1 = await discv5_protocol.ping(node1, bootnode.localNode)
|
pong1 = await discv5_protocol.ping(node1, bootnode.localNode)
|
||||||
pong2 = await discv5_protocol.ping(node1, node2.localNode)
|
pong2 = await discv5_protocol.ping(node1, node2.localNode)
|
||||||
|
@ -51,13 +56,14 @@ procSuite "Discovery v5 Tests":
|
||||||
|
|
||||||
|
|
||||||
asyncTest "Handshake cleanup":
|
asyncTest "Handshake cleanup":
|
||||||
let node = initDiscoveryNode(PrivateKey.random()[], localAddress(20302))
|
let node = initDiscoveryNode(
|
||||||
|
rng, PrivateKey.random(rng[]), localAddress(20302))
|
||||||
var tag: PacketTag
|
var tag: PacketTag
|
||||||
let a = localAddress(20303)
|
let a = localAddress(20303)
|
||||||
|
|
||||||
for i in 0 ..< 5:
|
for i in 0 ..< 5:
|
||||||
check randomBytes(tag) == tag.len
|
brHmacDrbgGenerate(rng[], tag)
|
||||||
node.receive(a, randomPacket(tag))
|
node.receive(a, randomPacket(rng[], tag))
|
||||||
|
|
||||||
# Checking different nodeIds but same address
|
# Checking different nodeIds but same address
|
||||||
check node.codec.handshakes.len == 5
|
check node.codec.handshakes.len == 5
|
||||||
|
@ -70,24 +76,26 @@ procSuite "Discovery v5 Tests":
|
||||||
await node.closeWait()
|
await node.closeWait()
|
||||||
|
|
||||||
asyncTest "Handshake different address":
|
asyncTest "Handshake different address":
|
||||||
let node = initDiscoveryNode(PrivateKey.random()[], localAddress(20302))
|
let node = initDiscoveryNode(
|
||||||
|
rng, PrivateKey.random(rng[]), localAddress(20302))
|
||||||
var tag: PacketTag
|
var tag: PacketTag
|
||||||
|
|
||||||
for i in 0 ..< 5:
|
for i in 0 ..< 5:
|
||||||
let a = localAddress(20303 + i)
|
let a = localAddress(20303 + i)
|
||||||
node.receive(a, randomPacket(tag))
|
node.receive(a, randomPacket(rng[], tag))
|
||||||
|
|
||||||
check node.codec.handshakes.len == 5
|
check node.codec.handshakes.len == 5
|
||||||
|
|
||||||
await node.closeWait()
|
await node.closeWait()
|
||||||
|
|
||||||
asyncTest "Handshake duplicates":
|
asyncTest "Handshake duplicates":
|
||||||
let node = initDiscoveryNode(PrivateKey.random()[], localAddress(20302))
|
let node = initDiscoveryNode(
|
||||||
|
rng, PrivateKey.random(rng[]), localAddress(20302))
|
||||||
var tag: PacketTag
|
var tag: PacketTag
|
||||||
let a = localAddress(20303)
|
let a = localAddress(20303)
|
||||||
|
|
||||||
for i in 0 ..< 5:
|
for i in 0 ..< 5:
|
||||||
node.receive(a, randomPacket(tag))
|
node.receive(a, randomPacket(rng[], tag))
|
||||||
|
|
||||||
# Checking handshake duplicates
|
# Checking handshake duplicates
|
||||||
check node.codec.handshakes.len == 1
|
check node.codec.handshakes.len == 1
|
||||||
|
@ -177,11 +185,11 @@ procSuite "Discovery v5 Tests":
|
||||||
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a617")[]
|
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a617")[]
|
||||||
testNodeKey = PrivateKey.fromHex(
|
testNodeKey = PrivateKey.fromHex(
|
||||||
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a618")[]
|
"a2b50376a79b1a8c8a3296485572bdfbf54708bb46d3c25d73d2723aaaf6a618")[]
|
||||||
mainNode = initDiscoveryNode(mainNodeKey, localAddress(20301))
|
mainNode = initDiscoveryNode(rng, mainNodeKey, localAddress(20301))
|
||||||
testNode = initDiscoveryNode(testNodeKey, localAddress(20302))
|
testNode = initDiscoveryNode(rng, testNodeKey, localAddress(20302))
|
||||||
# logarithmic distance between mainNode and testNode is 256
|
# logarithmic distance between mainNode and testNode is 256
|
||||||
|
|
||||||
let nodes = nodesAtDistance(mainNode.localNode, dist, 10)
|
let nodes = nodesAtDistance(mainNode.localNode, rng[], dist, 10)
|
||||||
for n in nodes:
|
for n in nodes:
|
||||||
discard mainNode.addSeenNode(n) # for testing only!
|
discard mainNode.addSeenNode(n) # for testing only!
|
||||||
|
|
||||||
|
@ -218,7 +226,7 @@ procSuite "Discovery v5 Tests":
|
||||||
check discovered.isOk
|
check discovered.isOk
|
||||||
check discovered[].len == 0
|
check discovered[].len == 0
|
||||||
|
|
||||||
let moreNodes = nodesAtDistance(mainNode.localNode, dist, 10)
|
let moreNodes = nodesAtDistance(mainNode.localNode, rng[], dist, 10)
|
||||||
for n in moreNodes:
|
for n in moreNodes:
|
||||||
discard mainNode.addSeenNode(n) # for testing only!
|
discard mainNode.addSeenNode(n) # for testing only!
|
||||||
|
|
||||||
|
@ -233,11 +241,12 @@ procSuite "Discovery v5 Tests":
|
||||||
|
|
||||||
asyncTest "FindNode with test table":
|
asyncTest "FindNode with test table":
|
||||||
|
|
||||||
let mainNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20301))
|
let mainNode =
|
||||||
|
initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(20301))
|
||||||
|
|
||||||
# Generate 1000 random nodes and add to our main node's routing table
|
# Generate 1000 random nodes and add to our main node's routing table
|
||||||
for i in 0..<1000:
|
for i in 0..<1000:
|
||||||
discard mainNode.addSeenNode(generateNode()) # for testing only!
|
discard mainNode.addSeenNode(generateNode(PrivateKey.random(rng[]))) # for testing only!
|
||||||
|
|
||||||
let
|
let
|
||||||
neighbours = mainNode.neighbours(mainNode.localNode.id)
|
neighbours = mainNode.neighbours(mainNode.localNode.id)
|
||||||
|
@ -247,7 +256,8 @@ procSuite "Discovery v5 Tests":
|
||||||
debug "Closest neighbour", closestDistance, id=closest.id.toHex()
|
debug "Closest neighbour", closestDistance, id=closest.id.toHex()
|
||||||
|
|
||||||
let
|
let
|
||||||
testNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20302),
|
testNode = initDiscoveryNode(
|
||||||
|
rng, PrivateKey.random(rng[]), localAddress(20302),
|
||||||
@[mainNode.localNode.record])
|
@[mainNode.localNode.record])
|
||||||
discovered = await discv5_protocol.findNode(testNode, mainNode.localNode,
|
discovered = await discv5_protocol.findNode(testNode, mainNode.localNode,
|
||||||
closestDistance)
|
closestDistance)
|
||||||
|
@ -262,13 +272,14 @@ procSuite "Discovery v5 Tests":
|
||||||
const
|
const
|
||||||
nodeCount = 17
|
nodeCount = 17
|
||||||
|
|
||||||
let bootNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20301))
|
let bootNode =
|
||||||
|
initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(20301))
|
||||||
bootNode.start()
|
bootNode.start()
|
||||||
|
|
||||||
var nodes = newSeqOfCap[discv5_protocol.Protocol](nodeCount)
|
var nodes = newSeqOfCap[discv5_protocol.Protocol](nodeCount)
|
||||||
nodes.add(bootNode)
|
nodes.add(bootNode)
|
||||||
for i in 1 ..< nodeCount:
|
for i in 1 ..< nodeCount:
|
||||||
nodes.add(initDiscoveryNode(PrivateKey.random()[], localAddress(20301 + i),
|
nodes.add(initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(20301 + i),
|
||||||
@[bootNode.localNode.record]))
|
@[bootNode.localNode.record]))
|
||||||
|
|
||||||
# Make sure all nodes have "seen" each other by forcing pings
|
# Make sure all nodes have "seen" each other by forcing pings
|
||||||
|
@ -292,11 +303,13 @@ procSuite "Discovery v5 Tests":
|
||||||
|
|
||||||
asyncTest "Resolve target":
|
asyncTest "Resolve target":
|
||||||
let
|
let
|
||||||
mainNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20301))
|
mainNode =
|
||||||
lookupNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20302))
|
initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(20301))
|
||||||
targetKey = PrivateKey.random()[]
|
lookupNode =
|
||||||
|
initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(20302))
|
||||||
|
targetKey = PrivateKey.random(rng[])
|
||||||
targetAddress = localAddress(20303)
|
targetAddress = localAddress(20303)
|
||||||
targetNode = initDiscoveryNode(targetKey, targetAddress)
|
targetNode = initDiscoveryNode(rng, targetKey, targetAddress)
|
||||||
targetId = targetNode.localNode.id
|
targetId = targetNode.localNode.id
|
||||||
|
|
||||||
var targetSeqNum = targetNode.localNode.record.seqNum
|
var targetSeqNum = targetNode.localNode.record.seqNum
|
||||||
|
@ -362,12 +375,12 @@ procSuite "Discovery v5 Tests":
|
||||||
|
|
||||||
asyncTest "Random nodes with enr field filter":
|
asyncTest "Random nodes with enr field filter":
|
||||||
let
|
let
|
||||||
lookupNode = initDiscoveryNode(PrivateKey.random()[], localAddress(20301))
|
lookupNode = initDiscoveryNode(rng, PrivateKey.random(rng[]), localAddress(20301))
|
||||||
targetFieldPair = toFieldPair("test", @[byte 1,2,3,4])
|
targetFieldPair = toFieldPair("test", @[byte 1,2,3,4])
|
||||||
targetNode = generateNode(localEnrFields = [targetFieldPair])
|
targetNode = generateNode(PrivateKey.random(rng[]), localEnrFields = [targetFieldPair])
|
||||||
otherFieldPair = toFieldPair("test", @[byte 1,2,3,4,5])
|
otherFieldPair = toFieldPair("test", @[byte 1,2,3,4,5])
|
||||||
otherNode = generateNode(localEnrFields = [otherFieldPair])
|
otherNode = generateNode(PrivateKey.random(rng[]), localEnrFields = [otherFieldPair])
|
||||||
anotherNode = generateNode()
|
anotherNode = generateNode(PrivateKey.random(rng[]))
|
||||||
|
|
||||||
check:
|
check:
|
||||||
lookupNode.addNode(targetNode)
|
lookupNode.addNode(targetNode)
|
||||||
|
|
|
@ -5,6 +5,8 @@ import
|
||||||
# According to test vectors:
|
# According to test vectors:
|
||||||
# https://github.com/ethereum/devp2p/blob/master/discv5/discv5-wire-test-vectors.md
|
# https://github.com/ethereum/devp2p/blob/master/discv5/discv5-wire-test-vectors.md
|
||||||
|
|
||||||
|
let rng = newRng()
|
||||||
|
|
||||||
suite "Discovery v5 Packet Encodings":
|
suite "Discovery v5 Packet Encodings":
|
||||||
# TODO: These tests are currently not completely representative for the code
|
# TODO: These tests are currently not completely representative for the code
|
||||||
# and thus will not necessarily notice failures. Refactor/restructure code
|
# and thus will not necessarily notice failures. Refactor/restructure code
|
||||||
|
@ -230,19 +232,19 @@ suite "Discovery v5 Additional":
|
||||||
|
|
||||||
test "AuthHeader encode/decode":
|
test "AuthHeader encode/decode":
|
||||||
let
|
let
|
||||||
privKey = PrivateKey.random()[]
|
privKey = PrivateKey.random(rng[])
|
||||||
enrRec = enr.Record.init(1, privKey, none(ValidIpAddress), Port(9000),
|
enrRec = enr.Record.init(1, privKey, none(ValidIpAddress), Port(9000),
|
||||||
Port(9000)).expect("Properly intialized private key")
|
Port(9000)).expect("Properly intialized private key")
|
||||||
node = newNode(enrRec).expect("Properly initialized record")
|
node = newNode(enrRec).expect("Properly initialized record")
|
||||||
nonce = hexToByteArray[authTagSize]("0x27b5af763c446acd2749fe8e")
|
nonce = hexToByteArray[authTagSize]("0x27b5af763c446acd2749fe8e")
|
||||||
pubKey = PrivateKey.random()[].toPublicKey()
|
pubKey = PrivateKey.random(rng[]).toPublicKey()
|
||||||
nodeId = pubKey.toNodeId()
|
nodeId = pubKey.toNodeId()
|
||||||
idNonce = hexToByteArray[idNonceSize](
|
idNonce = hexToByteArray[idNonceSize](
|
||||||
"0xa77e3aa0c144ae7c0a3af73692b7d6e5b7a2fdc0eda16e8d5e6cb0d08e88dd04")
|
"0xa77e3aa0c144ae7c0a3af73692b7d6e5b7a2fdc0eda16e8d5e6cb0d08e88dd04")
|
||||||
whoareyou = Whoareyou(idNonce: idNonce, recordSeq: 0, pubKey: pubKey)
|
whoareyou = Whoareyou(idNonce: idNonce, recordSeq: 0, pubKey: pubKey)
|
||||||
c = Codec(localNode: node, privKey: privKey)
|
c = Codec(localNode: node, privKey: privKey)
|
||||||
|
|
||||||
let (auth, _) = c.encodeAuthHeader(nodeId, nonce, whoareyou)[]
|
let (auth, _) = encodeAuthHeader(rng[], c, nodeId, nonce, whoareyou)
|
||||||
var rlp = rlpFromBytes(auth)
|
var rlp = rlpFromBytes(auth)
|
||||||
let authHeader = rlp.read(AuthHeader)
|
let authHeader = rlp.read(AuthHeader)
|
||||||
var newNode: Node
|
var newNode: Node
|
||||||
|
|
|
@ -23,6 +23,8 @@ proc compare[A, B](x: openarray[A], y: openarray[B], s: int = 0): bool =
|
||||||
template offsetOf(a, b): int =
|
template offsetOf(a, b): int =
|
||||||
cast[int](cast[uint](unsafeAddr b) - cast[uint](unsafeAddr a))
|
cast[int](cast[uint](unsafeAddr b) - cast[uint](unsafeAddr a))
|
||||||
|
|
||||||
|
let rng = newRng()
|
||||||
|
|
||||||
suite "ECIES test suite":
|
suite "ECIES test suite":
|
||||||
test "ECIES structures alignment":
|
test "ECIES structures alignment":
|
||||||
var header: EciesHeader
|
var header: EciesHeader
|
||||||
|
@ -69,17 +71,17 @@ suite "ECIES test suite":
|
||||||
var encr = newSeq[byte](eciesEncryptedLength(len(m)))
|
var encr = newSeq[byte](eciesEncryptedLength(len(m)))
|
||||||
var decr = newSeq[byte](len(m))
|
var decr = newSeq[byte](len(m))
|
||||||
var shmac = [0x13'u8, 0x13'u8]
|
var shmac = [0x13'u8, 0x13'u8]
|
||||||
var s = PrivateKey.random()[]
|
var s = PrivateKey.random(rng[])
|
||||||
var p = s.toPublicKey()
|
var p = s.toPublicKey()
|
||||||
|
|
||||||
eciesEncrypt(plain, encr, p).expect("encryption should succeed")
|
eciesEncrypt(rng[], plain, encr, p).expect("encryption should succeed")
|
||||||
eciesDecrypt(encr, decr, s).expect("decryption should succeed")
|
eciesDecrypt(encr, decr, s).expect("decryption should succeed")
|
||||||
|
|
||||||
check:
|
check:
|
||||||
# Without additional mac data
|
# Without additional mac data
|
||||||
equalMem(addr m[0], addr decr[0], len(m))
|
equalMem(addr m[0], addr decr[0], len(m))
|
||||||
# With additional mac data
|
# With additional mac data
|
||||||
eciesEncrypt(plain, encr, p, shmac).expect("encryption should succeed")
|
eciesEncrypt(rng[], plain, encr, p, shmac).expect("encryption should succeed")
|
||||||
eciesDecrypt(encr, decr, s, shmac).expect("decryption should succeed")
|
eciesDecrypt(encr, decr, s, shmac).expect("decryption should succeed")
|
||||||
|
|
||||||
check:
|
check:
|
||||||
|
|
|
@ -3,6 +3,8 @@ import
|
||||||
nimcrypto/utils, stew/shims/net,
|
nimcrypto/utils, stew/shims/net,
|
||||||
eth/p2p/enode, eth/p2p/discoveryv5/enr, eth/keys
|
eth/p2p/enode, eth/p2p/discoveryv5/enr, eth/keys
|
||||||
|
|
||||||
|
let rng = newRng()
|
||||||
|
|
||||||
suite "ENR":
|
suite "ENR":
|
||||||
test "Serialization":
|
test "Serialization":
|
||||||
var pk = PrivateKey.fromHex(
|
var pk = PrivateKey.fromHex(
|
||||||
|
@ -33,7 +35,7 @@ suite "ENR":
|
||||||
|
|
||||||
test "Create from ENode address":
|
test "Create from ENode address":
|
||||||
let
|
let
|
||||||
keys = KeyPair.random()[]
|
keys = KeyPair.random(rng[])
|
||||||
ip = ValidIpAddress.init("10.20.30.40")
|
ip = ValidIpAddress.init("10.20.30.40")
|
||||||
enr = Record.init(100, keys.seckey, some(ip), Port(9000), Port(9000), @[])[]
|
enr = Record.init(100, keys.seckey, some(ip), Port(9000), Port(9000), @[])[]
|
||||||
typedEnr = get enr.toTypedRecord()
|
typedEnr = get enr.toTypedRecord()
|
||||||
|
@ -53,7 +55,7 @@ suite "ENR":
|
||||||
|
|
||||||
test "ENR without address":
|
test "ENR without address":
|
||||||
let
|
let
|
||||||
keys = KeyPair.random()[]
|
keys = KeyPair.random(rng[])
|
||||||
enr = Record.init(100, keys.seckey, none(ValidIpAddress), Port(9000), Port(9000))[]
|
enr = Record.init(100, keys.seckey, none(ValidIpAddress), Port(9000), Port(9000))[]
|
||||||
typedEnr = get enr.toTypedRecord()
|
typedEnr = get enr.toTypedRecord()
|
||||||
|
|
||||||
|
|
|
@ -52,11 +52,13 @@ p2pProtocol hah(version = 1,
|
||||||
onPeerDisconnected do (peer: Peer, reason: DisconnectionReason) {.gcsafe.}:
|
onPeerDisconnected do (peer: Peer, reason: DisconnectionReason) {.gcsafe.}:
|
||||||
peer.networkState.count -= 1
|
peer.networkState.count -= 1
|
||||||
|
|
||||||
|
|
||||||
suite "Testing protocol handlers":
|
suite "Testing protocol handlers":
|
||||||
asyncTest "Failing disconnection handler":
|
asyncTest "Failing disconnection handler":
|
||||||
let bootENode = await setupBootNode()
|
let rng = newRng()
|
||||||
var node1 = setupTestNode(abc, xyz)
|
|
||||||
var node2 = setupTestNode(abc, xyz)
|
var node1 = setupTestNode(rng, abc, xyz)
|
||||||
|
var node2 = setupTestNode(rng, abc, xyz)
|
||||||
|
|
||||||
node2.startListening()
|
node2.startListening()
|
||||||
let peer = await node1.rlpxConnect(newNode(node2.toENode()))
|
let peer = await node1.rlpxConnect(newNode(node2.toENode()))
|
||||||
|
@ -71,8 +73,10 @@ suite "Testing protocol handlers":
|
||||||
node1.protocolState(xyz).count == 0
|
node1.protocolState(xyz).count == 0
|
||||||
|
|
||||||
asyncTest "Failing connection handler":
|
asyncTest "Failing connection handler":
|
||||||
var node1 = setupTestNode(hah)
|
let rng = newRng()
|
||||||
var node2 = setupTestNode(hah)
|
|
||||||
|
var node1 = setupTestNode(rng, hah)
|
||||||
|
var node2 = setupTestNode(rng, hah)
|
||||||
node2.startListening()
|
node2.startListening()
|
||||||
let peer = await node1.rlpxConnect(newNode(node2.toENode()))
|
let peer = await node1.rlpxConnect(newNode(node2.toENode()))
|
||||||
check:
|
check:
|
||||||
|
|
|
@ -3,17 +3,14 @@ import
|
||||||
eth/p2p, eth/p2p/rlpx_protocols/[whisper_protocol, eth_protocol],
|
eth/p2p, eth/p2p/rlpx_protocols/[whisper_protocol, eth_protocol],
|
||||||
../p2p/p2p_test_helper
|
../p2p/p2p_test_helper
|
||||||
|
|
||||||
|
let rng = newRng()
|
||||||
|
|
||||||
var
|
var
|
||||||
node1: EthereumNode
|
node1 = setupTestNode(rng, eth, Whisper)
|
||||||
node2: EthereumNode
|
node2 = setupTestNode(rng, eth, Whisper)
|
||||||
peer: Peer
|
|
||||||
|
|
||||||
|
|
||||||
node1 = setupTestNode(eth, Whisper)
|
|
||||||
node2 = setupTestNode(eth, Whisper)
|
|
||||||
|
|
||||||
node2.startListening()
|
node2.startListening()
|
||||||
peer = waitFor node1.rlpxConnect(newNode(node2.toENode()))
|
var peer = waitFor node1.rlpxConnect(newNode(node2.toENode()))
|
||||||
|
|
||||||
proc testThunk(payload: openArray[byte]) =
|
proc testThunk(payload: openArray[byte]) =
|
||||||
var (msgId, msgData) = recvMsgMock(payload)
|
var (msgId, msgData) = recvMsgMock(payload)
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import
|
import
|
||||||
unittest,
|
unittest, bearssl,
|
||||||
|
eth/keys,
|
||||||
eth/p2p/discoveryv5/[routing_table, node],
|
eth/p2p/discoveryv5/[routing_table, node],
|
||||||
./discv5_test_helper
|
./discv5_test_helper
|
||||||
|
|
||||||
suite "Routing Table Tests":
|
suite "Routing Table Tests":
|
||||||
|
let rng = newRng()
|
||||||
|
|
||||||
test "Bucket splitting in range branch b=1":
|
test "Bucket splitting in range branch b=1":
|
||||||
let node = generateNode()
|
let node = generateNode(PrivateKey.random(rng[]))
|
||||||
var table: RoutingTable
|
var table: RoutingTable
|
||||||
|
|
||||||
# bitsPerHop = 1 -> Split only the branch in range of own id
|
# bitsPerHop = 1 -> Split only the branch in range of own id
|
||||||
|
@ -13,11 +16,11 @@ suite "Routing Table Tests":
|
||||||
|
|
||||||
for j in 0..5'u32:
|
for j in 0..5'u32:
|
||||||
for i in 0..<BUCKET_SIZE:
|
for i in 0..<BUCKET_SIZE:
|
||||||
check table.addNode(node.nodeAtDistance(256-j)) == nil
|
check table.addNode(node.nodeAtDistance(rng[], 256-j)) == nil
|
||||||
check table.addNode(node.nodeAtDistance(256-j)) != nil
|
check table.addNode(node.nodeAtDistance(rng[], 256-j)) != nil
|
||||||
|
|
||||||
test "Bucket splitting off range branch b=1":
|
test "Bucket splitting off range branch b=1":
|
||||||
let node = generateNode()
|
let node = generateNode(PrivateKey.random(rng[]))
|
||||||
var table: RoutingTable
|
var table: RoutingTable
|
||||||
|
|
||||||
# bitsPerHop = 1 -> Split only the branch in range of own id
|
# bitsPerHop = 1 -> Split only the branch in range of own id
|
||||||
|
@ -25,19 +28,19 @@ suite "Routing Table Tests":
|
||||||
|
|
||||||
# Add 16 nodes, distance 256
|
# Add 16 nodes, distance 256
|
||||||
for i in 0..<BUCKET_SIZE:
|
for i in 0..<BUCKET_SIZE:
|
||||||
check table.addNode(node.nodeAtDistance(256)) == nil
|
check table.addNode(node.nodeAtDistance(rng[], 256)) == nil
|
||||||
|
|
||||||
# This should split the bucket in the distance 256 branch, and the distance
|
# This should split the bucket in the distance 256 branch, and the distance
|
||||||
# <=255 branch. But not add the node, as distance 256 bucket is already full
|
# <=255 branch. But not add the node, as distance 256 bucket is already full
|
||||||
# and b=1 will not allow it to spit any further
|
# and b=1 will not allow it to spit any further
|
||||||
check table.addNode(node.nodeAtDistance(256)) != nil
|
check table.addNode(node.nodeAtDistance(rng[], 256)) != nil
|
||||||
|
|
||||||
# This add should be allowed as it is on the branch where the own node's id
|
# This add should be allowed as it is on the branch where the own node's id
|
||||||
# id belongs to.
|
# id belongs to.
|
||||||
check table.addNode(node.nodeAtDistance(255)) == nil
|
check table.addNode(node.nodeAtDistance(rng[], 255)) == nil
|
||||||
|
|
||||||
test "Bucket splitting off range branch b=2":
|
test "Bucket splitting off range branch b=2":
|
||||||
let node = generateNode()
|
let node = generateNode(PrivateKey.random(rng[]))
|
||||||
var table: RoutingTable
|
var table: RoutingTable
|
||||||
|
|
||||||
# bitsPerHop = 2, allow not in range branch to split once (2 buckets).
|
# bitsPerHop = 2, allow not in range branch to split once (2 buckets).
|
||||||
|
@ -45,46 +48,46 @@ suite "Routing Table Tests":
|
||||||
|
|
||||||
# Add 16 nodes, distance 256 from `node`, but all with 2 bits shared prefix
|
# Add 16 nodes, distance 256 from `node`, but all with 2 bits shared prefix
|
||||||
# among themselves.
|
# among themselves.
|
||||||
let firstNode = node.nodeAtDistance(256)
|
let firstNode = node.nodeAtDistance(rng[], 256)
|
||||||
check table.addNode(firstNode) == nil
|
check table.addNode(firstNode) == nil
|
||||||
for n in 1..<BUCKET_SIZE:
|
for n in 1..<BUCKET_SIZE:
|
||||||
check table.addNode(firstNode.nodeAtDistance(254)) == nil
|
check table.addNode(firstNode.nodeAtDistance(rng[], 254)) == nil
|
||||||
|
|
||||||
# Add 16 more nodes with only 1 bit shared prefix with previous 16. This
|
# Add 16 more nodes with only 1 bit shared prefix with previous 16. This
|
||||||
# should cause the initial bucket to split and and fill the second bucket
|
# should cause the initial bucket to split and and fill the second bucket
|
||||||
# with the 16 new entries.
|
# with the 16 new entries.
|
||||||
for n in 0..<BUCKET_SIZE:
|
for n in 0..<BUCKET_SIZE:
|
||||||
check table.addNode(firstNode.nodeAtDistance(255)) == nil
|
check table.addNode(firstNode.nodeAtDistance(rng[], 255)) == nil
|
||||||
|
|
||||||
# Adding another should fail as both buckets will be full and not be
|
# Adding another should fail as both buckets will be full and not be
|
||||||
# allowed to split another time.
|
# allowed to split another time.
|
||||||
check table.addNode(node.nodeAtDistance(256)) != nil
|
check table.addNode(node.nodeAtDistance(rng[], 256)) != nil
|
||||||
# And also when targetting one of the two specific buckets.
|
# And also when targetting one of the two specific buckets.
|
||||||
check table.addNode(firstNode.nodeAtDistance(255)) != nil
|
check table.addNode(firstNode.nodeAtDistance(rng[], 255)) != nil
|
||||||
check table.addNode(firstNode.nodeAtDistance(254)) != nil
|
check table.addNode(firstNode.nodeAtDistance(rng[], 254)) != nil
|
||||||
# This add should be allowed as it is on the branch where the own node's id
|
# This add should be allowed as it is on the branch where the own node's id
|
||||||
# id belongs to.
|
# id belongs to.
|
||||||
check table.addNode(node.nodeAtDistance(255)) == nil
|
check table.addNode(node.nodeAtDistance(rng[], 255)) == nil
|
||||||
|
|
||||||
test "Replacement cache":
|
test "Replacement cache":
|
||||||
let node = generateNode()
|
let node = generateNode(PrivateKey.random(rng[]))
|
||||||
var table: RoutingTable
|
var table: RoutingTable
|
||||||
|
|
||||||
# bitsPerHop = 1 -> Split only the branch in range of own id
|
# bitsPerHop = 1 -> Split only the branch in range of own id
|
||||||
table.init(node, 1)
|
table.init(node, 1)
|
||||||
|
|
||||||
# create a full bucket
|
# create a full bucket
|
||||||
let bucketNodes = node.nodesAtDistance(256, BUCKET_SIZE)
|
let bucketNodes = node.nodesAtDistance(rng[], 256, BUCKET_SIZE)
|
||||||
for n in bucketNodes:
|
for n in bucketNodes:
|
||||||
check table.addNode(n) == nil
|
check table.addNode(n) == nil
|
||||||
|
|
||||||
# create a full replacement cache
|
# create a full replacement cache
|
||||||
let replacementNodes = node.nodesAtDistance(256, REPLACEMENT_CACHE_SIZE)
|
let replacementNodes = node.nodesAtDistance(rng[], 256, REPLACEMENT_CACHE_SIZE)
|
||||||
for n in replacementNodes:
|
for n in replacementNodes:
|
||||||
check table.addNode(n) != nil
|
check table.addNode(n) != nil
|
||||||
|
|
||||||
# Add one more node to replacement (would drop first one)
|
# Add one more node to replacement (would drop first one)
|
||||||
let lastNode = node.nodeAtDistance(256)
|
let lastNode = node.nodeAtDistance(rng[], 256)
|
||||||
check table.addNode(lastNode) != nil
|
check table.addNode(lastNode) != nil
|
||||||
|
|
||||||
# This should replace the last node in the bucket, with the last one of
|
# This should replace the last node in the bucket, with the last one of
|
||||||
|
@ -101,7 +104,7 @@ suite "Routing Table Tests":
|
||||||
check (table.getNode(bucketNodes[bucketNodes.high].id)).isNone()
|
check (table.getNode(bucketNodes[bucketNodes.high].id)).isNone()
|
||||||
|
|
||||||
test "Empty bucket":
|
test "Empty bucket":
|
||||||
let node = generateNode()
|
let node = generateNode(PrivateKey.random(rng[]))
|
||||||
var table: RoutingTable
|
var table: RoutingTable
|
||||||
|
|
||||||
# bitsPerHop = 1 -> Split only the branch in range of own id
|
# bitsPerHop = 1 -> Split only the branch in range of own id
|
||||||
|
@ -110,29 +113,29 @@ suite "Routing Table Tests":
|
||||||
check table.nodeToRevalidate().isNil()
|
check table.nodeToRevalidate().isNil()
|
||||||
|
|
||||||
# try to replace not existing node
|
# try to replace not existing node
|
||||||
table.replaceNode(generateNode())
|
table.replaceNode(generateNode(PrivateKey.random(rng[])))
|
||||||
check table.len == 0
|
check table.len == 0
|
||||||
|
|
||||||
let addedNode = generateNode()
|
let addedNode = generateNode(PrivateKey.random(rng[]))
|
||||||
check table.addNode(addedNode) == nil
|
check table.addNode(addedNode) == nil
|
||||||
check table.len == 1
|
check table.len == 1
|
||||||
|
|
||||||
# try to replace not existing node
|
# try to replace not existing node
|
||||||
table.replaceNode(generateNode())
|
table.replaceNode(generateNode(PrivateKey.random(rng[])))
|
||||||
check table.len == 1
|
check table.len == 1
|
||||||
|
|
||||||
table.replaceNode(addedNode)
|
table.replaceNode(addedNode)
|
||||||
check table.len == 0
|
check table.len == 0
|
||||||
|
|
||||||
test "Empty replacement cache":
|
test "Empty replacement cache":
|
||||||
let node = generateNode()
|
let node = generateNode(PrivateKey.random(rng[]))
|
||||||
var table: RoutingTable
|
var table: RoutingTable
|
||||||
|
|
||||||
# bitsPerHop = 1 -> Split only the branch in range of own id
|
# bitsPerHop = 1 -> Split only the branch in range of own id
|
||||||
table.init(node, 1)
|
table.init(node, 1)
|
||||||
|
|
||||||
# create a full bucket TODO: no need to store bucketNodes
|
# create a full bucket TODO: no need to store bucketNodes
|
||||||
let bucketNodes = node.nodesAtDistance(256, BUCKET_SIZE)
|
let bucketNodes = node.nodesAtDistance(rng[], 256, BUCKET_SIZE)
|
||||||
for n in bucketNodes:
|
for n in bucketNodes:
|
||||||
check table.addNode(n) == nil
|
check table.addNode(n) == nil
|
||||||
|
|
||||||
|
@ -141,21 +144,21 @@ suite "Routing Table Tests":
|
||||||
check (table.getNode(bucketNodes[bucketNodes.high].id)).isNone()
|
check (table.getNode(bucketNodes[bucketNodes.high].id)).isNone()
|
||||||
|
|
||||||
test "Double add":
|
test "Double add":
|
||||||
let node = generateNode()
|
let node = generateNode(PrivateKey.random(rng[]))
|
||||||
var table: RoutingTable
|
var table: RoutingTable
|
||||||
|
|
||||||
# bitsPerHop = 1 -> Split only the branch in range of own id
|
# bitsPerHop = 1 -> Split only the branch in range of own id
|
||||||
table.init(node, 1)
|
table.init(node, 1)
|
||||||
|
|
||||||
let doubleNode = node.nodeAtDistance(256)
|
let doubleNode = node.nodeAtDistance(rng[], 256)
|
||||||
# Try to add the node twice
|
# Try to add the node twice
|
||||||
check table.addNode(doubleNode) == nil
|
check table.addNode(doubleNode) == nil
|
||||||
check table.addNode(doubleNode) == nil
|
check table.addNode(doubleNode) == nil
|
||||||
|
|
||||||
for n in 0..<BUCKET_SIZE-1:
|
for n in 0..<BUCKET_SIZE-1:
|
||||||
check table.addNode(node.nodeAtDistance(256)) == nil
|
check table.addNode(node.nodeAtDistance(rng[], 256)) == nil
|
||||||
|
|
||||||
check table.addNode(node.nodeAtDistance(256)) != nil
|
check table.addNode(node.nodeAtDistance(rng[], 256)) != nil
|
||||||
# Check when adding again once the bucket is full
|
# Check when adding again once the bucket is full
|
||||||
check table.addNode(doubleNode) == nil
|
check table.addNode(doubleNode) == nil
|
||||||
|
|
||||||
|
@ -171,19 +174,19 @@ suite "Routing Table Tests":
|
||||||
table.len == 1
|
table.len == 1
|
||||||
|
|
||||||
test "Double replacement add":
|
test "Double replacement add":
|
||||||
let node = generateNode()
|
let node = generateNode(PrivateKey.random(rng[]))
|
||||||
var table: RoutingTable
|
var table: RoutingTable
|
||||||
|
|
||||||
# bitsPerHop = 1 -> Split only the branch in range of own id
|
# bitsPerHop = 1 -> Split only the branch in range of own id
|
||||||
table.init(node, 1)
|
table.init(node, 1)
|
||||||
|
|
||||||
# create a full bucket
|
# create a full bucket
|
||||||
let bucketNodes = node.nodesAtDistance(256, BUCKET_SIZE)
|
let bucketNodes = node.nodesAtDistance(rng[], 256, BUCKET_SIZE)
|
||||||
for n in bucketNodes:
|
for n in bucketNodes:
|
||||||
check table.addNode(n) == nil
|
check table.addNode(n) == nil
|
||||||
|
|
||||||
# create a full replacement cache
|
# create a full replacement cache
|
||||||
let replacementNodes = node.nodesAtDistance(256, REPLACEMENT_CACHE_SIZE)
|
let replacementNodes = node.nodesAtDistance(rng[], 256, REPLACEMENT_CACHE_SIZE)
|
||||||
for n in replacementNodes:
|
for n in replacementNodes:
|
||||||
check table.addNode(n) != nil
|
check table.addNode(n) != nil
|
||||||
|
|
||||||
|
@ -201,14 +204,14 @@ suite "Routing Table Tests":
|
||||||
check (table.getNode(bucketNodes[bucketNodes.high].id)).isNone()
|
check (table.getNode(bucketNodes[bucketNodes.high].id)).isNone()
|
||||||
|
|
||||||
test "Just seen":
|
test "Just seen":
|
||||||
let node = generateNode()
|
let node = generateNode(PrivateKey.random(rng[]))
|
||||||
var table: RoutingTable
|
var table: RoutingTable
|
||||||
|
|
||||||
# bitsPerHop = 1 -> Split only the branch in range of own id
|
# bitsPerHop = 1 -> Split only the branch in range of own id
|
||||||
table.init(node, 1)
|
table.init(node, 1)
|
||||||
|
|
||||||
# create a full bucket
|
# create a full bucket
|
||||||
let bucketNodes = node.nodesAtDistance(256, BUCKET_SIZE)
|
let bucketNodes = node.nodesAtDistance(rng[], 256, BUCKET_SIZE)
|
||||||
for n in bucketNodes:
|
for n in bucketNodes:
|
||||||
check table.addNode(n) == nil
|
check table.addNode(n) == nil
|
||||||
|
|
||||||
|
@ -221,19 +224,19 @@ suite "Routing Table Tests":
|
||||||
check (table.getNode(n.id)).isNone()
|
check (table.getNode(n.id)).isNone()
|
||||||
|
|
||||||
test "Just seen replacement":
|
test "Just seen replacement":
|
||||||
let node = generateNode()
|
let node = generateNode(PrivateKey.random(rng[]))
|
||||||
var table: RoutingTable
|
var table: RoutingTable
|
||||||
|
|
||||||
# bitsPerHop = 1 -> Split only the branch in range of own id
|
# bitsPerHop = 1 -> Split only the branch in range of own id
|
||||||
table.init(node, 1)
|
table.init(node, 1)
|
||||||
|
|
||||||
# create a full bucket
|
# create a full bucket
|
||||||
let bucketNodes = node.nodesAtDistance(256, BUCKET_SIZE)
|
let bucketNodes = node.nodesAtDistance(rng[], 256, BUCKET_SIZE)
|
||||||
for n in bucketNodes:
|
for n in bucketNodes:
|
||||||
check table.addNode(n) == nil
|
check table.addNode(n) == nil
|
||||||
|
|
||||||
# create a full replacement cache
|
# create a full replacement cache
|
||||||
let replacementNodes = node.nodesAtDistance(256, REPLACEMENT_CACHE_SIZE)
|
let replacementNodes = node.nodesAtDistance(rng[], 256, REPLACEMENT_CACHE_SIZE)
|
||||||
for n in replacementNodes:
|
for n in replacementNodes:
|
||||||
check table.addNode(n) != nil
|
check table.addNode(n) != nil
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,12 @@ import
|
||||||
sequtils, options, unittest, tables, nimcrypto/hash,
|
sequtils, options, unittest, tables, nimcrypto/hash,
|
||||||
eth/[keys, rlp], eth/p2p/rlpx_protocols/whisper/whisper_types as whisper
|
eth/[keys, rlp], eth/p2p/rlpx_protocols/whisper/whisper_types as whisper
|
||||||
|
|
||||||
|
let rng = newRng()
|
||||||
|
|
||||||
suite "Whisper payload":
|
suite "Whisper payload":
|
||||||
test "should roundtrip without keys":
|
test "should roundtrip without keys":
|
||||||
let payload = Payload(payload: @[byte 0, 1, 2])
|
let payload = Payload(payload: @[byte 0, 1, 2])
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
|
|
||||||
let decoded = whisper.decode(encoded.get())
|
let decoded = whisper.decode(encoded.get())
|
||||||
check:
|
check:
|
||||||
|
@ -26,7 +28,7 @@ suite "Whisper payload":
|
||||||
test "should roundtrip with symmetric encryption":
|
test "should roundtrip with symmetric encryption":
|
||||||
var symKey: SymKey
|
var symKey: SymKey
|
||||||
let payload = Payload(symKey: some(symKey), payload: @[byte 0, 1, 2])
|
let payload = Payload(symKey: some(symKey), payload: @[byte 0, 1, 2])
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
|
|
||||||
let decoded = whisper.decode(encoded.get(), symKey = some(symKey))
|
let decoded = whisper.decode(encoded.get(), symKey = some(symKey))
|
||||||
check:
|
check:
|
||||||
|
@ -36,10 +38,10 @@ suite "Whisper payload":
|
||||||
decoded.get().padding.get().len == 251 # 256 -1 -1 -3
|
decoded.get().padding.get().len == 251 # 256 -1 -1 -3
|
||||||
|
|
||||||
test "should roundtrip with signature":
|
test "should roundtrip with signature":
|
||||||
let privKey = PrivateKey.random()[]
|
let privKey = PrivateKey.random(rng[])
|
||||||
|
|
||||||
let payload = Payload(src: some(privKey), payload: @[byte 0, 1, 2])
|
let payload = Payload(src: some(privKey), payload: @[byte 0, 1, 2])
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
|
|
||||||
let decoded = whisper.decode(encoded.get())
|
let decoded = whisper.decode(encoded.get())
|
||||||
check:
|
check:
|
||||||
|
@ -49,11 +51,11 @@ suite "Whisper payload":
|
||||||
decoded.get().padding.get().len == 186 # 256 -1 -1 -3 -65
|
decoded.get().padding.get().len == 186 # 256 -1 -1 -3 -65
|
||||||
|
|
||||||
test "should roundtrip with asymmetric encryption":
|
test "should roundtrip with asymmetric encryption":
|
||||||
let privKey = PrivateKey.random()[]
|
let privKey = PrivateKey.random(rng[])
|
||||||
|
|
||||||
let payload = Payload(dst: some(privKey.toPublicKey()),
|
let payload = Payload(dst: some(privKey.toPublicKey()),
|
||||||
payload: @[byte 0, 1, 2])
|
payload: @[byte 0, 1, 2])
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
|
|
||||||
let decoded = whisper.decode(encoded.get(), dst = some(privKey))
|
let decoded = whisper.decode(encoded.get(), dst = some(privKey))
|
||||||
check:
|
check:
|
||||||
|
@ -74,7 +76,7 @@ suite "Whisper payload":
|
||||||
suite "Whisper payload padding":
|
suite "Whisper payload padding":
|
||||||
test "should do max padding":
|
test "should do max padding":
|
||||||
let payload = Payload(payload: repeat(byte 1, 254))
|
let payload = Payload(payload: repeat(byte 1, 254))
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
|
|
||||||
let decoded = whisper.decode(encoded.get())
|
let decoded = whisper.decode(encoded.get())
|
||||||
check:
|
check:
|
||||||
|
@ -84,10 +86,10 @@ suite "Whisper payload padding":
|
||||||
decoded.get().padding.get().len == 256 # as dataLen == 256
|
decoded.get().padding.get().len == 256 # as dataLen == 256
|
||||||
|
|
||||||
test "should do max padding with signature":
|
test "should do max padding with signature":
|
||||||
let privKey = PrivateKey.random()[]
|
let privKey = PrivateKey.random(rng[])
|
||||||
|
|
||||||
let payload = Payload(src: some(privKey), payload: repeat(byte 1, 189))
|
let payload = Payload(src: some(privKey), payload: repeat(byte 1, 189))
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
|
|
||||||
let decoded = whisper.decode(encoded.get())
|
let decoded = whisper.decode(encoded.get())
|
||||||
check:
|
check:
|
||||||
|
@ -99,7 +101,7 @@ suite "Whisper payload padding":
|
||||||
|
|
||||||
test "should do min padding":
|
test "should do min padding":
|
||||||
let payload = Payload(payload: repeat(byte 1, 253))
|
let payload = Payload(payload: repeat(byte 1, 253))
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
|
|
||||||
let decoded = whisper.decode(encoded.get())
|
let decoded = whisper.decode(encoded.get())
|
||||||
check:
|
check:
|
||||||
|
@ -109,10 +111,10 @@ suite "Whisper payload padding":
|
||||||
decoded.get().padding.get().len == 1 # as dataLen == 255
|
decoded.get().padding.get().len == 1 # as dataLen == 255
|
||||||
|
|
||||||
test "should do min padding with signature":
|
test "should do min padding with signature":
|
||||||
let privKey = PrivateKey.random()[]
|
let privKey = PrivateKey.random(rng[])
|
||||||
|
|
||||||
let payload = Payload(src: some(privKey), payload: repeat(byte 1, 188))
|
let payload = Payload(src: some(privKey), payload: repeat(byte 1, 188))
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
|
|
||||||
let decoded = whisper.decode(encoded.get())
|
let decoded = whisper.decode(encoded.get())
|
||||||
check:
|
check:
|
||||||
|
@ -125,7 +127,7 @@ suite "Whisper payload padding":
|
||||||
test "should roundtrip custom padding":
|
test "should roundtrip custom padding":
|
||||||
let payload = Payload(payload: repeat(byte 1, 10),
|
let payload = Payload(payload: repeat(byte 1, 10),
|
||||||
padding: some(repeat(byte 2, 100)))
|
padding: some(repeat(byte 2, 100)))
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
|
|
||||||
let decoded = whisper.decode(encoded.get())
|
let decoded = whisper.decode(encoded.get())
|
||||||
check:
|
check:
|
||||||
|
@ -138,7 +140,7 @@ suite "Whisper payload padding":
|
||||||
let padding: seq[byte] = @[]
|
let padding: seq[byte] = @[]
|
||||||
let payload = Payload(payload: repeat(byte 1, 10),
|
let payload = Payload(payload: repeat(byte 1, 10),
|
||||||
padding: some(padding))
|
padding: some(padding))
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
|
|
||||||
let decoded = whisper.decode(encoded.get())
|
let decoded = whisper.decode(encoded.get())
|
||||||
check:
|
check:
|
||||||
|
@ -147,10 +149,10 @@ suite "Whisper payload padding":
|
||||||
decoded.get().padding.isNone()
|
decoded.get().padding.isNone()
|
||||||
|
|
||||||
test "should roundtrip custom padding with signature":
|
test "should roundtrip custom padding with signature":
|
||||||
let privKey = PrivateKey.random()[]
|
let privKey = PrivateKey.random(rng[])
|
||||||
let payload = Payload(src: some(privKey), payload: repeat(byte 1, 10),
|
let payload = Payload(src: some(privKey), payload: repeat(byte 1, 10),
|
||||||
padding: some(repeat(byte 2, 100)))
|
padding: some(repeat(byte 2, 100)))
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
|
|
||||||
let decoded = whisper.decode(encoded.get())
|
let decoded = whisper.decode(encoded.get())
|
||||||
check:
|
check:
|
||||||
|
@ -162,10 +164,10 @@ suite "Whisper payload padding":
|
||||||
|
|
||||||
test "should roundtrip custom 0 padding with signature":
|
test "should roundtrip custom 0 padding with signature":
|
||||||
let padding: seq[byte] = @[]
|
let padding: seq[byte] = @[]
|
||||||
let privKey = PrivateKey.random()[]
|
let privKey = PrivateKey.random(rng[])
|
||||||
let payload = Payload(src: some(privKey), payload: repeat(byte 1, 10),
|
let payload = Payload(src: some(privKey), payload: repeat(byte 1, 10),
|
||||||
padding: some(padding))
|
padding: some(padding))
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
|
|
||||||
let decoded = whisper.decode(encoded.get())
|
let decoded = whisper.decode(encoded.get())
|
||||||
check:
|
check:
|
||||||
|
@ -276,7 +278,7 @@ proc prepFilterTestMsg(pubKey = none[PublicKey](), symKey = none[SymKey](),
|
||||||
padding = none[seq[byte]]()): Message =
|
padding = none[seq[byte]]()): Message =
|
||||||
let payload = Payload(dst: pubKey, symKey: symKey, src: src,
|
let payload = Payload(dst: pubKey, symKey: symKey, src: src,
|
||||||
payload: @[byte 0, 1, 2], padding: padding)
|
payload: @[byte 0, 1, 2], padding: padding)
|
||||||
let encoded = whisper.encode(payload)
|
let encoded = whisper.encode(rng[], payload)
|
||||||
let env = Envelope(expiry: 1, ttl: 1, topic: topic, data: encoded.get(),
|
let env = Envelope(expiry: 1, ttl: 1, topic: topic, data: encoded.get(),
|
||||||
nonce: 0)
|
nonce: 0)
|
||||||
result = initMessage(env)
|
result = initMessage(env)
|
||||||
|
@ -289,7 +291,7 @@ suite "Whisper filter":
|
||||||
|
|
||||||
var filters = initTable[string, Filter]()
|
var filters = initTable[string, Filter]()
|
||||||
let filter = initFilter(symKey = some(symKey), topics = @[topic])
|
let filter = initFilter(symKey = some(symKey), topics = @[topic])
|
||||||
let filterId = filters.subscribeFilter(filter)
|
let filterId = subscribeFilter(rng[], filters, filter)
|
||||||
|
|
||||||
notify(filters, msg)
|
notify(filters, msg)
|
||||||
|
|
||||||
|
@ -300,14 +302,14 @@ suite "Whisper filter":
|
||||||
messages[0].dst.isNone()
|
messages[0].dst.isNone()
|
||||||
|
|
||||||
test "should notify filter on message with asymmetric encryption":
|
test "should notify filter on message with asymmetric encryption":
|
||||||
let privKey = PrivateKey.random()[]
|
let privKey = PrivateKey.random(rng[])
|
||||||
let topic = [byte 0, 0, 0, 0]
|
let topic = [byte 0, 0, 0, 0]
|
||||||
let msg = prepFilterTestMsg(pubKey = some(privKey.toPublicKey()),
|
let msg = prepFilterTestMsg(pubKey = some(privKey.toPublicKey()),
|
||||||
topic = topic)
|
topic = topic)
|
||||||
|
|
||||||
var filters = initTable[string, Filter]()
|
var filters = initTable[string, Filter]()
|
||||||
let filter = initFilter(privateKey = some(privKey), topics = @[topic])
|
let filter = initFilter(privateKey = some(privKey), topics = @[topic])
|
||||||
let filterId = filters.subscribeFilter(filter)
|
let filterId = subscribeFilter(rng[], filters, filter)
|
||||||
|
|
||||||
notify(filters, msg)
|
notify(filters, msg)
|
||||||
|
|
||||||
|
@ -318,14 +320,14 @@ suite "Whisper filter":
|
||||||
messages[0].dst.isSome()
|
messages[0].dst.isSome()
|
||||||
|
|
||||||
test "should notify filter on message with signature":
|
test "should notify filter on message with signature":
|
||||||
let privKey = PrivateKey.random()[]
|
let privKey = PrivateKey.random(rng[])
|
||||||
let topic = [byte 0, 0, 0, 0]
|
let topic = [byte 0, 0, 0, 0]
|
||||||
let msg = prepFilterTestMsg(src = some(privKey), topic = topic)
|
let msg = prepFilterTestMsg(src = some(privKey), topic = topic)
|
||||||
|
|
||||||
var filters = initTable[string, Filter]()
|
var filters = initTable[string, Filter]()
|
||||||
let filter = initFilter(src = some(privKey.toPublicKey()),
|
let filter = initFilter(src = some(privKey.toPublicKey()),
|
||||||
topics = @[topic])
|
topics = @[topic])
|
||||||
let filterId = filters.subscribeFilter(filter)
|
let filterId = subscribeFilter(rng[], filters, filter)
|
||||||
|
|
||||||
notify(filters, msg)
|
notify(filters, msg)
|
||||||
|
|
||||||
|
@ -346,9 +348,9 @@ suite "Whisper filter":
|
||||||
|
|
||||||
var filters = initTable[string, Filter]()
|
var filters = initTable[string, Filter]()
|
||||||
let
|
let
|
||||||
filterId1 = filters.subscribeFilter(
|
filterId1 = subscribeFilter(rng[], filters,
|
||||||
initFilter(topics = @[topic], powReq = 0.014492753623188406))
|
initFilter(topics = @[topic], powReq = 0.014492753623188406))
|
||||||
filterId2 = filters.subscribeFilter(
|
filterId2 = subscribeFilter(rng[], filters,
|
||||||
initFilter(topics = @[topic], powReq = 0.014492753623188407))
|
initFilter(topics = @[topic], powReq = 0.014492753623188407))
|
||||||
|
|
||||||
notify(filters, msg)
|
notify(filters, msg)
|
||||||
|
@ -366,8 +368,8 @@ suite "Whisper filter":
|
||||||
|
|
||||||
var filters = initTable[string, Filter]()
|
var filters = initTable[string, Filter]()
|
||||||
let
|
let
|
||||||
filterId1 = filters.subscribeFilter(initFilter(topics = @[topic1]))
|
filterId1 = subscribeFilter(rng[], filters, initFilter(topics = @[topic1]))
|
||||||
filterId2 = filters.subscribeFilter(initFilter(topics = @[topic2]))
|
filterId2 = subscribeFilter(rng[], filters, initFilter(topics = @[topic2]))
|
||||||
|
|
||||||
notify(filters, msg)
|
notify(filters, msg)
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
# MIT license (LICENSE-MIT)
|
# MIT license (LICENSE-MIT)
|
||||||
|
|
||||||
import
|
import
|
||||||
sequtils, options, tables, chronos, testutils/unittests,
|
sequtils, options, tables, chronos, testutils/unittests, bearssl,
|
||||||
eth/[keys, p2p], eth/p2p/rlpx_protocols/whisper_protocol, eth/p2p/peer_pool,
|
eth/[keys, p2p], eth/p2p/rlpx_protocols/whisper_protocol, eth/p2p/peer_pool,
|
||||||
./p2p_test_helper
|
./p2p_test_helper
|
||||||
|
|
||||||
|
@ -20,8 +20,9 @@ let safeTTL = 5'u32
|
||||||
let waitInterval = messageInterval + 150.milliseconds
|
let waitInterval = messageInterval + 150.milliseconds
|
||||||
|
|
||||||
procSuite "Whisper connections":
|
procSuite "Whisper connections":
|
||||||
var node1 = setupTestNode(Whisper)
|
let rng = newRng()
|
||||||
var node2 = setupTestNode(Whisper)
|
var node1 = setupTestNode(rng, Whisper)
|
||||||
|
var node2 = setupTestNode(rng, Whisper)
|
||||||
node2.startListening()
|
node2.startListening()
|
||||||
waitFor node1.peerPool.connectToNode(newNode(node2.toENode()))
|
waitFor node1.peerPool.connectToNode(newNode(node2.toENode()))
|
||||||
asyncTest "Two peers connected":
|
asyncTest "Two peers connected":
|
||||||
|
@ -29,8 +30,8 @@ procSuite "Whisper connections":
|
||||||
node1.peerPool.connectedNodes.len() == 1
|
node1.peerPool.connectedNodes.len() == 1
|
||||||
|
|
||||||
asyncTest "Filters with encryption and signing":
|
asyncTest "Filters with encryption and signing":
|
||||||
let encryptKeyPair = KeyPair.random()[]
|
let encryptKeyPair = KeyPair.random(rng[])
|
||||||
let signKeyPair = KeyPair.random()[]
|
let signKeyPair = KeyPair.random(rng[])
|
||||||
var symKey: SymKey
|
var symKey: SymKey
|
||||||
let topic = [byte 0x12, 0, 0, 0]
|
let topic = [byte 0x12, 0, 0, 0]
|
||||||
var filters: seq[string] = @[]
|
var filters: seq[string] = @[]
|
||||||
|
@ -294,7 +295,7 @@ procSuite "Whisper connections":
|
||||||
node1.unsubscribeFilter(filter) == true
|
node1.unsubscribeFilter(filter) == true
|
||||||
|
|
||||||
asyncTest "Light node posting":
|
asyncTest "Light node posting":
|
||||||
var ln1 = setupTestNode(Whisper)
|
var ln1 = setupTestNode(rng, Whisper)
|
||||||
ln1.setLightNode(true)
|
ln1.setLightNode(true)
|
||||||
|
|
||||||
await ln1.peerPool.connectToNode(newNode(node2.toENode()))
|
await ln1.peerPool.connectToNode(newNode(node2.toENode()))
|
||||||
|
@ -313,8 +314,8 @@ procSuite "Whisper connections":
|
||||||
ln1.protocolState(Whisper).queue.items.len == 0
|
ln1.protocolState(Whisper).queue.items.len == 0
|
||||||
|
|
||||||
asyncTest "Connect two light nodes":
|
asyncTest "Connect two light nodes":
|
||||||
var ln1 = setupTestNode(Whisper)
|
var ln1 = setupTestNode(rng, Whisper)
|
||||||
var ln2 = setupTestNode(Whisper)
|
var ln2 = setupTestNode(rng, Whisper)
|
||||||
|
|
||||||
ln1.setLightNode(true)
|
ln1.setLightNode(true)
|
||||||
ln2.setLightNode(true)
|
ln2.setLightNode(true)
|
||||||
|
|
Loading…
Reference in New Issue