Skip to content

Commit

Permalink
chore: merge remote-tracking branch main into prerelease/2.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
guidanoli committed Aug 7, 2024
2 parents a6873a3 + 7f27379 commit d6db618
Show file tree
Hide file tree
Showing 22 changed files with 499 additions and 114 deletions.
5 changes: 5 additions & 0 deletions .changeset/little-cheetahs-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/rollups": major
---

Added a `lastProcessedBlockNumber` parameter to `IConsensus` functions and events.
5 changes: 5 additions & 0 deletions .changeset/pink-teachers-whisper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/rollups": major
---

Removed `authorityOwner` parameter from `AuthorityCreated` event.
9 changes: 9 additions & 0 deletions .changeset/popular-ghosts-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@cartesi/rollups": major
---

Added an `epochLength` parameter to functions of:

- `IAuthorityFactory`
- `ISelfHostedApplicationFactory`
- `IQuorumFactory`
5 changes: 5 additions & 0 deletions .changeset/six-schools-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/rollups": minor
---

Added a `getEpochLength` function to `IConsensus` interface.
29 changes: 23 additions & 6 deletions contracts/consensus/AbstractConsensus.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,43 @@ import {IConsensus} from "./IConsensus.sol";
/// @dev This contract was designed to be inherited by implementations of the `IConsensus` interface
/// that only need a simple mechanism of storage and retrieval of accepted claims.
abstract contract AbstractConsensus is IConsensus {
/// @notice The epoch length
uint256 private immutable _epochLength;

/// @notice Indexes accepted claims by application contract address.
mapping(address => mapping(bytes32 => bool)) private _acceptedClaims;

/// @notice Check if an output Merkle root hash was ever accepted by the consensus
/// for a particular application.
/// @param appContract The application contract address
/// @param claim The output Merkle root hash
/// @param epochLength The epoch length
/// @dev Reverts if the epoch length is zero.
constructor(uint256 epochLength) {
require(epochLength > 0, "epoch length must not be zero");
_epochLength = epochLength;
}

/// @inheritdoc IConsensus
function wasClaimAccepted(
address appContract,
bytes32 claim
) public view override returns (bool) {
return _acceptedClaims[appContract][claim];
}

/// @inheritdoc IConsensus
function getEpochLength() public view override returns (uint256) {
return _epochLength;
}

/// @notice Accept a claim.
/// @param appContract The application contract address
/// @param lastProcessedBlockNumber The number of the last processed block
/// @param claim The output Merkle root hash
/// @dev Emits a `ClaimAcceptance` event.
function _acceptClaim(address appContract, bytes32 claim) internal {
function _acceptClaim(
address appContract,
uint256 lastProcessedBlockNumber,
bytes32 claim
) internal {
_acceptedClaims[appContract][claim] = true;
emit ClaimAcceptance(appContract, claim);
emit ClaimAcceptance(appContract, lastProcessedBlockNumber, claim);
}
}
43 changes: 30 additions & 13 deletions contracts/consensus/IConsensus.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

pragma solidity ^0.8.8;

/// @notice Provides consensus over the set of valid output Merkle root hashes for applications.
/// @notice The latest output Merkle root hash is available after the machine processes every input.
/// This hash can be later used to prove that any given output was ever produced by the machine.
/// @notice After an epoch is finalized, a validator may submit a claim containing the application contract address,
/// and the output Merkle root hash.
/// @notice Validators may synchronize epoch finalization, but such mechanism is not specified by this interface.
/// @notice Each application has its own stream of inputs.
/// See the `IInputBox` interface for calldata-based on-chain data availability.
/// @notice When an input is fed to the application, it may yield several outputs.
/// @notice Since genesis, a Merkle tree of all outputs ever produced is maintained
/// both inside and outside the Cartesi Machine.
/// @notice The claim that validators may submit to the consensus contract
/// is the root of this Merkle tree after processing all base layer blocks until some height.
/// @notice A validator should be able to save transaction fees by not submitting a claim if it was...
/// - already submitted by the validator (see the `ClaimSubmission` event) or;
/// - already accepted by the consensus (see the `ClaimAcceptance` event).
Expand All @@ -22,32 +23,48 @@ interface IConsensus {
/// @notice MUST trigger when a claim is submitted.
/// @param submitter The submitter address
/// @param appContract The application contract address
/// @param claim The output Merkle root hash
/// @param lastProcessedBlockNumber The number of the last processed block
/// @param claim The root of the Merkle tree of outputs
event ClaimSubmission(
address indexed submitter,
address indexed appContract,
uint256 lastProcessedBlockNumber,
bytes32 claim
);

/// @notice MUST trigger when a claim is accepted.
/// @param appContract The application contract address
/// @param claim The output Merkle root hash
/// @dev MUST be triggered after some `ClaimSubmission` event regarding `appContract`.
event ClaimAcceptance(address indexed appContract, bytes32 claim);
/// @param lastProcessedBlockNumber The number of the last processed block
/// @param claim The root of the Merkle tree of outputs
event ClaimAcceptance(
address indexed appContract,
uint256 lastProcessedBlockNumber,
bytes32 claim
);

/// @notice Submit a claim to the consensus.
/// @param appContract The application contract address
/// @param claim The output Merkle root hash
/// @param lastProcessedBlockNumber The number of the last processed block
/// @param claim The root of the Merkle tree of outputs
/// @dev MUST fire a `ClaimSubmission` event.
/// @dev MAY fire a `ClaimAcceptance` event, if the acceptance criteria is met.
function submitClaim(address appContract, bytes32 claim) external;
function submitClaim(
address appContract,
uint256 lastProcessedBlockNumber,
bytes32 claim
) external;

/// @notice Check if an output Merkle root hash was ever accepted by the consensus
/// for a particular application.
/// @param appContract The application contract address
/// @param claim The output Merkle root hash
/// @param claim The root of the Merkle tree of outputs
function wasClaimAccepted(
address appContract,
bytes32 claim
) external view returns (bool);

/// @notice Get the epoch length, in number of base layer blocks.
/// @dev The epoch number of a block is defined as
/// the integer division of the block number by the epoch length.
function getEpochLength() external view returns (uint256);
}
18 changes: 15 additions & 3 deletions contracts/consensus/authority/Authority.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,30 @@ import {AbstractConsensus} from "../AbstractConsensus.sol";
/// For more information on `Ownable`, please consult OpenZeppelin's official documentation.
contract Authority is AbstractConsensus, Ownable {
/// @param initialOwner The initial contract owner
constructor(address initialOwner) Ownable(initialOwner) {}
/// @param epochLength The epoch length
/// @dev Reverts if the epoch length is zero.
constructor(
address initialOwner,
uint256 epochLength
) AbstractConsensus(epochLength) Ownable(initialOwner) {}

/// @notice Submit a claim.
/// @param appContract The application contract address
/// @param lastProcessedBlockNumber The number of the last processed block
/// @param claim The output Merkle root hash
/// @dev Fires a `ClaimSubmission` event and a `ClaimAcceptance` event.
/// @dev Can only be called by the owner.
function submitClaim(
address appContract,
uint256 lastProcessedBlockNumber,
bytes32 claim
) external onlyOwner {
emit ClaimSubmission(msg.sender, appContract, claim);
_acceptClaim(appContract, claim);
emit ClaimSubmission(
msg.sender,
appContract,
lastProcessedBlockNumber,
claim
);
_acceptClaim(appContract, lastProcessedBlockNumber, claim);
}
}
18 changes: 12 additions & 6 deletions contracts/consensus/authority/AuthorityFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,34 @@ import {Authority} from "./Authority.sol";
/// @notice Allows anyone to reliably deploy a new `Authority` contract.
contract AuthorityFactory is IAuthorityFactory {
function newAuthority(
address authorityOwner
address authorityOwner,
uint256 epochLength
) external override returns (Authority) {
Authority authority = new Authority(authorityOwner);
Authority authority = new Authority(authorityOwner, epochLength);

emit AuthorityCreated(authorityOwner, authority);
emit AuthorityCreated(authority);

return authority;
}

function newAuthority(
address authorityOwner,
uint256 epochLength,
bytes32 salt
) external override returns (Authority) {
Authority authority = new Authority{salt: salt}(authorityOwner);
Authority authority = new Authority{salt: salt}(
authorityOwner,
epochLength
);

emit AuthorityCreated(authorityOwner, authority);
emit AuthorityCreated(authority);

return authority;
}

function calculateAuthorityAddress(
address authorityOwner,
uint256 epochLength,
bytes32 salt
) external view override returns (address) {
return
Expand All @@ -42,7 +48,7 @@ contract AuthorityFactory is IAuthorityFactory {
keccak256(
abi.encodePacked(
type(Authority).creationCode,
abi.encode(authorityOwner)
abi.encode(authorityOwner, epochLength)
)
)
);
Expand Down
17 changes: 14 additions & 3 deletions contracts/consensus/authority/IAuthorityFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,48 @@ interface IAuthorityFactory {
// Events

/// @notice A new authority was deployed.
/// @param authorityOwner The initial authority owner
/// @param authority The authority
/// @dev MUST be triggered on a successful call to `newAuthority`.
event AuthorityCreated(address authorityOwner, Authority authority);
event AuthorityCreated(Authority authority);

// Permissionless functions

/// @notice Deploy a new authority.
/// @param authorityOwner The initial authority owner
/// @param epochLength The epoch length
/// @return The authority
/// @dev On success, MUST emit an `AuthorityCreated` event.
function newAuthority(address authorityOwner) external returns (Authority);
/// @dev Reverts if the authority owner address is zero.
/// @dev Reverts if the epoch length is zero.
function newAuthority(
address authorityOwner,
uint256 epochLength
) external returns (Authority);

/// @notice Deploy a new authority deterministically.
/// @param authorityOwner The initial authority owner
/// @param epochLength The epoch length
/// @param salt The salt used to deterministically generate the authority address
/// @return The authority
/// @dev On success, MUST emit an `AuthorityCreated` event.
/// @dev Reverts if the authority owner address is zero.
/// @dev Reverts if the epoch length is zero.
function newAuthority(
address authorityOwner,
uint256 epochLength,
bytes32 salt
) external returns (Authority);

/// @notice Calculate the address of an authority to be deployed deterministically.
/// @param authorityOwner The initial authority owner
/// @param epochLength The epoch length
/// @param salt The salt used to deterministically generate the authority address
/// @return The deterministic authority address
/// @dev Beware that only the `newAuthority` function with the `salt` parameter
/// is able to deterministically deploy an authority.
function calculateAuthorityAddress(
address authorityOwner,
uint256 epochLength,
bytes32 salt
) external view returns (address);
}
14 changes: 13 additions & 1 deletion contracts/consensus/quorum/IQuorumFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,40 @@ interface IQuorumFactory {

/// @notice Deploy a new quorum.
/// @param validators the list of validators
/// @param epochLength The epoch length
/// @return The quorum
/// @dev On success, MUST emit a `QuorumCreated` event.
function newQuorum(address[] calldata validators) external returns (Quorum);
/// @dev Duplicates in the `validators` array are ignored.
/// @dev Reverts if the epoch length is zero.
function newQuorum(
address[] calldata validators,
uint256 epochLength
) external returns (Quorum);

/// @notice Deploy a new quorum deterministically.
/// @param validators the list of validators
/// @param epochLength The epoch length
/// @param salt The salt used to deterministically generate the quorum address
/// @return The quorum
/// @dev On success, MUST emit a `QuorumCreated` event.
/// @dev Duplicates in the `validators` array are ignored.
/// @dev Reverts if the epoch length is zero.
function newQuorum(
address[] calldata validators,
uint256 epochLength,
bytes32 salt
) external returns (Quorum);

/// @notice Calculate the address of a quorum to be deployed deterministically.
/// @param validators the list of validators
/// @param epochLength The epoch length
/// @param salt The salt used to deterministically generate the quorum address
/// @return The deterministic quorum address
/// @dev Beware that only the `newQuorum` function with the `salt` parameter
/// is able to deterministically deploy a quorum.
function calculateQuorumAddress(
address[] calldata validators,
uint256 epochLength,
bytes32 salt
) external view returns (address);
}
Loading

0 comments on commit d6db618

Please sign in to comment.