fix(rln-relay): window of acceptable roots synced to rln metadata (#1953)

* fix(rln-relay): window of acceptable roots synced to rln metadata

* fix(rln-relay): s/var/let, use for loop
This commit is contained in:
Aaryamann Challani 2023-08-25 23:29:17 +05:30 committed by GitHub
parent cc9f8d4254
commit 01634f57f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 25 deletions

View File

@ -6,7 +6,7 @@ else:
{.push raises: [].}
import
std/[options, osproc, streams, strutils, tempfiles],
std/[options, osproc, sequtils, deques, streams, strutils, tempfiles],
stew/[results, byteutils],
stew/shims/net as stewNet,
testutils/unittests,
@ -351,6 +351,9 @@ suite "Onchain group manager":
await fut
check:
manager.rlnInstance.getMetadata().get().validRoots == manager.validRoots.toSeq()
asyncTest "withdraw: should guard against uninitialized state":
let manager = await setup()
let idSecretHash = generateCredentials(manager.rlnInstance).idSecretHash

View File

@ -75,6 +75,22 @@ template initializedGuard(g: OnchainGroupManager): untyped =
if not g.initialized:
raise newException(ValueError, "OnchainGroupManager is not initialized")
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,
validRoots: g.validRoots.toSeq()))
if metadataSetRes.isErr():
return err("failed to persist rln metadata: " & metadataSetRes.error)
except CatchableError:
return err("failed to persist rln metadata: " & getCurrentExceptionMsg())
return ok()
method atomicBatch*(g: OnchainGroupManager,
start: MembershipIndex,
idCommitments = newSeq[IDCommitment](),
@ -91,12 +107,15 @@ method atomicBatch*(g: OnchainGroupManager,
var membersSeq = newSeq[Membership]()
for i in 0 ..< idCommitments.len():
var index = start + MembershipIndex(i)
debug "registering member", idCommitment = idCommitments[i], index = index
trace "registering member", idCommitment = idCommitments[i], index = index
let member = Membership(idCommitment: idCommitments[i], index: index)
membersSeq.add(member)
await g.registerCb.get()(membersSeq)
g.validRootBuffer = g.slideRootQueue()
let setMetadataRes = g.setMetadata()
if setMetadataRes.isErr():
error "failed to persist rln metadata", error=setMetadataRes.error
method register*(g: OnchainGroupManager, idCommitment: IDCommitment): Future[void] {.async.} =
initializedGuard(g)
@ -286,20 +305,6 @@ 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.} =
@ -317,7 +322,7 @@ proc getAndHandleEvents(g: OnchainGroupManager,
# this is not a fatal error, hence we don't raise an exception
warn "failed to persist rln metadata", error=metadataSetRes.error()
else:
debug "rln metadata persisted", blockNumber = latestProcessedBlock
trace "rln metadata persisted", blockNumber = latestProcessedBlock
proc getNewHeadCallback(g: OnchainGroupManager): BlockHeaderHandler =
proc newHeadCallback(blockheader: BlockHeader) {.gcsafe.} =
@ -461,6 +466,7 @@ method init*(g: OnchainGroupManager): Future[void] {.async.} =
if metadata.contractAddress != g.ethContractAddress.toLower():
raise newException(ValueError, "persisted data: contract address mismatch")
g.latestProcessedBlock = some(metadata.lastProcessedBlock)
g.validRoots = metadata.validRoots.toDeque()
# check if the contract exists by calling a static function
var membershipFee: Uint256

View File

@ -353,13 +353,36 @@ type
lastProcessedBlock*: uint64
chainId*: uint64
contractAddress*: string
validRoots*: seq[MerkleNode]
proc serialize(metadata: RlnMetadata): seq[byte] =
## serializes the metadata
## returns the serialized metadata
return concat(@(metadata.lastProcessedBlock.toBytes()),
@(metadata.chainId.toBytes()),
@(hexToSeqByte(toLower(metadata.contractAddress))))
@(hexToSeqByte(toLower(metadata.contractAddress))),
@(uint64(metadata.validRoots.len()).toBytes()),
@(serialize(metadata.validRoots)))
type MerkleNodeSeq = seq[MerkleNode]
proc deserialize*(T: type MerkleNodeSeq, merkleNodeByteSeq: seq[byte]): T =
## deserializes a byte seq to a seq of MerkleNodes
## the order of serialization is |merkle_node_len<8>|merkle_node[len]|
var roots = newSeq[MerkleNode]()
var i = 1'u64
let len = uint64.fromBytes(merkleNodeByteSeq[0..7], Endianness.littleEndian)
trace "length of valid roots", len
let offset = 8'u64
for i in 1'u64..len:
# convert seq[byte] to array[32, byte]
let rawRoot = merkleNodeByteSeq[offset*i .. offset*i + 31]
trace "raw root", rawRoot = rawRoot
var root: MerkleNode
discard root.copyFrom(rawRoot)
roots.add(root)
return roots
proc setMetadata*(rlnInstance: ptr RLN, metadata: RlnMetadata): RlnRelayResult[void] =
## sets the metadata of the RLN instance
@ -368,6 +391,7 @@ proc setMetadata*(rlnInstance: ptr RLN, metadata: RlnMetadata): RlnRelayResult[v
# serialize the metadata
let metadataBytes = serialize(metadata)
trace "setting metadata", metadata = metadata, metadataBytes = metadataBytes, len = metadataBytes.len
var metadataBuffer = metadataBytes.toBuffer()
let metadataBufferPtr = addr metadataBuffer
@ -390,26 +414,31 @@ 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 == 36:
return err("wrong output size")
trace "metadata length", metadataLen = metadata.len
let
lastProcessedBlockOffset = 0
chainIdOffset = lastProcessedBlockOffset + 8
contractAddressOffset = chainIdOffset + 8
validRootsOffset = contractAddressOffset + 20
var
lastProcessedBlock: uint64
chainId: uint64
contractAddress: string
validRoots: MerkleNodeSeq
var metadataValue = cast[ptr array[36, byte]] (metadata.`ptr`)
let metadataBytes: array[36, byte] = metadataValue[]
# 8 + 8 + 20 + 8 + (5*32) = 204
var metadataBytes = cast[ptr array[204, byte]](metadata.`ptr`)[]
trace "received metadata bytes", metadataBytes = metadataBytes, len = metadataBytes.len
lastProcessedBlock = uint64.fromBytes(metadataBytes[lastProcessedBlockOffset..chainIdOffset-1])
chainId = uint64.fromBytes(metadataBytes[chainIdOffset..contractAddressOffset-1])
contractAddress = byteutils.toHex(metadataBytes[contractAddressOffset..metadataBytes.high])
contractAddress = byteutils.toHex(metadataBytes[contractAddressOffset..validRootsOffset - 1])
let validRootsBytes = metadataBytes[validRootsOffset..metadataBytes.high]
validRoots = MerkleNodeSeq.deserialize(validRootsBytes)
return ok(RlnMetadata(lastProcessedBlock: lastProcessedBlock,
chainId: chainId,
contractAddress: "0x" & contractAddress))
contractAddress: "0x" & contractAddress,
validRoots: validRoots))