From c385075ef63b56f6d803fe2978ce4e345dd4c2ea Mon Sep 17 00:00:00 2001 From: Victor Yves Crispim Date: Wed, 26 Jul 2023 16:48:02 -0300 Subject: [PATCH] feat(advance-runner): get off-chain machine hash --- offchain/advance-runner/src/runner.rs | 10 +++ .../advance-runner/src/snapshot/disabled.rs | 9 +++ .../advance-runner/src/snapshot/fs_manager.rs | 81 ++++++++++++++++++- offchain/advance-runner/src/snapshot/mod.rs | 11 ++- offchain/rollups-events/src/common.rs | 2 +- 5 files changed, 110 insertions(+), 3 deletions(-) diff --git a/offchain/advance-runner/src/runner.rs b/offchain/advance-runner/src/runner.rs index 6bf06c6d4..c00e9c884 100644 --- a/offchain/advance-runner/src/runner.rs +++ b/offchain/advance-runner/src/runner.rs @@ -52,6 +52,9 @@ pub enum RunnerError { got ))] ParentIdMismatchError { expected: String, got: String }, + + #[snafu(display("failed to get hash from snapshot "))] + GetSnapshotHashError { source: SnapError }, } type Result = std::result::Result>; @@ -118,6 +121,13 @@ impl Runner { .context(GetLatestSnapshotSnafu)?; tracing::info!(?snapshot, "got latest snapshot"); + let offchain_hash = self + .snapshot_manager + .get_template_hash(&snapshot) + .await + .context(GetSnapshotHashSnafu)?; + tracing::info!(?offchain_hash, "got snapshot hash"); + let event_id = self .broker .find_previous_finish_epoch(snapshot.epoch) diff --git a/offchain/advance-runner/src/snapshot/disabled.rs b/offchain/advance-runner/src/snapshot/disabled.rs index 340221073..5b22459b8 100644 --- a/offchain/advance-runner/src/snapshot/disabled.rs +++ b/offchain/advance-runner/src/snapshot/disabled.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 (see LICENSE) use super::{Snapshot, SnapshotManager}; +use rollups_events::Hash; #[derive(Debug)] pub struct SnapshotDisabled {} @@ -41,4 +42,12 @@ impl SnapshotManager for SnapshotDisabled { tracing::trace!("snapshots disabled; ignoring"); Ok(()) } + + async fn get_template_hash( + &self, + _: &Snapshot, + ) -> Result { + tracing::trace!("snapshots disabled; returning default"); + Ok(Hash::default()) + } } diff --git a/offchain/advance-runner/src/snapshot/fs_manager.rs b/offchain/advance-runner/src/snapshot/fs_manager.rs index 17077e45e..3996b92e5 100644 --- a/offchain/advance-runner/src/snapshot/fs_manager.rs +++ b/offchain/advance-runner/src/snapshot/fs_manager.rs @@ -1,14 +1,18 @@ // (c) Cartesi and individual authors (see AUTHORS) // SPDX-License-Identifier: Apache-2.0 (see LICENSE) +use rollups_events::{Hash, HASH_SIZE}; use snafu::{ensure, OptionExt, ResultExt, Snafu}; use std::collections::HashSet; -use std::fs; +use std::fs::{self, File}; +use std::io::Read; use std::path::{Path, PathBuf}; use super::config::FSManagerConfig; use super::{Snapshot, SnapshotManager}; +const HASH_FILE: &str = "hash"; + #[derive(Debug, Snafu)] pub enum FSSnapshotError { #[snafu(display("failed to follow latest symlink"))] @@ -66,6 +70,18 @@ pub enum FSSnapshotError { path: PathBuf, source: std::io::Error, }, + + #[snafu(display("failed to open hash file for snapshot ({})", path.display()))] + HashNotFoundError { + path: PathBuf, + source: std::io::Error, + }, + + #[snafu(display("failed to read hash file for snapshot ({})", path.display()))] + ReadHashError { + path: PathBuf, + source: std::io::Error, + }, } #[derive(Debug)] @@ -195,6 +211,22 @@ impl SnapshotManager for FSSnapshotManager { Ok(()) } + + //TODO: logs + async fn get_template_hash( + &self, + snapshot: &Snapshot, + ) -> Result { + let path = snapshot.path.with_file_name(HASH_FILE); + let file = File::open(path.clone()) + .context(HashNotFoundSnafu { path: path.clone() })?; + + let mut buffer = [0_u8; HASH_SIZE]; + file.take(HASH_SIZE as u64) + .read(&mut buffer) + .context(ReadHashSnafu { path: path.clone() })?; + Ok(Hash::new(buffer)) + } } fn encode_filename(epoch: u64, processed_input_count: u64) -> String { @@ -525,4 +557,51 @@ mod tests { state.tempdir.path().join("2_2"), ); } + + #[test_log::test(tokio::test)] + async fn test_it_gets_snapshot_hash() { + let state = TestState::setup(); + let path = state.create_snapshot("0_0"); + let hash_path = path.with_file_name(HASH_FILE); + let hash = [ + 160, 170, 75, 88, 113, 141, 144, 31, 252, 78, 159, 6, 79, 114, 6, + 16, 196, 49, 44, 208, 62, 83, 66, 97, 4, 151, 159, 105, 124, 85, + 51, 87, + ]; + fs::write(hash_path, hash).expect("should write hash to file"); + + let snap = Snapshot { + epoch: 0, + processed_input_count: 0, + path, + }; + + assert_eq!( + state + .manager + .get_template_hash(&snap) + .await + .expect("get template hash should work"), + Hash::new(hash) + ); + } + + #[test_log::test(tokio::test)] + async fn test_it_fails_to_get_hash_when_hash_file_does_not_exist() { + let state = TestState::setup(); + let path = state.create_snapshot("0_0"); + let snap = Snapshot { + epoch: 0, + processed_input_count: 0, + path, + }; + + let err = state + .manager + .get_template_hash(&snap) + .await + .expect_err("get template hash should fail"); + + assert!(matches!(err, FSSnapshotError::HashNotFoundError { .. })) + } } diff --git a/offchain/advance-runner/src/snapshot/mod.rs b/offchain/advance-runner/src/snapshot/mod.rs index 3149aa68b..a46c3b74f 100644 --- a/offchain/advance-runner/src/snapshot/mod.rs +++ b/offchain/advance-runner/src/snapshot/mod.rs @@ -1,14 +1,16 @@ // (c) Cartesi and individual authors (see AUTHORS) // SPDX-License-Identifier: Apache-2.0 (see LICENSE) +use rollups_events::Hash; use std::path::PathBuf; pub mod config; pub mod disabled; pub mod fs_manager; +//TODO: improve this description. Create a Metadata struct maybe? /// Cartesi Machine snapshot description -#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct Snapshot { pub path: PathBuf, pub epoch: u64, @@ -22,6 +24,7 @@ pub trait SnapshotManager { /// Get the most recent snapshot async fn get_latest(&self) -> Result; + //TODO: maybe rename to new_empty_snapshot? /// Get the target storage directory for the snapshot async fn get_storage_directory( &self, @@ -31,4 +34,10 @@ pub trait SnapshotManager { /// Set the most recent snapshot async fn set_latest(&self, snapshot: Snapshot) -> Result<(), Self::Error>; + + /// Get the snapshot's template hash + async fn get_template_hash( + &self, + snapshot: &Snapshot, + ) -> Result; } diff --git a/offchain/rollups-events/src/common.rs b/offchain/rollups-events/src/common.rs index a69e29e1f..ffd67b303 100644 --- a/offchain/rollups-events/src/common.rs +++ b/offchain/rollups-events/src/common.rs @@ -11,7 +11,7 @@ pub const ADDRESS_SIZE: usize = 20; pub const HASH_SIZE: usize = 32; /// A binary array that is converted to a hex string when serialized -#[derive(Clone, Hash, Eq, PartialEq)] +#[derive(Clone, Hash, Eq, PartialEq, PartialOrd, Ord)] pub struct HexArray([u8; N]); impl HexArray {