diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 16b0bc2f..a436d1dc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,12 +22,15 @@ jobs: with: version: nightly + - name: Install just + uses: extractions/setup-just@v2 + - name: Build, format check and test working-directory: ./prt/contracts run: | - forge build - forge fmt --check - forge test + just check-fmt + just build-smart-contracts + just test - name: Set up cache for Cargo uses: actions/cache@v3 @@ -39,9 +42,6 @@ jobs: restore-keys: | ${{ runner.os }}-cargo- - - name: Install just - uses: extractions/setup-just@v2 - - name: Deps run: | export CARTESI_MACHINE_VERSION=0.18.1 @@ -53,9 +53,13 @@ jobs: - name: Rust fmt and check run: | just setup - just format-rust-workspace + just check-fmt-rust-workspace just check-rust-workspace + - name: Rust build + run: | + just build-rust-workspace + - name: Rust test workspace run: | just test-rust-workspace diff --git a/Cargo.toml b/Cargo.toml index 797eacfc..8dd8ad8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,10 @@ members = [ "cartesi-rollups/node/epoch-manager", "cartesi-rollups/node/machine-runner", "cartesi-rollups/node/state-manager", + + # machine bindings + "machine/rust-bindings/cartesi-machine", + "machine/rust-bindings/cartesi-machine-sys", ] [workspace.package] diff --git a/cartesi-rollups/contracts/bindings-rs/src/lib.rs b/cartesi-rollups/contracts/bindings-rs/src/lib.rs index c89b3333..7b5afcc3 100644 --- a/cartesi-rollups/contracts/bindings-rs/src/lib.rs +++ b/cartesi-rollups/contracts/bindings-rs/src/lib.rs @@ -1,2 +1,3 @@ +#[rustfmt::skip] pub mod contract; pub use contract::*; diff --git a/cartesi-rollups/node/blockchain-reader/src/lib.rs b/cartesi-rollups/node/blockchain-reader/src/lib.rs index 7cef17f5..c0f4a631 100644 --- a/cartesi-rollups/node/blockchain-reader/src/lib.rs +++ b/cartesi-rollups/node/blockchain-reader/src/lib.rs @@ -443,26 +443,17 @@ impl PartitionProvider { mod blockchain_reader_tests { use crate::*; use alloy::{ + hex::FromHex, network::EthereumWallet, node_bindings::{Anvil, AnvilInstance}, primitives::Address, providers::ProviderBuilder, - signers::local::PrivateKeySigner, - signers::Signer, + signers::{local::PrivateKeySigner, Signer}, sol_types::{SolCall, SolValue}, transports::http::{Client, Http}, }; use cartesi_dave_contracts::daveconsensus::DaveConsensus::{self, EpochSealed}; use cartesi_dave_merkle::Digest; - use cartesi_prt_contracts::{ - bottomtournamentfactory::BottomTournamentFactory, - middletournamentfactory::MiddleTournamentFactory, - multileveltournamentfactory::MultiLevelTournamentFactory::{ - self, CommitmentStructure, DisputeParameters, MultiLevelTournamentFactoryInstance, - TimeConstants, - }, - toptournamentfactory::TopTournamentFactory, - }; use cartesi_prt_core::arena::SenderFiller; use cartesi_rollups_contracts::{ inputbox::InputBox::{self, InputAdded}, @@ -479,13 +470,24 @@ mod blockchain_reader_tests { type Result = std::result::Result>; const APP_ADDRESS: Address = Address::ZERO; - const INITIAL_STATE: Digest = Digest::ZERO; + // $ xxd -p -c32 test/programs/echo/machine-image/hash + const INITIAL_STATE: &str = + "0x84c8181abd120e0281f5032d22422b890f79880ae90d9a1416be1afccb8182a0"; const INPUT_PAYLOAD: &str = "Hello!"; const INPUT_PAYLOAD2: &str = "Hello Two!"; - fn spawn_anvil_and_provider() -> (AnvilInstance, Arc) { - let args = vec!["--slots-in-an-epoch", "1"]; - let anvil = Anvil::default().block_time(1).args(args).spawn(); + fn spawn_anvil_and_provider() -> (AnvilInstance, SenderFiller, Address, Address) { + let anvil = Anvil::default() + .block_time(1) + .args([ + "--disable-code-size-limit", + "--preserve-historical-states", + "--slots-in-an-epoch", + "1", + "--load-state", + "../../../test/programs/echo/anvil_state.json", + ]) + .spawn(); let mut signer: PrivateKeySigner = anvil.keys()[0].clone().into(); @@ -497,7 +499,12 @@ mod blockchain_reader_tests { .wallet(wallet) .on_http(anvil.endpoint_url()); - (anvil, Arc::new(provider)) + ( + anvil, + provider, + Address::from_hex("0x5fbdb2315678afecb367f032d93f642f64180aa3").unwrap(), + Address::from_hex("0x0165878a594ca255338adfa4d48449f69242eb8f").unwrap(), + ) } fn create_partition_rovider(url: &str) -> Result { @@ -513,70 +520,8 @@ mod blockchain_reader_tests { EventReader::::new() } - async fn deploy_inputbox<'a>( - provider: &'a Arc, - ) -> Result, &'a Arc>>> { - let inputbox = InputBox::deploy(provider).await?; - Ok(Arc::new(inputbox)) - } - - async fn deploy_daveconsensus<'a>( - provider: &'a Arc, - inputbox: &Address, - tournament_factory: &Address, - ) -> Result, &'a Arc>>> - { - let daveconsensus = DaveConsensus::deploy( - provider, - *inputbox, - APP_ADDRESS, - *tournament_factory, - INITIAL_STATE.into(), - ) - .await?; - Ok(Arc::new(daveconsensus)) - } - - async fn deploy_tournamentfactories<'a>( - provider: &'a Arc, - ) -> Result, &'a Arc>>> { - let dispute_parameters = DisputeParameters { - timeConstants: TimeConstants { - matchEffort: 60 * 2, - maxAllowance: 60 * (60 + 5 + 2), - }, - commitmentStructures: vec![ - CommitmentStructure { - log2step: 44, - height: 48, - }, - CommitmentStructure { - log2step: 28, - height: 16, - }, - CommitmentStructure { - log2step: 0, - height: 28, - }, - ], - }; - - let top_tournamentfactory = TopTournamentFactory::deploy(provider).await?; - let mid_tournamentfactory = MiddleTournamentFactory::deploy(provider).await?; - let bottom_tournamentfactory = BottomTournamentFactory::deploy(provider).await?; - let multi_tournamentfactory = MultiLevelTournamentFactory::deploy( - provider, - *top_tournamentfactory.address(), - *mid_tournamentfactory.address(), - *bottom_tournamentfactory.address(), - dispute_parameters, - ) - .await?; - Ok(Arc::new(multi_tournamentfactory)) - } - - async fn add_input<'a>( - inputbox: &'a Arc, &'a Arc>>, + async fn add_input( + inputbox: &InputBox::InputBoxInstance, impl Provider>>, input_payload: &'static str, count: usize, ) -> Result<()> { @@ -669,40 +614,40 @@ mod blockchain_reader_tests { #[tokio::test] async fn test_input_reader() -> Result<()> { - let (anvil, provider) = spawn_anvil_and_provider(); - - let inputbox = deploy_inputbox(&provider).await?; + let (anvil, provider, input_box_address, _) = spawn_anvil_and_provider(); + let inputbox = InputBox::new(input_box_address, &provider); - let mut input_count = 2; - add_input(&inputbox, &INPUT_PAYLOAD, input_count).await?; + let input_count_1 = 2; + // Inputbox is deployed with 1 input already + add_input(&inputbox, INPUT_PAYLOAD, input_count_1).await?; let input_reader = create_input_reader(); let mut read_inputs = read_inputs_until_count( &anvil.endpoint(), inputbox.address(), &input_reader, - input_count, + 1 + input_count_1, ) .await?; - assert_eq!(read_inputs.len(), input_count); + assert_eq!(read_inputs.len(), 1 + input_count_1); let received_payload = - EvmAdvanceCall::abi_decode(read_inputs[input_count - 1].input.as_ref(), true)?; + EvmAdvanceCall::abi_decode(read_inputs.last().unwrap().input.as_ref(), true)?; assert_eq!(received_payload.payload.as_ref(), INPUT_PAYLOAD.as_bytes()); - input_count = 3; - add_input(&inputbox, &INPUT_PAYLOAD2, input_count).await?; + let input_count_2 = 3; + add_input(&inputbox, INPUT_PAYLOAD2, input_count_2).await?; read_inputs = read_inputs_until_count( &anvil.endpoint(), inputbox.address(), &input_reader, - input_count, + 1 + input_count_1 + input_count_2, ) .await?; - assert_eq!(read_inputs.len(), input_count); + assert_eq!(read_inputs.len(), 1 + input_count_1 + input_count_2); let received_payload = - EvmAdvanceCall::abi_decode(read_inputs[input_count - 1].input.as_ref(), true)?; + EvmAdvanceCall::abi_decode(read_inputs.last().unwrap().input.as_ref(), true)?; assert_eq!(received_payload.payload.as_ref(), INPUT_PAYLOAD2.as_bytes()); drop(anvil); @@ -711,16 +656,8 @@ mod blockchain_reader_tests { #[tokio::test] async fn test_epoch_reader() -> Result<()> { - let (anvil, provider) = spawn_anvil_and_provider(); - - let inputbox = deploy_inputbox(&provider).await?; - let multi_tournamentfactory = deploy_tournamentfactories(&provider).await?; - let daveconsensus = deploy_daveconsensus( - &provider, - inputbox.address(), - multi_tournamentfactory.address(), - ) - .await?; + let (anvil, provider, _, consensus_address) = spawn_anvil_and_provider(); + let daveconsensus = DaveConsensus::new(consensus_address, &provider); let epoch_reader = create_epoch_reader(); let read_epochs = @@ -729,7 +666,7 @@ mod blockchain_reader_tests { assert_eq!(read_epochs.len(), 1); assert_eq!( &read_epochs[0].initialMachineStateHash.abi_encode(), - INITIAL_STATE.slice() + Digest::from_digest_hex(INITIAL_STATE).unwrap().slice() ); drop(anvil); @@ -737,25 +674,20 @@ mod blockchain_reader_tests { } #[tokio::test] - async fn test_blockchain_reader() -> Result<()> { - let (anvil, provider) = spawn_anvil_and_provider(); + async fn test_blockchain_reader_aaa() -> Result<()> { + let (anvil, provider, input_box_address, consensus_address) = spawn_anvil_and_provider(); - let inputbox = deploy_inputbox(&provider).await?; + let inputbox = InputBox::new(input_box_address, &provider); let state_manager = Arc::new(PersistentStateAccess::new( Connection::open_in_memory().unwrap(), )?); + // Note that inputbox is deployed with 1 input already // add inputs to epoch 0 - let mut input_count = 2; - add_input(&inputbox, &INPUT_PAYLOAD, input_count).await?; + let input_count_1 = 2; + add_input(&inputbox, INPUT_PAYLOAD, input_count_1).await?; - let multi_tournamentfactory = deploy_tournamentfactories(&provider).await?; - let daveconsensus = deploy_daveconsensus( - &provider, - inputbox.address(), - multi_tournamentfactory.address(), - ) - .await?; + let daveconsensus = DaveConsensus::new(consensus_address, &provider); let mut blockchain_reader = BlockchainReader::new( state_manager.clone(), AddressBook { @@ -767,23 +699,30 @@ mod blockchain_reader_tests { 1, )?; - let _ = spawn(async move { + let r = spawn(async move { blockchain_reader.start().await.unwrap(); }); - read_inputs_from_db_until_count(&state_manager, 0, input_count).await?; + read_inputs_from_db_until_count(&state_manager, 0, 1).await?; + read_inputs_from_db_until_count(&state_manager, 1, input_count_1).await?; // add inputs to epoch 1 - input_count = 3; - add_input(&inputbox, &INPUT_PAYLOAD, input_count).await?; - read_inputs_from_db_until_count(&state_manager, 1, input_count).await?; + let input_count_2 = 3; + add_input(&inputbox, INPUT_PAYLOAD, input_count_2).await?; + read_inputs_from_db_until_count(&state_manager, 1, input_count_1 + input_count_2).await?; // add more inputs to epoch 1 - let more_input_count = 3; - add_input(&inputbox, &INPUT_PAYLOAD, more_input_count).await?; - read_inputs_from_db_until_count(&state_manager, 1, input_count + more_input_count).await?; + let input_count_3 = 3; + add_input(&inputbox, INPUT_PAYLOAD, input_count_3).await?; + read_inputs_from_db_until_count( + &state_manager, + 1, + input_count_1 + input_count_2 + input_count_3, + ) + .await?; drop(anvil); + drop(r); Ok(()) } } diff --git a/cartesi-rollups/node/dave-rollups/src/lib.rs b/cartesi-rollups/node/dave-rollups/src/lib.rs index 6e056fca..9b92bbdc 100644 --- a/cartesi-rollups/node/dave-rollups/src/lib.rs +++ b/cartesi-rollups/node/dave-rollups/src/lib.rs @@ -3,9 +3,9 @@ use cartesi_prt_core::arena::{BlockchainConfig, EthArenaSender, SenderFiller}; use clap::Parser; use log::error; use rollups_blockchain_reader::{AddressBook, BlockchainReader}; -use rollups_prt_runner::ComputeRunner; use rollups_epoch_manager::EpochManager; use rollups_machine_runner::MachineRunner; +use rollups_prt_runner::ComputeRunner; use rollups_state_manager::persistent_state_access::PersistentStateAccess; use std::path::PathBuf; use std::sync::Arc; diff --git a/common-rs/merkle/src/digest/keccak.rs b/common-rs/merkle/src/digest/keccak.rs index 7a4757ca..65bc856e 100644 --- a/common-rs/merkle/src/digest/keccak.rs +++ b/common-rs/merkle/src/digest/keccak.rs @@ -22,4 +22,3 @@ impl Digest { Digest::from(digest) } } - diff --git a/justfile b/justfile index 6c457f44..efd9215e 100644 --- a/justfile +++ b/justfile @@ -30,8 +30,10 @@ build-smart-contracts: build-consensus build-prt bind: bind-consensus bind-prt clean-bindings: clean-consensus-bindings clean-prt-bindings -format-rust-workspace: bind +fmt-rust-workspace: bind cargo fmt +check-fmt-rust-workspace: bind + cargo fmt --check check-rust-workspace: bind cargo check test-rust-workspace: bind diff --git a/machine/rust-bindings/cartesi-machine/src/proof.rs b/machine/rust-bindings/cartesi-machine/src/proof.rs index 17dab0ae..38e93254 100644 --- a/machine/rust-bindings/cartesi-machine/src/proof.rs +++ b/machine/rust-bindings/cartesi-machine/src/proof.rs @@ -44,8 +44,9 @@ impl MerkleTreeProof { /// Sibling hashes towards root pub fn sibling_hashes(&self) -> Vec { let sibling_hashes = unsafe { (*self.0).sibling_hashes }; - let sibling_hashes = unsafe { std::slice::from_raw_parts(sibling_hashes.entry, sibling_hashes.count) }; + let sibling_hashes = + unsafe { std::slice::from_raw_parts(sibling_hashes.entry, sibling_hashes.count) }; sibling_hashes.iter().map(|hash| Hash::new(*hash)).collect() } -} \ No newline at end of file +} diff --git a/prt/contracts/bindings-rs/src/lib.rs b/prt/contracts/bindings-rs/src/lib.rs index c89b3333..7b5afcc3 100644 --- a/prt/contracts/bindings-rs/src/lib.rs +++ b/prt/contracts/bindings-rs/src/lib.rs @@ -1,2 +1,3 @@ +#[rustfmt::skip] pub mod contract; pub use contract::*; diff --git a/prt/contracts/justfile b/prt/contracts/justfile index b4c71b8c..f6230f95 100644 --- a/prt/contracts/justfile +++ b/prt/contracts/justfile @@ -10,12 +10,18 @@ clean: clean-smart-contracts clean-bindings build-smart-contracts: forge build +test: + forge test + clean-smart-contracts: forge clean fmt: forge fmt +check-fmt: + forge fmt --check + clean-bindings: rm -rf {{BINDINGS_DIR}} diff --git a/prt/tests/common/blockchain/node.lua b/prt/tests/common/blockchain/node.lua index 80ca463e..c891cee5 100644 --- a/prt/tests/common/blockchain/node.lua +++ b/prt/tests/common/blockchain/node.lua @@ -9,13 +9,13 @@ local function start_blockchain(load_state) local cmd if load_state then cmd = string.format( - [[sh -c "echo $$ ; exec anvil --load-state %s --block-time 1 --slots-in-an-epoch 1 -a %d > anvil.log 2>&1"]], + [[sh -c "echo $$ ; exec anvil --load-state %s --disable-code-size-limit --preserve-historical-states --block-time 1 --slots-in-an-epoch 1 -a %d > anvil.log 2>&1"]], load_state, default_account_number ) else cmd = string.format( - [[sh -c "echo $$ ; exec anvil --block-time 1 --slots-in-an-epoch 1 -a %d > anvil.log 2>&1"]], + [[sh -c "echo $$ ; exec anvil --disable-code-size-limit --preserve-historical-states --block-time 1 --slots-in-an-epoch 1 -a %d > anvil.log 2>&1"]], default_account_number ) end diff --git a/prt/tests/common/blockchain/utils.lua b/prt/tests/common/blockchain/utils.lua index 20670ac5..8b4024cd 100644 --- a/prt/tests/common/blockchain/utils.lua +++ b/prt/tests/common/blockchain/utils.lua @@ -19,6 +19,7 @@ local function advance_time(blocks, endpoint) end end +-- TODO remove this, since we're dumping/loading an "ready" anvil state. local deploy_cmd = [[sh -c "cd %s && ./deploy_anvil.sh"]] local function deploy_contracts(contracts_path) local reader = io.popen(string.format(deploy_cmd, contracts_path)) diff --git a/test/programs/build_anvil_state.sh b/test/programs/build_anvil_state.sh index 8eb51ac8..2d105e0e 100755 --- a/test/programs/build_anvil_state.sh +++ b/test/programs/build_anvil_state.sh @@ -6,7 +6,7 @@ mkdir -p $program_path # start anvil with dump state rm -f $program_path/anvil_state.json -anvil --disable-code-size-limit \ +anvil --disable-code-size-limit --preserve-historical-states --slots-in-an-epoch 1 \ --dump-state $program_path/anvil_state.json > $program_path/_anvil.log 2>&1 & anvil_pid=$! sleep 5 @@ -28,6 +28,8 @@ jq -r '.transactions[] | select(.transactionType=="CREATE") | select(.contractNa ../../cartesi-rollups/contracts/broadcast/DaveConsensus.s.sol/31337/run-latest.json \ >> $program_path/addresses +cast rpc anvil_mine 2 + # # kill anvil, thus dumping its state, to be loaded later by tests kill -INT "$anvil_pid"