Merge branch 'master' into nim-1.2

This commit is contained in:
Ștefan Talpalaru 2020-04-08 20:16:37 +02:00
commit af89b51503
No known key found for this signature in database
GPG Key ID: CBF7934204F1B6F9
17 changed files with 118 additions and 101 deletions

View File

@ -190,7 +190,7 @@ proc privateChainConfig*(): ChainConfig =
constantinopleBlock: config.customGenesis.constantinopleBlock,
)
trace "Custom genesis block configuration loaded", configuration=result
proc publicChainConfig*(id: PublicNetwork): ChainConfig =
result = case id
of MainNet:
@ -254,7 +254,7 @@ proc processCustomGenesisConfig(customGenesis: JsonNode): ConfigStatus =
proc parseConfig(T: type, c: JsonNode, field: string): T =
when T is string:
c[field].getStr()
c[field].getStr()
elif T is Uint256:
parseHexInt(c[field].getStr()).u256
elif T is bool:
@ -273,7 +273,7 @@ proc processCustomGenesisConfig(customGenesis: JsonNode): ConfigStatus =
hexToSeqByte(c[field].getStr())
elif T is int64:
fromHex[int64](c[field].getStr())
template validateConfigValue(chainDetails, field, jtype, T: untyped, checkError: static[bool] = true) =
let fieldName = field.astToStr()
@ -287,10 +287,10 @@ proc processCustomGenesisConfig(customGenesis: JsonNode): ConfigStatus =
when checkError:
error "No value found in genesis block for", fieldName
quit(1)
let config = getConfiguration()
let config = getConfiguration()
result = Success
var
var
chainId = 0.uint
homesteadBlock, daoForkblock, eip150Block, eip155Block, eip158Block, byzantiumBlock, constantinopleBlock = 0.toBlockNumber
eip150Hash, mixHash : MDigest[256]
@ -313,7 +313,7 @@ proc processCustomGenesisConfig(customGenesis: JsonNode): ConfigStatus =
validateConfigValue(forkDetails, daoForkSupport, JBool, bool, checkError=false)
if daoForkSupport == true:
checkForFork(forkDetails, daoForkBlock, 0.toBlockNumber)
checkForFork(forkDetails, eip150Block, homesteadBlock)
validateConfigValue(forkDetails, eip150Hash, JString, Hash256)
checkForFork(forkDetails, eip155Block, eip150Block)
@ -333,7 +333,7 @@ proc processCustomGenesisConfig(customGenesis: JsonNode): ConfigStatus =
validateConfigValue(customGenesis, mixHash, JString, Hash256)
validateConfigValue(customGenesis, coinbase, JString, EthAddress, checkError = false)
validateConfigValue(customGenesis, timestamp, JString, EthTime, checkError = false)
config.customGenesis = CustomGenesisConfig(
chainId: chainId,
homesteadBlock: homesteadBlock,
@ -353,7 +353,7 @@ proc processCustomGenesisConfig(customGenesis: JsonNode): ConfigStatus =
coinbase: coinbase,
timestamp: timestamp
)
proc processList(v: string, o: var seq[string]) =
## Process comma-separated list of strings.
if len(v) > 0:
@ -429,8 +429,9 @@ proc processProtocolList(v: string, flags: var set[ProtocolFlags]): ConfigStatus
proc processENode(v: string, o: var ENode): ConfigStatus =
## Convert string to ENode.
let res = initENode(v, o)
if res == ENodeStatus.Success:
let res = ENode.fromString(v)
if res.isOk:
o = res[]
result = Success
else:
result = ErrorParseOption
@ -450,11 +451,12 @@ proc processENodesList(v: string, o: var seq[ENode]): ConfigStatus =
proc processPrivateKey(v: string, o: var PrivateKey): ConfigStatus =
## Convert hexadecimal string to private key object.
try:
o = initPrivateKey(v)
result = Success
except CatchableError:
result = ErrorParseOption
let seckey = PrivateKey.fromHex(v)
if seckey.isOk():
o = seckey[]
return Success
result = ErrorParseOption
# proc processHexBytes(v: string, o: var seq[byte]): ConfigStatus =
# ## Convert hexadecimal string to seq[byte].

View File

@ -62,12 +62,10 @@ proc start(nimbus: NimbusNode) =
setupCommonRpc(nimbus.rpcServer)
## Creating P2P Server
if conf.net.nodekey.isZeroKey():
conf.net.nodekey = newPrivateKey()
if not conf.net.nodekey.verify():
conf.net.nodekey = PrivateKey.random().tryGet()
var keypair: KeyPair
keypair.seckey = conf.net.nodekey
keypair.pubkey = conf.net.nodekey.getPublicKey()
let keypair = conf.net.nodekey.toKeyPair().tryGet()
var address: Address
address.ip = parseIpAddress("0.0.0.0")

View File

@ -211,10 +211,10 @@ proc `%`*(value: Bytes): JsonNode =
# Helpers for the fromJson procs
proc toPublicKey*(key: string): PublicKey {.inline.} =
result = initPublicKey(key[4 .. ^1])
result = PublicKey.fromHex(key[4 .. ^1]).tryGet()
proc toPrivateKey*(key: string): PrivateKey {.inline.} =
result = initPrivateKey(key[2 .. ^1])
result = PrivateKey.fromHex(key[2 .. ^1]).tryGet()
proc toSymKey*(key: string): SymKey {.inline.} =
hexToByteArray(key[2 .. ^1], result)

View File

@ -226,7 +226,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
template sign(privateKey: PrivateKey, message: string): string =
# TODO: Is message length encoded as bytes or characters?
let msgData = "\x19Ethereum Signed Message:\n" & $message.len & message
$signMessage(privateKey, msgData)
$sign(privateKey, msgData.toBytes()).tryGet()
rpcsrv.rpc("eth_sign") do(data: EthAddressStr, message: HexDataStr) -> HexDataStr:
## The sign method calculates an Ethereum specific signature with: sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))).

View File

@ -1,5 +1,5 @@
import
json_rpc/rpcserver, tables, options, sequtils,
json_rpc/rpcserver, tables, options,
eth/[common, rlp, keys, p2p], eth/p2p/rlpx_protocols/waku_protocol,
nimcrypto/[sysrand, hmac, sha2, pbkdf2],
rpc_types, hexstrings, key_storage
@ -70,7 +70,7 @@ proc setupWakuRPC*(node: EthereumNode, keys: KeyStorage, rpcsrv: RpcServer) =
##
## Returns key identifier on success and an error on failure.
result = generateRandomID().Identifier
keys.asymKeys.add(result.string, newKeyPair())
keys.asymKeys.add(result.string, KeyPair.random().tryGet())
rpcsrv.rpc("waku_addPrivateKey") do(key: PrivateKey) -> Identifier:
## Stores the key pair, and returns its ID.
@ -80,7 +80,7 @@ proc setupWakuRPC*(node: EthereumNode, keys: KeyStorage, rpcsrv: RpcServer) =
## Returns key identifier on success and an error on failure.
result = generateRandomID().Identifier
keys.asymKeys.add(result.string, key.toKeyPair())
keys.asymKeys.add(result.string, key.toKeyPair().tryGet())
rpcsrv.rpc("waku_deleteKeyPair") do(id: Identifier) -> bool:
## Deletes the specifies key if it exists.

View File

@ -71,7 +71,7 @@ proc setupWhisperRPC*(node: EthereumNode, keys: KeyStorage, rpcsrv: RpcServer) =
##
## Returns key identifier on success and an error on failure.
result = generateRandomID().Identifier
keys.asymKeys.add(result.string, newKeyPair())
keys.asymKeys.add(result.string, KeyPair.random().tryGet())
rpcsrv.rpc("shh_addPrivateKey") do(key: PrivateKey) -> Identifier:
## Stores the key pair, and returns its ID.
@ -81,7 +81,7 @@ proc setupWhisperRPC*(node: EthereumNode, keys: KeyStorage, rpcsrv: RpcServer) =
## Returns key identifier on success and an error on failure.
result = generateRandomID().Identifier
keys.asymKeys.add(result.string, key.toKeyPair())
keys.asymKeys.add(result.string, key.toKeyPair().tryGet())
rpcsrv.rpc("shh_deleteKeyPair") do(id: Identifier) -> bool:
## Deletes the specifies key if it exists.

View File

@ -44,7 +44,11 @@ proc getSignature*(transaction: Transaction, output: var Signature): bool =
return false
bytes[64] = byte(v - 27)
result = recoverSignature(bytes, output) == EthKeysStatus.Success
let sig = Signature.fromRaw(bytes)
if sig.isOk:
output = sig[]
return true
return false
proc toSignature*(transaction: Transaction): Signature =
if not getSignature(transaction, result):
@ -54,10 +58,10 @@ proc getSender*(transaction: Transaction, output: var EthAddress): bool =
## Find the address the transaction was sent from.
var sig: Signature
if transaction.getSignature(sig):
var pubKey: PublicKey
var txHash = transaction.txHashNoSignature
if recoverSignatureKey(sig, txHash.data, pubKey) == EthKeysStatus.Success:
output = pubKey.toCanonicalAddress()
let pubkey = recover(sig, txHash)
if pubkey.isOk:
output = pubkey[].toCanonicalAddress()
result = true
proc getSender*(transaction: Transaction): EthAddress =

View File

@ -42,8 +42,10 @@ proc getSignature(computation: Computation): (array[32, byte], Signature) =
# Copy message data to buffer
bytes[0..(maxPos-64)] = data[64..maxPos]
if recoverSignature(bytes, result[1]) != EthKeysStatus.Success:
let sig = Signature.fromRaw(bytes)
if sig.isErr:
raise newException(ValidationError, "Could not recover signature computation")
result[1] = sig[]
# extract message hash, only need to copy when there is a valid signature
result[0][0..31] = data[0..31]
@ -98,14 +100,14 @@ proc ecRecover*(computation: Computation) =
var
(msgHash, sig) = computation.getSignature()
pubKey: PublicKey
if sig.recoverSignatureKey(msgHash, pubKey) != EthKeysStatus.Success:
var pubkey = recover(sig, SkMessage(data: msgHash))
if pubkey.isErr:
raise newException(ValidationError, "Could not derive public key from computation")
computation.output.setLen(32)
computation.output[12..31] = pubKey.toCanonicalAddress()
trace "ECRecover precompile", derivedKey = pubKey.toCanonicalAddress()
computation.output[12..31] = pubkey[].toCanonicalAddress()
trace "ECRecover precompile", derivedKey = pubkey[].toCanonicalAddress()
proc sha256*(computation: Computation) =
let

View File

@ -192,9 +192,9 @@ proc getFixtureTransaction*(j: JsonNode, dataIndex, gasIndex, valueIndex: int):
var secretKey = j["secretKey"].getStr
removePrefix(secretKey, "0x")
let privateKey = initPrivateKey(secretKey)
let sig = signMessage(privateKey, result.rlpEncode)
let raw = sig.getRaw()
let privateKey = PrivateKey.fromHex(secretKey).tryGet()
let sig = sign(privateKey, result.rlpEncode).tryGet()
let raw = sig.toRaw()
result.R = fromBytesBE(Uint256, raw[0..31])
result.S = fromBytesBE(Uint256, raw[32..63])
@ -206,15 +206,16 @@ proc hashLogEntries*(logs: seq[Log]): string =
proc setupEthNode*(capabilities: varargs[ProtocolInfo, `protocolInfo`]): EthereumNode =
var
conf = getConfiguration()
keypair: KeyPair
keypair.seckey = conf.net.nodekey
keypair.pubkey = conf.net.nodekey.getPublicKey()
if not conf.net.nodekey.verify():
conf.net.nodekey = PrivateKey.random().tryGet()
let keypair = conf.net.nodekey.toKeyPair().tryGet()
var srvAddress: Address
srvAddress.ip = parseIpAddress("0.0.0.0")
srvAddress.tcpPort = Port(conf.net.bindPort)
srvAddress.udpPort = Port(conf.net.discPort)
result = newEthereumNode(keypair, srvAddress, conf.net.networkId,
nil, "nimbus 0.1.0", addAllCapabilities = false)
result = newEthereumNode(
keypair, srvAddress, conf.net.networkId, nil, "nimbus 0.1.0",
addAllCapabilities = false)
for capability in capabilities:
result.addCapability capability

View File

@ -65,7 +65,7 @@ proc doTests {.async.} =
let keyID2 = await client.shh_addPrivateKey(privkey)
check:
await(client.shh_getPublicKey(keyID2)) == pubkey.toPublicKey
await(client.shh_getPrivateKey(keyID2)) == privkey.toPrivateKey
await(client.shh_getPrivateKey(keyID2)).toRaw() == privkey.toPrivateKey.toRaw()
await(client.shh_hasKeyPair(keyID2)) == true
await(client.shh_deleteKeyPair(keyID2)) == true
await(client.shh_hasKeyPair(keyID2)) == false

2
vendor/nim-eth vendored

@ -1 +1 @@
Subproject commit c3f23e5912efff98fc6c8181db579037e5a19a2c
Subproject commit 0b110f3287f26e03f5e7ac4c9e7f0103456895c0

2
vendor/nim-stew vendored

@ -1 +1 @@
Subproject commit 76beeb769e30adc912d648c014fd95bf748fef24
Subproject commit 9414202d53fac99a0b1af33acac816ff9236e6d0

View File

@ -87,9 +87,9 @@ This dashboard can be found at `./waku/metrics/waku-sim-all-nodes-grafana-dashbo
# Spec support
*This section last updated February 14, 2020*
*This section last updated April 7, 2020*
This client of Waku is spec compliant with [Waku spec v0.3](https://specs.vac.dev/waku/waku.html).
This client of Waku is spec compliant with [Waku spec v0.4](https://specs.vac.dev/waku/waku.html).
It doesn't yet implement the following recommended features:
- No support for rate limiting

View File

@ -5,7 +5,7 @@ import
type
Fleet* = enum
none
beta
prod
staging
WakuNodeConf* = object
@ -84,7 +84,7 @@ type
nodekey* {.
desc: "P2P node private key as hex.",
defaultValue: newKeyPair()
defaultValue: KeyPair.random().tryGet()
name: "nodekey" }: KeyPair
# TODO: Add nodekey file option
@ -135,8 +135,8 @@ type
proc parseCmdArg*(T: type KeyPair, p: TaintedString): T =
try:
# TODO: add isValidPrivateKey check from Nimbus?
result.seckey = initPrivateKey(p)
result.pubkey = result.seckey.getPublicKey()
result.seckey = PrivateKey.fromHex(string(p)).tryGet()
result.pubkey = result.seckey.toPublicKey()[]
except CatchableError as e:
raise newException(ConfigurationError, "Invalid private key")

View File

@ -45,7 +45,7 @@ proc initNodeCmd(nodeType: NodeType, shift: int, staticNodes: seq[string] = @[],
discovery = false, bootNodes: seq[string] = @[], topicInterest = false,
master = false, label: string): NodeInfo =
let
keypair = newKeyPair()
keypair = KeyPair.random().tryGet()
address = Address(ip: parseIpAddress("127.0.0.1"),
udpPort: (30303 + shift).Port, tcpPort: (30303 + shift).Port)
enode = ENode(pubkey: keypair.pubkey, address: address)

View File

@ -11,18 +11,15 @@ const clientId = "Nimbus waku node"
let globalListeningAddr = parseIpAddress("0.0.0.0")
proc setBootNodes(nodes: openArray[string]): seq[ENode] =
var bootnode: ENode
result = newSeqOfCap[ENode](nodes.len)
for nodeId in nodes:
# TODO: something more user friendly than an assert
doAssert(initENode(nodeId, bootnode) == ENodeStatus.Success)
result.add(bootnode)
# TODO: something more user friendly than an expect
result.add(ENode.fromString(nodeId).expect("correct node"))
proc connectToNodes(node: EthereumNode, nodes: openArray[string]) =
for nodeId in nodes:
var whisperENode: ENode
# TODO: something more user friendly than an assert
doAssert(initENode(nodeId, whisperENode) == ENodeStatus.Success)
let whisperENode = ENode.fromString(nodeId).expect("correct node")
traceAsyncErrors node.peerPool.connectToNode(newNode(whisperENode))
@ -97,7 +94,7 @@ proc run(config: WakuNodeConf) =
# TODO: Status fleet bootnodes are discv5? That will not work.
let bootnodes = if config.bootnodes.len > 0: setBootNodes(config.bootnodes)
elif config.fleet == beta: setBootNodes(StatusBootNodes)
elif config.fleet == prod: setBootNodes(StatusBootNodes)
elif config.fleet == staging: setBootNodes(StatusBootNodesStaging)
else: @[]
@ -107,7 +104,7 @@ proc run(config: WakuNodeConf) =
if not config.bootnodeOnly:
# Optionally direct connect with a set of nodes
if config.staticnodes.len > 0: connectToNodes(node, config.staticnodes)
elif config.fleet == beta: connectToNodes(node, WhisperNodes)
elif config.fleet == prod: connectToNodes(node, WhisperNodes)
elif config.fleet == staging: connectToNodes(node, WhisperNodesStaging)
if config.rpc:

View File

@ -69,20 +69,18 @@ proc generateRandomID(): Identifier =
break
proc setBootNodes(nodes: openArray[string]): seq[ENode] =
var bootnode: ENode
result = newSeqOfCap[ENode](nodes.len)
for nodeId in nodes:
# For now we can just do assert as we only pass our own const arrays.
doAssert(initENode(nodeId, bootnode) == ENodeStatus.Success)
result.add(bootnode)
let enode = ENode.fromString(nodeId).expect("correct enode")
result.add(enode)
proc connectToNodes(nodes: openArray[string]) =
for nodeId in nodes:
var whisperENode: ENode
# For now we can just do assert as we only pass our own const arrays.
doAssert(initENode(nodeId, whisperENode) == ENodeStatus.Success)
let enode = ENode.fromString(nodeId).expect("correct enode")
traceAsyncErrors node.peerPool.connectToNode(newNode(whisperENode))
traceAsyncErrors node.peerPool.connectToNode(newNode(enode))
# Setting up the node
@ -95,16 +93,21 @@ proc nimbus_start(port: uint16, startListening: bool, enableDiscovery: bool,
var keypair: KeyPair
if privateKey.isNil:
keypair = newKeyPair()
var kp = KeyPair.random()
if kp.isErr:
error "Can't generate keypair", err = kp.error
return false
keypair = kp[]
else:
try:
let privKey = initPrivateKey(makeOpenArray(privateKey, 32))
keypair = privKey.toKeyPair()
except EthKeysException:
let
privKey = PrivateKey.fromRaw(makeOpenArray(privateKey, 32))
kp = privKey and privKey[].toKeyPair()
if kp.isErr:
error "Passed an invalid private key."
return false
keypair = kp[]
node = newEthereumNode(keypair, address, 1, nil, addAllCapabilities = false)
node.addCapability Whisper
@ -130,12 +133,13 @@ proc nimbus_poll() {.exportc, dynlib.} =
proc nimbus_add_peer(nodeId: cstring): bool {.exportc, dynlib.} =
var
whisperENode: ENode
whisperNode: Node
discard initENode($nodeId, whisperENode)
let enode = ENode.fromString($nodeId)
if enode.isErr:
return false
try:
whisperNode = newNode(whisperENode)
except Secp256k1Exception:
whisperNode = newNode(enode[])
except CatchableError:
return false
# TODO: call can create `Exception`, why?
@ -145,7 +149,7 @@ proc nimbus_add_peer(nodeId: cstring): bool {.exportc, dynlib.} =
# Whisper API (Similar to Whisper JSON-RPC API)
proc nimbus_channel_to_topic(channel: cstring): CTopic
{.exportc, dynlib, raises: [].} =
{.exportc, dynlib, raises: [Defect].} =
# Only used for the example, to conveniently convert channel to topic.
doAssert(not channel.isNil, "Channel cannot be nil.")
@ -156,32 +160,41 @@ proc nimbus_channel_to_topic(channel: cstring): CTopic
# Asymmetric Keys
proc nimbus_new_keypair(id: var Identifier): bool
{.exportc, dynlib, raises: [].} =
{.exportc, dynlib, raises: [Defect].} =
## Caller needs to provide as id a pointer to 32 bytes allocation.
doAssert(not (unsafeAddr id).isNil, "Key id cannot be nil.")
id = generateRandomID()
try:
whisperKeys.asymKeys.add(id.toHex(), newKeyPair())
whisperKeys.asymKeys.add(id.toHex(), KeyPair.random().tryGet())
result = true
except Secp256k1Exception:
except CatchableError:
# Don't think this can actually happen, comes from the `getPublicKey` part
# in `newKeyPair`
discard
proc nimbus_add_keypair(privateKey: ptr byte, id: var Identifier):
bool {.exportc, dynlib, raises: [OSError, IOError, ValueError].} =
bool {.exportc, dynlib, raises: [Defect, OSError, IOError, ValueError].} =
## Caller needs to provide as id a pointer to 32 bytes allocation.
doAssert(not (unsafeAddr id).isNil, "Key id cannot be nil.")
doAssert(not privateKey.isNil, "Private key cannot be nil.")
var keypair: KeyPair
try:
let privKey = initPrivateKey(makeOpenArray(privateKey, 32))
keypair = privKey.toKeyPair()
except EthKeysException, Secp256k1Exception:
error "Passed an invalid private key."
return false
if privateKey.isNil:
var kp = KeyPair.random()
if kp.isErr:
error "Can't generate keypair", err = kp.error
return false
keypair = kp[]
else:
let
privKey = PrivateKey.fromRaw(makeOpenArray(privateKey, 32))
kp = privKey and privKey[].toKeyPair()
if kp.isErr:
error "Passed an invalid private key."
return false
keypair = kp[]
result = true
id = generateRandomID()
@ -220,7 +233,7 @@ proc nimbus_add_symkey(symKey: ptr SymKey, id: var Identifier): bool
whisperKeys.symKeys.add(id.toHex, symKey[])
proc nimbus_add_symkey_from_password(password: cstring, id: var Identifier):
bool {.exportc, dynlib, raises: [].} =
bool {.exportc, dynlib, raises: [Defect].} =
## Caller needs to provide as id a pointer to 32 bytes allocation.
doAssert(not (unsafeAddr id).isNil, "Key id cannot be nil.")
doAssert(not password.isNil, "Password cannot be nil.")
@ -277,11 +290,11 @@ proc nimbus_post(message: ptr CPostMessage): bool {.exportc, dynlib.} =
return false
if not message.pubKey.isNil():
try:
asymKey = some(initPublicKey(makeOpenArray(message.pubKey, 64)))
except EthKeysException:
let pubkey = PublicKey.fromRaw(makeOpenArray(message.pubKey, 64))
if pubkey.isErr:
error "Passed an invalid public key for encryption."
return false
asymKey = some(pubkey[])
try:
if not message.symKeyID.isNil():
@ -340,11 +353,11 @@ proc nimbus_subscribe_filter(options: ptr CFilterOptions,
return false
if not options.source.isNil():
try:
src = some(initPublicKey(makeOpenArray(options.source, 64)))
except EthKeysException:
let pubkey = PublicKey.fromRaw(makeOpenArray(options.source, 64))
if pubkey.isErr:
error "Passed an invalid public key as source."
return false
src = some(pubkey[])
try:
if not options.symKeyID.isNil():
@ -377,11 +390,11 @@ proc nimbus_subscribe_filter(options: ptr CFilterOptions,
recipientPublicKey: array[RawPublicKeySize, byte]
if msg.decoded.src.isSome():
# Need to pass the serialized form
source = msg.decoded.src.get().getRaw()
source = msg.decoded.src.get().toRaw()
cmsg.source = addr source[0]
if msg.dst.isSome():
# Need to pass the serialized form
recipientPublicKey = msg.decoded.src.get().getRaw()
recipientPublicKey = msg.decoded.src.get().toRaw()
cmsg.recipientPublicKey = addr recipientPublicKey[0]
handler(addr cmsg, udata)
@ -456,7 +469,7 @@ proc nimbus_join_public_chat(channel: cstring,
# TODO: How would we do key management? In nimbus (like in rpc) or in status go?
proc nimbus_post_public(channel: cstring, payload: cstring)
{.exportc, dynlib.} =
let encPrivateKey = initPrivateKey("5dc5381cae54ba3174dc0d46040fe11614d0cc94d41185922585198b4fcef9d3")
let encPrivateKey = PrivateKey.fromHex("5dc5381cae54ba3174dc0d46040fe11614d0cc94d41185922585198b4fcef9d3")[]
var ctx: HMAC[sha256]
var symKey: SymKey