mirror of
https://github.com/logos-messaging/logos-delivery.git
synced 2026-07-19 11:09:26 +00:00
Bake funded test account into cached Anvil state
Introduce FUNDED_TEST_PRIVATE_KEY and regenerate the cached Anvil state so the account is already funded, holds minted test tokens and has the RLN contract allowance approved. setupOnchainGroupManager with deployContracts=false now short-circuits to buildOnchainGroupManager with that key: no per-run fund/mint/approve transactions or sleeps. The state regeneration flow (test_rln_contract_deployment) funds the fixed key, so regenerated state stays compatible with the constant. Deployed contract addresses are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
77cb8a6c7a
commit
be9cf1b2ad
Binary file not shown.
@ -29,17 +29,16 @@ import
|
||||
../testlib/wakucore,
|
||||
./utils_onchain
|
||||
|
||||
# Anvil is started once for the whole suite. The first test runs the full
|
||||
# `setupOnchainGroupManager` flow (fund a fresh account + mint tokens + approve
|
||||
# allowance) and then takes a baseline snapshot capturing that post-setup chain
|
||||
# state. Subsequent tests revert to the baseline (restoring the funded account)
|
||||
# and build a bare manager pointing at the same key. evm_revert consumes the snapshot
|
||||
# ID, so we re-snapshot after every revert. Cleanup is registered via
|
||||
# Anvil is started once for the whole suite from the cached state file, which
|
||||
# already contains the deployed RLN contracts and the funded, token-approved
|
||||
# FUNDED_TEST_PRIVATE_KEY account — no per-run on-chain setup is needed. A
|
||||
# baseline snapshot is taken right after startup; every test reverts to it and
|
||||
# builds a bare manager pointing at the baked-in key. evm_revert consumes the
|
||||
# snapshot ID, so we re-snapshot after every revert. Cleanup is registered via
|
||||
# addExitProc so anvil is terminated when the test binary exits.
|
||||
var sharedAnvilProc: Process
|
||||
var anvilStarted: bool = false
|
||||
var baselineSnapshotId: string
|
||||
var fundedPrivateKey: string
|
||||
|
||||
suite "Onchain group manager":
|
||||
var manager {.threadVar.}: OnchainGroupManager
|
||||
@ -53,13 +52,10 @@ suite "Onchain group manager":
|
||||
if not sharedAnvilProc.isNil:
|
||||
stopAnvil(sharedAnvilProc)
|
||||
)
|
||||
manager = waitFor setupOnchainGroupManager(deployContracts = false)
|
||||
fundedPrivateKey = manager.ethPrivateKey.get()
|
||||
baselineSnapshotId = waitFor takeEvmSnapshot()
|
||||
else:
|
||||
discard waitFor revertEvmSnapshot(baselineSnapshotId)
|
||||
baselineSnapshotId = waitFor takeEvmSnapshot()
|
||||
manager = buildOnchainGroupManager(fundedPrivateKey)
|
||||
baselineSnapshotId = waitFor takeEvmSnapshot()
|
||||
manager = buildOnchainGroupManager(FUNDED_TEST_PRIVATE_KEY)
|
||||
|
||||
test "should initialize successfully":
|
||||
(waitFor manager.init()).isOkOr:
|
||||
|
||||
@ -31,6 +31,15 @@ const DEFAULT_ANVIL_STATE_PATH* =
|
||||
const TOKEN_ADDRESS* = "0x5FbDB2315678afecb367f032d93F642f64180aa3"
|
||||
const WAKU_RLNV2_PROXY_ADDRESS* = "0x5fc8d32690cc91d4c39d9d3abcbd16989f875707"
|
||||
|
||||
# Private key of the account baked into DEFAULT_ANVIL_STATE_PATH. The state
|
||||
# regeneration flow (test_rln_contract_deployment.nim) funds this exact account
|
||||
# with ETH, mints test tokens to it and approves the RLN contract allowance, so
|
||||
# tests that load the cached state can use it directly without any per-run
|
||||
# on-chain setup. Using a fixed key also makes the deployed contract addresses
|
||||
# deterministic across state regenerations.
|
||||
const FUNDED_TEST_PRIVATE_KEY* =
|
||||
"1111111111111111111111111111111111111111111111111111111111111111"
|
||||
|
||||
proc generateCredentials*(): IdentityCredential =
|
||||
let credRes = membershipKeyGen()
|
||||
return credRes.get()
|
||||
@ -639,128 +648,14 @@ proc stopAnvil*(runAnvil: Process) {.used.} =
|
||||
except Exception as e:
|
||||
error "Error stopping Anvil daemon", anvilPID = anvilPID, error = e.msg
|
||||
|
||||
proc setupOnchainGroupManager*(
|
||||
ethClientUrl: string = EthClient,
|
||||
amountEth: UInt256 = 10.u256,
|
||||
deployContracts: bool = true,
|
||||
): Future[OnchainGroupManager] {.async.} =
|
||||
## Setup an onchain group manager for testing
|
||||
## If deployContracts is false, it will assume that the Anvil testnet already has the required contracts deployed, this significantly speeds up test runs.
|
||||
## To run Anvil with a cached state file containing pre-deployed contracts, see runAnvil documentation.
|
||||
##
|
||||
## To generate/update the cached state file:
|
||||
## 1. Call runAnvil with stateFile and dumpStateOnExit=true
|
||||
## 2. Run setupOnchainGroupManager with deployContracts=true to deploy contracts
|
||||
## 3. The state will be saved to the specified file when anvil exits
|
||||
## 4. Commit this file to git
|
||||
##
|
||||
## To use cached state:
|
||||
## 1. Call runAnvil with stateFile and dumpStateOnExit=false
|
||||
## 2. Anvil loads state in read-only mode (won't overwrite the cached file)
|
||||
## 3. Call setupOnchainGroupManager with deployContracts=false
|
||||
## 4. Tests run fast using pre-deployed contracts
|
||||
let rlnInstanceRes = createRlnInstance()
|
||||
check:
|
||||
rlnInstanceRes.isOk()
|
||||
|
||||
let rlnInstance = rlnInstanceRes.get()
|
||||
|
||||
var web3 = await newWeb3(ethClientUrl)
|
||||
let accounts = await web3.provider.eth_accounts()
|
||||
web3.defaultAccount = accounts[1]
|
||||
|
||||
var privateKey: keys.PrivateKey
|
||||
var acc: Address
|
||||
var testTokenAddress: Address
|
||||
var contractAddress: Address
|
||||
|
||||
if not deployContracts:
|
||||
debug "Using contract addresses from constants"
|
||||
|
||||
testTokenAddress = Address(hexToByteArray[20](TOKEN_ADDRESS))
|
||||
contractAddress = Address(hexToByteArray[20](WAKU_RLNV2_PROXY_ADDRESS))
|
||||
|
||||
(privateKey, acc) = createEthAccount(web3)
|
||||
|
||||
discard await sendEthTransfer(web3, web3.defaultAccount, acc, ethToWei(1000.u256))
|
||||
|
||||
await sendMintCall(
|
||||
web3, web3.defaultAccount, testTokenAddress, acc, ethToWei(1000.u256)
|
||||
)
|
||||
|
||||
let tokenApprovalResult = await approveTokenAllowanceAndVerify(
|
||||
web3, acc, privateKey, testTokenAddress, contractAddress, ethToWei(2000.u256)
|
||||
)
|
||||
assert tokenApprovalResult.isOk(), tokenApprovalResult.error
|
||||
else:
|
||||
debug "Performing Token and RLN contracts deployment"
|
||||
(privateKey, acc) = createEthAccount(web3)
|
||||
|
||||
discard await sendEthTransfer(
|
||||
web3, web3.defaultAccount, acc, ethToWei(1000.u256), some(0.u256)
|
||||
)
|
||||
|
||||
testTokenAddress = (await deployTestToken(privateKey, acc, web3)).valueOr:
|
||||
assert false, "Failed to deploy test token contract: " & $error
|
||||
return
|
||||
|
||||
await sendMintCall(
|
||||
web3,
|
||||
web3.defaultAccount,
|
||||
testTokenAddress,
|
||||
acc,
|
||||
ethToWei(1000.u256),
|
||||
some(0.u256),
|
||||
)
|
||||
|
||||
contractAddress = (await executeForgeContractDeployScripts(privateKey, acc, web3)).valueOr:
|
||||
assert false, "Failed to deploy RLN contract: " & $error
|
||||
return
|
||||
|
||||
# `executeForgeContractDeployScripts` shells out to `forge` via blocking
|
||||
# `execCmdEx` calls (many seconds). While those run the chronos event loop
|
||||
# is frozen and the existing web3 HTTP connection to Anvil rots; the next
|
||||
# eth_call fails with "Not connected". Reconnect before continuing.
|
||||
try:
|
||||
await web3.close()
|
||||
except CatchableError:
|
||||
discard
|
||||
web3 = await newWeb3(ethClientUrl)
|
||||
web3.defaultAccount = accounts[1]
|
||||
|
||||
let tokenApprovalResult = await approveTokenAllowanceAndVerify(
|
||||
web3,
|
||||
acc,
|
||||
privateKey,
|
||||
testTokenAddress,
|
||||
contractAddress,
|
||||
ethToWei(2000.u256),
|
||||
some(0.u256),
|
||||
)
|
||||
|
||||
assert tokenApprovalResult.isOk(), tokenApprovalResult.error
|
||||
|
||||
let manager = OnchainGroupManager(
|
||||
ethClientUrls: @[ethClientUrl],
|
||||
ethContractAddress: $contractAddress,
|
||||
chainId: CHAIN_ID,
|
||||
ethPrivateKey: some($privateKey),
|
||||
rlnInstance: rlnInstance,
|
||||
onFatalErrorAction: proc(errStr: string) =
|
||||
raiseAssert errStr
|
||||
,
|
||||
)
|
||||
|
||||
return manager
|
||||
|
||||
proc buildOnchainGroupManager*(
|
||||
privateKey: string, ethClientUrl: string = EthClient
|
||||
privateKey: string = FUNDED_TEST_PRIVATE_KEY, ethClientUrl: string = EthClient
|
||||
): OnchainGroupManager =
|
||||
## Constructs an OnchainGroupManager pointing at the cached RLN proxy contract
|
||||
## using the supplied private key. No on-chain work happens here — the caller
|
||||
## is expected to have an Anvil snapshot where this key already owns a funded,
|
||||
## token-approved account (e.g. via a prior `setupOnchainGroupManager` followed
|
||||
## by `takeEvmSnapshot`). Each call returns a fresh RLN instance.
|
||||
## is expected to run Anvil from a state where this key already owns a funded,
|
||||
## token-approved account (the cached DEFAULT_ANVIL_STATE_PATH state provides
|
||||
## this for FUNDED_TEST_PRIVATE_KEY). Each call returns a fresh RLN instance.
|
||||
let rlnInstanceRes = createRlnInstance()
|
||||
check:
|
||||
rlnInstanceRes.isOk()
|
||||
@ -775,4 +670,98 @@ proc buildOnchainGroupManager*(
|
||||
,
|
||||
)
|
||||
|
||||
proc setupOnchainGroupManager*(
|
||||
ethClientUrl: string = EthClient,
|
||||
amountEth: UInt256 = 10.u256,
|
||||
deployContracts: bool = true,
|
||||
): Future[OnchainGroupManager] {.async.} =
|
||||
## Setup an onchain group manager for testing
|
||||
## If deployContracts is false, it assumes the Anvil testnet was started from
|
||||
## the cached state file (DEFAULT_ANVIL_STATE_PATH), which already contains the
|
||||
## deployed contracts and the funded, token-approved FUNDED_TEST_PRIVATE_KEY
|
||||
## account — no on-chain setup happens at all.
|
||||
##
|
||||
## To generate/update the cached state file:
|
||||
## 1. Call runAnvil with stateFile and dumpStateOnExit=true
|
||||
## 2. Run setupOnchainGroupManager with deployContracts=true to deploy contracts
|
||||
## (this funds/mints/approves FUNDED_TEST_PRIVATE_KEY, baking it into state)
|
||||
## 3. The state will be saved to the specified file when anvil exits
|
||||
## 4. Commit this file to git
|
||||
##
|
||||
## To use cached state:
|
||||
## 1. Call runAnvil with stateFile and dumpStateOnExit=false
|
||||
## 2. Anvil loads state in read-only mode (won't overwrite the cached file)
|
||||
## 3. Call setupOnchainGroupManager with deployContracts=false
|
||||
## 4. Tests run fast using pre-deployed contracts
|
||||
if not deployContracts:
|
||||
return buildOnchainGroupManager(FUNDED_TEST_PRIVATE_KEY, ethClientUrl)
|
||||
|
||||
let rlnInstanceRes = createRlnInstance()
|
||||
check:
|
||||
rlnInstanceRes.isOk()
|
||||
|
||||
let rlnInstance = rlnInstanceRes.get()
|
||||
|
||||
var web3 = await newWeb3(ethClientUrl)
|
||||
let accounts = await web3.provider.eth_accounts()
|
||||
web3.defaultAccount = accounts[1]
|
||||
|
||||
debug "Performing Token and RLN contracts deployment"
|
||||
let privateKey = keys.PrivateKey.fromHex(FUNDED_TEST_PRIVATE_KEY).valueOr:
|
||||
assert false, "invalid FUNDED_TEST_PRIVATE_KEY: " & $error
|
||||
return
|
||||
let acc = Address(toCanonicalAddress(privateKey.toPublicKey()))
|
||||
|
||||
discard await sendEthTransfer(
|
||||
web3, web3.defaultAccount, acc, ethToWei(1000.u256), some(0.u256)
|
||||
)
|
||||
|
||||
let testTokenAddress = (await deployTestToken(privateKey, acc, web3)).valueOr:
|
||||
assert false, "Failed to deploy test token contract: " & $error
|
||||
return
|
||||
|
||||
await sendMintCall(
|
||||
web3, web3.defaultAccount, testTokenAddress, acc, ethToWei(1000.u256), some(0.u256)
|
||||
)
|
||||
|
||||
let contractAddress = (await executeForgeContractDeployScripts(privateKey, acc, web3)).valueOr:
|
||||
assert false, "Failed to deploy RLN contract: " & $error
|
||||
return
|
||||
|
||||
# `executeForgeContractDeployScripts` shells out to `forge` via blocking
|
||||
# `execCmdEx` calls (many seconds). While those run the chronos event loop
|
||||
# is frozen and the existing web3 HTTP connection to Anvil rots; the next
|
||||
# eth_call fails with "Not connected". Reconnect before continuing.
|
||||
try:
|
||||
await web3.close()
|
||||
except CatchableError:
|
||||
discard
|
||||
web3 = await newWeb3(ethClientUrl)
|
||||
web3.defaultAccount = accounts[1]
|
||||
|
||||
let tokenApprovalResult = await approveTokenAllowanceAndVerify(
|
||||
web3,
|
||||
acc,
|
||||
privateKey,
|
||||
testTokenAddress,
|
||||
contractAddress,
|
||||
ethToWei(2000.u256),
|
||||
some(0.u256),
|
||||
)
|
||||
|
||||
assert tokenApprovalResult.isOk(), tokenApprovalResult.error
|
||||
|
||||
let manager = OnchainGroupManager(
|
||||
ethClientUrls: @[ethClientUrl],
|
||||
ethContractAddress: $contractAddress,
|
||||
chainId: CHAIN_ID,
|
||||
ethPrivateKey: some($privateKey),
|
||||
rlnInstance: rlnInstance,
|
||||
onFatalErrorAction: proc(errStr: string) =
|
||||
raiseAssert errStr
|
||||
,
|
||||
)
|
||||
|
||||
return manager
|
||||
|
||||
{.pop.}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user