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 { ...@@ -218,6 +218,10 @@ type DeployConfig struct {
FaultGameGenesisOutputRoot common.Hash `json:"faultGameGenesisOutputRoot"` FaultGameGenesisOutputRoot common.Hash `json:"faultGameGenesisOutputRoot"`
// FaultGameSplitDepth is the depth at which the fault dispute game splits from output roots to execution trace claims. // FaultGameSplitDepth is the depth at which the fault dispute game splits from output roots to execution trace claims.
FaultGameSplitDepth uint64 `json:"faultGameSplitDepth"` 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 // FundDevAccounts configures whether or not to fund the dev accounts. Should only be used
// during devnet deployments. // during devnet deployments.
FundDevAccounts bool `json:"fundDevAccounts"` FundDevAccounts bool `json:"fundDevAccounts"`
......
...@@ -71,6 +71,8 @@ ...@@ -71,6 +71,8 @@
"faultGameGenesisBlock": 0, "faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameSplitDepth": 0, "faultGameSplitDepth": 0,
"preimageOracleMinProposalSize": 1800000,
"preimageOracleChallengePeriod": 86400,
"systemConfigStartBlock": 0, "systemConfigStartBlock": 0,
"requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
"recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000" "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000"
......
...@@ -54,5 +54,7 @@ ...@@ -54,5 +54,7 @@
"faultGameMaxDuration": 1200, "faultGameMaxDuration": 1200,
"faultGameGenesisBlock": 0, "faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameSplitDepth": 14 "faultGameSplitDepth": 14,
"preimageOracleMinProposalSize": 1800000,
"preimageOracleChallengePeriod": 86400
} }
...@@ -47,5 +47,7 @@ ...@@ -47,5 +47,7 @@
"faultGameMaxDuration": 86400, "faultGameMaxDuration": 86400,
"faultGameGenesisBlock": 0, "faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0x6a2fb9128c8bc82eed49ee590fba3e975bd67fede20535d0d20b3000ea6d99b1", "faultGameGenesisOutputRoot": "0x6a2fb9128c8bc82eed49ee590fba3e975bd67fede20535d0d20b3000ea6d99b1",
"faultGameSplitDepth": 32 "faultGameSplitDepth": 32,
"preimageOracleMinProposalSize": 1800000,
"preimageOracleChallengePeriod": 86400
} }
...@@ -584,7 +584,10 @@ contract Deploy is Deployer { ...@@ -584,7 +584,10 @@ contract Deploy is Deployer {
/// @notice Deploy the PreimageOracle /// @notice Deploy the PreimageOracle
function deployPreimageOracle() public onlyTestnetOrDevnet broadcast returns (address addr_) { function deployPreimageOracle() public onlyTestnetOrDevnet broadcast returns (address addr_) {
console.log("Deploying PreimageOracle implementation"); 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)); save("PreimageOracle", address(preimageOracle));
console.log("PreimageOracle deployed at %s", address(preimageOracle)); console.log("PreimageOracle deployed at %s", address(preimageOracle));
......
...@@ -53,6 +53,8 @@ contract DeployConfig is Script { ...@@ -53,6 +53,8 @@ contract DeployConfig is Script {
uint256 public faultGameMaxDepth; uint256 public faultGameMaxDepth;
uint256 public faultGameSplitDepth; uint256 public faultGameSplitDepth;
uint256 public faultGameMaxDuration; uint256 public faultGameMaxDuration;
uint256 public preimageOracleMinProposalSize;
uint256 public preimageOracleChallengePeriod;
uint256 public systemConfigStartBlock; uint256 public systemConfigStartBlock;
uint256 public requiredProtocolVersion; uint256 public requiredProtocolVersion;
uint256 public recommendedProtocolVersion; uint256 public recommendedProtocolVersion;
...@@ -113,6 +115,9 @@ contract DeployConfig is Script { ...@@ -113,6 +115,9 @@ contract DeployConfig is Script {
faultGameMaxDuration = stdJson.readUint(_json, "$.faultGameMaxDuration"); faultGameMaxDuration = stdJson.readUint(_json, "$.faultGameMaxDuration");
faultGameGenesisBlock = stdJson.readUint(_json, "$.faultGameGenesisBlock"); faultGameGenesisBlock = stdJson.readUint(_json, "$.faultGameGenesisBlock");
faultGameGenesisOutputRoot = stdJson.readBytes32(_json, "$.faultGameGenesisOutputRoot"); faultGameGenesisOutputRoot = stdJson.readBytes32(_json, "$.faultGameGenesisOutputRoot");
preimageOracleMinProposalSize = stdJson.readUint(_json, "$.preimageOracleMinProposalSize");
preimageOracleChallengePeriod = stdJson.readUint(_json, "$.preimageOracleChallengePeriod");
} }
} }
......
...@@ -1096,10 +1096,10 @@ ...@@ -1096,10 +1096,10 @@
"impact": "Medium", "impact": "Medium",
"confidence": "Medium", "confidence": "Medium",
"check": "uninitialized-local", "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", "type": "variable",
"name": "stateMatrix", "name": "stateMatrix",
"start": 17910, "start": 18772,
"length": 40, "length": 40,
"filename_relative": "src/cannon/PreimageOracle.sol" "filename_relative": "src/cannon/PreimageOracle.sol"
}, },
......
[ [
{ {
"inputs": [], "inputs": [
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "CHALLENGE_PERIOD",
"outputs": [
{ {
"internalType": "uint256", "internalType": "uint256",
"name": "", "name": "_minProposalSize",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_challengePeriod",
"type": "uint256" "type": "uint256"
} }
], ],
"stateMutability": "view", "stateMutability": "nonpayable",
"type": "function" "type": "constructor"
}, },
{ {
"inputs": [], "inputs": [],
...@@ -200,6 +198,19 @@ ...@@ -200,6 +198,19 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "challengePeriod",
"outputs": [
{
"internalType": "uint256",
"name": "challengePeriod_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
...@@ -304,6 +315,19 @@ ...@@ -304,6 +315,19 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "minProposalSize",
"outputs": [
{
"internalType": "uint256",
"name": "minProposalSize_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
......
...@@ -13,15 +13,17 @@ import "src/cannon/libraries/CannonTypes.sol"; ...@@ -13,15 +13,17 @@ import "src/cannon/libraries/CannonTypes.sol";
/// @custom:attribution Beacon Deposit Contract <0x00000000219ab540356cbb839cbe05303d7705fa> /// @custom:attribution Beacon Deposit Contract <0x00000000219ab540356cbb839cbe05303d7705fa>
contract PreimageOracle is IPreimageOracle { 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. /// @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; uint256 public constant KECCAK_TREE_DEPTH = 16;
/// @notice The maximum number of keccak blocks that can fit into the merkle tree. /// @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; 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 // // Authorized Preimage Parts //
...@@ -75,7 +77,10 @@ contract PreimageOracle is IPreimageOracle { ...@@ -75,7 +77,10 @@ contract PreimageOracle is IPreimageOracle {
// Constructor // // 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. // 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++) { for (uint256 height = 0; height < KECCAK_TREE_DEPTH - 1; height++) {
zeroHashes[height + 1] = keccak256(abi.encodePacked(zeroHashes[height], zeroHashes[height])); zeroHashes[height + 1] = keccak256(abi.encodePacked(zeroHashes[height], zeroHashes[height]));
...@@ -187,6 +192,22 @@ contract PreimageOracle is IPreimageOracle { ...@@ -187,6 +192,22 @@ contract PreimageOracle is IPreimageOracle {
count_ = proposals.length; 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. /// @notice Initialize a large preimage proposal. Must be called before adding any leaves.
function initLPP(uint256 _uuid, uint32 _partOffset, uint32 _claimedSize) external { function initLPP(uint256 _uuid, uint32 _partOffset, uint32 _claimedSize) external {
// The caller of `addLeavesLPP` must be an EOA. // The caller of `addLeavesLPP` must be an EOA.
...@@ -195,17 +216,14 @@ contract PreimageOracle is IPreimageOracle { ...@@ -195,17 +216,14 @@ contract PreimageOracle is IPreimageOracle {
// The part offset must be within the bounds of the claimed size + 8. // The part offset must be within the bounds of the claimed size + 8.
if (_partOffset >= _claimedSize + 8) revert PartOffsetOOB(); 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]; LPPMetaData metaData = proposalMetadata[msg.sender][_uuid];
proposalMetadata[msg.sender][_uuid] = metaData.setPartOffset(_partOffset).setClaimedSize(_claimedSize); proposalMetadata[msg.sender][_uuid] = metaData.setPartOffset(_partOffset).setClaimedSize(_claimedSize);
proposals.push(LargePreimageProposalKeys(msg.sender, _uuid)); 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. /// @notice Adds a contiguous list of keccak state matrices to the merkle tree.
function addLeavesLPP( function addLeavesLPP(
uint256 _uuid, uint256 _uuid,
......
...@@ -12,7 +12,7 @@ contract MIPS_Test is CommonTest { ...@@ -12,7 +12,7 @@ contract MIPS_Test is CommonTest {
function setUp() public virtual override { function setUp() public virtual override {
super.setUp(); super.setUp();
oracle = new PreimageOracle(); oracle = new PreimageOracle(0, 0);
mips = new MIPS(oracle); mips = new MIPS(oracle);
vm.store(address(mips), 0x0, bytes32(abi.encode(address(oracle)))); vm.store(address(mips), 0x0, bytes32(abi.encode(address(oracle))));
vm.label(address(oracle), "PreimageOracle"); vm.label(address(oracle), "PreimageOracle");
......
...@@ -15,7 +15,7 @@ contract PreimageOracle_Test is Test { ...@@ -15,7 +15,7 @@ contract PreimageOracle_Test is Test {
/// @notice Sets up the testing suite. /// @notice Sets up the testing suite.
function setUp() public { function setUp() public {
oracle = new PreimageOracle(); oracle = new PreimageOracle(0, 0);
vm.label(address(oracle), "PreimageOracle"); vm.label(address(oracle), "PreimageOracle");
} }
...@@ -174,13 +174,15 @@ contract PreimageOracle_Test is Test { ...@@ -174,13 +174,15 @@ contract PreimageOracle_Test is Test {
} }
contract PreimageOracle_LargePreimageProposals_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; uint256 internal constant TEST_UUID = 0xFACADE;
PreimageOracle internal oracle; PreimageOracle internal oracle;
/// @notice Sets up the testing suite. /// @notice Sets up the testing suite.
function setUp() public { function setUp() public {
oracle = new PreimageOracle(); oracle = new PreimageOracle({ _minProposalSize: MIN_SIZE_BYTES, _challengePeriod: CHALLENGE_PERIOD });
vm.label(address(oracle), "PreimageOracle"); vm.label(address(oracle), "PreimageOracle");
// Set `tx.origin` and `msg.sender` to `address(this)` so that it may behave like an EOA for `addLeavesLPP`. // 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 { ...@@ -200,6 +202,21 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
oracle.initLPP(TEST_UUID, 136 + 8, uint32(data.length)); 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` /// @notice Gas snapshot for `addLeaves`
function test_addLeaves_gasSnapshot() public { function test_addLeaves_gasSnapshot() public {
// Allocate the preimage data. // Allocate the preimage data.
...@@ -360,7 +377,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test { ...@@ -360,7 +377,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
postProof[i] = zeroHash; postProof[i] = zeroHash;
} }
vm.warp(block.timestamp + oracle.CHALLENGE_PERIOD() + 1 seconds); vm.warp(block.timestamp + oracle.challengePeriod() + 1 seconds);
// Finalize the proposal. // Finalize the proposal.
oracle.squeezeLPP({ oracle.squeezeLPP({
...@@ -425,7 +442,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test { ...@@ -425,7 +442,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
LPPMetaData metaData = oracle.proposalMetadata(address(this), TEST_UUID); LPPMetaData metaData = oracle.proposalMetadata(address(this), TEST_UUID);
assertTrue(metaData.countered()); assertTrue(metaData.countered());
vm.warp(block.timestamp + oracle.CHALLENGE_PERIOD() + 1 seconds); vm.warp(block.timestamp + oracle.challengePeriod() + 1 seconds);
// Finalize the proposal. // Finalize the proposal.
vm.expectRevert(BadProposal.selector); vm.expectRevert(BadProposal.selector);
...@@ -532,7 +549,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test { ...@@ -532,7 +549,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
postProof[i] = zeroHash; postProof[i] = zeroHash;
} }
vm.warp(block.timestamp + oracle.CHALLENGE_PERIOD() + 1 seconds); vm.warp(block.timestamp + oracle.challengePeriod() + 1 seconds);
// Finalize the proposal. // Finalize the proposal.
vm.expectRevert(StatesNotContiguous.selector); vm.expectRevert(StatesNotContiguous.selector);
...@@ -578,7 +595,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test { ...@@ -578,7 +595,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
postProof[i] = zeroHash; postProof[i] = zeroHash;
} }
vm.warp(block.timestamp + oracle.CHALLENGE_PERIOD() + 1 seconds); vm.warp(block.timestamp + oracle.challengePeriod() + 1 seconds);
// Finalize the proposal. // Finalize the proposal.
vm.expectRevert(InvalidPreimage.selector); vm.expectRevert(InvalidPreimage.selector);
...@@ -624,7 +641,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test { ...@@ -624,7 +641,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
postProof[i] = zeroHash; postProof[i] = zeroHash;
} }
vm.warp(block.timestamp + oracle.CHALLENGE_PERIOD() + 1 seconds); vm.warp(block.timestamp + oracle.challengePeriod() + 1 seconds);
vm.expectRevert(InvalidInputSize.selector); vm.expectRevert(InvalidInputSize.selector);
oracle.squeezeLPP({ oracle.squeezeLPP({
......
...@@ -14,7 +14,7 @@ contract AlphabetVM is IBigStepper { ...@@ -14,7 +14,7 @@ contract AlphabetVM is IBigStepper {
constructor(Claim _absolutePrestate) { constructor(Claim _absolutePrestate) {
ABSOLUTE_PRESTATE = _absolutePrestate; ABSOLUTE_PRESTATE = _absolutePrestate;
oracle = new PreimageOracle(); oracle = new PreimageOracle(0, 0);
} }
/// @inheritdoc IBigStepper /// @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