Skip to content

Commit

Permalink
fix(rln-relay): RLN DB should be aware of chain and contract address (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
rymnc authored Aug 23, 2023
1 parent c9b48ea commit 1ae5b5a
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 22 deletions.
23 changes: 23 additions & 0 deletions tests/waku_rln_relay/test_rln_group_manager_onchain.nim
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,29 @@ suite "Onchain group manager":
manager.membershipFee.isSome()
manager.initialized

asyncTest "should error on initialization when loaded metadata does not match":
let manager = await setup()
await manager.init()

let metadataSetRes = manager.setMetadata()
assert metadataSetRes.isOk(), metadataSetRes.error
let metadataRes = manager.rlnInstance.getMetadata()
assert metadataRes.isOk(), metadataRes.error
let metadata = metadataRes.get()
require:
metadata.chainId == 1337
metadata.contractAddress == manager.ethContractAddress

await manager.stop()

# simulating a change in the contractAddress
let manager2 = OnchainGroupManager(ethClientUrl: EthClient,
ethContractAddress: "0x0000000000000000000000000000000000000000",
ethPrivateKey: manager.ethPrivateKey,
rlnInstance: manager.rlnInstance,
saveKeystore: false)
expect(ValueError): await manager2.init()

asyncTest "startGroupSync: should start group sync":
let manager = await setup()

Expand Down
11 changes: 8 additions & 3 deletions tests/waku_rln_relay/test_waku_rln_relay.nim
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,9 @@ suite "Waku rln relay":
rlnInstance.isOk()
let rln = rlnInstance.get()
check:
rln.setMetadata(RlnMetadata(lastProcessedBlock: 128)).isOk()
rln.setMetadata(RlnMetadata(lastProcessedBlock: 128,
chainId: 1155511,
contractAddress: "0x9c09146844c1326c2dbc41c451766c7138f88155")).isOk()

test "getMetadata rln utils":
# create an RLN instance which also includes an empty Merkle tree
Expand All @@ -255,7 +257,9 @@ suite "Waku rln relay":
let rln = rlnInstance.get()

require:
rln.setMetadata(RlnMetadata(lastProcessedBlock: 128)).isOk()
rln.setMetadata(RlnMetadata(lastProcessedBlock: 128,
chainId: 1155511,
contractAddress: "0x9c09146844c1326c2dbc41c451766c7138f88155")).isOk()

let metadataRes = rln.getMetadata()

Expand All @@ -266,7 +270,8 @@ suite "Waku rln relay":

check:
metadata.lastProcessedBlock == 128

metadata.chainId == 1155511
metadata.contractAddress == "0x9c09146844c1326c2dbc41c451766c7138f88155"

test "Merkle tree consistency check between deletion and insertion":
# create an RLN instance
Expand Down
43 changes: 31 additions & 12 deletions waku/waku_rln_relay/group_manager/on_chain/group_manager.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import
json,
std/tables,
stew/[byteutils, arrayops],
sequtils
sequtils,
strutils
import
../../../waku_keystore,
../../rln,
Expand Down Expand Up @@ -281,6 +282,20 @@ proc handleRemovedEvents(g: OnchainGroupManager, blockTable: BlockTable): Future

await g.backfillRootQueue(numRemovedBlocks)

proc setMetadata*(g: OnchainGroupManager): RlnRelayResult[void] =
if g.latestProcessedBlock.isNone():
return err("latest processed block is not set")
try:
let metadataSetRes = g.rlnInstance.setMetadata(RlnMetadata(
lastProcessedBlock: g.latestProcessedBlock.get(),
chainId: uint64(g.chainId.get()),
contractAddress: g.ethContractAddress))
if metadataSetRes.isErr():
return err("failed to persist rln metadata: " & metadataSetRes.error())
except CatchableError:
return err("failed to persist rln metadata: " & getCurrentExceptionMsg())
return ok()

proc getAndHandleEvents(g: OnchainGroupManager,
fromBlock: BlockNumber,
toBlock: Option[BlockNumber] = none(BlockNumber)): Future[void] {.async.} =
Expand All @@ -293,8 +308,7 @@ proc getAndHandleEvents(g: OnchainGroupManager,
let latestProcessedBlock = if toBlock.isSome(): toBlock.get()
else: fromBlock
g.latestProcessedBlock = some(latestProcessedBlock)
let metadataSetRes = g.rlnInstance.setMetadata(RlnMetadata(
lastProcessedBlock: latestProcessedBlock))
let metadataSetRes = g.setMetadata()
if metadataSetRes.isErr():
# this is not a fatal error, hence we don't raise an exception
warn "failed to persist rln metadata", error=metadataSetRes.error()
Expand Down Expand Up @@ -465,17 +479,8 @@ method init*(g: OnchainGroupManager): Future[void] {.async.} =
let contractAddress = web3.fromHex(web3.Address, g.ethContractAddress)
contract = ethRpc.contractSender(RlnContract, contractAddress)

# check if the contract exists by calling a static function
var membershipFee: Uint256
try:
membershipFee = await contract.MEMBERSHIP_DEPOSIT().call()
except CatchableError:
raise newException(ValueError, "could not get the membership deposit: {}")


g.ethRpc = some(ethRpc)
g.rlnContract = some(contract)
g.membershipFee = some(membershipFee)

if g.keystorePath.isSome() and g.keystorePassword.isSome():
waku_rln_membership_credentials_import_duration_seconds.nanosecondTime:
Expand All @@ -498,8 +503,22 @@ method init*(g: OnchainGroupManager): Future[void] {.async.} =
g.latestProcessedBlock = some(BlockNumber(0))
else:
let metadata = metadataGetRes.get()
if metadata.chainId != uint64(g.chainId.get()):
raise newException(ValueError, "persisted data: chain id mismatch")

if metadata.contractAddress != g.ethContractAddress.toLower():
raise newException(ValueError, "persisted data: contract address mismatch")
g.latestProcessedBlock = some(metadata.lastProcessedBlock)

# check if the contract exists by calling a static function
var membershipFee: Uint256
try:
membershipFee = await contract.MEMBERSHIP_DEPOSIT().call()
except CatchableError:
raise newException(ValueError,
"could not get the membership deposit: " & getCurrentExceptionMsg())
g.membershipFee = some(membershipFee)

ethRpc.ondisconnect = proc() =
error "Ethereum client disconnected"
let fromBlock = g.latestProcessedBlock.get()
Expand Down
38 changes: 31 additions & 7 deletions waku/waku_rln_relay/rln/wrappers.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import
import
chronicles,
options,
stew/[arrayops, results],
eth/keys,
stew/[arrayops, byteutils, results, endians2],
std/[sequtils, strformat, strutils, tables],
nimcrypto/utils

import
Expand Down Expand Up @@ -120,7 +122,6 @@ proc createRLNInstance*(d = MerkleTreeDepth,

proc sha256*(data: openArray[byte]): RlnRelayResult[MerkleNode] =
## a thin layer on top of the Nim wrapper of the sha256 hasher
trace "sha256 hash input", hashhex = data.toHex()
var lenPrefData = encodeLengthPrefix(data)
var
hashInputBuffer = lenPrefData.toBuffer()
Expand Down Expand Up @@ -247,7 +248,7 @@ proc proofVerify*(rlnInstance: ptr RLN,
rootsBytes = serialize(validRoots)
rootsBuffer = rootsBytes.toBuffer()

trace "serialized proof", proof = proofBytes.toHex()
trace "serialized proof", proof = byteutils.toHex(proofBytes)

let verifyIsSuccessful = verify_with_roots(rlnInstance, addr proofBuffer, addr rootsBuffer, addr validProof)
if not verifyIsSuccessful:
Expand Down Expand Up @@ -350,11 +351,15 @@ proc getMerkleRoot*(rlnInstance: ptr RLN): MerkleNodeResult =
type
RlnMetadata* = object
lastProcessedBlock*: uint64
chainId*: uint64
contractAddress*: string

proc serialize(metadata: RlnMetadata): seq[byte] =
## serializes the metadata
## returns the serialized metadata
return @(metadata.lastProcessedBlock.toBytes())
return concat(@(metadata.lastProcessedBlock.toBytes()),
@(metadata.chainId.toBytes()),
@(hexToSeqByte(toLower(metadata.contractAddress))))

proc setMetadata*(rlnInstance: ptr RLN, metadata: RlnMetadata): RlnRelayResult[void] =
## sets the metadata of the RLN instance
Expand All @@ -368,6 +373,7 @@ proc setMetadata*(rlnInstance: ptr RLN, metadata: RlnMetadata): RlnRelayResult[v

# set the metadata
let metadataSet = set_metadata(rlnInstance, metadataBufferPtr)

if not metadataSet:
return err("could not set the metadata")
return ok()
Expand All @@ -384,8 +390,26 @@ proc getMetadata*(rlnInstance: ptr RLN): RlnRelayResult[RlnMetadata] =
getMetadataSuccessful = get_metadata(rlnInstance, metadataPtr)
if not getMetadataSuccessful:
return err("could not get the metadata")
if not metadata.len == 8:
if not metadata.len == 36:
return err("wrong output size")

var metadataValue = cast[ptr uint64] (metadata.`ptr`)[]
return ok(RlnMetadata(lastProcessedBlock: metadataValue))
let
lastProcessedBlockOffset = 0
chainIdOffset = lastProcessedBlockOffset + 8
contractAddressOffset = chainIdOffset + 8

var
lastProcessedBlock: uint64
chainId: uint64
contractAddress: string

var metadataValue = cast[ptr array[36, byte]] (metadata.`ptr`)
let metadataBytes: array[36, byte] = metadataValue[]

lastProcessedBlock = uint64.fromBytes(metadataBytes[lastProcessedBlockOffset..chainIdOffset-1])
chainId = uint64.fromBytes(metadataBytes[chainIdOffset..contractAddressOffset-1])
contractAddress = byteutils.toHex(metadataBytes[contractAddressOffset..metadataBytes.high])

return ok(RlnMetadata(lastProcessedBlock: lastProcessedBlock,
chainId: chainId,
contractAddress: "0x" & contractAddress))

0 comments on commit 1ae5b5a

Please sign in to comment.