Skip to content

RNG Fallback #2054

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 0 additions & 31 deletions contracts/deploy/00-ethereum-pnk.ts

This file was deleted.

18 changes: 8 additions & 10 deletions contracts/deploy/00-home-chain-arbitration-neo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import { changeCurrencyRate } from "./utils/klerosCoreHelper";
import { HomeChains, isSkipped, isDevnet, PNK, ETH } from "./utils";
import { getContractOrDeploy, getContractOrDeployUpgradable } from "./utils/getContractOrDeploy";
import { deployERC20AndFaucet, deployERC721 } from "./utils/deployTokens";
import { ChainlinkRNG, DisputeKitClassic, KlerosCoreNeo } from "../typechain-types";
import { ChainlinkRNG, DisputeKitClassic, KlerosCoreNeo, RNGWithFallback } from "../typechain-types";

const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { ethers, deployments, getNamedAccounts, getChainId } = hre;
const { deploy } = deployments;
const { ZeroAddress } = hre.ethers;
const RNG_LOOKAHEAD = 20;

// fallback to hardhat node signers on local network
const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
Expand Down Expand Up @@ -45,7 +44,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
const devnet = isDevnet(hre.network);
const minStakingTime = devnet ? 180 : 1800;
const maxFreezingTime = devnet ? 600 : 1800;
const rng = (await ethers.getContract("ChainlinkRNG")) as ChainlinkRNG;
const rngWithFallback = await ethers.getContract<RNGWithFallback>("RNGWithFallback");
const maxStakePerJuror = PNK(2_000);
const maxTotalStaked = PNK(2_000_000);
const sortitionModule = await deployUpgradable(deployments, "SortitionModuleNeo", {
Expand All @@ -55,8 +54,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
klerosCoreAddress,
minStakingTime,
maxFreezingTime,
rng.target,
RNG_LOOKAHEAD,
rngWithFallback.target,
maxStakePerJuror,
maxTotalStaked,
],
Expand Down Expand Up @@ -94,11 +92,11 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
await disputeKitContract.changeCore(klerosCore.address);
}

// rng.changeSortitionModule() only if necessary
const rngSortitionModule = await rng.sortitionModule();
if (rngSortitionModule !== sortitionModule.address) {
console.log(`rng.changeSortitionModule(${sortitionModule.address})`);
await rng.changeSortitionModule(sortitionModule.address);
// rngWithFallback.changeConsumer() only if necessary
const rngConsumer = await rngWithFallback.consumer();
if (rngConsumer !== sortitionModule.address) {
console.log(`rngWithFallback.changeConsumer(${sortitionModule.address})`);
await rngWithFallback.changeConsumer(sortitionModule.address);
}

const core = (await hre.ethers.getContract("KlerosCoreNeo")) as KlerosCoreNeo;
Expand Down
19 changes: 9 additions & 10 deletions contracts/deploy/00-home-chain-arbitration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import { changeCurrencyRate } from "./utils/klerosCoreHelper";
import { HomeChains, isSkipped, isDevnet, PNK, ETH, Courts } from "./utils";
import { getContractOrDeploy, getContractOrDeployUpgradable } from "./utils/getContractOrDeploy";
import { deployERC20AndFaucet } from "./utils/deployTokens";
import { ChainlinkRNG, DisputeKitClassic, KlerosCore } from "../typechain-types";
import { ChainlinkRNG, DisputeKitClassic, KlerosCore, RNGWithFallback } from "../typechain-types";

const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { ethers, deployments, getNamedAccounts, getChainId } = hre;
const { deploy } = deployments;
const { ZeroAddress } = hre.ethers;
const RNG_LOOKAHEAD = 20;

// fallback to hardhat node signers on local network
const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
Expand Down Expand Up @@ -50,10 +49,10 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
const devnet = isDevnet(hre.network);
const minStakingTime = devnet ? 180 : 1800;
const maxFreezingTime = devnet ? 600 : 1800;
const rng = (await ethers.getContract("ChainlinkRNG")) as ChainlinkRNG;
const rngWithFallback = await ethers.getContract<RNGWithFallback>("RNGWithFallback");
const sortitionModule = await deployUpgradable(deployments, "SortitionModule", {
from: deployer,
args: [deployer, klerosCoreAddress, minStakingTime, maxFreezingTime, rng.target, RNG_LOOKAHEAD],
args: [deployer, klerosCoreAddress, minStakingTime, maxFreezingTime, rngWithFallback.target],
log: true,
}); // nonce (implementation), nonce+1 (proxy)

Expand All @@ -80,18 +79,18 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
}); // nonce+2 (implementation), nonce+3 (proxy)

// disputeKit.changeCore() only if necessary
const disputeKitContract = (await ethers.getContract("DisputeKitClassic")) as DisputeKitClassic;
const disputeKitContract = await ethers.getContract<DisputeKitClassic>("DisputeKitClassic");
const currentCore = await disputeKitContract.core();
if (currentCore !== klerosCore.address) {
console.log(`disputeKit.changeCore(${klerosCore.address})`);
await disputeKitContract.changeCore(klerosCore.address);
}

// rng.changeSortitionModule() only if necessary
const rngSortitionModule = await rng.sortitionModule();
if (rngSortitionModule !== sortitionModule.address) {
console.log(`rng.changeSortitionModule(${sortitionModule.address})`);
await rng.changeSortitionModule(sortitionModule.address);
// rngWithFallback.changeConsumer() only if necessary
const rngConsumer = await rngWithFallback.consumer();
if (rngConsumer !== sortitionModule.address) {
console.log(`rngWithFallback.changeConsumer(${sortitionModule.address})`);
await rngWithFallback.changeConsumer(sortitionModule.address);
}

const core = (await hre.ethers.getContract("KlerosCore")) as KlerosCore;
Expand Down
36 changes: 0 additions & 36 deletions contracts/deploy/00-home-chain-pnk-faucet.ts

This file was deleted.

4 changes: 2 additions & 2 deletions contracts/deploy/00-home-chain-resolver.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { HomeChains, isSkipped } from "./utils";
import { deployUpgradable } from "./utils/deployUpgradable";
import { getContractOrDeploy } from "./utils/getContractOrDeploy";

const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { deployments, getNamedAccounts, getChainId } = hre;
Expand All @@ -15,7 +15,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
const klerosCore = await deployments.get("KlerosCore");
const disputeTemplateRegistry = await deployments.get("DisputeTemplateRegistry");

await deploy("DisputeResolver", {
await getContractOrDeploy(hre, "DisputeResolver", {
from: deployer,
args: [klerosCore.address, disputeTemplateRegistry.address],
log: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { HomeChains, isSkipped } from "./utils";
import { getContractOrDeploy } from "./utils/getContractOrDeploy";
import { RNGWithFallback } from "../typechain-types";

const deployRng: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { deployments, getNamedAccounts, getChainId } = hre;
const { deploy } = deployments;
const { getNamedAccounts, getChainId, ethers } = hre;

// fallback to hardhat node signers on local network
const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
Expand Down Expand Up @@ -57,11 +57,16 @@ const deployRng: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const requestConfirmations = 200; // between 1 and 200 L2 blocks
const callbackGasLimit = 100000;

await deploy("ChainlinkRNG", {
const oldRng = await ethers.getContractOrNull("ChainlinkRNG");
if (!oldRng) {
console.log("Register this Chainlink consumer here: http://vrf.chain.link/");
}

const rng = await getContractOrDeploy(hre, "ChainlinkRNG", {
from: deployer,
args: [
deployer,
deployer, // The consumer is configured as the SortitionModule later
deployer, // The consumer is configured as the RNGWithFallback later
ChainlinkVRFCoordinator.target,
keyHash,
subscriptionId,
Expand All @@ -70,6 +75,26 @@ const deployRng: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
],
log: true,
});

const fallbackTimeoutSeconds = 30 * 60; // 30 minutes
await getContractOrDeploy(hre, "RNGWithFallback", {
from: deployer,
args: [
deployer,
deployer, // The consumer is configured as the SortitionModule later
fallbackTimeoutSeconds,
rng.target,
],
log: true,
});

// rng.changeConsumer() only if necessary
const rngWithFallback = await ethers.getContract<RNGWithFallback>("RNGWithFallback");
const rngConsumer = await rng.consumer();
if (rngConsumer !== rngWithFallback.target) {
console.log(`rng.changeConsumer(${rngWithFallback.target})`);
await rng.changeConsumer(rngWithFallback.target);
}
};

deployRng.tags = ["ChainlinkRNG"];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { HomeChains, isSkipped } from "./utils";
import { getContractOrDeploy } from "./utils/getContractOrDeploy";
import { RNGWithFallback } from "../typechain-types";

const deployRng: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { deployments, getNamedAccounts, getChainId } = hre;
const { deploy } = deployments;
const { getNamedAccounts, getChainId, ethers } = hre;

// fallback to hardhat node signers on local network
const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
Expand All @@ -20,11 +20,35 @@ const deployRng: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
log: true,
});

await getContractOrDeploy(hre, "RandomizerRNG", {
const rng = await getContractOrDeploy(hre, "RandomizerRNG", {
from: deployer,
args: [deployer, deployer, randomizerOracle.target], // The consumer is configured as the SortitionModule later
args: [
deployer,
deployer, // The consumer is configured as the RNGWithFallback later
randomizerOracle.target,
],
log: true,
});
Comment on lines +23 to 31
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure Randomizer Oracle is not a Mock on live networks

RandomizerOracle is deployed as RandomizerMock unconditionally. This should be gated to Hardhat; on live networks, provide the actual oracle address via env/config.

Suggested localized refactor:

-  const rng = await getContractOrDeploy(hre, "RandomizerRNG", {
+  const oracleAddress =
+    chainId === HomeChains.HARDHAT
+      ? (await getContractOrDeploy(hre, "RandomizerOracle", { from: deployer, contract: "RandomizerMock", args: [], log: true })).target
+      : (process.env.RANDOMIZER_ORACLE as string);
+  if (chainId !== HomeChains.HARDHAT && !oracleAddress) {
+    throw new Error("Missing RANDOMIZER_ORACLE env var for this network");
+  }
+  const rng = await getContractOrDeploy(hre, "RandomizerRNG", {
     from: deployer,
-    args: [
-      deployer,
-      deployer, // The consumer is configured as the RNGWithFallback later
-      randomizerOracle.target,
-    ],
+    args: [deployer, deployer, oracleAddress], // The consumer is configured as the RNGWithFallback later
     log: true,
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const rng = await getContractOrDeploy(hre, "RandomizerRNG", {
from: deployer,
args: [deployer, deployer, randomizerOracle.target], // The consumer is configured as the SortitionModule later
args: [
deployer,
deployer, // The consumer is configured as the RNGWithFallback later
randomizerOracle.target,
],
log: true,
});
const oracleAddress =
chainId === HomeChains.HARDHAT
? (await getContractOrDeploy(hre, "RandomizerOracle", {
from: deployer,
contract: "RandomizerMock",
args: [],
log: true,
})).target
: (process.env.RANDOMIZER_ORACLE as string);
if (chainId !== HomeChains.HARDHAT && !oracleAddress) {
throw new Error("Missing RANDOMIZER_ORACLE env var for this network");
}
const rng = await getContractOrDeploy(hre, "RandomizerRNG", {
from: deployer,
args: [deployer, deployer, oracleAddress], // The consumer is configured as the RNGWithFallback later
log: true,
});
🤖 Prompt for AI Agents
In contracts/deploy/00-rng-randomizer.ts around lines 23 to 31, RandomizerOracle
is always deployed as RandomizerMock; change this so the mock is only deployed
on local/hardhat networks and on live networks the oracle address must be
provided from env or config. Detect the network (e.g., hre.network.name ===
'hardhat' || 'localhost'), set an oracleAddress variable to the deployed mock's
address when local, otherwise read process.env.RANDOMIZER_ORACLE_ADDRESS (or a
config value) and throw a clear error if it's missing; then pass oracleAddress
into the RandomizerRNG args instead of randomizerOracle.target.


const fallbackTimeoutSeconds = 30 * 60; // 30 minutes
await getContractOrDeploy(hre, "RNGWithFallback", {
from: deployer,
args: [
deployer,
deployer, // The consumer is configured as the SortitionModule later
fallbackTimeoutSeconds,
rng.target,
],
log: true,
});

// rng.changeConsumer() only if necessary
const rngWithFallback = await ethers.getContract<RNGWithFallback>("RNGWithFallback");
const rngConsumer = await rng.consumer();
if (rngConsumer !== rngWithFallback.target) {
console.log(`rng.changeConsumer(${rngWithFallback.target})`);
await rng.changeConsumer(rngWithFallback.target);
}
};

deployRng.tags = ["RandomizerRNG"];
Expand Down
47 changes: 0 additions & 47 deletions contracts/deploy/00-rng.ts

This file was deleted.

8 changes: 4 additions & 4 deletions contracts/deploy/change-sortition-module-rng.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ const task: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
sortitionModule = await ethers.getContract<SortitionModule>("SortitionModule");
}

console.log(`chainlinkRng.changeSortitionModule(${sortitionModule.target})`);
await chainlinkRng.changeSortitionModule(sortitionModule.target);
console.log(`chainlinkRng.changeConsumer(${sortitionModule.target})`);
await chainlinkRng.changeConsumer(sortitionModule.target);

console.log(`sortitionModule.changeRandomNumberGenerator(${chainlinkRng.target}, 0)`);
await sortitionModule.changeRandomNumberGenerator(chainlinkRng.target, 0);
console.log(`sortitionModule.changeRandomNumberGenerator(${chainlinkRng.target})`);
await sortitionModule.changeRandomNumberGenerator(chainlinkRng.target);
};

task.tags = ["ChangeSortitionModuleRNG"];
Expand Down
8 changes: 3 additions & 5 deletions contracts/src/arbitration/SortitionModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pragma solidity ^0.8.24;

import {SortitionModuleBase, KlerosCore, RNG} from "./SortitionModuleBase.sol";
import {SortitionModuleBase, KlerosCore, IRNG} from "./SortitionModuleBase.sol";

/// @title SortitionModule
/// @dev A factory of trees that keeps track of staked values for sortition.
Expand All @@ -24,16 +24,14 @@ contract SortitionModule is SortitionModuleBase {
/// @param _minStakingTime Minimal time to stake
/// @param _maxDrawingTime Time after which the drawing phase can be switched
/// @param _rng The random number generator.
/// @param _rngLookahead Lookahead value for rng.
function initialize(
address _governor,
KlerosCore _core,
uint256 _minStakingTime,
uint256 _maxDrawingTime,
RNG _rng,
uint256 _rngLookahead
IRNG _rng
) external reinitializer(1) {
__SortitionModuleBase_initialize(_governor, _core, _minStakingTime, _maxDrawingTime, _rng, _rngLookahead);
__SortitionModuleBase_initialize(_governor, _core, _minStakingTime, _maxDrawingTime, _rng);
}

function initialize4() external reinitializer(4) {
Expand Down
Loading
Loading