Skip to content

Commit 4f97986

Browse files
committed
Merge branch 'chore/bump-wakurlnv2contract-repo-commit' into fix/pex-remove-enr-cache
2 parents e47a56d + a1b9715 commit 4f97986

File tree

5 files changed

+140
-59
lines changed

5 files changed

+140
-59
lines changed

tests/waku_rln_relay/anvil_state/state-deployed-contracts-mint-and-approved.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

tests/waku_rln_relay/test_rln_group_manager_onchain.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ suite "Onchain group manager":
3333
var manager {.threadVar.}: OnchainGroupManager
3434

3535
setup:
36-
anvilProc = runAnvil()
37-
manager = waitFor setupOnchainGroupManager()
36+
anvilProc = runAnvil(stateFile = some(DEFAULT_ANVIL_STATE_PATH))
37+
manager = waitFor setupOnchainGroupManager(deployContracts = false)
3838

3939
teardown:
4040
stopAnvil(anvilProc)

tests/waku_rln_relay/test_waku_rln_relay.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ suite "Waku rln relay":
2727
var manager {.threadVar.}: OnchainGroupManager
2828

2929
setup:
30-
anvilProc = runAnvil()
31-
manager = waitFor setupOnchainGroupManager()
30+
anvilProc = runAnvil(stateFile = some(DEFAULT_ANVIL_STATE_PATH))
31+
manager = waitFor setupOnchainGroupManager(deployContracts = false)
3232

3333
teardown:
3434
stopAnvil(anvilProc)

tests/waku_rln_relay/test_wakunode_rln_relay.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ procSuite "WakuNode - RLN relay":
3030
var manager {.threadVar.}: OnchainGroupManager
3131

3232
setup:
33-
anvilProc = runAnvil()
34-
manager = waitFor setupOnchainGroupManager()
33+
anvilProc = runAnvil(stateFile = some(DEFAULT_ANVIL_STATE_PATH))
34+
manager = waitFor setupOnchainGroupManager(deployContracts = false)
3535

3636
teardown:
3737
stopAnvil(anvilProc)

tests/waku_rln_relay/utils_onchain.nim

Lines changed: 133 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{.push raises: [].}
44

55
import
6-
std/[options, os, osproc, deques, streams, strutils, tempfiles, strformat],
6+
std/[options, os, osproc, streams, strutils, strformat],
77
results,
88
stew/byteutils,
99
testutils/unittests,
@@ -14,7 +14,6 @@ import
1414
web3/conversions,
1515
web3/eth_api_types,
1616
json_rpc/rpcclient,
17-
json,
1817
libp2p/crypto/crypto,
1918
eth/keys,
2019
results
@@ -24,25 +23,15 @@ import
2423
waku_rln_relay,
2524
waku_rln_relay/protocol_types,
2625
waku_rln_relay/constants,
27-
waku_rln_relay/contract,
2826
waku_rln_relay/rln,
2927
],
30-
../testlib/common,
31-
./utils
28+
../testlib/common
3229

3330
const CHAIN_ID* = 1234'u256
34-
35-
template skip0xPrefix(hexStr: string): int =
36-
## Returns the index of the first meaningful char in `hexStr` by skipping
37-
## "0x" prefix
38-
if hexStr.len > 1 and hexStr[0] == '0' and hexStr[1] in {'x', 'X'}: 2 else: 0
39-
40-
func strip0xPrefix(s: string): string =
41-
let prefixLen = skip0xPrefix(s)
42-
if prefixLen != 0:
43-
s[prefixLen .. ^1]
44-
else:
45-
s
31+
const DEFAULT_ANVIL_STATE_PATH* =
32+
"tests/waku_rln_relay/anvil_state/state-deployed-contracts-mint-and-approved.json"
33+
const TOKEN_ADDRESS* = "0x5FbDB2315678afecb367f032d93F642f64180aa3"
34+
const WAKU_RLNV2_PROXY_ADDRESS* = "0x5fc8d32690cc91d4c39d9d3abcbd16989f875707"
4635

4736
proc generateCredentials*(): IdentityCredential =
4837
let credRes = membershipKeyGen()
@@ -488,19 +477,26 @@ proc getAnvilPath*(): string =
488477
return $anvilPath
489478

490479
# Runs Anvil daemon
491-
proc runAnvil*(port: int = 8540, chainId: string = "1234"): Process =
480+
proc runAnvil*(
481+
port: int = 8540,
482+
chainId: string = "1234",
483+
stateFile: Option[string] = none(string),
484+
dumpStateOnExit: bool = false,
485+
): Process =
492486
# Passed options are
493487
# --port Port to listen on.
494488
# --gas-limit Sets the block gas limit in WEI.
495489
# --balance The default account balance, specified in ether.
496490
# --chain-id Chain ID of the network.
491+
# --load-state Initialize the chain from a previously saved state snapshot (read-only)
492+
# --dump-state Dump the state on exit to the given file (write-only)
497493
# See anvil documentation https://book.getfoundry.sh/reference/anvil/ for more details
498494
try:
499495
let anvilPath = getAnvilPath()
500496
info "Anvil path", anvilPath
501-
let runAnvil = startProcess(
502-
anvilPath,
503-
args = [
497+
498+
var args =
499+
@[
504500
"--port",
505501
$port,
506502
"--gas-limit",
@@ -509,9 +505,45 @@ proc runAnvil*(port: int = 8540, chainId: string = "1234"): Process =
509505
"1000000000",
510506
"--chain-id",
511507
$chainId,
512-
],
513-
options = {poUsePath, poStdErrToStdOut},
514-
)
508+
]
509+
510+
# Add state file argument if provided
511+
if stateFile.isSome():
512+
let statePath = stateFile.get()
513+
info "State file parameter provided",
514+
statePath = statePath,
515+
dumpStateOnExit = dumpStateOnExit,
516+
absolutePath = absolutePath(statePath)
517+
518+
# Ensure the directory exists
519+
let stateDir = parentDir(statePath)
520+
if not dirExists(stateDir):
521+
info "Creating state directory", dir = stateDir
522+
createDir(stateDir)
523+
524+
# Use --load-state (read-only) when we want to use cached state without modifying it
525+
# Use --dump-state (write-only) when we want to create a new cache from fresh deployment
526+
if dumpStateOnExit:
527+
# Fresh deployment: start clean and dump state on exit
528+
args.add("--dump-state")
529+
args.add(statePath)
530+
debug "Anvil configured to dump state on exit", path = statePath
531+
else:
532+
# Using cache: only load state, don't overwrite it (preserves clean cached state)
533+
if fileExists(statePath):
534+
args.add("--load-state")
535+
args.add(statePath)
536+
debug "Anvil configured to load state file (read-only)", path = statePath
537+
else:
538+
warn "State file does not exist, anvil will start fresh",
539+
path = statePath, absolutePath = absolutePath(statePath)
540+
else:
541+
info "No state file provided, anvil will start fresh without state persistence"
542+
543+
info "Starting anvil with arguments", args = args.join(" ")
544+
545+
let runAnvil =
546+
startProcess(anvilPath, args = args, options = {poUsePath, poStdErrToStdOut})
515547
let anvilPID = runAnvil.processID
516548

517549
# We read stdout from Anvil to see when daemon is ready
@@ -560,52 +592,100 @@ proc stopAnvil*(runAnvil: Process) {.used.} =
560592
info "Error stopping Anvil daemon", anvilPID = anvilPID, error = e.msg
561593

562594
proc setupOnchainGroupManager*(
563-
ethClientUrl: string = EthClient, amountEth: UInt256 = 10.u256
595+
ethClientUrl: string = EthClient,
596+
amountEth: UInt256 = 10.u256,
597+
deployContracts: bool = true,
564598
): Future[OnchainGroupManager] {.async.} =
599+
## Setup an onchain group manager for testing
600+
## If deployContracts is false, it will assume that the Anvil testnet already has the required contracts deployed, this significantly speeds up test runs.
601+
## To run Anvil with a cached state file containing pre-deployed contracts, see runAnvil documentation.
602+
##
603+
## To generate/update the cached state file:
604+
## 1. Call runAnvil with stateFile and dumpStateOnExit=true
605+
## 2. Run setupOnchainGroupManager with deployContracts=true to deploy contracts
606+
## 3. The state will be saved to the specified file when anvil exits
607+
## 4. Commit this file to git
608+
##
609+
## To use cached state:
610+
## 1. Call runAnvil with stateFile and dumpStateOnExit=false
611+
## 2. Anvil loads state in read-only mode (won't overwrite the cached file)
612+
## 3. Call setupOnchainGroupManager with deployContracts=false
613+
## 4. Tests run fast using pre-deployed contracts
565614
let rlnInstanceRes = createRlnInstance()
566615
check:
567616
rlnInstanceRes.isOk()
568617

569618
let rlnInstance = rlnInstanceRes.get()
570619

571-
# connect to the eth client
572620
let web3 = await newWeb3(ethClientUrl)
573621
let accounts = await web3.provider.eth_accounts()
574622
web3.defaultAccount = accounts[1]
575623

576-
let (privateKey, acc) = createEthAccount(web3)
624+
var privateKey: keys.PrivateKey
625+
var acc: Address
626+
var testTokenAddress: Address
627+
var contractAddress: Address
577628

578-
# we just need to fund the default account
579-
# the send procedure returns a tx hash that we don't use, hence discard
580-
discard await sendEthTransfer(
581-
web3, web3.defaultAccount, acc, ethToWei(1000.u256), some(0.u256)
582-
)
629+
if not deployContracts:
630+
info "Using contract addresses from constants"
583631

584-
let testTokenAddress = (await deployTestToken(privateKey, acc, web3)).valueOr:
585-
assert false, "Failed to deploy test token contract: " & $error
586-
return
632+
testTokenAddress = Address(hexToByteArray[20](TOKEN_ADDRESS))
633+
contractAddress = Address(hexToByteArray[20](WAKU_RLNV2_PROXY_ADDRESS))
587634

588-
# mint the token from the generated account
589-
discard await sendMintCall(
590-
web3, web3.defaultAccount, testTokenAddress, acc, ethToWei(1000.u256), some(0.u256)
591-
)
635+
(privateKey, acc) = createEthAccount(web3)
592636

593-
let contractAddress = (await executeForgeContractDeployScripts(privateKey, acc, web3)).valueOr:
594-
assert false, "Failed to deploy RLN contract: " & $error
595-
return
637+
# Fund the test account
638+
discard await sendEthTransfer(web3, web3.defaultAccount, acc, ethToWei(1000.u256))
596639

597-
# If the generated account wishes to register a membership, it needs to approve the contract to spend its tokens
598-
let tokenApprovalResult = await approveTokenAllowanceAndVerify(
599-
web3,
600-
acc,
601-
privateKey,
602-
testTokenAddress,
603-
contractAddress,
604-
ethToWei(200.u256),
605-
some(0.u256),
606-
)
640+
# Mint tokens to the test account
641+
discard await sendMintCall(
642+
web3, web3.defaultAccount, testTokenAddress, acc, ethToWei(1000.u256)
643+
)
644+
645+
# Approve the contract to spend tokens
646+
let tokenApprovalResult = await approveTokenAllowanceAndVerify(
647+
web3, acc, privateKey, testTokenAddress, contractAddress, ethToWei(200.u256)
648+
)
649+
assert tokenApprovalResult.isOk, tokenApprovalResult.error()
650+
else:
651+
info "Performing Token and RLN contracts deployment"
652+
(privateKey, acc) = createEthAccount(web3)
653+
654+
# fund the default account
655+
discard await sendEthTransfer(
656+
web3, web3.defaultAccount, acc, ethToWei(1000.u256), some(0.u256)
657+
)
658+
659+
testTokenAddress = (await deployTestToken(privateKey, acc, web3)).valueOr:
660+
assert false, "Failed to deploy test token contract: " & $error
661+
return
662+
663+
# mint the token from the generated account
664+
discard await sendMintCall(
665+
web3,
666+
web3.defaultAccount,
667+
testTokenAddress,
668+
acc,
669+
ethToWei(1000.u256),
670+
some(0.u256),
671+
)
672+
673+
contractAddress = (await executeForgeContractDeployScripts(privateKey, acc, web3)).valueOr:
674+
assert false, "Failed to deploy RLN contract: " & $error
675+
return
676+
677+
# If the generated account wishes to register a membership, it needs to approve the contract to spend its tokens
678+
let tokenApprovalResult = await approveTokenAllowanceAndVerify(
679+
web3,
680+
acc,
681+
privateKey,
682+
testTokenAddress,
683+
contractAddress,
684+
ethToWei(200.u256),
685+
some(0.u256),
686+
)
607687

608-
assert tokenApprovalResult.isOk, tokenApprovalResult.error()
688+
assert tokenApprovalResult.isOk, tokenApprovalResult.error()
609689

610690
let manager = OnchainGroupManager(
611691
ethClientUrls: @[ethClientUrl],

0 commit comments

Comments
 (0)