Commit 2ce0ccfd authored by clabby's avatar clabby Committed by GitHub

feat(ctb): Minimum large preimage proposal size in `PreimageOracle` (#9039)

* Add minimum proposal size + configuration

* @inphi review
parent d658b948
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -218,6 +218,10 @@ type DeployConfig struct {
FaultGameGenesisOutputRoot common.Hash `json:"faultGameGenesisOutputRoot"`
// FaultGameSplitDepth is the depth at which the fault dispute game splits from output roots to execution trace claims.
FaultGameSplitDepth uint64 `json:"faultGameSplitDepth"`
// PreimageOracleMinProposalSize is the minimum number of bytes that a large preimage oracle proposal can be.
PreimageOracleMinProposalSize uint64 `json:"preimageOracleMinProposalSize"`
// PreimageOracleChallengePeriod is the number of seconds that challengers have to challenge a large preimage proposal.
PreimageOracleChallengePeriod uint64 `json:"preimageOracleChallengePeriod"`
// FundDevAccounts configures whether or not to fund the dev accounts. Should only be used
// during devnet deployments.
FundDevAccounts bool `json:"fundDevAccounts"`
......
......@@ -71,6 +71,8 @@
"faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameSplitDepth": 0,
"preimageOracleMinProposalSize": 1800000,
"preimageOracleChallengePeriod": 86400,
"systemConfigStartBlock": 0,
"requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
"recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000"
......
......@@ -54,5 +54,7 @@
"faultGameMaxDuration": 1200,
"faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameSplitDepth": 14
"faultGameSplitDepth": 14,
"preimageOracleMinProposalSize": 1800000,
"preimageOracleChallengePeriod": 86400
}
......@@ -47,5 +47,7 @@
"faultGameMaxDuration": 86400,
"faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0x6a2fb9128c8bc82eed49ee590fba3e975bd67fede20535d0d20b3000ea6d99b1",
"faultGameSplitDepth": 32
"faultGameSplitDepth": 32,
"preimageOracleMinProposalSize": 1800000,
"preimageOracleChallengePeriod": 86400
}
......@@ -584,7 +584,10 @@ contract Deploy is Deployer {
/// @notice Deploy the PreimageOracle
function deployPreimageOracle() public onlyTestnetOrDevnet broadcast returns (address addr_) {
console.log("Deploying PreimageOracle implementation");
PreimageOracle preimageOracle = new PreimageOracle{ salt: _implSalt() }();
PreimageOracle preimageOracle = new PreimageOracle{ salt: _implSalt() }({
_minProposalSize: cfg.preimageOracleMinProposalSize(),
_challengePeriod: cfg.preimageOracleChallengePeriod()
});
save("PreimageOracle", address(preimageOracle));
console.log("PreimageOracle deployed at %s", address(preimageOracle));
......
......@@ -53,6 +53,8 @@ contract DeployConfig is Script {
uint256 public faultGameMaxDepth;
uint256 public faultGameSplitDepth;
uint256 public faultGameMaxDuration;
uint256 public preimageOracleMinProposalSize;
uint256 public preimageOracleChallengePeriod;
uint256 public systemConfigStartBlock;
uint256 public requiredProtocolVersion;
uint256 public recommendedProtocolVersion;
......@@ -113,6 +115,9 @@ contract DeployConfig is Script {
faultGameMaxDuration = stdJson.readUint(_json, "$.faultGameMaxDuration");
faultGameGenesisBlock = stdJson.readUint(_json, "$.faultGameGenesisBlock");
faultGameGenesisOutputRoot = stdJson.readBytes32(_json, "$.faultGameGenesisOutputRoot");
preimageOracleMinProposalSize = stdJson.readUint(_json, "$.preimageOracleMinProposalSize");
preimageOracleChallengePeriod = stdJson.readUint(_json, "$.preimageOracleChallengePeriod");
}
}
......
......@@ -1096,10 +1096,10 @@
"impact": "Medium",
"confidence": "Medium",
"check": "uninitialized-local",
"description": "PreimageOracle.challengeFirstLPP(address,uint256,PreimageOracle.Leaf,bytes32[]).stateMatrix (src/cannon/PreimageOracle.sol#390) is a local variable never initialized\n",
"description": "PreimageOracle.challengeFirstLPP(address,uint256,PreimageOracle.Leaf,bytes32[]).stateMatrix (src/cannon/PreimageOracle.sol#408) is a local variable never initialized\n",
"type": "variable",
"name": "stateMatrix",
"start": 17910,
"start": 18772,
"length": 40,
"filename_relative": "src/cannon/PreimageOracle.sol"
},
......
[
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "CHALLENGE_PERIOD",
"outputs": [
"inputs": [
{
"internalType": "uint256",
"name": "",
"name": "_minProposalSize",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_challengePeriod",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
......@@ -200,6 +198,19 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "challengePeriod",
"outputs": [
{
"internalType": "uint256",
"name": "challengePeriod_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
......@@ -304,6 +315,19 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "minProposalSize",
"outputs": [
{
"internalType": "uint256",
"name": "minProposalSize_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
......
......@@ -13,15 +13,17 @@ import "src/cannon/libraries/CannonTypes.sol";
/// @custom:attribution Beacon Deposit Contract <0x00000000219ab540356cbb839cbe05303d7705fa>
contract PreimageOracle is IPreimageOracle {
////////////////////////////////////////////////////////////////
// Constants //
// Constants & Immutables //
////////////////////////////////////////////////////////////////
/// @notice The duration of the large preimage proposal challenge period.
uint256 internal immutable CHALLENGE_PERIOD;
/// @notice The minimum size of a preimage that can be proposed in the large preimage path.
uint256 internal immutable MIN_LPP_SIZE_BYTES;
/// @notice The depth of the keccak256 merkle tree. Supports up to 65,536 keccak blocks, or ~8.91MB preimages.
uint256 public constant KECCAK_TREE_DEPTH = 16;
/// @notice The maximum number of keccak blocks that can fit into the merkle tree.
uint256 public constant MAX_LEAF_COUNT = 2 ** KECCAK_TREE_DEPTH - 1;
/// @notice The duration of the large preimage proposal challenge period.
uint256 public constant CHALLENGE_PERIOD = 1 days;
////////////////////////////////////////////////////////////////
// Authorized Preimage Parts //
......@@ -75,7 +77,10 @@ contract PreimageOracle is IPreimageOracle {
// Constructor //
////////////////////////////////////////////////////////////////
constructor() {
constructor(uint256 _minProposalSize, uint256 _challengePeriod) {
MIN_LPP_SIZE_BYTES = _minProposalSize;
CHALLENGE_PERIOD = _challengePeriod;
// Compute hashes in empty sparse Merkle tree. The first hash is not set, and kept as zero as the identity.
for (uint256 height = 0; height < KECCAK_TREE_DEPTH - 1; height++) {
zeroHashes[height + 1] = keccak256(abi.encodePacked(zeroHashes[height], zeroHashes[height]));
......@@ -187,6 +192,22 @@ contract PreimageOracle is IPreimageOracle {
count_ = proposals.length;
}
/// @notice Returns the length of the array with the block numbers of `addLeavesLPP` calls for a given large
/// preimage proposal.
function proposalBlocksLen(address _claimant, uint256 _uuid) external view returns (uint256 len_) {
len_ = proposalBlocks[_claimant][_uuid].length;
}
/// @notice Returns the length of the large preimage proposal challenge period.
function challengePeriod() external view returns (uint256 challengePeriod_) {
challengePeriod_ = CHALLENGE_PERIOD;
}
/// @notice Returns the minimum size (in bytes) of a large preimage proposal.
function minProposalSize() external view returns (uint256 minProposalSize_) {
minProposalSize_ = MIN_LPP_SIZE_BYTES;
}
/// @notice Initialize a large preimage proposal. Must be called before adding any leaves.
function initLPP(uint256 _uuid, uint32 _partOffset, uint32 _claimedSize) external {
// The caller of `addLeavesLPP` must be an EOA.
......@@ -195,17 +216,14 @@ contract PreimageOracle is IPreimageOracle {
// The part offset must be within the bounds of the claimed size + 8.
if (_partOffset >= _claimedSize + 8) revert PartOffsetOOB();
// The claimed size must be at least `MIN_LPP_SIZE_BYTES`.
if (_claimedSize < MIN_LPP_SIZE_BYTES) revert InvalidInputSize();
LPPMetaData metaData = proposalMetadata[msg.sender][_uuid];
proposalMetadata[msg.sender][_uuid] = metaData.setPartOffset(_partOffset).setClaimedSize(_claimedSize);
proposals.push(LargePreimageProposalKeys(msg.sender, _uuid));
}
/// @notice Returns the length of the array with the block numbers of `addLeavesLPP` calls for a given large
/// preimage proposal.
function proposalBlocksLen(address _claimant, uint256 _uuid) external view returns (uint256 len_) {
len_ = proposalBlocks[_claimant][_uuid].length;
}
/// @notice Adds a contiguous list of keccak state matrices to the merkle tree.
function addLeavesLPP(
uint256 _uuid,
......
......@@ -12,7 +12,7 @@ contract MIPS_Test is CommonTest {
function setUp() public virtual override {
super.setUp();
oracle = new PreimageOracle();
oracle = new PreimageOracle(0, 0);
mips = new MIPS(oracle);
vm.store(address(mips), 0x0, bytes32(abi.encode(address(oracle))));
vm.label(address(oracle), "PreimageOracle");
......
......@@ -15,7 +15,7 @@ contract PreimageOracle_Test is Test {
/// @notice Sets up the testing suite.
function setUp() public {
oracle = new PreimageOracle();
oracle = new PreimageOracle(0, 0);
vm.label(address(oracle), "PreimageOracle");
}
......@@ -174,13 +174,15 @@ contract PreimageOracle_Test is Test {
}
contract PreimageOracle_LargePreimageProposals_Test is Test {
uint256 internal constant MIN_SIZE_BYTES = 0;
uint256 internal constant CHALLENGE_PERIOD = 1 days;
uint256 internal constant TEST_UUID = 0xFACADE;
PreimageOracle internal oracle;
/// @notice Sets up the testing suite.
function setUp() public {
oracle = new PreimageOracle();
oracle = new PreimageOracle({ _minProposalSize: MIN_SIZE_BYTES, _challengePeriod: CHALLENGE_PERIOD });
vm.label(address(oracle), "PreimageOracle");
// Set `tx.origin` and `msg.sender` to `address(this)` so that it may behave like an EOA for `addLeavesLPP`.
......@@ -200,6 +202,21 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
oracle.initLPP(TEST_UUID, 136 + 8, uint32(data.length));
}
/// @notice Tests that the `initLPP` function reverts when the part offset is out of bounds of the full preimage.
function test_initLPP_sizeTooSmall_reverts() public {
oracle = new PreimageOracle({ _minProposalSize: 1000, _challengePeriod: CHALLENGE_PERIOD });
// Allocate the preimage data.
bytes memory data = new bytes(136);
for (uint256 i; i < data.length; i++) {
data[i] = 0xFF;
}
// Initialize the proposal.
vm.expectRevert(InvalidInputSize.selector);
oracle.initLPP(TEST_UUID, 0, uint32(data.length));
}
/// @notice Gas snapshot for `addLeaves`
function test_addLeaves_gasSnapshot() public {
// Allocate the preimage data.
......@@ -360,7 +377,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
postProof[i] = zeroHash;
}
vm.warp(block.timestamp + oracle.CHALLENGE_PERIOD() + 1 seconds);
vm.warp(block.timestamp + oracle.challengePeriod() + 1 seconds);
// Finalize the proposal.
oracle.squeezeLPP({
......@@ -425,7 +442,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
LPPMetaData metaData = oracle.proposalMetadata(address(this), TEST_UUID);
assertTrue(metaData.countered());
vm.warp(block.timestamp + oracle.CHALLENGE_PERIOD() + 1 seconds);
vm.warp(block.timestamp + oracle.challengePeriod() + 1 seconds);
// Finalize the proposal.
vm.expectRevert(BadProposal.selector);
......@@ -532,7 +549,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
postProof[i] = zeroHash;
}
vm.warp(block.timestamp + oracle.CHALLENGE_PERIOD() + 1 seconds);
vm.warp(block.timestamp + oracle.challengePeriod() + 1 seconds);
// Finalize the proposal.
vm.expectRevert(StatesNotContiguous.selector);
......@@ -578,7 +595,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
postProof[i] = zeroHash;
}
vm.warp(block.timestamp + oracle.CHALLENGE_PERIOD() + 1 seconds);
vm.warp(block.timestamp + oracle.challengePeriod() + 1 seconds);
// Finalize the proposal.
vm.expectRevert(InvalidPreimage.selector);
......@@ -624,7 +641,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
postProof[i] = zeroHash;
}
vm.warp(block.timestamp + oracle.CHALLENGE_PERIOD() + 1 seconds);
vm.warp(block.timestamp + oracle.challengePeriod() + 1 seconds);
vm.expectRevert(InvalidInputSize.selector);
oracle.squeezeLPP({
......
......@@ -14,7 +14,7 @@ contract AlphabetVM is IBigStepper {
constructor(Claim _absolutePrestate) {
ABSOLUTE_PRESTATE = _absolutePrestate;
oracle = new PreimageOracle();
oracle = new PreimageOracle(0, 0);
}
/// @inheritdoc IBigStepper
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment