Skip to content

Commit

Permalink
feat!: unify trees in OutputValidityProof
Browse files Browse the repository at this point in the history
  • Loading branch information
guidanoli committed Jan 23, 2024
1 parent 5428703 commit e26b527
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 69 deletions.
5 changes: 5 additions & 0 deletions onchain/rollups/.changeset/sharp-yaks-sing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/rollups": minor
---

Added `Outputs` interface.
9 changes: 9 additions & 0 deletions onchain/rollups/.changeset/thin-wolves-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@cartesi/rollups": major
---

Modified the `OutputValidityProof` struct:

- Removed the `vouchersEpochRootHash` field
- Removed the `noticesEpochRootHash` field
- Added an `outputsEpochRootHash` field
29 changes: 0 additions & 29 deletions onchain/rollups/contracts/common/OutputEncoding.sol

This file was deleted.

6 changes: 2 additions & 4 deletions onchain/rollups/contracts/common/OutputValidityProof.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,15 @@ pragma solidity ^0.8.8;
/// @param inputIndexWithinEpoch Which input, inside the epoch, the output belongs to
/// @param outputIndexWithinInput Index of output emitted by the input
/// @param outputHashesRootHash Merkle root of hashes of outputs emitted by the input
/// @param vouchersEpochRootHash Merkle root of all epoch's voucher metadata hashes
/// @param noticesEpochRootHash Merkle root of all epoch's notice metadata hashes
/// @param outputsEpochRootHash Merkle root of all epoch's outputs metadata hashes
/// @param machineStateHash Hash of the machine state claimed this epoch
/// @param outputHashInOutputHashesSiblings Proof that this output metadata is in metadata memory range
/// @param outputHashesInEpochSiblings Proof that this output metadata is in epoch's output memory range
struct OutputValidityProof {
uint64 inputIndexWithinEpoch;
uint64 outputIndexWithinInput;
bytes32 outputHashesRootHash;
bytes32 vouchersEpochRootHash;
bytes32 noticesEpochRootHash;
bytes32 outputsEpochRootHash;
bytes32 machineStateHash;
bytes32[] outputHashInOutputHashesSiblings;
bytes32[] outputHashesInEpochSiblings;
Expand Down
20 changes: 20 additions & 0 deletions onchain/rollups/contracts/common/Outputs.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.8;

/// @title Outputs
/// @notice Defines the signatures of outputs that can be generated by the
/// off-chain machine and verified by the on-chain contracts.
interface Outputs {
/// @notice A piece of verifiable information.
/// @param notice An arbitrary blob.
function Notice(bytes calldata notice) external;

/// @notice A single-use permission to execute a specific message call
/// from the context of the application contract.
/// @param destination The address that will be called
/// @param payload The payload, which—in the case of Solidity
/// contracts—encodes a function call
function Voucher(address destination, bytes calldata payload) external;
}
32 changes: 9 additions & 23 deletions onchain/rollups/contracts/library/LibOutputValidation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pragma solidity ^0.8.8;
import {CanonicalMachine} from "../common/CanonicalMachine.sol";
import {IApplication} from "../dapp/IApplication.sol";
import {MerkleV2} from "@cartesi/util/contracts/MerkleV2.sol";
import {OutputEncoding} from "../common/OutputEncoding.sol";
import {Outputs} from "../common/Outputs.sol";
import {OutputValidityProof} from "../common/OutputValidityProof.sol";

/// @title Output Validation Library
Expand All @@ -17,22 +17,15 @@ library LibOutputValidation {
/// @param v The output validity proof
/// @param encodedOutput The encoded output
/// @param epochHash The hash of the epoch in which the output was generated
/// @param outputsEpochRootHash Either `v.vouchersEpochRootHash` (for vouchers)
/// or `v.noticesEpochRootHash` (for notices)
function validateEncodedOutput(
OutputValidityProof calldata v,
bytes memory encodedOutput,
bytes32 epochHash,
bytes32 outputsEpochRootHash
bytes32 epochHash
) internal pure {
// prove that outputs hash is represented in a finalized epoch
if (
keccak256(
abi.encodePacked(
v.vouchersEpochRootHash,
v.noticesEpochRootHash,
v.machineStateHash
)
abi.encodePacked(v.outputsEpochRootHash, v.machineStateHash)
) != epochHash
) {
revert IApplication.IncorrectEpochHash();
Expand All @@ -49,7 +42,7 @@ library LibOutputValidation {
CanonicalMachine.EPOCH_OUTPUT_LOG2_SIZE.uint64OfSize(),
v.outputHashesRootHash,
v.outputHashesInEpochSiblings
) != outputsEpochRootHash
) != v.outputsEpochRootHash
) {
revert IApplication.IncorrectOutputsEpochRootHash();
}
Expand All @@ -72,7 +65,7 @@ library LibOutputValidation {
// is contained in it. We can't simply use hashOfOutput because the
// log2size of the leaf is three (8 bytes) not five (32 bytes)
bytes32 merkleRootOfHashOfOutput = MerkleV2.getMerkleRootFromBytes(
abi.encodePacked(keccak256(encodedOutput)),
abi.encodePacked(keccak256(abi.encode(encodedOutput))),
CanonicalMachine.KECCAK_LOG2_SIZE.uint64OfSize()
);

Expand Down Expand Up @@ -105,15 +98,10 @@ library LibOutputValidation {
bytes calldata payload,
bytes32 epochHash
) internal pure {
bytes memory encodedVoucher = OutputEncoding.encodeVoucher(
destination,
payload
);
validateEncodedOutput(
v,
encodedVoucher,
epochHash,
v.vouchersEpochRootHash
abi.encodeCall(Outputs.Voucher, (destination, payload)),
epochHash
);
}

Expand All @@ -126,12 +114,10 @@ library LibOutputValidation {
bytes calldata notice,
bytes32 epochHash
) internal pure {
bytes memory encodedNotice = OutputEncoding.encodeNotice(notice);
validateEncodedOutput(
v,
encodedNotice,
epochHash,
v.noticesEpochRootHash
abi.encodeCall(Outputs.Notice, (notice)),
epochHash
);
}
}
39 changes: 26 additions & 13 deletions onchain/rollups/test/foundry/dapp/Application.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {IInputRelay} from "contracts/inputs/IInputRelay.sol";
import {LibOutputValidation} from "contracts/library/LibOutputValidation.sol";
import {LibProof} from "contracts/library/LibProof.sol";
import {OutputValidityProof} from "contracts/common/OutputValidityProof.sol";
import {OutputEncoding} from "contracts/common/OutputEncoding.sol";
import {Outputs} from "contracts/common/Outputs.sol";
import {InputRange} from "contracts/common/InputRange.sol";

import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
Expand Down Expand Up @@ -69,7 +69,7 @@ contract ApplicationTest is TestBase {
bytes _encodedFinishEpochResponse;
IInputBox immutable _inputBox;
address immutable _appOwner;
address immutable _noticeSender;
address immutable _inputSender;
address immutable _recipient;
address immutable _tokenOwner;
bytes32 immutable _salt;
Expand Down Expand Up @@ -98,7 +98,7 @@ contract ApplicationTest is TestBase {
_appOwner = LibBytes.hashToAddress("appOwner");
_initialSupply = LibBytes.hashToUint256("initialSupply");
_inputBox = IInputBox(LibBytes.hashToAddress("inputBox"));
_noticeSender = LibBytes.hashToAddress("noticeSender");
_inputSender = LibBytes.hashToAddress("inputSender");
_recipient = LibBytes.hashToAddress("recipient");
_salt = keccak256("salt");
_templateHash = keccak256("templateHash");
Expand Down Expand Up @@ -330,7 +330,7 @@ contract ApplicationTest is TestBase {
OutputName.ERC20TransferVoucher
);

proof.validity.vouchersEpochRootHash = bytes32(uint256(0xdeadbeef));
proof.validity.outputsEpochRootHash = bytes32(uint256(0xdeadbeef));

vm.expectRevert(IApplication.IncorrectEpochHash.selector);
_executeVoucher(voucher, proof);
Expand Down Expand Up @@ -686,22 +686,37 @@ contract ApplicationTest is TestBase {
);
}

function _encodeVoucher(
Voucher memory voucher
) internal pure returns (bytes memory) {
return
abi.encodeCall(
Outputs.Voucher,
(voucher.destination, voucher.payload)
);
}

function _encodeNotice(
bytes memory notice
) internal pure returns (bytes memory) {
return abi.encodeCall(Outputs.Notice, (notice));
}

function _writeInputs() internal {
for (uint256 i; i < _outputEnums.length; ++i) {
LibServerManager.OutputEnum outputEnum = _outputEnums[i];
if (outputEnum == LibServerManager.OutputEnum.VOUCHER) {
Voucher memory voucher = _getVoucher(i);
_writeInput(i, voucher.destination, voucher.payload);
_writeInput(i, _encodeVoucher(voucher));
} else {
bytes memory notice = _getNotice(i);
_writeInput(i, _noticeSender, notice);
_writeInput(i, _encodeNotice(notice));
}
}
}

function _writeInput(
uint256 inputIndexWithinEpoch,
address sender,
bytes memory payload
) internal {
string memory inputIndexWithinEpochStr = vm.toString(
Expand All @@ -711,7 +726,7 @@ contract ApplicationTest is TestBase {
"input",
inputIndexWithinEpochStr
);
vm.serializeAddress(objectKey, "sender", sender);
vm.serializeAddress(objectKey, "sender", _inputSender);
string memory json = vm.serializeBytes(objectKey, "payload", payload);
string memory path = _getInputPath(inputIndexWithinEpochStr);
vm.writeJson(json, path);
Expand Down Expand Up @@ -762,7 +777,7 @@ contract ApplicationTest is TestBase {
OutputName outputName
) internal returns (Proof memory) {
uint256 inputIndexWithinEpoch = uint256(outputName);
Proof memory proof = _getVoucherProof(inputIndexWithinEpoch);
Proof memory proof = _getNoticeProof(inputIndexWithinEpoch);
_mockConsensus(proof);
return proof;
}
Expand Down Expand Up @@ -963,8 +978,7 @@ contract ApplicationTest is TestBase {
return
keccak256(
abi.encodePacked(
validity.vouchersEpochRootHash,
validity.noticesEpochRootHash,
validity.outputsEpochRootHash,
validity.machineStateHash
)
);
Expand All @@ -978,8 +992,7 @@ contract ApplicationTest is TestBase {
inputIndexWithinEpoch: v.inputIndexWithinEpoch.toUint64(),
outputIndexWithinInput: v.outputIndexWithinInput.toUint64(),
outputHashesRootHash: v.outputHashesRootHash,
vouchersEpochRootHash: v.vouchersEpochRootHash,
noticesEpochRootHash: v.noticesEpochRootHash,
outputsEpochRootHash: v.noticesEpochRootHash,
machineStateHash: v.machineStateHash,
outputHashInOutputHashesSiblings: v
.outputHashInOutputHashesSiblings,
Expand Down

0 comments on commit e26b527

Please sign in to comment.