From bddad8bb910258e47b1c9ddea9bd167dbcff40d4 Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Fri, 27 Sep 2024 15:55:10 -0500 Subject: [PATCH 01/18] Start Frost signer in `nomic signer` --- src/bin/nomic.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/bin/nomic.rs b/src/bin/nomic.rs index abe233e1..18727fc6 100644 --- a/src/bin/nomic.rs +++ b/src/bin/nomic.rs @@ -180,7 +180,6 @@ pub enum Command { PayToFeePool(PayToFeePoolCmd), BabylonRelayer(BabylonRelayerCmd), StakeNbtc(StakeNbtcCmd), - FrostSigner(FrostSignerCmd), #[cfg(feature = "ethereum")] RelayEthereum(RelayEthereumCmd), #[cfg(feature = "ethereum")] @@ -251,7 +250,6 @@ impl Command { PayToFeePool(cmd) => cmd.run().await, BabylonRelayer(cmd) => cmd.run().await, StakeNbtc(cmd) => cmd.run().await, - FrostSigner(cmd) => cmd.run().await, #[cfg(feature = "ethereum")] RelayEthereum(cmd) => cmd.run().await, #[cfg(feature = "ethereum")] @@ -1485,7 +1483,12 @@ impl SignerCmd { let relaunch = relaunch_on_migrate(&self.config); - futures::try_join!(signer, relaunch).unwrap(); + let frost_cmd = FrostSignerCmd { + config: self.config.clone(), + }; + let frost_signer = frost_cmd.run(); + + futures::try_join!(signer, relaunch, frost_signer).unwrap(); Ok(()) } From 6e4fc1fb0aa3cb017b5671897a52b4452e733f5d Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Fri, 27 Sep 2024 15:55:47 -0500 Subject: [PATCH 02/18] Update frost-secp256k1-tr dependency --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- rest/Cargo.lock | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a61a87c7..b8bd2a01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2312,7 +2312,7 @@ dependencies = [ [[package]] name = "frost-core" version = "1.0.0" -source = "git+https://github.com/ZcashFoundation/frost?rev=20c2c98a931c564655e2a03719e19ba916e11545#20c2c98a931c564655e2a03719e19ba916e11545" +source = "git+https://github.com/ZcashFoundation/frost?rev=51fa7d09f3742563a35d065afcff6ad486430dac#51fa7d09f3742563a35d065afcff6ad486430dac" dependencies = [ "byteorder", "const-crc32", @@ -2333,7 +2333,7 @@ dependencies = [ [[package]] name = "frost-rerandomized" version = "1.0.0" -source = "git+https://github.com/ZcashFoundation/frost?rev=20c2c98a931c564655e2a03719e19ba916e11545#20c2c98a931c564655e2a03719e19ba916e11545" +source = "git+https://github.com/ZcashFoundation/frost?rev=51fa7d09f3742563a35d065afcff6ad486430dac#51fa7d09f3742563a35d065afcff6ad486430dac" dependencies = [ "derive-getters", "document-features", @@ -2344,7 +2344,7 @@ dependencies = [ [[package]] name = "frost-secp256k1-tr" version = "1.0.0" -source = "git+https://github.com/ZcashFoundation/frost?rev=20c2c98a931c564655e2a03719e19ba916e11545#20c2c98a931c564655e2a03719e19ba916e11545" +source = "git+https://github.com/ZcashFoundation/frost?rev=51fa7d09f3742563a35d065afcff6ad486430dac#51fa7d09f3742563a35d065afcff6ad486430dac" dependencies = [ "document-features", "frost-core", diff --git a/Cargo.toml b/Cargo.toml index 76fcfcde..3f7155e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ lazy_static = "1.4.0" prost = "0.13.3" cosmrs = "0.14.0" ripemd = "0.1.3" -frost-secp256k1-tr = { git = "https://github.com/ZcashFoundation/frost", rev = "20c2c98a931c564655e2a03719e19ba916e11545", features = [ +frost-secp256k1-tr = { git = "https://github.com/ZcashFoundation/frost", rev = "51fa7d09f3742563a35d065afcff6ad486430dac", features = [ "nightly", ] } alloy = { version = "0.2.1", features = [ diff --git a/rest/Cargo.lock b/rest/Cargo.lock index 83119f63..e93f72b5 100644 --- a/rest/Cargo.lock +++ b/rest/Cargo.lock @@ -1447,7 +1447,7 @@ dependencies = [ [[package]] name = "frost-core" version = "1.0.0" -source = "git+https://github.com/ZcashFoundation/frost?rev=20c2c98a931c564655e2a03719e19ba916e11545#20c2c98a931c564655e2a03719e19ba916e11545" +source = "git+https://github.com/ZcashFoundation/frost?rev=51fa7d09f3742563a35d065afcff6ad486430dac#51fa7d09f3742563a35d065afcff6ad486430dac" dependencies = [ "byteorder", "const-crc32", @@ -1468,7 +1468,7 @@ dependencies = [ [[package]] name = "frost-rerandomized" version = "1.0.0" -source = "git+https://github.com/ZcashFoundation/frost?rev=20c2c98a931c564655e2a03719e19ba916e11545#20c2c98a931c564655e2a03719e19ba916e11545" +source = "git+https://github.com/ZcashFoundation/frost?rev=51fa7d09f3742563a35d065afcff6ad486430dac#51fa7d09f3742563a35d065afcff6ad486430dac" dependencies = [ "derive-getters", "document-features", @@ -1479,7 +1479,7 @@ dependencies = [ [[package]] name = "frost-secp256k1-tr" version = "1.0.0" -source = "git+https://github.com/ZcashFoundation/frost?rev=20c2c98a931c564655e2a03719e19ba916e11545#20c2c98a931c564655e2a03719e19ba916e11545" +source = "git+https://github.com/ZcashFoundation/frost?rev=51fa7d09f3742563a35d065afcff6ad486430dac#51fa7d09f3742563a35d065afcff6ad486430dac" dependencies = [ "document-features", "frost-core", From 55eb14616aec4e7145fbde9a9333b435b2e4700d Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Wed, 9 Oct 2024 15:13:22 -0500 Subject: [PATCH 03/18] Expose grpc server config --- Cargo.toml | 2 +- src/bin/nomic.rs | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fc5644ae..94677662 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ toml = { version = "0.7.2", features = ["parse"] } semver = "1.0.18" [features] -default = ["full", "feat-ibc", "legacy-bin"] +default = ["full", "feat-ibc"] full = [ "bitcoincore-rpc-async", "clap", diff --git a/src/bin/nomic.rs b/src/bin/nomic.rs index a0aacda1..feb08a84 100644 --- a/src/bin/nomic.rs +++ b/src/bin/nomic.rs @@ -1749,8 +1749,10 @@ impl EthTransferNbtcCmd { #[derive(Parser, Debug)] pub struct GrpcCmd { /// The port to listen on. - #[clap(default_value_t = 9001)] + #[clap(long, default_value_t = 9001)] port: u16, + #[clap(long, default_value = "127.0.0.1")] + host: String, #[clap(flatten)] config: nomic::network::Config, @@ -1760,12 +1762,16 @@ impl GrpcCmd { /// Runs the `grpc` command. async fn run(&self) -> Result<()> { use orga::ibc::GrpcOpts; - std::panic::set_hook(Box::new(|_| {})); + std::panic::set_hook(Box::new(|e| { + log::error!("{}", e.to_string()); + })); + log::info!("Starting gRPC server on {}:{}", self.host, self.port); orga::ibc::start_grpc( - // TODO: support configuring RPC address + // TODO: support configuring RPC address (closure capturing `self.config.node` + // breaks coercion to fn pointer) || nomic::app_client("http://localhost:26657").sub(|app| app.ibc.ctx), &GrpcOpts { - host: "127.0.0.1".to_string(), + host: self.host.to_string(), port: self.port, chain_id: self.config.chain_id.clone().unwrap(), }, From be74869237e056c2a6233713d9bdd858edfd803f Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Fri, 11 Oct 2024 13:20:33 -0500 Subject: [PATCH 04/18] Add miner fee and sigset index to pending deposits --- src/bitcoin/deposit_index.rs | 21 +++++----------- src/bitcoin/relayer.rs | 49 +++++++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/bitcoin/deposit_index.rs b/src/bitcoin/deposit_index.rs index c2ae80b3..27c73113 100644 --- a/src/bitcoin/deposit_index.rs +++ b/src/bitcoin/deposit_index.rs @@ -5,21 +5,12 @@ use std::collections::HashMap; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Deposit { - txid: Txid, - vout: u32, - amount: u64, - height: Option, -} - -impl Deposit { - pub fn new(txid: Txid, vout: u32, amount: u64, height: Option) -> Self { - Self { - txid, - vout, - amount, - height, - } - } + pub txid: Txid, + pub vout: u32, + pub amount: u64, + pub height: Option, + pub sigset_index: u32, + pub miner_fee_rate: f64, } #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/src/bitcoin/relayer.rs b/src/bitcoin/relayer.rs index 443bebf0..cc3ac323 100644 --- a/src/bitcoin/relayer.rs +++ b/src/bitcoin/relayer.rs @@ -2,6 +2,7 @@ use super::signatory::Signatory; use super::SignatorySet; use super::SIGSET_THRESHOLD; use crate::app::Dest; +use crate::app::InnerApp; use crate::app_client; use crate::bitcoin::deposit_index::{Deposit, DepositIndex}; use crate::bitcoin::{adapter::Adapter, header_queue::WrappedHeader}; @@ -273,6 +274,8 @@ impl Relayer { let sigset = app_client(app_client_addr) .query(|app: crate::app::InnerApp| { let building = app.bitcoin.checkpoints.building()?; + // TODO: use self.miner_fee_rate() once this endpoint + // takes an optional `index` arg. let est_miner_fee = (app.bitcoin.checkpoints.active_sigset()?.est_witness_vsize() + 40) * building.fee_rate @@ -440,7 +443,9 @@ impl Relayer { return Ok(()); } - if let Some((dest, _)) = script_guard.as_ref().unwrap().scripts.get(&script) { + if let Some((dest, sigset_index)) = + script_guard.as_ref().unwrap().scripts.get(&script) + { let bitcoin_address = bitcoin::Address::from_script( &output.script_pubkey.clone(), super::NETWORK, @@ -451,10 +456,20 @@ impl Relayer { Some(addr) => addr, None => continue, }; + + let miner_fee_rate = self.miner_fee_rate(sigset_index).await?; + index.insert_deposit( receiver_addr, bitcoin_address, - Deposit::new(txid, vout as u32, output.value, None), + Deposit { + txid, + vout: vout as u32, + amount: output.value, + height: None, + sigset_index, + miner_fee_rate, + }, ) } } @@ -464,6 +479,23 @@ impl Relayer { Ok(()) } + pub async fn miner_fee_rate(&self, sigset_index: u32) -> Result { + let client = app_client(&self.app_client_addr); + let miner_fee_rate = client + .query(|app: InnerApp| { + let chkpt = app.bitcoin.checkpoints.get(sigset_index)?; + let est_miner_fee = (chkpt.sigset.est_witness_vsize() + 40) + * chkpt.fee_rate + * app.bitcoin.checkpoints.config.user_fee_factor + / 10_000; + + Ok(est_miner_fee as f64 / 100_000_000.0) + }) + .await?; + + Ok(miner_fee_rate) + } + pub async fn start_emergency_disbursal_transaction_relay(&mut self) -> Result<()> { info!("Starting emergency disbursal transaction relay..."); @@ -885,6 +917,7 @@ impl Relayer { let outpoint = (txid.into_inner(), output.vout); let dest = output.dest.clone(); let vout = output.vout; + let sigset_index = output.sigset_index; let contains_outpoint = app_client(&self.app_client_addr) .query(|app| app.bitcoin.processed_outpoints.contains(outpoint)) .await?; @@ -901,16 +934,20 @@ impl Relayer { return Ok(()); } + let miner_fee_rate = self.miner_fee_rate(sigset_index).await?; + let mut index_guard = index.lock().await; index_guard.insert_deposit( receiver_addr, deposit_address.clone(), - Deposit::new( + Deposit { txid, vout, - tx.output.get(vout as usize).unwrap().value, - Some(height.into()), - ), + amount: tx.output.get(vout as usize).unwrap().value, + height: Some(height.into()), + sigset_index, + miner_fee_rate, + }, ); } From 0c600db0cb11c72adf47d22bb25504d83fe6b729 Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Fri, 11 Oct 2024 13:35:20 -0500 Subject: [PATCH 05/18] Add bridge fee rate for pending deposits --- src/bitcoin/deposit_index.rs | 1 + src/bitcoin/relayer.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/bitcoin/deposit_index.rs b/src/bitcoin/deposit_index.rs index 27c73113..75ded64a 100644 --- a/src/bitcoin/deposit_index.rs +++ b/src/bitcoin/deposit_index.rs @@ -11,6 +11,7 @@ pub struct Deposit { pub height: Option, pub sigset_index: u32, pub miner_fee_rate: f64, + pub bridge_fee_rate: f64, } #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/src/bitcoin/relayer.rs b/src/bitcoin/relayer.rs index cc3ac323..0e915ca6 100644 --- a/src/bitcoin/relayer.rs +++ b/src/bitcoin/relayer.rs @@ -458,6 +458,7 @@ impl Relayer { }; let miner_fee_rate = self.miner_fee_rate(sigset_index).await?; + let bridge_fee_rate = self.bridge_fee_rate(&dest, sigset_index)?; index.insert_deposit( receiver_addr, @@ -469,6 +470,7 @@ impl Relayer { height: None, sigset_index, miner_fee_rate, + bridge_fee_rate, }, ) } @@ -496,6 +498,21 @@ impl Relayer { Ok(miner_fee_rate) } + pub fn bridge_fee_rate(&self, dest: &Dest, _sigset_index: u32) -> Result { + // TODO: fee should depend on sigset index + let fee_rate = if dest.is_fee_exempt() { + 0.0 + } else if matches!(dest, Dest::Ibc { .. }) { + // deposit fee + transfer fee + 0.015 + } else { + // deposit fee + 0.01 + }; + + Ok(fee_rate) + } + pub async fn start_emergency_disbursal_transaction_relay(&mut self) -> Result<()> { info!("Starting emergency disbursal transaction relay..."); @@ -935,6 +952,7 @@ impl Relayer { } let miner_fee_rate = self.miner_fee_rate(sigset_index).await?; + let bridge_fee_rate = self.bridge_fee_rate(&dest, sigset_index)?; let mut index_guard = index.lock().await; index_guard.insert_deposit( @@ -947,6 +965,7 @@ impl Relayer { height: Some(height.into()), sigset_index, miner_fee_rate, + bridge_fee_rate, }, ); } From f1bc220b2221650c124876108fa9008c8352219e Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Fri, 11 Oct 2024 14:00:28 -0500 Subject: [PATCH 06/18] Add destination-specific bridge fee rate quotes to relayer --- src/app.rs | 2 +- src/bitcoin/relayer.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/app.rs b/src/app.rs index 968a6625..27b2a408 100644 --- a/src/app.rs +++ b/src/app.rs @@ -89,7 +89,7 @@ const IBC_FEE_USATS: u64 = 1_000_000; /// The fixed amount of nBTC fee required to make any application call, in /// micro-satoshis. const CALL_FEE_USATS: u64 = 100_000_000; -const OSMOSIS_CHANNEL_ID: &str = "channel-1"; +pub const OSMOSIS_CHANNEL_ID: &str = "channel-1"; /// The top-level application state type and logic. This contains the major /// state types for the various subsystems of the Nomic protocol. diff --git a/src/bitcoin/relayer.rs b/src/bitcoin/relayer.rs index 443bebf0..810fdb38 100644 --- a/src/bitcoin/relayer.rs +++ b/src/bitcoin/relayer.rs @@ -1084,6 +1084,19 @@ pub struct OutputMatch { vout: u32, dest: Dest, } +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct BridgeFeeOverrides { + /// Map of channel id to bridge fee rate + pub ibc: HashMap, +} + +impl Default for BridgeFeeOverrides { + fn default() -> Self { + Self { + ibc: HashMap::from([(crate::app::OSMOSIS_CHANNEL_ID.to_string(), 0.0)]), + } + } +} #[derive(Clone, Serialize, Deserialize, Debug)] pub struct RawSignatorySet { @@ -1096,6 +1109,7 @@ pub struct RawSignatorySet { #[serde(rename = "depositsEnabled")] pub deposits_enabled: bool, pub threshold: (u64, u64), + pub bridge_fee_overrides: BridgeFeeOverrides, } impl RawSignatorySet { @@ -1121,6 +1135,7 @@ impl RawSignatorySet { threshold: (9, 10), #[cfg(not(feature = "testnet"))] threshold: (2, 3), + bridge_fee_overrides: BridgeFeeOverrides::default(), } } } From f450f81c400bdd7044be207685ddc735a5252b3a Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Fri, 11 Oct 2024 15:13:55 -0500 Subject: [PATCH 07/18] Add --rpc-url option to Bitcoin relayer command --- src/bin/nomic.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/bin/nomic.rs b/src/bin/nomic.rs index a0aacda1..a39be72e 100644 --- a/src/bin/nomic.rs +++ b/src/bin/nomic.rs @@ -1312,7 +1312,7 @@ impl ClaimAirdropCmd { /// Relays data between the Bitcoin and Nomic networks. #[derive(Parser, Debug)] pub struct RelayerCmd { - /// The port of the Bitcoin RPC server. + /// The port of the local Bitcoin RPC server. // TODO: get the default based on the network #[clap(short = 'p', long, default_value_t = 8332)] rpc_port: u16, @@ -1325,6 +1325,10 @@ pub struct RelayerCmd { #[clap(short = 'P', long)] rpc_pass: Option, + /// The URL for the Bitcoin RPC server, e.g. http://localhost:8332. + #[clap(short = 'r', long, conflicts_with = "rpc-port")] + rpc_url: Option, + #[clap(flatten)] config: nomic::network::Config, } @@ -1332,7 +1336,11 @@ pub struct RelayerCmd { impl RelayerCmd { /// Builds Bitcoin RPC client. async fn btc_client(&self) -> Result { - let rpc_url = format!("http://localhost:{}", self.rpc_port); + let rpc_url = if let Some(rpc) = self.rpc_url.clone() { + rpc + } else { + format!("http://localhost:{}", self.rpc_port) + }; let auth = match (self.rpc_user.clone(), self.rpc_pass.clone()) { (Some(user), Some(pass)) => Auth::UserPass(user, pass), _ => Auth::None, From 925b4f846bd3b14e8166453b656333a344f169bf Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Fri, 11 Oct 2024 15:33:42 -0500 Subject: [PATCH 08/18] Use camelCase for pending deposit info --- src/bitcoin/deposit_index.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitcoin/deposit_index.rs b/src/bitcoin/deposit_index.rs index 75ded64a..598e6f46 100644 --- a/src/bitcoin/deposit_index.rs +++ b/src/bitcoin/deposit_index.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct Deposit { pub txid: Txid, pub vout: u32, From 0fc24387feb38fc900d1ef15e41339cf219cc9a5 Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Fri, 11 Oct 2024 15:35:09 -0500 Subject: [PATCH 09/18] Use camelCase for bridge fee overrides --- src/bitcoin/relayer.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/bitcoin/relayer.rs b/src/bitcoin/relayer.rs index 810fdb38..0fb1460d 100644 --- a/src/bitcoin/relayer.rs +++ b/src/bitcoin/relayer.rs @@ -1099,14 +1099,12 @@ impl Default for BridgeFeeOverrides { } #[derive(Clone, Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] pub struct RawSignatorySet { pub signatories: Vec, pub index: u32, - #[serde(rename = "bridgeFeeRate")] pub bridge_fee_rate: f64, - #[serde(rename = "minerFeeRate")] pub miner_fee_rate: f64, - #[serde(rename = "depositsEnabled")] pub deposits_enabled: bool, pub threshold: (u64, u64), pub bridge_fee_overrides: BridgeFeeOverrides, From b17f972d104d779ca04fa578e5885e4f0fa23943 Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Fri, 11 Oct 2024 17:47:04 -0500 Subject: [PATCH 10/18] Update orga --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f1594684..6930daa3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3923,7 +3923,7 @@ dependencies = [ [[package]] name = "orga" version = "0.3.1" -source = "git+https://github.com/nomic-io/orga.git?rev=4274220595a14f759e009a912ee96b6e8013e281#4274220595a14f759e009a912ee96b6e8013e281" +source = "git+https://github.com/nomic-io/orga.git?rev=73a3a567f68e3ca0c67a6c8b67f6392df31958a0#73a3a567f68e3ca0c67a6c8b67f6392df31958a0" dependencies = [ "abci2", "async-trait", @@ -3980,7 +3980,7 @@ dependencies = [ [[package]] name = "orga-macros" version = "0.3.1" -source = "git+https://github.com/nomic-io/orga.git?rev=4274220595a14f759e009a912ee96b6e8013e281#4274220595a14f759e009a912ee96b6e8013e281" +source = "git+https://github.com/nomic-io/orga.git?rev=73a3a567f68e3ca0c67a6c8b67f6392df31958a0#73a3a567f68e3ca0c67a6c8b67f6392df31958a0" dependencies = [ "darling", "heck 0.3.3", diff --git a/Cargo.toml b/Cargo.toml index 94677662..7c1fec15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ default-run = "nomic" [dependencies] bitcoin = { version = "0.29.2", features = ["serde", "rand"] } -orga = { git = "https://github.com/nomic-io/orga.git", rev = "4274220595a14f759e009a912ee96b6e8013e281", features = [ +orga = { git = "https://github.com/nomic-io/orga.git", rev = "73a3a567f68e3ca0c67a6c8b67f6392df31958a0", features = [ "merk-verify", ] } thiserror = "1.0.30" From f1297a4cffe35411d7449969e342b779a716e305 Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Fri, 11 Oct 2024 17:50:21 -0500 Subject: [PATCH 11/18] Allow configurable Nomic RPC in gRPC command --- src/bin/nomic.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/bin/nomic.rs b/src/bin/nomic.rs index feb08a84..910d4783 100644 --- a/src/bin/nomic.rs +++ b/src/bin/nomic.rs @@ -1767,9 +1767,7 @@ impl GrpcCmd { })); log::info!("Starting gRPC server on {}:{}", self.host, self.port); orga::ibc::start_grpc( - // TODO: support configuring RPC address (closure capturing `self.config.node` - // breaks coercion to fn pointer) - || nomic::app_client("http://localhost:26657").sub(|app| app.ibc.ctx), + || self.config.client().sub(|app| app.ibc.ctx), &GrpcOpts { host: self.host.to_string(), port: self.port, From 4656af72f73116f5b0b998e0c7fddd071448d083 Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Fri, 11 Oct 2024 19:42:23 -0500 Subject: [PATCH 12/18] Add more data to relayer `/sigset` endpoint response --- src/bitcoin/relayer.rs | 60 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/src/bitcoin/relayer.rs b/src/bitcoin/relayer.rs index 0fb1460d..8254b4d7 100644 --- a/src/bitcoin/relayer.rs +++ b/src/bitcoin/relayer.rs @@ -41,6 +41,11 @@ pub struct DepositsQuery { pub receiver: String, } +#[derive(Serialize, Deserialize)] +pub struct SigsetQuery { + pub index: Option, +} + pub struct Relayer { btc_client: Arc>, app_client_addr: String, @@ -269,21 +274,42 @@ impl Relayer { ); let sigset_route = warp::path("sigset") - .and_then(move || async { + .and(warp::query::()) + .and_then(move |query: SigsetQuery| async move { let sigset = app_client(app_client_addr) - .query(|app: crate::app::InnerApp| { - let building = app.bitcoin.checkpoints.building()?; - let est_miner_fee = - (app.bitcoin.checkpoints.active_sigset()?.est_witness_vsize() + 40) - * building.fee_rate - * app.bitcoin.checkpoints.config.user_fee_factor - / 10_000; - let deposits_enabled = building.deposits_enabled; + .query(move |app: crate::app::InnerApp| { + let building_index = app.bitcoin.checkpoints.building()?.sigset.index; + let index = match query.index { + Some(index) => index, + None => building_index, + }; + + let chkpt = app.bitcoin.checkpoints.get(index)?; + + let maybe_chkpt_tx = (index < building_index) + .then(|| chkpt.checkpoint_tx()) + .transpose()?; + + let mut pending = vec![]; + for entry in chkpt.pending.iter()? { + let (dest, coin) = entry?; + pending.push((dest.clone(), coin.amount.into())); + } + + let est_miner_fee = (chkpt.sigset.est_witness_vsize() + 40) + * chkpt.fee_rate + * app.bitcoin.checkpoints.config.user_fee_factor + / 10_000; + let sigset = RawSignatorySet::new( - app.bitcoin.checkpoints.active_sigset()?, + chkpt.sigset.clone(), 0.015, est_miner_fee as f64 / 100_000_000.0, - deposits_enabled, + chkpt.deposits_enabled, + maybe_chkpt_tx, + chkpt.signed_at_btc_height, + chkpt.create_time(), + pending, ); Ok(sigset) }) @@ -1108,6 +1134,10 @@ pub struct RawSignatorySet { pub deposits_enabled: bool, pub threshold: (u64, u64), pub bridge_fee_overrides: BridgeFeeOverrides, + pub txid: Option, + pub signed_at_btc_height: Option, + pub create_time: u64, + pub pending: Vec<(Dest, u64)>, } impl RawSignatorySet { @@ -1116,6 +1146,10 @@ impl RawSignatorySet { bridge_fee_rate: f64, miner_fee_rate: f64, deposits_enabled: bool, + maybe_checkpoint_tx: Option>, + signed_at_btc_height: Option, + create_time: u64, + pending: Vec<(Dest, u64)>, ) -> Self { let signatories = sigset .iter() @@ -1134,6 +1168,10 @@ impl RawSignatorySet { #[cfg(not(feature = "testnet"))] threshold: (2, 3), bridge_fee_overrides: BridgeFeeOverrides::default(), + txid: maybe_checkpoint_tx.map(|tx| tx.txid().to_string()), + signed_at_btc_height, + create_time, + pending, } } } From 6b614056c2346cf692b6a87d59fd11bde28e0793 Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Fri, 18 Oct 2024 17:27:12 -0500 Subject: [PATCH 13/18] Add pending transfers query --- src/bitcoin/checkpoint.rs | 13 +++++++++++++ src/bitcoin/relayer.rs | 24 ++++++++++-------------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/bitcoin/checkpoint.rs b/src/bitcoin/checkpoint.rs index 69c7e988..0faca5e4 100644 --- a/src/bitcoin/checkpoint.rs +++ b/src/bitcoin/checkpoint.rs @@ -2419,6 +2419,19 @@ impl CheckpointQueue { Ok(()) } + + /// Returns the pending transfers for the building checkpoint. + /// + /// This query is a temporary workaround for a client iteration issue. + #[query] + pub fn pending(&self) -> Result> { + let mut pending = vec![]; + for entry in self.building()?.pending.iter()? { + let (dest, coin) = entry?; + pending.push((dest.clone(), coin.amount.into())); + } + Ok(pending) + } } /// Takes a previous fee rate and returns a new fee rate, adjusted up or down by diff --git a/src/bitcoin/relayer.rs b/src/bitcoin/relayer.rs index 082c1719..4c7a2ade 100644 --- a/src/bitcoin/relayer.rs +++ b/src/bitcoin/relayer.rs @@ -280,28 +280,24 @@ impl Relayer { .and_then(move |query: SigsetQuery| async move { let sigset = app_client(app_client_addr) .query(move |app: crate::app::InnerApp| { - let chkpt = match query.index { - Some(index) => &app.bitcoin.checkpoints.get(index)?, - None => &*app.bitcoin.checkpoints.building()?, + let (chkpt, pending) = match query.index { + Some(index) => (&app.bitcoin.checkpoints.get(index)?, vec![]), + None => ( + &*app.bitcoin.checkpoints.building()?, + app.bitcoin.checkpoints.pending()?, + ), }; let maybe_chkpt_tx = (chkpt.status != CheckpointStatus::Building) .then(|| chkpt.checkpoint_tx()) .transpose()?; - let mut pending = vec![]; - for entry in chkpt.pending.iter()? { - let (dest, coin) = entry?; - pending.push((dest.clone(), coin.amount.into())); - } - // TODO: use self.miner_fee_rate() once this endpoint // takes an optional `index` arg. - let est_miner_fee = - (app.bitcoin.checkpoints.active_sigset()?.est_witness_vsize() + 40) - * chkpt.fee_rate - * app.bitcoin.checkpoints.config.user_fee_factor - / 10_000; + let est_miner_fee = (chkpt.sigset.est_witness_vsize() + 40) + * chkpt.fee_rate + * app.bitcoin.checkpoints.config.user_fee_factor + / 10_000; let sigset = RawSignatorySet::new( chkpt.sigset.clone(), From ace4aba868b9bae0e5572f9201b7453ad8e6ca30 Mon Sep 17 00:00:00 2001 From: Judd Keppel Date: Tue, 22 Oct 2024 18:13:23 -0500 Subject: [PATCH 14/18] Fix empty pending deposits response --- src/bitcoin/deposit_index.rs | 11 ++++------- src/bitcoin/relayer.rs | 5 ++++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/bitcoin/deposit_index.rs b/src/bitcoin/deposit_index.rs index 598e6f46..d2fc1cbc 100644 --- a/src/bitcoin/deposit_index.rs +++ b/src/bitcoin/deposit_index.rs @@ -89,13 +89,10 @@ impl DepositIndex { None => 0, }; - // TODO - if confirmations == 0 { - deposits.push(DepositInfo { - deposit: deposit.clone(), - confirmations, - }); - } + deposits.push(DepositInfo { + deposit: deposit.clone(), + confirmations, + }); } } } diff --git a/src/bitcoin/relayer.rs b/src/bitcoin/relayer.rs index 4c7a2ade..203d4fca 100644 --- a/src/bitcoin/relayer.rs +++ b/src/bitcoin/relayer.rs @@ -888,7 +888,9 @@ impl Relayer { let mut hash = bitcoin::BlockHash::from_inner(hash.into_inner()); for _ in 0..n { - let block = self.btc_client().await.get_block(&hash.clone()).await?; + let Ok(block) = self.btc_client().await.get_block(&hash.clone()).await else { + return Ok(blocks); + }; hash = block.header.prev_blockhash; let mut block_bytes = vec![]; @@ -1192,6 +1194,7 @@ pub struct RawSignatorySet { } impl RawSignatorySet { + #[allow(clippy::too_many_arguments)] pub fn new( sigset: SignatorySet, bridge_fee_rate: f64, From 2a0d98a4c24e12cb5526a0c5601b62bddaff8670 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 22 Oct 2024 22:01:47 -0500 Subject: [PATCH 15/18] Update IbcDest encoding, and add legacy encoding --- src/app.rs | 63 +++++++++++++++++++++++++++++++++++++++++----- src/bitcoin/mod.rs | 16 +++++++++--- 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/app.rs b/src/app.rs index f16b66b6..e1735767 100644 --- a/src/app.rs +++ b/src/app.rs @@ -31,6 +31,7 @@ use orga::describe::{Describe, Descriptor}; use orga::encoding::{Decode, Encode, LengthString, LengthVec}; use orga::ibc::ibc_rs::apps::transfer::types::Memo; use orga::ibc::ClientIdKey as ClientId; +use sha2::{Digest, Sha256}; use std::io::Read; use std::str::FromStr; @@ -1328,7 +1329,7 @@ pub struct IbcDest { pub receiver: LengthString, pub sender: LengthString, pub timeout_timestamp: u64, - pub memo: LengthString, + pub memo: LengthString, } impl IbcDest { @@ -1415,7 +1416,9 @@ impl IbcDest { Ok(()) } - pub fn legacy_encode(&self) -> Result> { + pub fn legacy_encode(&self) -> Result>> { + let mut encodings = vec![]; + let mut bytes = vec![]; self.source_port.encode_into(&mut bytes)?; self.source_channel.encode_into(&mut bytes)?; @@ -1423,8 +1426,46 @@ impl IbcDest { EdAdapter(self.sender_signer()?).encode_into(&mut bytes)?; self.timeout_timestamp.encode_into(&mut bytes)?; self.memo.encode_into(&mut bytes)?; + encodings.push(Sha256::digest(bytes).to_vec()); + + if self.memo.len() < 256 { + let mut bytes = vec![]; + self.source_port.encode_into(&mut bytes)?; + self.source_channel.encode_into(&mut bytes)?; + self.receiver.encode_into(&mut bytes)?; + self.sender.encode_into(&mut bytes)?; + self.timeout_timestamp.encode_into(&mut bytes)?; + LengthString::::new(self.memo.len() as u8, self.memo.to_string()) + .encode_into(&mut bytes)?; + + let hash = Sha256::digest(bytes); + let mut bytes = Vec::with_capacity(hash.len() + 1); + bytes.push(0); // version byte + bytes.extend_from_slice(&hash); + encodings.push(bytes); + } - Ok(bytes) + Ok(encodings) + } +} + +impl Migrate for IbcDest { + fn migrate(_src: Store, _dest: Store, mut bytes: &mut &[u8]) -> Result { + let source_port = LengthString::::decode(&mut bytes)?; + let source_channel = LengthString::::decode(&mut bytes)?; + let receiver = LengthString::::decode(&mut bytes)?; + let sender = LengthString::::decode(&mut bytes)?; + let timeout_timestamp = u64::decode(&mut bytes)?; + let memo = LengthString::::decode(&mut bytes)?; + + Ok(IbcDest { + source_port, + source_channel, + receiver, + sender, + timeout_timestamp, + memo: memo.to_string().try_into().unwrap(), + }) } } @@ -1610,11 +1651,11 @@ impl Dest { } // TODO: remove once there are no legacy commitments in-flight - pub fn legacy_commitment_bytes(&self) -> Result> { + pub fn legacy_commitment_bytes(&self) -> Result>> { use sha2::{Digest, Sha256}; let bytes = match self { - Dest::NativeAccount { address } => address.bytes().into(), - Dest::Ibc { data } => Sha256::digest(data.legacy_encode()?).to_vec(), + Dest::NativeAccount { address } => vec![address.bytes().into()], + Dest::Ibc { data } => data.legacy_encode()?, _ => return Err(Error::App("Invalid dest for legacy commitment".to_string())), }; @@ -1722,6 +1763,16 @@ impl Query for Dest { impl Migrate for Dest { fn migrate(src: Store, dest: Store, bytes: &mut &[u8]) -> Result { + // TODO: !!!!!!!! remove from here once there are no legacy IBC dests + // Migrate IBC dests + let mut maybe_ibc_bytes = &mut &**bytes; + let variant = u8::decode(&mut maybe_ibc_bytes)?; + if variant == 1 { + let ibc_dest = IbcDest::migrate(src, dest, maybe_ibc_bytes)?; + return Ok(Self::Ibc { data: ibc_dest }); + } + // TODO: !!!!!!!! remove to here once there are no legacy IBC dests + Self::load(src, bytes) } } diff --git a/src/bitcoin/mod.rs b/src/bitcoin/mod.rs index 1c8a0bec..a9417374 100644 --- a/src/bitcoin/mod.rs +++ b/src/bitcoin/mod.rs @@ -540,10 +540,18 @@ impl Bitcoin { let expected_script = sigset.output_script(&dest_bytes, self.checkpoints.config.sigset_threshold)?; if output.script_pubkey != expected_script { - dest_bytes = dest.legacy_commitment_bytes()?; - let expected_script = - sigset.output_script(&dest_bytes, self.checkpoints.config.sigset_threshold)?; - if output.script_pubkey != expected_script { + let legacy_commitments = dest.legacy_commitment_bytes()?; + let mut matched = false; + for bytes in legacy_commitments { + let expected_script = + sigset.output_script(&dest_bytes, self.checkpoints.config.sigset_threshold)?; + if output.script_pubkey == expected_script { + matched = true; + dest_bytes = bytes; + break; + } + } + if !matched { return Err(OrgaError::App( "Output script does not match signature set".to_string(), ))?; From 1cf6f1de2bc9f4156336ca9d430d0531a3163434 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 22 Oct 2024 22:03:31 -0500 Subject: [PATCH 16/18] Bump versions for network upgrade --- networks/testnet.toml | 6 +++--- src/app.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/networks/testnet.toml b/networks/testnet.toml index e0f4fde4..4f04fc17 100644 --- a/networks/testnet.toml +++ b/networks/testnet.toml @@ -1,13 +1,13 @@ state_sync_rpc = [ - "http://147.182.171.216:26657", - "http://147.182.171.216:26657", + "http://147.182.171.216:26657", + "http://147.182.171.216:26657", ] tendermint_flags = ["--p2p.seeds", """ a07d56aa65e395c332a7bf226ec4e2f844519ffa@147.182.171.216:26656,\ """] btc_relayer = ["https://relayer.nomic-testnet.mappum.io:8443"] -legacy_version = "8.1.x" +legacy_version = "9.1.x" genesis = """ { diff --git a/src/app.rs b/src/app.rs index e1735767..b44e5d6b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -191,7 +191,7 @@ impl InnerApp { /// breaking changes are made to either the state encoding or logic of the /// protocol, and requires a network upgrade to be coordinated via the /// upgrade module. - pub const CONSENSUS_VERSION: u8 = 13; + pub const CONSENSUS_VERSION: u8 = 14; #[cfg(feature = "full")] fn configure_faucets(&mut self) -> Result<()> { From 3e41338e24e9923f20b5e537dc07e660564fcd0f Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 22 Oct 2024 22:03:43 -0500 Subject: [PATCH 17/18] v9.2.0 --- Cargo.lock | 4 +--- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d44b7e1..458cf9a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3981,7 +3981,7 @@ dependencies = [ [[package]] name = "nomic" -version = "9.1.4" +version = "9.2.0" dependencies = [ "alloy", "base64 0.13.1", @@ -4180,7 +4180,6 @@ dependencies = [ [[package]] name = "orga" version = "0.3.1" -source = "git+https://github.com/nomic-io/orga.git?rev=73a3a567f68e3ca0c67a6c8b67f6392df31958a0#73a3a567f68e3ca0c67a6c8b67f6392df31958a0" dependencies = [ "abci2", "async-trait", @@ -4237,7 +4236,6 @@ dependencies = [ [[package]] name = "orga-macros" version = "0.3.1" -source = "git+https://github.com/nomic-io/orga.git?rev=73a3a567f68e3ca0c67a6c8b67f6392df31958a0#73a3a567f68e3ca0c67a6c8b67f6392df31958a0" dependencies = [ "darling", "heck 0.3.3", diff --git a/Cargo.toml b/Cargo.toml index 84bd98a5..3f73509a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nomic" -version = "9.1.4" +version = "9.2.0" authors = ["Nomic DAO Foundation "] edition = "2021" default-run = "nomic" From ffaea4ecbd382bce2c754e1cf6f57725979d5f21 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 22 Oct 2024 22:44:26 -0500 Subject: [PATCH 18/18] Upgrade orga dependency --- Cargo.lock | 4 +++- Cargo.toml | 2 +- src/bin/nomic.rs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 458cf9a3..6bf27ff0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3854,7 +3854,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "merk" version = "2.0.0" -source = "git+https://github.com/nomic-io/merk?rev=cc496300bff8a9223e5589cdc2f2e0db3ae14208#cc496300bff8a9223e5589cdc2f2e0db3ae14208" +source = "git+https://github.com/nomic-io/merk?rev=d6f0490993bcf88f786c5271091aa9a84ff2fe69#d6f0490993bcf88f786c5271091aa9a84ff2fe69" dependencies = [ "colored", "ed 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4180,6 +4180,7 @@ dependencies = [ [[package]] name = "orga" version = "0.3.1" +source = "git+https://github.com/nomic-io/orga.git?rev=3b3d25ade40d81cb64f19335535e3a47bb47778f#3b3d25ade40d81cb64f19335535e3a47bb47778f" dependencies = [ "abci2", "async-trait", @@ -4236,6 +4237,7 @@ dependencies = [ [[package]] name = "orga-macros" version = "0.3.1" +source = "git+https://github.com/nomic-io/orga.git?rev=3b3d25ade40d81cb64f19335535e3a47bb47778f#3b3d25ade40d81cb64f19335535e3a47bb47778f" dependencies = [ "darling", "heck 0.3.3", diff --git a/Cargo.toml b/Cargo.toml index 3f73509a..1404578d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ default-run = "nomic" [dependencies] bitcoin = { version = "0.29.2", features = ["serde", "rand"] } -orga = { git = "https://github.com/nomic-io/orga.git", rev = "73a3a567f68e3ca0c67a6c8b67f6392df31958a0", features = [ +orga = { git = "https://github.com/nomic-io/orga.git", rev = "3b3d25ade40d81cb64f19335535e3a47bb47778f", features = [ "merk-verify", ] } thiserror = "1.0.30" diff --git a/src/bin/nomic.rs b/src/bin/nomic.rs index a09f3469..d203ab27 100644 --- a/src/bin/nomic.rs +++ b/src/bin/nomic.rs @@ -1817,7 +1817,7 @@ impl GrpcCmd { })); log::info!("Starting gRPC server on {}:{}", self.host, self.port); orga::ibc::start_grpc( - || self.config.client().sub(|app| app.ibc.ctx), + || self.config.client().sub(|app| Ok(app.ibc.ctx)), &GrpcOpts { host: self.host.to_string(), port: self.port,