Skip to content

Commit

Permalink
feat(advance-runner): get off-chain machine hash
Browse files Browse the repository at this point in the history
  • Loading branch information
torives authored and gligneul committed Aug 23, 2023
1 parent a28bca6 commit 7e62b90
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 3 deletions.
10 changes: 10 additions & 0 deletions offchain/advance-runner/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ pub enum RunnerError<SnapError: snafu::Error + 'static> {
got
))]
ParentIdMismatchError { expected: String, got: String },

#[snafu(display("failed to get hash from snapshot "))]
GetSnapshotHashError { source: SnapError },
}

type Result<T, SnapError> = std::result::Result<T, RunnerError<SnapError>>;
Expand Down Expand Up @@ -118,6 +121,13 @@ impl<Snap: SnapshotManager + std::fmt::Debug + 'static> Runner<Snap> {
.context(GetLatestSnapshotSnafu)?;
tracing::info!(?snapshot, "got latest snapshot");

let offchain_hash = self
.snapshot_manager
.get_template_hash(&snapshot)
.await
.context(GetSnapshotHashSnafu)?;
tracing::trace!(?offchain_hash, "got snapshot hash");

let event_id = self
.broker
.find_previous_finish_epoch(snapshot.epoch)
Expand Down
9 changes: 9 additions & 0 deletions offchain/advance-runner/src/snapshot/disabled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand Down Expand Up @@ -41,4 +42,12 @@ impl SnapshotManager for SnapshotDisabled {
tracing::trace!("snapshots disabled; ignoring");
Ok(())
}

async fn get_template_hash(
&self,
_: &Snapshot,
) -> Result<Hash, SnapshotDisabledError> {
tracing::trace!("snapshots disabled; returning default");
Ok(Hash::default())
}
}
87 changes: 86 additions & 1 deletion offchain/advance-runner/src/snapshot/fs_manager.rs
Original file line number Diff line number Diff line change
@@ -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)]
#[allow(clippy::enum_variant_names)]
pub enum FSSnapshotError {
Expand Down Expand Up @@ -67,6 +71,18 @@ pub enum FSSnapshotError {
path: PathBuf,
source: std::io::Error,
},

#[snafu(display("failed to open hash file for snapshot ({})", path.display()))]
OpenHashError {
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)]
Expand Down Expand Up @@ -196,6 +212,28 @@ impl SnapshotManager for FSSnapshotManager {

Ok(())
}

/// Reads the binary contents of the hash file in snapshot's directory
/// and converts them to a `Hash`. It assumes the file was created correctly
/// and makes no checks in this regard.
#[tracing::instrument(level = "trace", skip_all)]
async fn get_template_hash(
&self,
snapshot: &Snapshot,
) -> Result<Hash, FSSnapshotError> {
let path = snapshot.path.join(HASH_FILE);
tracing::trace!(?path, "opening hash file at");
let file = File::open(path.clone())
.context(OpenHashSnafu { path: path.clone() })?;

let mut buffer = [0_u8; HASH_SIZE];
let bytes = file
.take(HASH_SIZE as u64)
.read(&mut buffer)
.context(ReadHashSnafu { path: path.clone() })?;
tracing::trace!("read {bytes} bytes from file");
Ok(Hash::new(buffer))
}
}

fn encode_filename(epoch: u64, processed_input_count: u64) -> String {
Expand Down Expand Up @@ -525,4 +563,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.join(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::OpenHashError { .. }))
}
}
11 changes: 9 additions & 2 deletions offchain/advance-runner/src/snapshot/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// (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;

/// Cartesi Machine snapshot description
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
/// A path to a Cartesi Machine snapshot and its metadata
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Snapshot {
pub path: PathBuf,
pub epoch: u64,
Expand All @@ -31,4 +32,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<Hash, Self::Error>;
}

0 comments on commit 7e62b90

Please sign in to comment.