Skip to content

Commit

Permalink
refactor: simplify IDataProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
guidanoli committed Dec 14, 2024
1 parent 20a32e5 commit 0405697
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 63 deletions.
93 changes: 45 additions & 48 deletions cartesi-rollups/contracts/src/DaveConsensus.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
pragma solidity ^0.8.8;

import {IInputBox} from "rollups-contracts/inputs/IInputBox.sol";
import {Inputs} from "rollups-contracts/common/Inputs.sol";

import {IDataProvider} from "prt-contracts/IDataProvider.sol";
import {ITournamentFactory} from "prt-contracts/ITournamentFactory.sol";
Expand Down Expand Up @@ -38,9 +37,6 @@ import {Merkle} from "./Merkle.sol";
contract DaveConsensus is IDataProvider {
using Merkle for bytes;

/// @notice GIO namespace for getting advance requests from the InputBox contract
uint16 constant INPUT_BOX_NAMESPACE = 0;

/// @notice The input box contract
IInputBox immutable _inputBox;

Expand All @@ -53,11 +49,11 @@ contract DaveConsensus is IDataProvider {
/// @notice Current sealed epoch number
uint256 _epochNumber;

/// @notice Block number (inclusive) lower bound of the current sealed epoch
uint256 _blockNumberLowerBound;
/// @notice Input index (inclusive) lower bound of the current sealed epoch
uint256 _inputIndexLowerBound;

/// @notice Block number (exclusive) upper bound of the current sealed epoch
uint256 _blockNumberUpperBound;
/// @notice Input index (exclusive) upper bound of the current sealed epoch
uint256 _inputIndexUpperBound;

/// @notice Current sealed epoch tournament
ITournament _tournament;
Expand All @@ -70,18 +66,31 @@ contract DaveConsensus is IDataProvider {

/// @notice An epoch was sealed
/// @param epochNumber the sealed epoch number
/// @param blockNumberLowerBound the block number (inclusive) lower bound in the sealed epoch
/// @param blockNumberUpperBound the block number (exclusive) upper bound in the sealed epoch
/// @param inputIndexLowerBound the input index (inclusive) lower bound in the sealed epoch
/// @param inputIndexUpperBound the input index (exclusive) upper bound in the sealed epoch
/// @param initialMachineStateHash the initial machine state hash
/// @param tournament the sealed epoch tournament contract
event EpochSealed(
uint256 epochNumber,
uint256 blockNumberLowerBound,
uint256 blockNumberUpperBound,
uint256 inputIndexLowerBound,
uint256 inputIndexUpperBound,
Machine.Hash initialMachineStateHash,
ITournament tournament
);

/// @notice Received epoch number is different from actual
/// @param received The epoch number received as argument
/// @param actual The actual epoch number in storage
error IncorrectEpochNumber(uint256 received, uint256 actual);

/// @notice Tournament is not finished yet
error TournamentNotFinishedYet();

/// @notice Hash of received input blob is different from stored on-chain
/// @param fromReceivedInput Hash of received input blob
/// @param fromInputBox Hash of input stored on the input box contract
error InputHashMismatch(bytes32 fromReceivedInput, bytes32 fromInputBox);

constructor(
IInputBox inputBox,
address appContract,
Expand All @@ -95,11 +104,11 @@ contract DaveConsensus is IDataProvider {
emit ConsensusCreation(inputBox, appContract, tournamentFactory);

// Initialize first sealed epoch
uint256 blockNumberUpperBound = block.number;
_blockNumberUpperBound = blockNumberUpperBound;
uint256 inputIndexUpperBound = inputBox.getNumberOfInputs(appContract);
_inputIndexUpperBound = inputIndexUpperBound;
ITournament tournament = tournamentFactory.instantiate(initialMachineStateHash, this);
_tournament = tournament;
emit EpochSealed(0, 0, blockNumberUpperBound, initialMachineStateHash, tournament);
emit EpochSealed(0, 0, inputIndexUpperBound, initialMachineStateHash, tournament);
}

function canSettle() external view returns (bool isFinished, uint256 epochNumber) {
Expand All @@ -109,34 +118,35 @@ contract DaveConsensus is IDataProvider {

function settle(uint256 epochNumber) external {
// Check tournament settlement
require(epochNumber == _epochNumber, "Dave: incorrect epoch number");
uint256 actualEpochNumber = _epochNumber;
require(epochNumber == actualEpochNumber, IncorrectEpochNumber(epochNumber, actualEpochNumber));
(bool isFinished,, Machine.Hash finalMachineStateHash) = _tournament.arbitrationResult();
require(isFinished, "Dave: tournament not finished");
require(isFinished, TournamentNotFinishedYet());

// Seal current accumulating epoch
_epochNumber = ++epochNumber;
uint256 blockNumberLowerBound = _blockNumberUpperBound;
_blockNumberLowerBound = blockNumberLowerBound;
uint256 blockNumberUpperBound = block.number;
_blockNumberUpperBound = blockNumberUpperBound;
uint256 inputIndexLowerBound = _inputIndexUpperBound;
_inputIndexLowerBound = inputIndexLowerBound;
uint256 inputIndexUpperBound = _inputBox.getNumberOfInputs(_appContract);
_inputIndexUpperBound = inputIndexUpperBound;
ITournament tournament = _tournamentFactory.instantiate(finalMachineStateHash, this);
_tournament = tournament;
emit EpochSealed(epochNumber, blockNumberLowerBound, blockNumberUpperBound, finalMachineStateHash, tournament);
emit EpochSealed(epochNumber, inputIndexLowerBound, inputIndexUpperBound, finalMachineStateHash, tournament);
}

function getCurrentSealedEpoch()
external
view
returns (
uint256 epochNumber,
uint256 blockNumberLowerBound,
uint256 blockNumberUpperBound,
uint256 inputIndexLowerBound,
uint256 inputIndexUpperBound,
ITournament tournament
)
{
epochNumber = _epochNumber;
blockNumberLowerBound = _blockNumberLowerBound;
blockNumberUpperBound = _blockNumberUpperBound;
inputIndexLowerBound = _inputIndexLowerBound;
inputIndexUpperBound = _inputIndexUpperBound;
tournament = _tournament;
}

Expand All @@ -153,36 +163,23 @@ contract DaveConsensus is IDataProvider {
}

/// @inheritdoc IDataProvider
function gio(uint16 namespace, bytes calldata id, bytes calldata input)
function provideMerkleRootOfInput(uint256 inputIndexWithinEpoch, bytes calldata input)
external
view
override
returns (bytes32, uint256)
returns (bytes32)
{
require(namespace == INPUT_BOX_NAMESPACE, "Dave: bad namespace");
uint256 inputIndex = abi.decode(id, (uint256));
uint256 inputCount = _inputBox.getNumberOfInputs(_appContract);
uint256 inputIndex = _inputIndexLowerBound + inputIndexWithinEpoch;

if (inputIndex >= inputCount) {
if (inputIndex >= _inputIndexUpperBound) {
// out-of-bounds index: repeat the state (as a fixpoint function)
return (bytes32(0), 0);
return bytes32(0);
}

bytes32 inputHash = _inputBox.getInputHash(_appContract, inputIndex);
require(keccak256(input) == inputHash, "Dave: bad input hash");
require(input.length >= 4, "Dave: bad input length");
bytes32 calculatedInputHash = keccak256(input);
bytes32 realInputHash = _inputBox.getInputHash(_appContract, inputIndex);
require(calculatedInputHash == realInputHash, InputHashMismatch(calculatedInputHash, realInputHash));

bytes4 selector = bytes4(input[:4]);
bytes calldata args = input[4:];
require(selector == Inputs.EvmAdvance.selector, "Dave: bad input selector");
(,,, uint256 blockNumber,,,,) =
abi.decode(args, (uint256, address, address, uint256, uint256, uint256, uint256, bytes));

if (_blockNumberLowerBound <= blockNumber && blockNumber < _blockNumberUpperBound) {
return (input.getSmallestMerkleRootFromBytes(), input.length);
} else {
// out-of-bounds index: repeat the state (as a fixpoint function)
return (bytes32(0), 0);
}
return input.getSmallestMerkleRootFromBytes();
}
}
18 changes: 8 additions & 10 deletions prt/contracts/src/IDataProvider.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@
pragma solidity ^0.8.17;

interface IDataProvider {
/// @notice Provides the Merkle root of the response to a Generic I/O request
/// @param namespace The request namespace
/// @param id The request ID
/// @param extra Extra data (e.g. proofs)
/// @return Merkle root of response
/// @return Size of the response (in bytes)
function gio(uint16 namespace, bytes calldata id, bytes calldata extra)
external
view
returns (bytes32, uint256);
/// @notice Provides the Merkle root of an input
/// @param inputIndexWithinEpoch The index of the input within the epoch
/// @param input The input blob (to hash and check against the input box)
/// @return The root of smallest Merkle tree that fits the input
function provideMerkleRootOfInput(
uint256 inputIndexWithinEpoch,
bytes calldata input
) external view returns (bytes32);
}
10 changes: 5 additions & 5 deletions prt/contracts/src/tournament/abstracts/LeafTournament.sol
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,17 @@ abstract contract LeafTournament is Tournament {

if (inputLength > 0) {
bytes calldata input = proofs[32:32 + inputLength];
uint256 inputIndex = counter
uint256 inputIndexWithinEpoch = counter
>> (
ArbitrationConstants.LOG2_EMULATOR_SPAN
+ ArbitrationConstants.LOG2_UARCH_SPAN
); // TODO: add input index offset of the epoch
);

// TODO: maybe assert retrieved input length matches?
(bytes32 inputMerkleRoot, uint256 retrievedInputLength) =
provider.gio(0, abi.encode(inputIndex), input);
bytes32 inputMerkleRoot = provider.provideMerkleRootOfInput(
inputIndexWithinEpoch, input
);

require(inputLength == retrievedInputLength);
require(inputMerkleRoot != bytes32(0));
SendCmioResponse.sendCmioResponse(
accessLogs,
Expand Down

0 comments on commit 0405697

Please sign in to comment.