Skip to content

Commit

Permalink
♻ Init refactors
Browse files Browse the repository at this point in the history
  • Loading branch information
clabby committed Jan 14, 2024
1 parent 69b7a59 commit e0fe105
Show file tree
Hide file tree
Showing 16 changed files with 1,560 additions and 172 deletions.
1,316 changes: 1,276 additions & 40 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ members = ["crates/*"]
[workspace.package]
edition = "2021"
version = "0.0.1"
authors = ["clabby"]
23 changes: 18 additions & 5 deletions crates/fault/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
[package]
name = "durin-fault"
description = "Game solver for the OP Stack's FaultDisputeGame"
authors = ["clabby"]
resolver = "2"

edition.workspace = true
version.workspace = true
authors.workspace = true

[dependencies]
# Internal
durin-primitives = { path = "../primitives" }

# External
alloy-primitives = { version = "0.4.2" }
alloy-sol-types = { version = "0.4.2" }
anyhow = "1.0.75"

alloy-primitives = "0.6.0"
alloy-sol-types = "0.6.0"
alloy-rpc-client = { git = "https://github.com/alloy-rs/alloy" }
alloy-transport = { git = "https://github.com/alloy-rs/alloy" }
alloy-transport-http = { git = "https://github.com/alloy-rs/alloy" }
anyhow = "1.0.79"

# Async
tokio = { version = "1.35.1", features = ["macros"] }
url = "2.5.0"
reqwest = "0.11.23"
async-trait = "0.1.77"
futures = "0.3.30"

[dev-dependencies]
proptest = "1.2.0"
proptest = "1.4.0"
4 changes: 1 addition & 3 deletions crates/fault/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! The fault module contains types and traits related to the FaultDisputeGame.
extern crate alloy_primitives;
extern crate alloy_sol_types;
extern crate durin_primitives;
#![allow(unused, dead_code)]

#[cfg(test)]
extern crate proptest;
Expand Down
41 changes: 19 additions & 22 deletions crates/fault/src/providers/alphabet.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
//! This module contains the implementation of the [crate::TraceProvider] trait for the
//! mock Alphabet VM.
#![allow(dead_code, unused_variables)]
//! This module contains the implementation of the [crate::TraceProvider] trait for the mock Alphabet VM.
use crate::{Gindex, Position, TraceProvider, VMStatus};
use alloy_primitives::{keccak256, U256};
Expand All @@ -11,8 +8,7 @@ use std::{convert::TryInto, sync::Arc};

type AlphabetClaimConstruction = sol! { tuple(uint256, uint256) };

/// The [AlphabetTraceProvider] is a [TraceProvider] that provides the correct
/// trace for the mock Alphabet VM.
/// The [AlphabetTraceProvider] is a [TraceProvider] that provides the correct trace for the mock Alphabet VM.
pub struct AlphabetTraceProvider {
/// The absolute prestate of the alphabet VM is the setup state.
/// This will be the ascii representation of letter prior to the first
Expand All @@ -31,19 +27,20 @@ impl AlphabetTraceProvider {
}
}

#[async_trait::async_trait]
impl TraceProvider<[u8; 1]> for AlphabetTraceProvider {
fn absolute_prestate(&self) -> Arc<[u8; 1]> {
Arc::new([self.absolute_prestate])
async fn absolute_prestate(&self) -> anyhow::Result<Arc<[u8; 1]>> {
Ok(Arc::new([self.absolute_prestate]))
}

fn absolute_prestate_hash(&self) -> Claim {
async fn absolute_prestate_hash(&self) -> anyhow::Result<Claim> {
let prestate = U256::from(self.absolute_prestate);
let mut prestate_hash = keccak256(<sol!(uint256)>::abi_encode(&prestate));
prestate_hash[0] = VMStatus::Unfinished as u8;
prestate_hash
Ok(prestate_hash)
}

fn state_at(&self, position: Position) -> anyhow::Result<Arc<[u8; 1]>> {
async fn state_at(&self, position: Position) -> anyhow::Result<Arc<[u8; 1]>> {
let absolute_prestate = self.absolute_prestate as u64;
let trace_index = position.trace_index(self.max_depth);

Expand All @@ -53,17 +50,17 @@ impl TraceProvider<[u8; 1]> for AlphabetTraceProvider {
Ok(Arc::new([state]))
}

fn state_hash(&self, position: Position) -> anyhow::Result<Claim> {
async fn state_hash(&self, position: Position) -> anyhow::Result<Claim> {
let state_sol = (
U256::from(position.trace_index(self.max_depth)),
U256::from(self.state_at(position)?[0]),
U256::from(self.state_at(position).await?[0]),
);
let mut state_hash = keccak256(AlphabetClaimConstruction::abi_encode(&state_sol));
state_hash[0] = VMStatus::Invalid as u8;
Ok(state_hash)
}

fn proof_at(&self, position: Position) -> anyhow::Result<Arc<[u8]>> {
async fn proof_at(&self, _: Position) -> anyhow::Result<Arc<[u8]>> {
Ok(Arc::new([]))
}
}
Expand All @@ -74,30 +71,30 @@ mod test {
use crate::compute_gindex;
use alloy_primitives::hex;

#[test]
fn alphabet_encoding() {
#[tokio::test]
async fn alphabet_encoding() {
let provider = AlphabetTraceProvider {
absolute_prestate: b'a',
max_depth: 4,
};

let prestate_sol = U256::from(provider.absolute_prestate()[0]);
let prestate_sol = U256::from(provider.absolute_prestate().await.unwrap()[0]);
let prestate = <sol!(uint256)>::abi_encode(&prestate_sol);
assert_eq!(
hex!("0000000000000000000000000000000000000000000000000000000000000061"),
prestate.as_slice()
);

let mut prestate_hash = provider.absolute_prestate_hash();
let mut prestate_hash = provider.absolute_prestate_hash().await.unwrap();
prestate_hash[0] = VMStatus::Unfinished as u8;
assert_eq!(
hex!("03ecb75dd1820844c57b6762233d4e26853b3a7b8157bbd9f41f280a0f1cee9b"),
prestate_hash.as_slice()
);
}

#[test]
fn alphabet_trace_at() {
#[tokio::test]
async fn alphabet_trace_at() {
let provider = AlphabetTraceProvider {
absolute_prestate: b'a',
max_depth: 4,
Expand All @@ -112,8 +109,8 @@ mod test {
keccak256(AlphabetClaimConstruction::abi_encode(&expected_encoded));
expected_hash[0] = VMStatus::Invalid as u8;

assert_eq!(provider.state_at(position).unwrap()[0], expected);
assert_eq!(provider.state_hash(position).unwrap(), expected_hash);
assert_eq!(provider.state_at(position).await.unwrap()[0], expected);
assert_eq!(provider.state_hash(position).await.unwrap(), expected_hash);
}
}
}
3 changes: 3 additions & 0 deletions crates/fault/src/providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
mod alphabet;
pub use self::alphabet::AlphabetTraceProvider;

mod output;
pub use self::output::OutputTraceProvider;
57 changes: 57 additions & 0 deletions crates/fault/src/providers/output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//! This module contains the implementation of the [crate::TraceProvider] trait for the mock Alphabet VM.
use crate::{Position, TraceProvider};
use alloy_rpc_client::RpcClient;
use alloy_transport::TransportResult;
use alloy_transport_http::Http;
use anyhow::Result;
use durin_primitives::Claim;
use reqwest::{Client, Url};
use std::sync::Arc;

/// The [OutputTraceProvider] is a [TraceProvider] that provides L2 output commitments relative to a [Position] in the
/// output bisection portion of the dispute game.
pub struct OutputTraceProvider {
pub rpc_client: RpcClient<Http<Client>>,
pub starting_block_number: u64,
pub leaf_depth: u64,
}

impl OutputTraceProvider {
pub fn try_new(
l2_archive_url: String,
starting_block_number: u64,
leaf_depth: u64,
) -> Result<Self> {
let rpc_client = RpcClient::builder().reqwest_http(Url::parse(&l2_archive_url)?);
Ok(Self {
rpc_client,
starting_block_number,
leaf_depth,
})
}
}

#[async_trait::async_trait]
impl TraceProvider<[u8; 32]> for OutputTraceProvider {
async fn absolute_prestate(&self) -> anyhow::Result<Arc<[u8; 32]>> {
todo!()
// let transport_result: TransportResult<> = self.rpc_client.prepare("optimism_outputAtBlock", (self.starting_block_number)).await.map_err(|e| anyhow::anyhow!(e))?
}

async fn absolute_prestate_hash(&self) -> anyhow::Result<Claim> {
todo!()
}

async fn state_at(&self, position: Position) -> anyhow::Result<Arc<[u8; 32]>> {
todo!()
}

async fn state_hash(&self, position: Position) -> anyhow::Result<Claim> {
todo!()
}

async fn proof_at(&self, _: Position) -> anyhow::Result<Arc<[u8]>> {
todo!()
}
}
44 changes: 29 additions & 15 deletions crates/fault/src/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ use crate::{
};
use durin_primitives::{DisputeGame, DisputeSolver};
use std::{marker::PhantomData, sync::Arc};
use tokio::sync::Mutex;

/// A [FaultDisputeSolver] is a [DisputeSolver] that is played over a fault proof VM backend. The
/// solver is responsible for honestly responding to any given [ClaimData] in a given
/// [FaultDisputeState]. It uses a [TraceProvider] to fetch the absolute prestate of the VM as
/// well as the state at any given [Position] within the tree.
/// A [FaultDisputeSolver] is a [DisputeSolver] that is played over a fault proof VM backend. The solver is responsible
/// for honestly responding to any given [ClaimData] in a given [FaultDisputeState]. It uses a [TraceProvider] to fetch
/// the absolute prestate of the VM as well as the state at any given [Position] within the tree.
pub struct FaultDisputeSolver<T, P, S>
where
T: AsRef<[u8]>,
Expand All @@ -33,34 +33,48 @@ where
}
}

#[async_trait::async_trait]
impl<T, P, S> DisputeSolver<FaultDisputeState, FaultSolverResponse<T>>
for FaultDisputeSolver<T, P, S>
where
T: AsRef<[u8]>,
P: TraceProvider<T>,
S: FaultClaimSolver<T, P>,
T: AsRef<[u8]> + Sync + Send,
P: TraceProvider<T> + Sync,
S: FaultClaimSolver<T, P> + Sync,
{
fn available_moves(
async fn available_moves(
&self,
game: &mut FaultDisputeState,
game: Arc<Mutex<FaultDisputeState>>,
) -> anyhow::Result<Arc<[FaultSolverResponse<T>]>> {
let game_lock = game.lock().await;

// Fetch the local opinion on the root claim.
let attacking_root =
self.provider().state_hash(Self::ROOT_CLAIM_POSITION)? != game.root_claim();
let attacking_root = self
.provider()
.state_hash(Self::ROOT_CLAIM_POSITION)
.await?
!= game_lock.root_claim();

// Fetch the indices of all unvisited claims within the world DAG.
let unvisited_indices = game
let unvisited_indices = game_lock
.state()
.iter()
.enumerate()
.filter_map(|(i, c)| (!c.visited).then_some(i))
.collect::<Vec<_>>();

// Drop the mutex lock prior to creating the tasks.
drop(game_lock);

// Solve each unvisited claim, set the visited flag, and return the responses.
unvisited_indices
let tasks = unvisited_indices
.iter()
.map(|claim_index| self.inner.solve_claim(game, *claim_index, attacking_root))
.collect()
.map(|claim_index| {
self.inner
.solve_claim(game.clone(), *claim_index, attacking_root)
})
.collect::<Vec<_>>();

futures::future::join_all(tasks).await.into_iter().collect()
}
}

Expand Down
Loading

0 comments on commit e0fe105

Please sign in to comment.