2024-06-28 10:34:57 +00:00
{. push raises : [ ] . }
2023-02-28 13:38:30 +00:00
import
2024-05-16 20:29:11 +00:00
std / [ sequtils , tables , times , deques ] ,
2024-03-15 23:08:47 +00:00
chronicles ,
options ,
chronos ,
stint ,
web3 ,
json ,
2023-02-28 13:38:30 +00:00
web3 / ethtypes ,
eth / keys ,
libp2p / protocols / pubsub / rpc / messages ,
libp2p / protocols / pubsub / pubsub ,
2024-07-09 11:14:28 +00:00
results ,
2023-02-28 13:38:30 +00:00
stew / [ byteutils , arrayops ]
import
. / group_manager ,
. / rln ,
. / conversion_utils ,
. / constants ,
. / protocol_types ,
2024-06-20 09:35:21 +00:00
. / protocol_metrics ,
. / nonce_manager
2024-02-13 04:48:02 +00:00
2023-02-28 13:38:30 +00:00
import
2024-02-15 11:25:08 +00:00
.. / common / error_handling ,
2023-09-05 09:05:07 +00:00
.. / waku_relay , # for WakuRelayHandler
2023-04-19 14:39:52 +00:00
.. / waku_core ,
2024-05-16 20:29:11 +00:00
.. / waku_keystore
2023-02-28 13:38:30 +00:00
logScope :
topics = " waku rln_relay "
2024-03-15 23:08:47 +00:00
type WakuRlnConfig * = object
rlnRelayDynamic * : bool
rlnRelayCredIndex * : Option [ uint ]
rlnRelayEthContractAddress * : string
rlnRelayEthClientAddress * : string
2024-06-28 09:19:16 +00:00
rlnRelayChainId * : uint
2024-03-15 23:08:47 +00:00
rlnRelayCredPath * : string
rlnRelayCredPassword * : string
rlnRelayTreePath * : string
rlnEpochSizeSec * : uint64
onFatalErrorAction * : OnFatalErrorHandler
2024-06-20 09:35:21 +00:00
rlnRelayUserMessageLimit * : uint64
2024-03-15 23:08:47 +00:00
proc createMembershipList * (
rln : ptr RLN , n : int
) : RlnRelayResult [ ( seq [ RawMembershipCredentials ] , string ) ] =
2023-02-28 13:38:30 +00:00
## createMembershipList produces a sequence of identity credentials in the form of (identity trapdoor, identity nullifier, identity secret hash, id commitment) in the hexadecimal format
## this proc also returns the root of a Merkle tree constructed out of the identity commitment keys of the generated list
## the output of this proc is used to initialize a static group keys (to test waku-rln-relay in the off-chain mode)
## Returns an error if it cannot create the membership list
var output = newSeq [ RawMembershipCredentials ] ( )
var idCommitments = newSeq [ IDCommitment ] ( )
2024-03-15 23:08:47 +00:00
for i in 0 .. n - 1 :
2023-02-28 13:38:30 +00:00
# generate an identity credential
let idCredentialRes = rln . membershipKeyGen ( )
if idCredentialRes . isErr ( ) :
2024-03-15 23:08:47 +00:00
return
err ( " could not generate an identity credential: " & idCredentialRes . error ( ) )
2023-02-28 13:38:30 +00:00
let idCredential = idCredentialRes . get ( )
2024-03-15 23:08:47 +00:00
let idTuple = (
idCredential . idTrapdoor . inHex ( ) ,
idCredential . idNullifier . inHex ( ) ,
idCredential . idSecretHash . inHex ( ) ,
idCredential . idCommitment . inHex ( ) ,
)
2023-02-28 13:38:30 +00:00
output . add ( idTuple )
idCommitments . add ( idCredential . idCommitment )
# Insert members into tree
let membersAdded = rln . insertMembers ( 0 , idCommitments )
if not membersAdded :
return err ( " could not insert members into the tree " )
let root = rln . getMerkleRoot ( ) . value ( ) . inHex ( )
return ok ( ( output , root ) )
type WakuRLNRelay * = ref object of RootObj
# the log of nullifiers and Shamir shares of the past messages grouped per epoch
2024-03-06 18:29:07 +00:00
nullifierLog * : OrderedTable [ Epoch , Table [ Nullifier , ProofMetadata ] ]
2023-02-28 13:38:30 +00:00
lastEpoch * : Epoch # the epoch of the last published rln message
2024-02-28 16:19:20 +00:00
rlnEpochSizeSec * : uint64
rlnMaxEpochGap * : uint64
2023-02-28 13:38:30 +00:00
groupManager * : GroupManager
2024-02-15 11:25:08 +00:00
onFatalErrorAction * : OnFatalErrorHandler
2024-06-20 09:35:21 +00:00
nonceManager * : NonceManager
2024-12-17 11:16:38 +00:00
epochMonitorFuture * : Future [ void ]
2023-02-28 13:38:30 +00:00
2024-02-28 16:19:20 +00:00
proc calcEpoch * ( rlnPeer : WakuRLNRelay , t : float64 ) : Epoch =
## gets time `t` as `flaot64` with subseconds resolution in the fractional part
## and returns its corresponding rln `Epoch` value
2024-03-15 23:08:47 +00:00
let e = uint64 ( t / rlnPeer . rlnEpochSizeSec . float64 )
2024-02-28 16:19:20 +00:00
return toEpoch ( e )
2024-12-17 11:16:38 +00:00
proc nextEpoch * ( rlnPeer : WakuRLNRelay , t : float64 ) : float64 =
# Calculates the next epoch time from the given time `t`.
let currentEpoch = rlnPeer . calcEpoch ( t )
var timePtr = t
# Increment by minutes until the epoch changes
while rlnPeer . calcEpoch ( timePtr ) = = currentEpoch :
timePtr + = 60 # 1 minute
# Backtrack to the last minute of the current epoch
timePtr - = 60
# Increment by seconds to find the exact transition
while rlnPeer . calcEpoch ( timePtr ) = = currentEpoch :
timePtr + = 1 # 1 second
# Ensure the returned time is in the future
if timePtr > epochTime ( ) :
return timePtr
else :
return epochTime ( )
2024-02-15 11:25:08 +00:00
proc stop * ( rlnPeer : WakuRLNRelay ) {. async : ( raises : [ Exception ] ) . } =
2023-07-27 11:51:21 +00:00
## stops the rln-relay protocol
## Throws an error if it cannot stop the rln-relay protocol
# stop the group sync, and flush data to tree db
2023-08-18 11:08:24 +00:00
info " stopping rln-relay "
2024-12-17 11:16:38 +00:00
await rlnPeer . epochMonitorFuture . cancelAndWait ( )
2023-07-27 11:51:21 +00:00
await rlnPeer . groupManager . stop ( )
2024-03-15 23:08:47 +00:00
proc hasDuplicate * (
rlnPeer : WakuRLNRelay , epoch : Epoch , proofMetadata : ProofMetadata
) : RlnRelayResult [ bool ] =
2023-02-28 13:38:30 +00:00
## returns true if there is another message in the `nullifierLog` of the `rlnPeer` with the same
2023-08-02 05:10:18 +00:00
## epoch and nullifier as `proofMetadata`'s epoch and nullifier
2023-02-28 13:38:30 +00:00
## otherwise, returns false
## Returns an error if it cannot check for duplicates
# check if the epoch exists
2024-03-06 18:29:07 +00:00
let nullifier = proofMetadata . nullifier
if not rlnPeer . nullifierLog . hasKey ( epoch ) :
2023-02-28 13:38:30 +00:00
return ok ( false )
try :
2024-03-06 18:29:07 +00:00
if rlnPeer . nullifierLog [ epoch ] . hasKey ( nullifier ) :
2023-08-02 05:10:18 +00:00
# there is an identical record, mark it as spam
return ok ( true )
2023-02-28 13:38:30 +00:00
# there is no duplicate
return ok ( false )
2024-03-06 18:29:07 +00:00
except KeyError :
return err ( " the epoch was not found: " & getCurrentExceptionMsg ( ) )
2023-02-28 13:38:30 +00:00
2024-03-15 23:08:47 +00:00
proc updateLog * (
rlnPeer : WakuRLNRelay , epoch : Epoch , proofMetadata : ProofMetadata
) : RlnRelayResult [ void ] =
2023-03-13 14:39:33 +00:00
## saves supplied proofMetadata `proofMetadata`
## in the `nullifierLog` of the `rlnPeer`
2023-02-28 13:38:30 +00:00
## Returns an error if it cannot update the log
2024-03-06 18:29:07 +00:00
# check if the epoch exists
2024-03-15 23:08:47 +00:00
if not rlnPeer . nullifierLog . hasKeyOrPut (
epoch , { proofMetadata . nullifier : proofMetadata } . toTable ( )
) :
2023-03-13 14:39:33 +00:00
return ok ( )
2023-02-28 13:38:30 +00:00
try :
# check if an identical record exists
2024-03-06 18:29:07 +00:00
if rlnPeer . nullifierLog [ epoch ] . hasKeyOrPut ( proofMetadata . nullifier , proofMetadata ) :
2024-06-28 07:25:10 +00:00
# the above condition could be `discarded` but it is kept for clarity, that slashing will
2024-03-06 18:29:07 +00:00
# be implemented here
2023-03-13 14:39:33 +00:00
# TODO: slashing logic
return ok ( )
return ok ( )
2024-03-06 18:29:07 +00:00
except KeyError :
2024-03-15 23:08:47 +00:00
return
err ( " the epoch was not found: " & getCurrentExceptionMsg ( ) ) # should never happen
2023-02-28 13:38:30 +00:00
2024-02-28 16:19:20 +00:00
proc getCurrentEpoch * ( rlnPeer : WakuRLNRelay ) : Epoch =
2023-02-28 13:38:30 +00:00
## gets the current rln Epoch time
2024-02-28 16:19:20 +00:00
return rlnPeer . calcEpoch ( epochTime ( ) )
2023-02-28 13:38:30 +00:00
proc absDiff * ( e1 , e2 : Epoch ) : uint64 =
## returns the absolute difference between the two rln `Epoch`s `e1` and `e2`
## i.e., e1 - e2
# convert epochs to their corresponding unsigned numerical values
let
epoch1 = fromEpoch ( e1 )
epoch2 = fromEpoch ( e2 )
# Manually perform an `abs` calculation
if epoch1 > epoch2 :
return epoch1 - epoch2
else :
return epoch2 - epoch1
2024-03-15 23:08:47 +00:00
proc validateMessage * (
rlnPeer : WakuRLNRelay , msg : WakuMessage , timeOption = none ( float64 )
) : MessageValidationResult =
2023-02-28 13:38:30 +00:00
## validate the supplied `msg` based on the waku-rln-relay routing protocol i.e.,
## the `msg`'s epoch is within MaxEpochGap of the current epoch
## the `msg` has valid rate limit proof
## the `msg` does not violate the rate limit
## `timeOption` indicates Unix epoch time (fractional part holds sub-seconds)
## if `timeOption` is supplied, then the current epoch is calculated based on that
2023-07-07 11:58:37 +00:00
2023-02-28 13:38:30 +00:00
let decodeRes = RateLimitProof . init ( msg . proof )
if decodeRes . isErr ( ) :
return MessageValidationResult . Invalid
let proof = decodeRes . get ( )
# track message count for metrics
waku_rln_messages_total . inc ( )
2023-09-01 13:03:59 +00:00
# checks if the `msg`'s epoch is far from the current epoch
2023-02-28 13:38:30 +00:00
# it corresponds to the validation of rln external nullifier
var epoch : Epoch
if timeOption . isSome ( ) :
2024-02-28 16:19:20 +00:00
epoch = rlnPeer . calcEpoch ( timeOption . get ( ) )
2023-02-28 13:38:30 +00:00
else :
# get current rln epoch
2024-02-28 16:19:20 +00:00
epoch = rlnPeer . getCurrentEpoch ( )
2023-02-28 13:38:30 +00:00
let
msgEpoch = proof . epoch
# calculate the gaps
gap = absDiff ( epoch , msgEpoch )
2023-09-04 13:13:59 +00:00
trace " epoch info " , currentEpoch = fromEpoch ( epoch ) , msgEpoch = fromEpoch ( msgEpoch )
2023-02-28 13:38:30 +00:00
# validate the epoch
2024-02-28 16:19:20 +00:00
if gap > rlnPeer . rlnMaxEpochGap :
2023-02-28 13:38:30 +00:00
# message's epoch is too old or too ahead
# accept messages whose epoch is within +-MaxEpochGap from the current epoch
2024-03-15 23:08:47 +00:00
warn " invalid message: epoch gap exceeds a threshold " ,
gap = gap , payloadLen = msg . payload . len , msgEpoch = fromEpoch ( proof . epoch )
waku_rln_invalid_messages_total . inc ( labelValues = [ " invalid_epoch " ] )
2023-02-28 13:38:30 +00:00
return MessageValidationResult . Invalid
let rootValidationRes = rlnPeer . groupManager . validateRoot ( proof . merkleRoot )
if not rootValidationRes :
2024-03-15 23:08:47 +00:00
warn " invalid message: provided root does not belong to acceptable window of roots " ,
provided = proof . merkleRoot . inHex ( ) ,
validRoots = rlnPeer . groupManager . validRoots . mapIt ( it . inHex ( ) )
waku_rln_invalid_messages_total . inc ( labelValues = [ " invalid_root " ] )
2023-02-28 13:38:30 +00:00
return MessageValidationResult . Invalid
# verify the proof
let
contentTopicBytes = msg . contentTopic . toBytes
input = concat ( msg . payload , contentTopicBytes )
waku_rln_proof_verification_total . inc ( )
waku_rln_proof_verification_duration_seconds . nanosecondTime :
let proofVerificationRes = rlnPeer . groupManager . verifyProof ( input , proof )
if proofVerificationRes . isErr ( ) :
2024-03-15 23:08:47 +00:00
waku_rln_errors_total . inc ( labelValues = [ " proof_verification " ] )
2023-09-01 13:03:59 +00:00
warn " invalid message: proof verification failed " , payloadLen = msg . payload . len
2023-02-28 13:38:30 +00:00
return MessageValidationResult . Invalid
if not proofVerificationRes . value ( ) :
# invalid proof
2023-09-04 13:13:59 +00:00
warn " invalid message: invalid proof " , payloadLen = msg . payload . len
2024-03-15 23:08:47 +00:00
waku_rln_invalid_messages_total . inc ( labelValues = [ " invalid_proof " ] )
2023-02-28 13:38:30 +00:00
return MessageValidationResult . Invalid
# check if double messaging has happened
2023-03-13 14:39:33 +00:00
let proofMetadataRes = proof . extractMetadata ( )
if proofMetadataRes . isErr ( ) :
2024-03-15 23:08:47 +00:00
waku_rln_errors_total . inc ( labelValues = [ " proof_metadata_extraction " ] )
2023-03-13 14:39:33 +00:00
return MessageValidationResult . Invalid
2024-03-06 18:29:07 +00:00
let hasDup = rlnPeer . hasDuplicate ( msgEpoch , proofMetadataRes . get ( ) )
2023-02-28 13:38:30 +00:00
if hasDup . isErr ( ) :
2024-03-15 23:08:47 +00:00
waku_rln_errors_total . inc ( labelValues = [ " duplicate_check " ] )
2023-02-28 13:38:30 +00:00
elif hasDup . value = = true :
2023-09-04 13:13:59 +00:00
trace " invalid message: message is spam " , payloadLen = msg . payload . len
2023-02-28 13:38:30 +00:00
waku_rln_spam_messages_total . inc ( )
return MessageValidationResult . Spam
2023-09-04 13:13:59 +00:00
trace " message is valid " , payloadLen = msg . payload . len
2023-02-28 13:38:30 +00:00
let rootIndex = rlnPeer . groupManager . indexOfRoot ( proof . merkleRoot )
waku_rln_valid_messages_total . observe ( rootIndex . toFloat ( ) )
return MessageValidationResult . Valid
2023-09-01 13:03:59 +00:00
proc validateMessageAndUpdateLog * (
2024-03-15 23:08:47 +00:00
rlnPeer : WakuRLNRelay , msg : WakuMessage , timeOption = none ( float64 )
) : MessageValidationResult =
2023-09-01 13:03:59 +00:00
## validates the message and updates the log to prevent double messaging
## in future messages
2024-04-26 09:53:58 +00:00
let isValidMessage = rlnPeer . validateMessage ( msg , timeOption )
2023-09-01 13:03:59 +00:00
let decodeRes = RateLimitProof . init ( msg . proof )
if decodeRes . isErr ( ) :
return MessageValidationResult . Invalid
let msgProof = decodeRes . get ( )
let proofMetadataRes = msgProof . extractMetadata ( )
if proofMetadataRes . isErr ( ) :
return MessageValidationResult . Invalid
2024-12-17 11:16:38 +00:00
# insert the message to the log (never errors) only if the
2024-06-28 07:25:10 +00:00
# message is valid.
if isValidMessage = = MessageValidationResult . Valid :
discard rlnPeer . updateLog ( msgProof . epoch , proofMetadataRes . get ( ) )
2023-09-01 13:03:59 +00:00
2024-04-26 09:53:58 +00:00
return isValidMessage
2023-09-01 13:03:59 +00:00
2023-02-28 13:38:30 +00:00
proc toRLNSignal * ( wakumessage : WakuMessage ) : seq [ byte ] =
## it is a utility proc that prepares the `data` parameter of the proof generation procedure i.e., `proofGen` that resides in the current module
## it extracts the `contentTopic` and the `payload` of the supplied `wakumessage` and serializes them into a byte sequence
let
contentTopicBytes = wakumessage . contentTopic . toBytes ( )
output = concat ( wakumessage . payload , contentTopicBytes )
return output
2024-03-15 23:08:47 +00:00
proc appendRLNProof * (
rlnPeer : WakuRLNRelay , msg : var WakuMessage , senderEpochTime : float64
) : RlnRelayResult [ void ] =
2023-02-28 13:38:30 +00:00
## returns true if it can create and append a `RateLimitProof` to the supplied `msg`
## returns false otherwise
## `senderEpochTime` indicates the number of seconds passed since Unix epoch. The fractional part holds sub-seconds.
## The `epoch` field of `RateLimitProof` is derived from the provided `senderEpochTime` (using `calcEpoch()`)
let input = msg . toRLNSignal ( )
2024-02-28 16:19:20 +00:00
let epoch = rlnPeer . calcEpoch ( senderEpochTime )
2023-02-28 13:38:30 +00:00
2024-06-20 09:35:21 +00:00
let nonce = rlnPeer . nonceManager . getNonce ( ) . valueOr :
return err ( " could not get new message id to generate an rln proof: " & $ error )
let proof = rlnPeer . groupManager . generateProof ( input , epoch , nonce ) . valueOr :
return err ( " could not generate rln-v2 proof: " & $ error )
2024-02-13 04:48:02 +00:00
msg . proof = proof . encode ( ) . buffer
return ok ( )
2023-02-28 13:38:30 +00:00
2024-06-24 11:29:56 +00:00
proc clearNullifierLog * ( rlnPeer : WakuRlnRelay ) =
2023-09-06 08:18:02 +00:00
# clear the first MaxEpochGap epochs of the nullifer log
# if more than MaxEpochGap epochs are in the log
2024-06-28 07:25:10 +00:00
let currentEpoch = fromEpoch ( rlnPeer . getCurrentEpoch ( ) )
var epochsToRemove : seq [ Epoch ] = @ [ ]
for epoch in rlnPeer . nullifierLog . keys ( ) :
let epochInt = fromEpoch ( epoch )
2023-09-06 08:18:02 +00:00
2024-06-28 07:25:10 +00:00
# clean all epochs that are +- rlnMaxEpochGap from the current epoch
2024-07-09 11:14:28 +00:00
if ( currentEpoch + rlnPeer . rlnMaxEpochGap ) < = epochInt or
epochInt < = ( currentEpoch - rlnPeer . rlnMaxEpochGap ) :
2024-06-28 07:25:10 +00:00
epochsToRemove . add ( epoch )
2024-07-09 11:14:28 +00:00
2024-06-28 07:25:10 +00:00
for epochRemove in epochsToRemove :
2024-07-09 11:14:28 +00:00
trace " clearing epochs from the nullifier log " ,
currentEpoch = currentEpoch , cleanedEpoch = fromEpoch ( epochRemove )
2024-06-28 07:25:10 +00:00
rlnPeer . nullifierLog . del ( epochRemove )
2023-09-06 08:18:02 +00:00
2024-03-15 23:08:47 +00:00
proc generateRlnValidator * (
wakuRlnRelay : WakuRLNRelay , spamHandler = none ( SpamHandler )
) : WakuValidatorHandler =
2023-02-28 13:38:30 +00:00
## this procedure is a thin wrapper for the pubsub addValidator method
2023-08-21 06:55:34 +00:00
## it sets a validator for waku messages, acting in the registered pubsub topic
2023-02-28 13:38:30 +00:00
## the message validation logic is according to https://rfc.vac.dev/spec/17/
2024-03-15 23:08:47 +00:00
proc validator (
topic : string , message : WakuMessage
) : Future [ pubsub . ValidationResult ] {. async . } =
2023-02-28 13:38:30 +00:00
trace " rln-relay topic validator is called "
2023-09-06 08:18:02 +00:00
wakuRlnRelay . clearNullifierLog ( )
2023-07-07 11:58:37 +00:00
2023-09-05 09:05:07 +00:00
let decodeRes = RateLimitProof . init ( message . proof )
2023-07-07 11:58:37 +00:00
2023-09-05 09:05:07 +00:00
if decodeRes . isErr ( ) :
2024-03-15 23:08:47 +00:00
trace " generateRlnValidator reject " , error = decodeRes . error
2023-09-05 09:05:07 +00:00
return pubsub . ValidationResult . Reject
2023-08-21 06:55:34 +00:00
2023-09-05 09:05:07 +00:00
let msgProof = decodeRes . get ( )
2024-03-15 23:08:47 +00:00
2023-09-05 09:05:07 +00:00
# validate the message and update log
let validationRes = wakuRlnRelay . validateMessageAndUpdateLog ( message )
2023-02-28 13:38:30 +00:00
2023-09-05 09:05:07 +00:00
let
proof = toHex ( msgProof . proof )
epoch = fromEpoch ( msgProof . epoch )
root = inHex ( msgProof . merkleRoot )
shareX = inHex ( msgProof . shareX )
shareY = inHex ( msgProof . shareY )
nullifier = inHex ( msgProof . nullifier )
payload = string . fromBytes ( message . payload )
2024-03-15 23:08:47 +00:00
case validationRes
of Valid :
trace " message validity is verified, relaying: " ,
proof = proof ,
root = root ,
shareX = shareX ,
shareY = shareY ,
nullifier = nullifier
return pubsub . ValidationResult . Accept
of Invalid :
trace " message validity could not be verified, discarding: " ,
proof = proof ,
root = root ,
shareX = shareX ,
shareY = shareY ,
nullifier = nullifier
return pubsub . ValidationResult . Reject
of Spam :
trace " A spam message is found! yay! discarding: " ,
proof = proof ,
root = root ,
shareX = shareX ,
shareY = shareY ,
nullifier = nullifier
if spamHandler . isSome ( ) :
let handler = spamHandler . get ( )
handler ( message )
return pubsub . ValidationResult . Reject
2023-02-28 13:38:30 +00:00
return validator
2024-12-17 11:16:38 +00:00
proc monitorEpochs ( wakuRlnRelay : WakuRLNRelay ) : Future [ void ] {. async . } =
while true :
try :
waku_rln_remaining_proofs_per_epoch . set (
wakuRlnRelay . groupManager . userMessageLimit . get ( ) . float64
)
except CatchableError :
error " Error in epoch monitoring " , error = getCurrentExceptionMsg ( )
let nextEpochTime = wakuRlnRelay . nextEpoch ( epochTime ( ) )
await sleepAsync ( int ( wakuRlnRelay . rlnEpochSizeSec * 1000 ) )
2024-03-15 23:08:47 +00:00
proc mount (
conf : WakuRlnConfig , registrationHandler = none ( RegistrationHandler )
2024-04-26 09:53:58 +00:00
) : Future [ RlnRelayResult [ WakuRlnRelay ] ] {. async . } =
2023-02-28 13:38:30 +00:00
var
groupManager : GroupManager
2024-02-15 11:25:08 +00:00
wakuRlnRelay : WakuRLNRelay
2023-02-28 13:38:30 +00:00
# create an RLN instance
2024-04-26 09:53:58 +00:00
let rlnInstance = createRLNInstance ( tree_path = conf . rlnRelayTreePath ) . valueOr :
return err ( " could not create RLN instance: " & $ error )
2023-02-28 13:38:30 +00:00
if not conf . rlnRelayDynamic :
# static setup
2024-04-26 09:53:58 +00:00
let parsedGroupKeys = StaticGroupKeys . toIdentityCredentials ( ) . valueOr :
return err ( " could not parse static group keys: " & $ error )
2024-03-15 23:08:47 +00:00
groupManager = StaticGroupManager (
groupSize : StaticGroupSize ,
2024-04-26 09:53:58 +00:00
groupKeys : parsedGroupKeys ,
2024-03-15 23:08:47 +00:00
membershipIndex : conf . rlnRelayCredIndex ,
rlnInstance : rlnInstance ,
onFatalErrorAction : conf . onFatalErrorAction ,
)
2023-02-28 13:38:30 +00:00
# we don't persist credentials in static mode since they exist in ./constants.nim
else :
# dynamic setup
proc useValueOrNone ( s : string ) : Option [ string ] =
2024-03-15 23:08:47 +00:00
if s = = " " :
none ( string )
else :
some ( s )
2023-02-28 13:38:30 +00:00
let
rlnRelayCredPath = useValueOrNone ( conf . rlnRelayCredPath )
2023-08-29 12:16:21 +00:00
rlnRelayCredPassword = useValueOrNone ( conf . rlnRelayCredPassword )
2024-03-15 23:08:47 +00:00
groupManager = OnchainGroupManager (
ethClientUrl : string ( conf . rlnRelayethClientAddress ) ,
ethContractAddress : $ conf . rlnRelayEthContractAddress ,
2024-06-28 09:19:16 +00:00
chainId : conf . rlnRelayChainId ,
2024-03-15 23:08:47 +00:00
rlnInstance : rlnInstance ,
registrationHandler : registrationHandler ,
keystorePath : rlnRelayCredPath ,
keystorePassword : rlnRelayCredPassword ,
membershipIndex : conf . rlnRelayCredIndex ,
onFatalErrorAction : conf . onFatalErrorAction ,
)
2024-02-15 11:25:08 +00:00
2023-02-28 13:38:30 +00:00
# Initialize the groupManager
2024-04-26 09:53:58 +00:00
( await groupManager . init ( ) ) . isOkOr :
return err ( " could not initialize the group manager: " & $ error )
2023-02-28 13:38:30 +00:00
# Start the group sync
2024-04-26 09:53:58 +00:00
( await groupManager . startGroupSync ( ) ) . isOkOr :
return err ( " could not start the group sync: " & $ error )
2023-02-28 13:38:30 +00:00
2024-12-17 11:16:38 +00:00
wakuRlnRelay = WakuRLNRelay (
groupManager : groupManager ,
nonceManager :
NonceManager . init ( conf . rlnRelayUserMessageLimit , conf . rlnEpochSizeSec . float ) ,
rlnEpochSizeSec : conf . rlnEpochSizeSec ,
rlnMaxEpochGap : max ( uint64 ( MaxClockGapSeconds / float64 ( conf . rlnEpochSizeSec ) ) , 1 ) ,
onFatalErrorAction : conf . onFatalErrorAction ,
2024-06-20 09:35:21 +00:00
)
2024-12-17 11:16:38 +00:00
# Start epoch monitoring in the background
wakuRlnRelay . epochMonitorFuture = monitorEpochs ( wakuRlnRelay )
return ok ( wakuRlnRelay )
2023-12-14 06:16:39 +00:00
proc isReady * ( rlnPeer : WakuRLNRelay ) : Future [ bool ] {. async : ( raises : [ Exception ] ) . } =
2023-09-06 08:46:19 +00:00
## returns true if the rln-relay protocol is ready to relay messages
## returns false otherwise
2024-03-15 23:08:47 +00:00
2023-09-06 08:46:19 +00:00
# could be nil during startup
if rlnPeer . groupManager = = nil :
return false
try :
return await rlnPeer . groupManager . isReady ( )
except CatchableError :
2024-03-15 23:08:47 +00:00
error " could not check if the rln-relay protocol is ready " ,
err = getCurrentExceptionMsg ( )
2023-09-06 08:46:19 +00:00
return false
2023-02-28 13:38:30 +00:00
2024-03-15 23:08:47 +00:00
proc new * (
T : type WakuRlnRelay ,
conf : WakuRlnConfig ,
registrationHandler = none ( RegistrationHandler ) ,
) : Future [ RlnRelayResult [ WakuRlnRelay ] ] {. async . } =
2023-02-28 13:38:30 +00:00
## Mounts the rln-relay protocol on the node.
## The rln-relay protocol can be mounted in two modes: on-chain and off-chain.
## Returns an error if the rln-relay protocol could not be mounted.
try :
2024-04-26 09:53:58 +00:00
return await mount ( conf , registrationHandler )
except CatchableError :
return err ( " could not mount the rln-relay protocol: " & getCurrentExceptionMsg ( ) )