Skip to content

Commit

Permalink
feat(offchain): add garbage collector strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenctw committed Jan 5, 2024
1 parent 3ca3525 commit df95069
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 12 deletions.
30 changes: 30 additions & 0 deletions offchain/core/src/arena/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ pub trait Arena: Send + Sync {
proofs: MachineProof,
) -> Result<(), Box<dyn Error>>;

async fn eliminate_match(
&self,
tournament: Address,
match_id: MatchID,
) -> Result<(), Box<dyn Error>>;

async fn created_tournament(
&self,
tournament: Address,
Expand Down Expand Up @@ -173,6 +179,30 @@ pub struct ClockState {
pub start_instant: u64,
pub block_time: U256,
}

impl ClockState {
pub fn has_time(&self) -> bool {
if self.start_instant == 0 {
true
} else {
self.deadline() > self.block_time.as_u64()
}
}

pub fn time_since_timeout(&self) -> u64 {
if self.start_instant == 0 {
0
} else {
self.block_time.as_u64() - self.deadline()
}
}

// deadline of clock if it's ticking
fn deadline(&self) -> u64 {
self.start_instant + self.allowance
}
}

impl std::fmt::Display for ClockState {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if self.start_instant == 0 {
Expand Down
25 changes: 19 additions & 6 deletions offchain/core/src/arena/ethers_arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use crate::{
merkle::{Digest, MerkleProof},
};

#[derive(Clone)]
/// The [EthersArena] struct implements the [Arena] trait for an ethereum node.
pub struct EthersArena {
config: ArenaConfig,
Expand Down Expand Up @@ -116,12 +117,6 @@ impl EthersArena {
.await?;
Ok(contract.address())
}

pub fn clone_with_new_key(&self, new_key: String) -> Result<Self, Box<dyn Error>> {
let mut new_arena_config = self.config.clone();
new_arena_config.web3_private_key = new_key;
Self::new(new_arena_config, Some(self.tournament_factory))
}
}

#[async_trait]
Expand Down Expand Up @@ -305,6 +300,24 @@ impl Arena for EthersArena {
Ok(())
}

async fn eliminate_match(
&self,
tournament: Address,
match_id: MatchID,
) -> Result<(), Box<dyn Error>> {
let tournament = tournament::Tournament::new(tournament, self.client.clone());
let match_id = tournament::Id {
commitment_one: match_id.commitment_one.into(),
commitment_two: match_id.commitment_two.into(),
};
tournament
.eliminate_match_by_timeout(match_id)
.send()
.await?
.await?;
Ok(())
}

async fn created_tournament(
&self,
tournament_address: Address,
Expand Down
2 changes: 1 addition & 1 deletion offchain/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ pub mod arena;
pub mod contract;
pub mod machine;
pub mod merkle;
pub mod player;
pub mod strategy;
pub mod utils;
93 changes: 93 additions & 0 deletions offchain/core/src/strategy/gc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use std::{collections::HashMap, error::Error};

use ::log::info;
use async_recursion::async_recursion;
use ethers::types::Address;

use crate::arena::{Arena, MatchState, TournamentState};

#[derive(Debug)]
pub enum PlayerTournamentResult {
TournamentWon,
TournamentLost,
}

pub struct GarbageCollector<A: Arena> {
arena: A,
root_tournamet: Address,
}

impl<A: Arena> GarbageCollector<A> {
pub fn new(arena: A, root_tournamet: Address) -> Self {
Self {
arena,
root_tournamet,
}
}

pub async fn react(&mut self) -> Result<(), Box<dyn Error>> {
let tournament_states = self.arena.fetch_from_root(self.root_tournamet).await?;
self.react_tournament(self.root_tournamet, tournament_states)
.await
}

#[async_recursion]
async fn react_tournament(
&mut self,
tournament_address: Address,
tournament_states: HashMap<Address, TournamentState>,
) -> Result<(), Box<dyn Error>> {
info!("Enter tournament at address: {}", tournament_address);
let tournament_state = tournament_states
.get(&tournament_address)
.expect("tournament state not found");

for m in tournament_state.matches.clone() {
self.react_match(&m, tournament_states.clone()).await?;

let status_1 = tournament_state
.commitment_states
.get(&m.id.commitment_one)
.expect("status of commitment 1 not found");
let status_2 = tournament_state
.commitment_states
.get(&m.id.commitment_two)
.expect("status of commitment 2 not found");
if (!status_1.clock.has_time()
&& (status_1.clock.time_since_timeout() > status_2.clock.allowance))
|| (!status_2.clock.has_time()
&& (status_2.clock.time_since_timeout() > status_1.clock.allowance))
{
info!(
"eliminate match for commitment {} and {} at tournament {} of level {}",
m.id.commitment_one,
m.id.commitment_two,
tournament_address,
tournament_state.level
);

self.arena
.eliminate_match(tournament_address, m.id)
.await
.expect("fail to eliminate match");
}
}
Ok(())
}

#[async_recursion]
async fn react_match(
&mut self,
match_state: &MatchState,
tournament_states: HashMap<Address, TournamentState>,
) -> Result<(), Box<dyn Error>> {
info!("Enter match at HEIGHT: {}", match_state.current_height);
if let Some(inner_tournament) = match_state.inner_tournament {
return self
.react_tournament(inner_tournament, tournament_states)
.await;
}

Ok(())
}
}
2 changes: 2 additions & 0 deletions offchain/core/src/strategy/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod gc;
pub mod player;
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl<A: Arena> Player<A> {
commitment_builder: CachingMachineCommitmentBuilder,
root_tournamet: Address,
) -> Self {
Player {
Self {
arena,
machine_factory,
machine_path,
Expand Down
13 changes: 9 additions & 4 deletions offchain/dave-compute/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use cartesi_compute_core::arena::{ArenaConfig, ContractArtifactsConfig, EthersArena};
use cartesi_compute_core::machine::{CachingMachineCommitmentBuilder, MachineFactory};
use cartesi_compute_core::player::Player;
use cartesi_compute_core::strategy::{gc::GarbageCollector, player::Player};
use ethers::types::Address;
use log::info;
use std::str::FromStr;
Expand Down Expand Up @@ -46,22 +46,27 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

let player1_machine_factory =
MachineFactory::new(String::from(machine_rpc_host), machine_rpc_port).await?;
let root_tournament = Address::from_str("0xcafac3dd18ac6c6e92c921884f9e4176737c052c")?;

let mut player1 = Player::new(
player1_arena,
player1_arena.clone(),
player1_machine_factory.clone(),
simple_linux_program.clone(),
CachingMachineCommitmentBuilder::new(player1_machine_factory, simple_linux_program),
Address::from_str("0xcafac3dd18ac6c6e92c921884f9e4176737c052c")?,
root_tournament.clone(),
);

let mut player1_gc = GarbageCollector::new(player1_arena, root_tournament);

loop {
let res = player1.react().await?;
if let Some(r) = res {
info!("Tournament finished, {:?}", r);
break;
}
// player2.react().await?;
tokio::time::sleep(Duration::from_secs(1)).await;

player1_gc.react().await?;
tokio::time::sleep(Duration::from_secs(1)).await;
}

Expand Down

0 comments on commit df95069

Please sign in to comment.