Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion crates/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ use bitcoin::hashes::Hash;
use bitcoin::{Address as BtcAddress, TxMerkleNode, Txid};
use bitcoin::{Block, Network};
use esplora_client::{AsyncClient, Builder, MerkleProof, Utxo};
use store::localdb::LocalDB;
use store::{ipfs::IPFS, localdb::LocalDB};
use uuid::Uuid;

pub struct BitVM2Client {
pub local_db: LocalDB,
pub esplora: AsyncClient,
pub btc_network: Network,
pub chain_service: Chain,
pub ipfs: IPFS,
}

impl BitVM2Client {
Expand All @@ -27,6 +28,7 @@ impl BitVM2Client {
btc_network: Network,
goat_network: GoatNetwork,
goat_config: GoatInitConfig,
ipfs_endpoint: &str,
) -> Self {
let local_db = LocalDB::new(&format!("sqlite:{db_path}"), true).await;
local_db.migrate().await;
Expand All @@ -37,6 +39,7 @@ impl BitVM2Client {
.expect("Could not build esplora client"),
btc_network,
chain_service: Chain::new(get_chain_adaptor(goat_network, goat_config, None)),
ipfs: IPFS::new(ipfs_endpoint),
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ mod tests {
Network::Testnet,
GoatNetwork::Test,
global_init_config,
"http://localhost:5001",
)
.await;
let tx_id =
Expand Down
27 changes: 14 additions & 13 deletions crates/store/src/ipfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,36 @@ pub struct IPFS {
#[derive(Deserialize, Debug, PartialEq, Hash)]
#[serde(rename_all = "PascalCase")]
pub struct Link {
hash: String,
mod_time: String,
mode: u32,
name: String,
size: u32,
target: String,
pub hash: String,
pub mod_time: String,
pub mode: u32,
pub name: String,
pub size: u32,
pub target: String,
#[serde(rename = "Type")]
type_: u32,
pub type_: u32,
}

#[derive(Deserialize, Debug, PartialEq, Hash)]
#[serde(rename_all = "PascalCase")]
pub struct Object {
hash: String,
links: Vec<Link>,
pub hash: String,
pub links: Vec<Link>,
}

#[derive(Deserialize, Debug, PartialEq, Hash)]
#[serde(rename_all = "PascalCase")]
pub struct Objects {
objects: Vec<Object>,
pub objects: Vec<Object>,
}

/// If the name is empty, it's the directory name
#[derive(Deserialize, Debug, PartialEq, Hash)]
#[serde(rename_all = "PascalCase")]
pub struct AddedFile {
name: String,
hash: String,
size: String,
pub name: String,
pub hash: String,
pub size: String,
}

// Collects all files and returns relative + absolute paths
Expand Down Expand Up @@ -154,6 +154,7 @@ pub mod tests {
}

// it works, but skip for avoiding creating too much garbage
// use std::io::Write;
// let base_dir = tempfile::tempdir().unwrap();
// vec!["1.txt", "2.txt"].iter().for_each(|name| {
// let mut file = std::fs::File::create(
Expand Down
2 changes: 1 addition & 1 deletion crates/store/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod ipfs;
pub mod ipfs;
pub mod localdb;
mod schema;

Expand Down
1 change: 1 addition & 0 deletions node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,4 @@ ark-serialize = { workspace = true }

[dev-dependencies]
tempfile = "3.19.1"
serial_test = "3.2.0"
33 changes: 26 additions & 7 deletions node/src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use bitvm2_lib::keys::*;
use bitvm2_lib::types::{Bitvm2Graph, Bitvm2Parameters, CustomInputs};
use bitvm2_lib::verifier::export_challenge_tx;
use bitvm2_lib::{committee::*, operator::*, verifier::*};
use client::client::BitVM2Client;
use goat::transactions::{assert::utils::COMMIT_TX_NUM, pre_signed::PreSignedTransaction};
use libp2p::gossipsub::MessageId;
use libp2p::{PeerId, Swarm, gossipsub};
Expand Down Expand Up @@ -95,6 +96,7 @@ pub struct GraphFinalize {
pub instance_id: Uuid,
pub graph_id: Uuid,
pub graph: Bitvm2Graph,
pub graph_ipfs_cid: String,
}

#[derive(Serialize, Deserialize)]
Expand Down Expand Up @@ -179,6 +181,7 @@ impl GOATMessage {
/// * peers: send
pub async fn recv_and_dispatch(
swarm: &mut Swarm<AllBehaviours>,
client: &BitVM2Client,
actor: Actor,
peer_id: PeerId,
id: MessageId,
Expand All @@ -204,7 +207,6 @@ pub async fn recv_and_dispatch(
println!("Handle message: {:?}", message);
let content: GOATMessageContent = message.to_typed()?;
// TODO: validate message
let client = client()?;
match (content, actor) {
// pegin
// CreateInstance sent by bootnode
Expand Down Expand Up @@ -378,6 +380,12 @@ pub async fn recv_and_dispatch(
&receive_data.agg_nonces,
&mut graph,
)?;
let prekickoff_tx = graph.pre_kickoff.tx().clone();
let node_keypair =
OperatorMasterKey::new(env::get_bitvm_key()?).master_keypair();
sign_and_broadcast_prekickoff_tx(&client, node_keypair, prekickoff_tx).await?;
let graph_ipfs_cid =
publish_graph_to_ipfs(client, receive_data.graph_id, &graph).await?;
store_graph(
&client,
receive_data.instance_id,
Expand All @@ -386,14 +394,18 @@ pub async fn recv_and_dispatch(
Some(GraphStatus::CommitteePresigned.to_string()),
)
.await?;
let prekickoff_tx = graph.pre_kickoff.tx().clone();
let node_keypair =
OperatorMasterKey::new(env::get_bitvm_key()?).master_keypair();
sign_and_broadcast_prekickoff_tx(&client, node_keypair, prekickoff_tx).await?;
update_graph_status_or_ipfs_base(
client,
receive_data.graph_id,
None,
Some(graph_ipfs_cid.clone()),
)
.await?;
let message_content = GOATMessageContent::GraphFinalize(GraphFinalize {
instance_id: receive_data.instance_id,
graph_id: receive_data.graph_id,
graph,
graph_ipfs_cid,
});
// TODO: ipfs
send_to_peer(swarm, GOATMessage::from_typed(Actor::All, &message_content)?)?;
Expand All @@ -402,7 +414,7 @@ pub async fn recv_and_dispatch(
};
}
(GOATMessageContent::GraphFinalize(receive_data), _) => {
// TODO: validate graph
// TODO: validate graph & ipfs
store_graph(
&client,
receive_data.instance_id,
Expand All @@ -411,6 +423,13 @@ pub async fn recv_and_dispatch(
Some(GraphStatus::CommitteePresigned.to_string()),
)
.await?;
update_graph_status_or_ipfs_base(
client,
receive_data.graph_id,
None,
Some(receive_data.graph_ipfs_cid.clone()),
)
.await?;
}

// peg-out
Expand Down Expand Up @@ -454,7 +473,7 @@ pub async fn recv_and_dispatch(
Amount::from_sat(graph.challenge.min_crowdfunding_amount()),
receive_data.instance_id,
receive_data.graph_id,
&graph,
&graph.kickoff.tx().compute_txid(),
)
.await?
{
Expand Down
54 changes: 50 additions & 4 deletions node/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use alloy::eips::BlockNumberOrTag;
use alloy::primitives::Address as EvmAddress;
use bitcoin::{Network, PublicKey, key::Keypair};
use bitvm2_lib::keys::NodeMasterKey;
use client::chain::goat_adaptor::GoatInitConfig;
use client::chain::{chain_adaptor::GoatNetwork, goat_adaptor::GoatInitConfig};
use reqwest::Url;
use std::collections::HashMap;
use std::str::FromStr;

pub const ENV_GOAT_CHAIN_URL: &str = "GOAT_CHAIN_URL";
Expand All @@ -13,8 +14,14 @@ pub const ENV_GOAT_GATEWAY_CONTRACT_CREATION: &str = "GOAT_GATEWAY_CONTRACT_CREA
pub const ENV_GOAT_GATEWAY_CONTRACT_TO_BLOCK: &str = "GOAT_GATEWAY_CONTRACT_TO_BLOCK";
pub const ENV_GOAT_PRIVATE_KEY: &str = "GOAT_PRIVATE_KEY";
pub const ENV_GOAT_CHAIN_ID: &str = "GOAT_CHAIN_ID";
pub const ENV_BITVM_SECRET: &str = "BITVM_SECRET";
pub const ENV_PEER_KEY: &str = "KEY";
pub const ENV_PERR_ID: &str = "PEER_ID";
pub const ENV_ACTOR: &str = "ACTOR";
pub const ENV_IPFS_ENDPOINT: &str = "IPFS_ENDPOINT";

pub const SCRIPT_CACHE_FILE_NAME: &str = "cache/partial_script.bin";
pub const IPFS_GRAPH_CACHE_DIR: &str = "cache/graph_cache/";
pub const DUST_AMOUNT: u64 = goat::transactions::base::DUST_AMOUNT;
pub const MAX_CUSTOM_INPUTS: usize = 100;

Expand All @@ -36,15 +43,20 @@ pub const CHALLENGE_RATE: u64 = 0; // 0%
pub const RATE_MULTIPLIER: u64 = 10000;

const COMMITTEE_MEMBER_NUMBER: usize = 3;
const NETWORK: Network = Network::Testnet;
const BTC_NETWORK: Network = Network::Testnet;
const GOAT_NETWORK: GoatNetwork = GoatNetwork::Test;

pub fn get_network() -> Network {
NETWORK
BTC_NETWORK
}

pub fn get_goat_network() -> GoatNetwork {
GOAT_NETWORK
}

pub fn get_bitvm_key() -> Result<Keypair, Box<dyn std::error::Error>> {
// TODO: what if node restart with different BITVM_SECRET ?
let bitvm_secret = std::env::var("BITVM_SECRET").expect("BITVM_SECRET is missing");
let bitvm_secret = std::env::var(ENV_BITVM_SECRET).expect("{ENV_BITVM_SECRET} is missing");
Ok(Keypair::from_seckey_str_global(&bitvm_secret)?)
}

Expand Down Expand Up @@ -85,3 +97,37 @@ pub fn get_bitvm2_client_config() -> GoatInitConfig {
chain_id: chain_id.parse().expect("fail to parse int"),
}
}

pub enum IpfsTxName {
AssertCommit0,
AssertCommit1,
AssertCommit2,
AssertCommit3,
AssertFinal,
AssertInit,
Challenge,
Disprove,
Kickoff,
Pegin,
Take1,
Take2,
}

impl IpfsTxName {
pub fn as_str(&self) -> &'static str {
match self {
IpfsTxName::AssertCommit0 => "assert-commit0.hex",
IpfsTxName::AssertCommit1 => "assert-commit1.hex",
IpfsTxName::AssertCommit2 => "assert-commit2.hex",
IpfsTxName::AssertCommit3 => "assert-commit3.hex",
IpfsTxName::AssertFinal => "assert-final.hex",
IpfsTxName::AssertInit => "assert-init.hex",
IpfsTxName::Challenge => "challenge.hex",
IpfsTxName::Disprove => "disprove.hex",
IpfsTxName::Kickoff => "kickoff.hex",
IpfsTxName::Pegin => "pegin.hex",
IpfsTxName::Take1 => "take1.hex",
IpfsTxName::Take2 => "take2.hex",
}
}
}
37 changes: 28 additions & 9 deletions node/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#![feature(trivial_bounds)]
use base64::Engine;
use clap::{Parser, Subcommand, command};
use client::client::BitVM2Client;
use env::ENV_IPFS_ENDPOINT;
use libp2p::PeerId;
use libp2p::futures::StreamExt;
use libp2p::{gossipsub, kad, mdns, multiaddr::Protocol, noise, swarm::SwarmEvent, tcp, yamux};
Expand All @@ -25,6 +27,7 @@ mod rpc_service;
mod utils;

use crate::action::GOATMessage;
use crate::env::{ENV_ACTOR, ENV_PEER_KEY, ENV_PERR_ID};
use crate::middleware::behaviour::AllBehavioursEvent;
use anyhow::Result;
use middleware::AllBehaviours;
Expand Down Expand Up @@ -107,19 +110,19 @@ async fn main() -> Result<(), Box<dyn Error>> {
let local_key = identity::generate_local_key();
let base64_key = base64::engine::general_purpose::STANDARD
.encode(&local_key.to_protobuf_encoding()?);
tracing::info!("export KEY={}", base64_key);
tracing::info!("export PEER_ID={}", local_key.public().to_peer_id());
tracing::info!("export {}={}", ENV_PEER_KEY, base64_key);
tracing::info!("export {}={}", ENV_PERR_ID, local_key.public().to_peer_id());
}
}
return Ok(());
}
// load role
let actor =
Actor::from_str(std::env::var("ACTOR").unwrap_or("Challenger".to_string()).as_str())
Actor::from_str(std::env::var(ENV_ACTOR).unwrap_or("Challenger".to_string()).as_str())
.unwrap();

let local_key = std::env::var("KEY").expect("KEY is missing");
let arg_peer_id = std::env::var("PEER_ID").expect("Peer ID is missing");
let local_key = std::env::var(ENV_PEER_KEY).expect("KEY is missing");
let arg_peer_id = std::env::var(ENV_PERR_ID).expect("Peer ID is missing");

let _ = tracing_subscriber::fmt().with_env_filter(EnvFilter::from_default_env()).try_init();
let mut metric_registry = Registry::default();
Expand Down Expand Up @@ -207,8 +210,24 @@ async fn main() -> Result<(), Box<dyn Error>> {
tracing::debug!("RPC service listening on {}", &opt.rpc_addr);
let rpc_addr = opt.rpc_addr.clone();
let db_path = opt.db_path.clone();

tokio::spawn(rpc_service::serve(rpc_addr, db_path, Arc::new(Mutex::new(metric_registry))));
let ipfs_url = std::env::var(ENV_IPFS_ENDPOINT).expect("IPFS_ENDPOINT is missing");

let client = BitVM2Client::new(
&db_path,
None,
env::get_network(),
env::get_goat_network(),
env::get_bitvm2_client_config(),
&ipfs_url,
)
.await;

tokio::spawn(rpc_service::serve(
rpc_addr,
db_path.clone(),
ipfs_url.clone(),
Arc::new(Mutex::new(metric_registry)),
));
// Read full lines from stdin
let mut interval = interval(Duration::from_secs(20));
let mut stdin = io::BufReader::new(io::stdin()).lines();
Expand Down Expand Up @@ -243,7 +262,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
actor: actor.clone(),
content: "tick".as_bytes().to_vec(),
})?;
match action::recv_and_dispatch(&mut swarm, actor.clone(), peer_id, GOATMessage::default_message_id(), &tick_data).await{
match action::recv_and_dispatch(&mut swarm, &client, actor.clone(), peer_id, GOATMessage::default_message_id(), &tick_data).await{
Ok(_) => {}
Err(e) => { tracing::error!(e) }
}
Expand All @@ -256,7 +275,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
message_id: id,
message,
})) => {
match action::recv_and_dispatch(&mut swarm, actor.clone(), peer_id, id, &message.data).await {
match action::recv_and_dispatch(&mut swarm, &client, actor.clone(), peer_id, id, &message.data).await {
Ok(_) => {},
Err(e) => { tracing::error!(e) }
}
Expand Down
Loading
Loading