diff --git a/cartesi-rollups/node/Dockerfile.test b/cartesi-rollups/node/Dockerfile.test index c8e22342..9cfee6f5 100644 --- a/cartesi-rollups/node/Dockerfile.test +++ b/cartesi-rollups/node/Dockerfile.test @@ -8,7 +8,7 @@ RUN curl https://sh.rustup.rs -sSf | bash -s -- -y ENV PATH="/root/.cargo/bin:${PATH}" -COPY --from=ethereum/solc:0.8.23 /usr/bin/solc /usr/bin/solc +COPY --from=ethereum/solc:0.8.27 /usr/bin/solc /usr/bin/solc RUN chmod u+x /usr/bin/solc WORKDIR /app diff --git a/prt/contracts/foundry.toml b/prt/contracts/foundry.toml index a7cdd817..1b7a83e9 100644 --- a/prt/contracts/foundry.toml +++ b/prt/contracts/foundry.toml @@ -7,6 +7,7 @@ allow_paths = ['../../machine/step/'] remappings = [ 'step/=../../machine/step/', ] +solc-version = "0.8.27" [fmt] line_length = 80 diff --git a/prt/contracts/src/tournament/abstracts/LeafTournament.sol b/prt/contracts/src/tournament/abstracts/LeafTournament.sol index 98bff7c1..b873ae51 100644 --- a/prt/contracts/src/tournament/abstracts/LeafTournament.sol +++ b/prt/contracts/src/tournament/abstracts/LeafTournament.sol @@ -55,6 +55,11 @@ abstract contract LeafTournament is Tournament { ); } + error WrongFinalState( + uint256 commitment, Machine.Hash expected, Machine.Hash got + ); + error WrongNodesForStep(); + function winLeafMatch( Match.Id calldata _matchId, Tree.Node _leftNode, @@ -82,21 +87,27 @@ abstract contract LeafTournament is Tournament { ); if (_leftNode.join(_rightNode).eq(_matchId.commitmentOne)) { - require(_finalState.eq(_finalStateOne), "final state one mismatch"); + require( + _finalState.eq(_finalStateOne), + WrongFinalState(1, _finalState, _finalStateOne) + ); _clockOne.setPaused(); pairCommitment( _matchId.commitmentOne, _clockOne, _leftNode, _rightNode ); } else if (_leftNode.join(_rightNode).eq(_matchId.commitmentTwo)) { - require(_finalState.eq(_finalStateTwo), "final state two mismatch"); + require( + _finalState.eq(_finalStateTwo), + WrongFinalState(2, _finalState, _finalStateTwo) + ); _clockTwo.setPaused(); pairCommitment( _matchId.commitmentTwo, _clockTwo, _leftNode, _rightNode ); } else { - revert("wrong nodes for step"); + revert WrongNodesForStep(); } // delete storage @@ -144,13 +155,12 @@ abstract contract LeafTournament is Tournament { accessLogs = AccessLogs.Context( machineState, Buffer.Context(proofs, 32 + inputLength) ); - // TODO: contract size too big... - // SendCmioResponse.sendCmioResponse( - // accessLogs, - // EmulatorConstants.HTIF_YIELD_REASON_ADVANCE_STATE, - // inputMerkleRoot, - // uint32(inputLength) - // ); + SendCmioResponse.sendCmioResponse( + accessLogs, + EmulatorConstants.HTIF_YIELD_REASON_ADVANCE_STATE, + inputMerkleRoot, + uint32(inputLength) + ); UArchStep.step(accessLogs); } else if ((counter + 1) & uarch_step_mask == 0) { UArchReset.reset(accessLogs); diff --git a/prt/contracts/src/tournament/abstracts/NonLeafTournament.sol b/prt/contracts/src/tournament/abstracts/NonLeafTournament.sol index b9d0d759..f5da1581 100644 --- a/prt/contracts/src/tournament/abstracts/NonLeafTournament.sol +++ b/prt/contracts/src/tournament/abstracts/NonLeafTournament.sol @@ -93,6 +93,9 @@ abstract contract NonLeafTournament is Tournament { emit newInnerTournament(_matchId.hashFromId(), _inner); } + error ChildTournamentNotFinished(); + error WrongTournamentWinner(Tree.Node commitmentRoot, Tree.Node winner); + function winInnerMatch( NonRootTournament _childTournament, Tree.Node _leftNode, @@ -108,11 +111,14 @@ abstract contract NonLeafTournament is Tournament { (bool finished, Tree.Node _winner, Tree.Node _innerWinner) = _childTournament.innerTournamentWinner(); - require(finished, "child tournament is not finished"); + require(finished, ChildTournamentNotFinished()); _winner.requireExist(); Tree.Node _commitmentRoot = _leftNode.join(_rightNode); - require(_commitmentRoot.eq(_winner), "tournament winner is different"); + require( + _commitmentRoot.eq(_winner), + WrongTournamentWinner(_commitmentRoot, _winner) + ); (Clock.State memory _innerClock,) = _childTournament.getCommitment(_innerWinner); diff --git a/prt/contracts/src/tournament/abstracts/Tournament.sol b/prt/contracts/src/tournament/abstracts/Tournament.sol index 088f8d18..3a514e8b 100644 --- a/prt/contracts/src/tournament/abstracts/Tournament.sol +++ b/prt/contracts/src/tournament/abstracts/Tournament.sol @@ -70,14 +70,17 @@ abstract contract Tournament { // // Modifiers // + error TournamentIsFinished(); + error TournamentIsClosed(); + modifier tournamentNotFinished() { - require(!isFinished(), "tournament is finished"); + require(!isFinished(), TournamentIsFinished()); _; } modifier tournamentOpen() { - require(!isClosed(), "tournament check-in elapsed"); + require(!isClosed(), TournamentIsClosed()); _; } @@ -166,6 +169,11 @@ abstract contract Tournament { clocks[_matchId.commitmentTwo].advanceClock(); } + error WrongChildren( + uint256 commitment, Tree.Node parent, Tree.Node left, Tree.Node right + ); + error WinByTimeout(); + function winMatchByTimeout( Match.Id calldata _matchId, Tree.Node _leftNode, @@ -181,7 +189,7 @@ abstract contract Tournament { if (_clockOne.hasTimeLeft() && !_clockTwo.hasTimeLeft()) { require( _matchId.commitmentOne.verify(_leftNode, _rightNode), - "child nodes do not match parent (commitmentOne)" + WrongChildren(1, _matchId.commitmentOne, _leftNode, _rightNode) ); _clockOne.deduct(_clockTwo.timeSinceTimeout()); @@ -191,7 +199,7 @@ abstract contract Tournament { } else if (!_clockOne.hasTimeLeft() && _clockTwo.hasTimeLeft()) { require( _matchId.commitmentTwo.verify(_leftNode, _rightNode), - "child nodes do not match parent (commitmentTwo)" + WrongChildren(2, _matchId.commitmentTwo, _leftNode, _rightNode) ); _clockTwo.deduct(_clockOne.timeSinceTimeout()); @@ -199,13 +207,15 @@ abstract contract Tournament { _matchId.commitmentTwo, _clockTwo, _leftNode, _rightNode ); } else { - revert("cannot win by timeout"); + revert WinByTimeout(); } // delete storage deleteMatch(_matchId.hashFromId()); } + error EliminateByTimeout(); + function eliminateMatchByTimeout(Match.Id calldata _matchId) external tournamentNotFinished @@ -231,7 +241,7 @@ abstract contract Tournament { // delete storage deleteMatch(_matchId.hashFromId()); } else { - revert("cannot eliminate by timeout"); + revert EliminateByTimeout(); } } @@ -293,13 +303,15 @@ abstract contract Tournament { // // Helper functions // + error InvalidContestedFinalState(Machine.Hash finalState); + function requireValidContestedFinalState(Machine.Hash _finalState) internal view { require( validContestedFinalState(_finalState), - "tournament doesn't have contested final state" + InvalidContestedFinalState(_finalState) ); } diff --git a/prt/contracts/test/MultiTournament.t.sol b/prt/contracts/test/MultiTournament.t.sol index 8c3acdb4..a8056a08 100644 --- a/prt/contracts/test/MultiTournament.t.sol +++ b/prt/contracts/test/MultiTournament.t.sol @@ -389,7 +389,7 @@ contract MultiTournamentTest is Util, Test { _match = middleTournament.getMatch(_matchId.hashFromId()); assertTrue(_match.exists(), "match should exist"); - vm.expectRevert("cannot win by timeout"); + vm.expectRevert(Tournament.WinByTimeout.selector); middleTournament.winMatchByTimeout( _matchId, playerNodes[1][ArbitrationConstants.height(1) - 1], @@ -457,7 +457,7 @@ contract MultiTournamentTest is Util, Test { vm.warp(_rootTournamentFinish - 1); // cannot eliminate match when both blocks still have time - vm.expectRevert("cannot eliminate by timeout"); + vm.expectRevert(Tournament.EliminateByTimeout.selector); topTournament.eliminateMatchByTimeout(_matchId); vm.warp(_rootTournamentFinish); diff --git a/prt/tests/compute-rs/Dockerfile b/prt/tests/compute-rs/Dockerfile index f3a0bd43..cb765f24 100644 --- a/prt/tests/compute-rs/Dockerfile +++ b/prt/tests/compute-rs/Dockerfile @@ -29,7 +29,7 @@ WORKDIR /app/prt/tests/compute-rs RUN cargo chef cook --release --recipe-path recipe.json # Build application -COPY --from=ethereum/solc:0.8.23 /usr/bin/solc /usr/bin/solc +COPY --from=ethereum/solc:0.8.27 /usr/bin/solc /usr/bin/solc RUN chmod u+x /usr/bin/solc COPY ./prt /app/prt