mirror of https://github.com/waku-org/nwaku.git
fix(rln-relay): RLN DB should be aware of chain and contract address (#1932)
This commit is contained in:
parent
c9b48ea1a0
commit
1ae5b5a951
|
@ -197,6 +197,29 @@ suite "Onchain group manager":
|
||||||
manager.membershipFee.isSome()
|
manager.membershipFee.isSome()
|
||||||
manager.initialized
|
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":
|
asyncTest "startGroupSync: should start group sync":
|
||||||
let manager = await setup()
|
let manager = await setup()
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,9 @@ suite "Waku rln relay":
|
||||||
rlnInstance.isOk()
|
rlnInstance.isOk()
|
||||||
let rln = rlnInstance.get()
|
let rln = rlnInstance.get()
|
||||||
check:
|
check:
|
||||||
rln.setMetadata(RlnMetadata(lastProcessedBlock: 128)).isOk()
|
rln.setMetadata(RlnMetadata(lastProcessedBlock: 128,
|
||||||
|
chainId: 1155511,
|
||||||
|
contractAddress: "0x9c09146844c1326c2dbc41c451766c7138f88155")).isOk()
|
||||||
|
|
||||||
test "getMetadata rln utils":
|
test "getMetadata rln utils":
|
||||||
# create an RLN instance which also includes an empty Merkle tree
|
# create an RLN instance which also includes an empty Merkle tree
|
||||||
|
@ -255,7 +257,9 @@ suite "Waku rln relay":
|
||||||
let rln = rlnInstance.get()
|
let rln = rlnInstance.get()
|
||||||
|
|
||||||
require:
|
require:
|
||||||
rln.setMetadata(RlnMetadata(lastProcessedBlock: 128)).isOk()
|
rln.setMetadata(RlnMetadata(lastProcessedBlock: 128,
|
||||||
|
chainId: 1155511,
|
||||||
|
contractAddress: "0x9c09146844c1326c2dbc41c451766c7138f88155")).isOk()
|
||||||
|
|
||||||
let metadataRes = rln.getMetadata()
|
let metadataRes = rln.getMetadata()
|
||||||
|
|
||||||
|
@ -266,7 +270,8 @@ suite "Waku rln relay":
|
||||||
|
|
||||||
check:
|
check:
|
||||||
metadata.lastProcessedBlock == 128
|
metadata.lastProcessedBlock == 128
|
||||||
|
metadata.chainId == 1155511
|
||||||
|
metadata.contractAddress == "0x9c09146844c1326c2dbc41c451766c7138f88155"
|
||||||
|
|
||||||
test "Merkle tree consistency check between deletion and insertion":
|
test "Merkle tree consistency check between deletion and insertion":
|
||||||
# create an RLN instance
|
# create an RLN instance
|
||||||
|
|
|
@ -12,7 +12,8 @@ import
|
||||||
json,
|
json,
|
||||||
std/tables,
|
std/tables,
|
||||||
stew/[byteutils, arrayops],
|
stew/[byteutils, arrayops],
|
||||||
sequtils
|
sequtils,
|
||||||
|
strutils
|
||||||
import
|
import
|
||||||
../../../waku_keystore,
|
../../../waku_keystore,
|
||||||
../../rln,
|
../../rln,
|
||||||
|
@ -281,6 +282,20 @@ proc handleRemovedEvents(g: OnchainGroupManager, blockTable: BlockTable): Future
|
||||||
|
|
||||||
await g.backfillRootQueue(numRemovedBlocks)
|
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,
|
proc getAndHandleEvents(g: OnchainGroupManager,
|
||||||
fromBlock: BlockNumber,
|
fromBlock: BlockNumber,
|
||||||
toBlock: Option[BlockNumber] = none(BlockNumber)): Future[void] {.async.} =
|
toBlock: Option[BlockNumber] = none(BlockNumber)): Future[void] {.async.} =
|
||||||
|
@ -293,8 +308,7 @@ proc getAndHandleEvents(g: OnchainGroupManager,
|
||||||
let latestProcessedBlock = if toBlock.isSome(): toBlock.get()
|
let latestProcessedBlock = if toBlock.isSome(): toBlock.get()
|
||||||
else: fromBlock
|
else: fromBlock
|
||||||
g.latestProcessedBlock = some(latestProcessedBlock)
|
g.latestProcessedBlock = some(latestProcessedBlock)
|
||||||
let metadataSetRes = g.rlnInstance.setMetadata(RlnMetadata(
|
let metadataSetRes = g.setMetadata()
|
||||||
lastProcessedBlock: latestProcessedBlock))
|
|
||||||
if metadataSetRes.isErr():
|
if metadataSetRes.isErr():
|
||||||
# this is not a fatal error, hence we don't raise an exception
|
# this is not a fatal error, hence we don't raise an exception
|
||||||
warn "failed to persist rln metadata", error=metadataSetRes.error()
|
warn "failed to persist rln metadata", error=metadataSetRes.error()
|
||||||
|
@ -465,17 +479,8 @@ method init*(g: OnchainGroupManager): Future[void] {.async.} =
|
||||||
let contractAddress = web3.fromHex(web3.Address, g.ethContractAddress)
|
let contractAddress = web3.fromHex(web3.Address, g.ethContractAddress)
|
||||||
contract = ethRpc.contractSender(RlnContract, contractAddress)
|
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.ethRpc = some(ethRpc)
|
||||||
g.rlnContract = some(contract)
|
g.rlnContract = some(contract)
|
||||||
g.membershipFee = some(membershipFee)
|
|
||||||
|
|
||||||
if g.keystorePath.isSome() and g.keystorePassword.isSome():
|
if g.keystorePath.isSome() and g.keystorePassword.isSome():
|
||||||
waku_rln_membership_credentials_import_duration_seconds.nanosecondTime:
|
waku_rln_membership_credentials_import_duration_seconds.nanosecondTime:
|
||||||
|
@ -498,8 +503,22 @@ method init*(g: OnchainGroupManager): Future[void] {.async.} =
|
||||||
g.latestProcessedBlock = some(BlockNumber(0))
|
g.latestProcessedBlock = some(BlockNumber(0))
|
||||||
else:
|
else:
|
||||||
let metadata = metadataGetRes.get()
|
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)
|
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() =
|
ethRpc.ondisconnect = proc() =
|
||||||
error "Ethereum client disconnected"
|
error "Ethereum client disconnected"
|
||||||
let fromBlock = g.latestProcessedBlock.get()
|
let fromBlock = g.latestProcessedBlock.get()
|
||||||
|
|
|
@ -3,7 +3,9 @@ import
|
||||||
import
|
import
|
||||||
chronicles,
|
chronicles,
|
||||||
options,
|
options,
|
||||||
stew/[arrayops, results],
|
eth/keys,
|
||||||
|
stew/[arrayops, byteutils, results, endians2],
|
||||||
|
std/[sequtils, strformat, strutils, tables],
|
||||||
nimcrypto/utils
|
nimcrypto/utils
|
||||||
|
|
||||||
import
|
import
|
||||||
|
@ -120,7 +122,6 @@ proc createRLNInstance*(d = MerkleTreeDepth,
|
||||||
|
|
||||||
proc sha256*(data: openArray[byte]): RlnRelayResult[MerkleNode] =
|
proc sha256*(data: openArray[byte]): RlnRelayResult[MerkleNode] =
|
||||||
## a thin layer on top of the Nim wrapper of the sha256 hasher
|
## 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 lenPrefData = encodeLengthPrefix(data)
|
||||||
var
|
var
|
||||||
hashInputBuffer = lenPrefData.toBuffer()
|
hashInputBuffer = lenPrefData.toBuffer()
|
||||||
|
@ -247,7 +248,7 @@ proc proofVerify*(rlnInstance: ptr RLN,
|
||||||
rootsBytes = serialize(validRoots)
|
rootsBytes = serialize(validRoots)
|
||||||
rootsBuffer = rootsBytes.toBuffer()
|
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)
|
let verifyIsSuccessful = verify_with_roots(rlnInstance, addr proofBuffer, addr rootsBuffer, addr validProof)
|
||||||
if not verifyIsSuccessful:
|
if not verifyIsSuccessful:
|
||||||
|
@ -350,11 +351,15 @@ proc getMerkleRoot*(rlnInstance: ptr RLN): MerkleNodeResult =
|
||||||
type
|
type
|
||||||
RlnMetadata* = object
|
RlnMetadata* = object
|
||||||
lastProcessedBlock*: uint64
|
lastProcessedBlock*: uint64
|
||||||
|
chainId*: uint64
|
||||||
|
contractAddress*: string
|
||||||
|
|
||||||
proc serialize(metadata: RlnMetadata): seq[byte] =
|
proc serialize(metadata: RlnMetadata): seq[byte] =
|
||||||
## serializes the metadata
|
## serializes the metadata
|
||||||
## returns the serialized 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] =
|
proc setMetadata*(rlnInstance: ptr RLN, metadata: RlnMetadata): RlnRelayResult[void] =
|
||||||
## sets the metadata of the RLN instance
|
## sets the metadata of the RLN instance
|
||||||
|
@ -368,6 +373,7 @@ proc setMetadata*(rlnInstance: ptr RLN, metadata: RlnMetadata): RlnRelayResult[v
|
||||||
|
|
||||||
# set the metadata
|
# set the metadata
|
||||||
let metadataSet = set_metadata(rlnInstance, metadataBufferPtr)
|
let metadataSet = set_metadata(rlnInstance, metadataBufferPtr)
|
||||||
|
|
||||||
if not metadataSet:
|
if not metadataSet:
|
||||||
return err("could not set the metadata")
|
return err("could not set the metadata")
|
||||||
return ok()
|
return ok()
|
||||||
|
@ -384,8 +390,26 @@ proc getMetadata*(rlnInstance: ptr RLN): RlnRelayResult[RlnMetadata] =
|
||||||
getMetadataSuccessful = get_metadata(rlnInstance, metadataPtr)
|
getMetadataSuccessful = get_metadata(rlnInstance, metadataPtr)
|
||||||
if not getMetadataSuccessful:
|
if not getMetadataSuccessful:
|
||||||
return err("could not get the metadata")
|
return err("could not get the metadata")
|
||||||
if not metadata.len == 8:
|
if not metadata.len == 36:
|
||||||
return err("wrong output size")
|
return err("wrong output size")
|
||||||
|
|
||||||
var metadataValue = cast[ptr uint64] (metadata.`ptr`)[]
|
let
|
||||||
return ok(RlnMetadata(lastProcessedBlock: metadataValue))
|
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))
|
||||||
|
|
Loading…
Reference in New Issue