mirror of https://github.com/waku-org/nwaku.git
chore(rln-relay): use the only key from keystore if only 1 exists (#1984)
* chore(rln-relay): use the only key from keystore if only 1 exists * fix: convert iterator to seq and then index into it
This commit is contained in:
parent
1b835b4e2a
commit
a14c32614a
|
@ -233,9 +233,8 @@ type
|
|||
name: "rln-relay-cred-path" }: string
|
||||
|
||||
rlnRelayCredIndex* {.
|
||||
desc: "the index of credentials to use",
|
||||
defaultValue: 0
|
||||
name: "rln-relay-cred-index" }: uint
|
||||
desc: "the index of the onchain commitment to use",
|
||||
name: "rln-relay-cred-index" }: Option[uint]
|
||||
|
||||
rlnRelayDynamic* {.
|
||||
desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false",
|
||||
|
@ -297,6 +296,12 @@ proc parseCmdArg*(T: type Port, p: string): T =
|
|||
proc completeCmdArg*(T: type Port, val: string): seq[string] =
|
||||
return @[]
|
||||
|
||||
proc parseCmdArg*(T: type Option[uint], p: string): T =
|
||||
try:
|
||||
some(parseUint(p))
|
||||
except CatchableError:
|
||||
raise newException(ConfigurationError, "Invalid unsigned integer")
|
||||
|
||||
func defaultListenAddress*(conf: Chat2Conf): ValidIpAddress =
|
||||
# TODO: How should we select between IPv4 and IPv6
|
||||
# Maybe there should be a config option for this.
|
||||
|
|
|
@ -146,9 +146,8 @@ type
|
|||
name: "rln-relay-cred-path" }: string
|
||||
|
||||
rlnRelayCredIndex* {.
|
||||
desc: "the index of credentials to use",
|
||||
defaultValue: 0
|
||||
name: "rln-relay-membership-index" }: uint
|
||||
desc: "the index of the onchain commitment to use",
|
||||
name: "rln-relay-membership-index" }: Option[uint]
|
||||
|
||||
rlnRelayDynamic* {.
|
||||
desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false",
|
||||
|
@ -506,6 +505,12 @@ proc parseCmdArg*(T: type Option[int], p: string): T =
|
|||
except CatchableError:
|
||||
raise newException(ConfigurationError, "Invalid number")
|
||||
|
||||
proc parseCmdArg*(T: type Option[uint], p: string): T =
|
||||
try:
|
||||
some(parseUint(p))
|
||||
except CatchableError:
|
||||
raise newException(ConfigurationError, "Invalid unsigned integer")
|
||||
|
||||
## Configuration validation
|
||||
|
||||
let DbUrlRegex = re"^[\w\+]+:\/\/[\w\/\\\.\:\@]+$"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import
|
||||
std/[os, json],
|
||||
chronos,
|
||||
testutils/unittests
|
||||
testutils/unittests
|
||||
import
|
||||
../../waku/waku_keystore,
|
||||
./testlib/common
|
||||
|
@ -123,3 +123,89 @@ procSuite "Credentials test suite":
|
|||
recoveredCredentialsRes.isOk()
|
||||
recoveredCredentialsRes.get() == expectedMembership
|
||||
|
||||
test "if the keystore contains only one credential, fetch that irrespective of treeIndex":
|
||||
|
||||
let filepath = "./testAppKeystore.txt"
|
||||
defer: removeFile(filepath)
|
||||
|
||||
# We generate random identity credentials (inter-value constrains are not enforced, otherwise we need to load e.g. zerokit RLN keygen)
|
||||
let
|
||||
idTrapdoor = randomSeqByte(rng[], 32)
|
||||
idNullifier = randomSeqByte(rng[], 32)
|
||||
idSecretHash = randomSeqByte(rng[], 32)
|
||||
idCommitment = randomSeqByte(rng[], 32)
|
||||
idCredential = IdentityCredential(idTrapdoor: idTrapdoor, idNullifier: idNullifier, idSecretHash: idSecretHash, idCommitment: idCommitment)
|
||||
|
||||
let contract = MembershipContract(chainId: "5", address: "0x0123456789012345678901234567890123456789")
|
||||
let index = MembershipIndex(1)
|
||||
let membershipCredential = KeystoreMembership(membershipContract: contract,
|
||||
treeIndex: index,
|
||||
identityCredential: idCredential)
|
||||
|
||||
let password = "%m0um0ucoW%"
|
||||
|
||||
let keystoreRes = addMembershipCredentials(path = filepath,
|
||||
membership = membershipCredential,
|
||||
password = password,
|
||||
appInfo = testAppInfo)
|
||||
|
||||
assert(keystoreRes.isOk(), $keystoreRes.error)
|
||||
|
||||
# We test retrieval of credentials.
|
||||
let expectedMembership = membershipCredential
|
||||
let membershipQuery = KeystoreMembership(membershipContract: contract)
|
||||
|
||||
let recoveredCredentialsRes = getMembershipCredentials(path = filepath,
|
||||
password = password,
|
||||
query = membershipQuery,
|
||||
appInfo = testAppInfo)
|
||||
|
||||
assert(recoveredCredentialsRes.isOk(), $recoveredCredentialsRes.error)
|
||||
check: recoveredCredentialsRes.get() == expectedMembership
|
||||
|
||||
test "if the keystore contains multiple credentials, then error out if treeIndex has not been passed in":
|
||||
let filepath = "./testAppKeystore.txt"
|
||||
defer: removeFile(filepath)
|
||||
|
||||
# We generate random identity credentials (inter-value constrains are not enforced, otherwise we need to load e.g. zerokit RLN keygen)
|
||||
let
|
||||
idTrapdoor = randomSeqByte(rng[], 32)
|
||||
idNullifier = randomSeqByte(rng[], 32)
|
||||
idSecretHash = randomSeqByte(rng[], 32)
|
||||
idCommitment = randomSeqByte(rng[], 32)
|
||||
idCredential = IdentityCredential(idTrapdoor: idTrapdoor, idNullifier: idNullifier, idSecretHash: idSecretHash, idCommitment: idCommitment)
|
||||
|
||||
# We generate two distinct membership groups
|
||||
let contract = MembershipContract(chainId: "5", address: "0x0123456789012345678901234567890123456789")
|
||||
let index = MembershipIndex(1)
|
||||
var membershipCredential = KeystoreMembership(membershipContract: contract,
|
||||
treeIndex: index,
|
||||
identityCredential: idCredential)
|
||||
|
||||
let password = "%m0um0ucoW%"
|
||||
|
||||
let keystoreRes = addMembershipCredentials(path = filepath,
|
||||
membership = membershipCredential,
|
||||
password = password,
|
||||
appInfo = testAppInfo)
|
||||
|
||||
assert(keystoreRes.isOk(), $keystoreRes.error)
|
||||
|
||||
membershipCredential.treeIndex = MembershipIndex(2)
|
||||
let keystoreRes2 = addMembershipCredentials(path = filepath,
|
||||
membership = membershipCredential,
|
||||
password = password,
|
||||
appInfo = testAppInfo)
|
||||
assert(keystoreRes2.isOk(), $keystoreRes2.error)
|
||||
|
||||
# We test retrieval of credentials.
|
||||
let membershipQuery = KeystoreMembership(membershipContract: contract)
|
||||
|
||||
let recoveredCredentialsRes = getMembershipCredentials(path = filepath,
|
||||
password = password,
|
||||
query = membershipQuery,
|
||||
appInfo = testAppInfo)
|
||||
|
||||
check:
|
||||
recoveredCredentialsRes.isErr()
|
||||
recoveredCredentialsRes.error.kind == KeystoreCredentialNotFoundError
|
||||
|
|
|
@ -662,7 +662,7 @@ suite "Waku rln relay":
|
|||
let index = MembershipIndex(5)
|
||||
|
||||
let rlnConf = WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: index.uint,
|
||||
rlnRelayCredIndex: some(index),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_2"))
|
||||
let wakuRlnRelayRes = await WakuRlnRelay.new(rlnConf)
|
||||
require:
|
||||
|
@ -714,7 +714,7 @@ suite "Waku rln relay":
|
|||
let index = MembershipIndex(5)
|
||||
|
||||
let rlnConf = WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: index.uint,
|
||||
rlnRelayCredIndex: some(index),
|
||||
rlnRelayBandwidthThreshold: 4,
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_3"))
|
||||
let wakuRlnRelayRes = await WakuRlnRelay.new(rlnConf)
|
||||
|
|
|
@ -45,7 +45,7 @@ procSuite "WakuNode - RLN relay":
|
|||
|
||||
# mount rlnrelay in off-chain mode
|
||||
await node1.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: 1.uint,
|
||||
rlnRelayCredIndex: some(1.uint),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode"),
|
||||
))
|
||||
|
||||
|
@ -55,7 +55,7 @@ procSuite "WakuNode - RLN relay":
|
|||
await node2.mountRelay(@[DefaultPubsubTopic])
|
||||
# mount rlnrelay in off-chain mode
|
||||
await node2.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: 2.uint,
|
||||
rlnRelayCredIndex: some(2.uint),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_2"),
|
||||
))
|
||||
|
||||
|
@ -65,7 +65,7 @@ procSuite "WakuNode - RLN relay":
|
|||
await node3.mountRelay(@[DefaultPubsubTopic])
|
||||
|
||||
await node3.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: 3.uint,
|
||||
rlnRelayCredIndex: some(3.uint),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_3"),
|
||||
))
|
||||
|
||||
|
@ -126,7 +126,7 @@ procSuite "WakuNode - RLN relay":
|
|||
# mount rlnrelay in off-chain mode
|
||||
for index, node in nodes:
|
||||
await node.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: index.uint + 1,
|
||||
rlnRelayCredIndex: some(index.uint + 1),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_" & $(index+1))))
|
||||
|
||||
# start them
|
||||
|
@ -204,7 +204,7 @@ procSuite "WakuNode - RLN relay":
|
|||
|
||||
# mount rlnrelay in off-chain mode
|
||||
await node1.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: 1.uint,
|
||||
rlnRelayCredIndex: some(1.uint),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_4"),
|
||||
rlnRelayBandwidthThreshold: 0,
|
||||
))
|
||||
|
@ -215,7 +215,7 @@ procSuite "WakuNode - RLN relay":
|
|||
await node2.mountRelay(@[DefaultPubsubTopic])
|
||||
# mount rlnrelay in off-chain mode
|
||||
await node2.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: 2.uint,
|
||||
rlnRelayCredIndex: some(2.uint),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_5"),
|
||||
rlnRelayBandwidthThreshold: 0,
|
||||
))
|
||||
|
@ -226,7 +226,7 @@ procSuite "WakuNode - RLN relay":
|
|||
await node3.mountRelay(@[DefaultPubsubTopic])
|
||||
|
||||
await node3.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: 3.uint,
|
||||
rlnRelayCredIndex: some(3.uint),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_6"),
|
||||
rlnRelayBandwidthThreshold: 0,
|
||||
))
|
||||
|
@ -306,7 +306,7 @@ procSuite "WakuNode - RLN relay":
|
|||
|
||||
# mount rlnrelay in off-chain mode
|
||||
await node1.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: 1.uint,
|
||||
rlnRelayCredIndex: some(1.uint),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_7"),
|
||||
rlnRelayBandwidthThreshold: 0,
|
||||
))
|
||||
|
@ -318,7 +318,7 @@ procSuite "WakuNode - RLN relay":
|
|||
|
||||
# mount rlnrelay in off-chain mode
|
||||
await node2.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: 2.uint,
|
||||
rlnRelayCredIndex: some(2.uint),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_8"),
|
||||
rlnRelayBandwidthThreshold: 0,
|
||||
))
|
||||
|
@ -330,7 +330,7 @@ procSuite "WakuNode - RLN relay":
|
|||
|
||||
# mount rlnrelay in off-chain mode
|
||||
await node3.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: 3.uint,
|
||||
rlnRelayCredIndex: some(3.uint),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_9"),
|
||||
rlnRelayBandwidthThreshold: 0,
|
||||
))
|
||||
|
|
|
@ -106,11 +106,11 @@ suite "Waku v2 JSON-RPC API - Relay":
|
|||
|
||||
when defined(rln):
|
||||
await srcNode.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: 1,
|
||||
rlnRelayCredIndex: some(1.uint),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1")))
|
||||
|
||||
await dstNode.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: 2,
|
||||
rlnRelayCredIndex: some(2.uint),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_2")))
|
||||
|
||||
await srcNode.connectToNodes(@[dstNode.peerInfo.toRemotePeerInfo()])
|
||||
|
|
|
@ -188,7 +188,7 @@ suite "Waku v2 Rest API - Relay":
|
|||
await node.mountRelay()
|
||||
when defined(rln):
|
||||
await node.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
|
||||
rlnRelayCredIndex: 1,
|
||||
rlnRelayCredIndex: some(1.uint),
|
||||
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1")))
|
||||
|
||||
# RPC server setup
|
||||
|
|
|
@ -4,7 +4,10 @@ else:
|
|||
{.push raises: [].}
|
||||
|
||||
import
|
||||
options, json, strutils,
|
||||
options,
|
||||
json,
|
||||
strutils,
|
||||
sequtils,
|
||||
std/[tables, os]
|
||||
|
||||
import
|
||||
|
@ -144,7 +147,7 @@ proc addMembershipCredentials*(path: string,
|
|||
let encodedMembershipCredential = membership.encode()
|
||||
let keyfileRes = createKeyFileJson(encodedMembershipCredential, password)
|
||||
if keyfileRes.isErr():
|
||||
return err(AppKeystoreError(kind: KeystoreCreateKeyfileError,
|
||||
return err(AppKeystoreError(kind: KeystoreCreateKeyfileError,
|
||||
msg: $keyfileRes.error))
|
||||
|
||||
# We add it to the credentials field of the keystore
|
||||
|
@ -183,13 +186,24 @@ proc getMembershipCredentials*(path: string,
|
|||
if jsonKeystore.hasKey("credentials"):
|
||||
# We get all credentials in keystore
|
||||
var keystoreCredentials = jsonKeystore["credentials"]
|
||||
let key = query.hash()
|
||||
if not keystoreCredentials.hasKey(key):
|
||||
if keystoreCredentials.len == 0:
|
||||
# error
|
||||
return err(AppKeystoreError(kind: KeystoreCredentialNotFoundError,
|
||||
msg: "Credential not found in keystore"))
|
||||
msg: "No credentials found in keystore"))
|
||||
var keystoreCredential: JsonNode
|
||||
if keystoreCredentials.len == 1:
|
||||
keystoreCredential = keystoreCredentials
|
||||
.getFields()
|
||||
.values()
|
||||
.toSeq()[0]
|
||||
else:
|
||||
let key = query.hash()
|
||||
if not keystoreCredentials.hasKey(key):
|
||||
# error
|
||||
return err(AppKeystoreError(kind: KeystoreCredentialNotFoundError,
|
||||
msg: "Credential not found in keystore"))
|
||||
keystoreCredential = keystoreCredentials[key]
|
||||
|
||||
let keystoreCredential = keystoreCredentials[key]
|
||||
let decodedKeyfileRes = decodeKeyFileJson(keystoreCredential, password)
|
||||
if decodedKeyfileRes.isErr():
|
||||
return err(AppKeystoreError(kind: KeystoreReadKeyfileError,
|
||||
|
|
|
@ -440,23 +440,23 @@ method init*(g: OnchainGroupManager): Future[void] {.async.} =
|
|||
g.registryContract = some(registryContract)
|
||||
|
||||
if g.keystorePath.isSome() and g.keystorePassword.isSome():
|
||||
if g.membershipIndex.isNone():
|
||||
raise newException(CatchableError, "membership index is not set when keystore is provided")
|
||||
let keystoreQuery = KeystoreMembership(
|
||||
var keystoreQuery = KeystoreMembership(
|
||||
membershipContract: MembershipContract(
|
||||
chainId: $g.chainId.get(),
|
||||
address: g.ethContractAddress
|
||||
),
|
||||
treeIndex: MembershipIndex(g.membershipIndex.get()),
|
||||
)
|
||||
)
|
||||
if g.membershipIndex.isSome():
|
||||
keystoreQuery.treeIndex = MembershipIndex(g.membershipIndex.get())
|
||||
waku_rln_membership_credentials_import_duration_seconds.nanosecondTime:
|
||||
let keystoreCredRes = getMembershipCredentials(path = g.keystorePath.get(),
|
||||
password = g.keystorePassword.get(),
|
||||
query = keystoreQuery,
|
||||
appInfo = RLNAppInfo)
|
||||
if keystoreCredRes.isErr():
|
||||
raise newException(ValueError, "could not parse the keystore: " & $keystoreCredRes.error)
|
||||
raise newException(CatchableError, "could not parse the keystore: " & $keystoreCredRes.error)
|
||||
let keystoreCred = keystoreCredRes.get()
|
||||
g.membershipIndex = some(keystoreCred.treeIndex)
|
||||
# now we check on the contract if the commitment actually has a membership
|
||||
try:
|
||||
let membershipExists = await rlnContract.memberExists(keystoreCred
|
||||
|
|
|
@ -31,7 +31,7 @@ logScope:
|
|||
|
||||
type WakuRlnConfig* = object
|
||||
rlnRelayDynamic*: bool
|
||||
rlnRelayCredIndex*: uint
|
||||
rlnRelayCredIndex*: Option[uint]
|
||||
rlnRelayEthContractAddress*: string
|
||||
rlnRelayEthClientAddress*: string
|
||||
rlnRelayCredPath*: string
|
||||
|
@ -374,7 +374,7 @@ proc mount(conf: WakuRlnConfig,
|
|||
raise newException(ValueError, "Static group keys are not valid")
|
||||
groupManager = StaticGroupManager(groupSize: StaticGroupSize,
|
||||
groupKeys: parsedGroupKeysRes.get(),
|
||||
membershipIndex: some(conf.rlnRelayCredIndex),
|
||||
membershipIndex: conf.rlnRelayCredIndex,
|
||||
rlnInstance: rlnInstance)
|
||||
# we don't persist credentials in static mode since they exist in ./constants.nim
|
||||
else:
|
||||
|
@ -390,7 +390,7 @@ proc mount(conf: WakuRlnConfig,
|
|||
registrationHandler: registrationHandler,
|
||||
keystorePath: rlnRelayCredPath,
|
||||
keystorePassword: rlnRelayCredPassword,
|
||||
membershipIndex: some(conf.rlnRelayCredIndex))
|
||||
membershipIndex: conf.rlnRelayCredIndex)
|
||||
# Initialize the groupManager
|
||||
await groupManager.init()
|
||||
# Start the group sync
|
||||
|
|
Loading…
Reference in New Issue