Skip to content

Commit

Permalink
Merge branch 'develop' into multi-building-checkpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
cwlittle committed Sep 6, 2024
2 parents 9cd6585 + f3a9322 commit 377c371
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 30 deletions.
34 changes: 31 additions & 3 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use crate::airdrop::Airdrop;
use crate::bitcoin::adapter::Adapter;
use crate::bitcoin::matches_bitcoin_network;
use crate::bitcoin::{Bitcoin, Nbtc};
use crate::cosmos::{Chain, Cosmos, Proof};

Expand Down Expand Up @@ -286,6 +287,7 @@ impl InnerApp {
match dest {
Dest::Address(addr) => self.bitcoin.accounts.deposit(addr, nbtc),
Dest::Ibc(dest) => dest.transfer(nbtc, &mut self.bitcoin, &mut self.ibc),
Dest::Fee => Ok(self.bitcoin.give_rewards(nbtc)?),
}
}

Expand Down Expand Up @@ -411,6 +413,13 @@ impl FromStr for NbtcMemo {
}
let dest = parts[1];
let script = if let Ok(addr) = bitcoin::Address::from_str(dest) {
if !matches_bitcoin_network(&addr.network) {
return Err(Error::App(format!(
"Invalid network for nBTC memo. Got {}, Expected {}",
addr.network,
crate::bitcoin::NETWORK
)));
}
addr.script_pubkey()
} else {
bitcoin::Script::from_str(parts[1]).map_err(|e| Error::App(e.to_string()))?
Expand Down Expand Up @@ -835,6 +844,14 @@ impl ConvertSdkTx for InnerApp {
let dest_addr: bitcoin::Address = msg.dst_address.parse().map_err(
|e: bitcoin::util::address::Error| Error::App(e.to_string()),
)?;
if !matches_bitcoin_network(&dest_addr.network) {
return Err(Error::App(format!(
"Invalid network for destination address. Got {}, Expected {}",
dest_addr.network,
crate::bitcoin::NETWORK
)));
}

let dest_script =
crate::bitcoin::adapter::Adapter::new(dest_addr.script_pubkey());

Expand Down Expand Up @@ -961,6 +978,14 @@ impl ConvertSdkTx for InnerApp {
.parse()
.map_err(|_| Error::App("Invalid recovery address".to_string()))?;

if !matches_bitcoin_network(&recovery_addr.network) {
return Err(Error::App(format!(
"Invalid network for recovery address. Got {}, Expected {}",
recovery_addr.network,
crate::bitcoin::NETWORK
)));
}

let script =
crate::bitcoin::adapter::Adapter::new(recovery_addr.script_pubkey());

Expand Down Expand Up @@ -1018,13 +1043,15 @@ pub struct MsgIbcTransfer {
pub enum Dest {
Address(Address),
Ibc(IbcDest),
Fee,
}

impl Dest {
pub fn to_receiver_addr(&self) -> String {
pub fn to_receiver_addr(&self) -> Option<String> {
match self {
Dest::Address(addr) => addr.to_string(),
Dest::Ibc(dest) => dest.receiver.0.to_string(),
Dest::Address(addr) => Some(addr.to_string()),
Dest::Ibc(dest) => Some(dest.receiver.0.to_string()),
Dest::Fee => None,
}
}
}
Expand Down Expand Up @@ -1115,6 +1142,7 @@ impl Dest {
let bytes = match self {
Address(addr) => addr.bytes().into(),
Ibc(dest) => Sha256::digest(dest.encode()?).to_vec(),
Fee => vec![1],
};

Ok(bytes)
Expand Down
22 changes: 19 additions & 3 deletions src/bin/nomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ use nomic::app::IbcDest;
use nomic::app::InnerApp;
use nomic::app::Nom;
use nomic::bitcoin::adapter::Adapter;
use nomic::bitcoin::matches_bitcoin_network;
use nomic::bitcoin::signatory::SignatorySet;
use nomic::bitcoin::Nbtc;
use nomic::bitcoin::{relayer::Relayer, signer::Signer};
use nomic::error::Result;
use nomic::utils::load_bitcoin_key;
use nomic::utils::load_or_generate;
use nomic::utils::{load_bitcoin_key, load_or_generate};
use orga::abci::Node;
use orga::client::wallet::{SimpleWallet, Wallet};
use orga::coins::{Address, Commission, Decimal, Declaration, Symbol};
Expand Down Expand Up @@ -1327,7 +1327,8 @@ async fn deposit(
))
})
.await?;
let script = sigset.output_script(dest.commitment_bytes()?.as_slice(), threshold)?;
let commitment_bytes = dest.commitment_bytes()?;
let script = sigset.output_script(&commitment_bytes, threshold)?;
let btc_addr = bitcoin::Address::from_script(&script, nomic::bitcoin::NETWORK).unwrap();

let mut successes = 0;
Expand Down Expand Up @@ -1428,6 +1429,13 @@ pub struct WithdrawCmd {
impl WithdrawCmd {
async fn run(&self) -> Result<()> {
let script = self.dest.script_pubkey();
if !matches_bitcoin_network(&self.dest.network) {
return Err(nomic::error::Error::Address(format!(
"Invalid network for destination address. Got {}, Expected {}",
self.dest.network,
nomic::bitcoin::NETWORK
)));
}

self.config
.client()
Expand Down Expand Up @@ -1802,6 +1810,14 @@ pub struct SetRecoveryAddressCmd {
impl SetRecoveryAddressCmd {
async fn run(&self) -> Result<()> {
let script = self.address.script_pubkey();
if !matches_bitcoin_network(&self.address.network) {
return Err(nomic::error::Error::Address(format!(
"Invalid network for recovery address. Got {}, Expected {}",
self.address.network,
nomic::bitcoin::NETWORK
)));
}

Ok(self
.config
.client()
Expand Down
16 changes: 11 additions & 5 deletions src/bitcoin/checkpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,12 @@ impl BitcoinTx {

/// The estimated size of the transaction, including the worst-case sizes of
/// all input witnesses once fully signed, in virtual bytes.
pub fn vsize(&self) -> Result<u64> {
Ok(self.to_bitcoin_tx()?.vsize().try_into()?)
pub fn est_vsize(&self) -> Result<u64> {
let base_vsize: u64 = self.to_bitcoin_tx()?.vsize().try_into()?;
let est_witness_vsize = self.input.iter()?.try_fold(0, |sum: u64, input| {
Ok::<_, Error>(sum + input?.est_witness_vsize)
})?;
Ok(base_vsize + est_witness_vsize)
}

/// The hash of the transaction. Note that this will change if any inputs or
Expand Down Expand Up @@ -1350,7 +1354,7 @@ impl<'a> BuildingCheckpointMut<'a> {
.get_mut(BatchType::IntermediateTx as u64)?
.unwrap();
let mut intermediate_tx = intermediate_tx_batch.get_mut(0)?.unwrap();
let fee = intermediate_tx.vsize()? * fee_rate;
let fee = intermediate_tx.est_vsize()? * fee_rate;
intermediate_tx.deduct_fee(fee)?;
fee
};
Expand Down Expand Up @@ -1413,7 +1417,9 @@ impl<'a> BuildingCheckpointMut<'a> {
// Deduct the final tx's miner fee from its outputs,
// removing any outputs which are too small to pay their
// share of the fee.
let tx_size = tx.vsize().map_err(|err| OrgaError::App(err.to_string()))?;
let tx_size = tx
.est_vsize()
.map_err(|err| OrgaError::App(err.to_string()))?;
let fee = intermediate_tx_fee / intermediate_tx_len + tx_size * fee_rate;
tx.deduct_fee(fee)
.map_err(|err| OrgaError::App(err.to_string()))?;
Expand Down Expand Up @@ -1526,7 +1532,7 @@ impl<'a> BuildingCheckpointMut<'a> {
// and add our output there instead.
// TODO: don't pop and repush, just get a mutable reference
let mut curr_tx = final_txs.pop().unwrap();
if curr_tx.vsize()? >= config.emergency_disbursal_max_tx_size {
if curr_tx.est_vsize()? >= config.emergency_disbursal_max_tx_size {
self.link_intermediate_tx(&mut curr_tx, config.sigset_threshold)?;
final_txs.push(curr_tx);
curr_tx = BitcoinTx::with_lock_time(lock_time);
Expand Down
22 changes: 16 additions & 6 deletions src/bitcoin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,18 @@ impl Default for Config {
}
}

pub fn matches_bitcoin_network(network: &bitcoin::Network) -> bool {
match crate::bitcoin::NETWORK {
bitcoin::Network::Bitcoin => network == &crate::bitcoin::NETWORK,
bitcoin::Network::Regtest => {
network == &bitcoin::Network::Regtest || network == &bitcoin::Network::Testnet
}
bitcoin::Network::Testnet | bitcoin::Network::Signet => {
network == &bitcoin::Network::Testnet || network == &bitcoin::Network::Signet
}
}
}

/// Calculates the bridge fee for a deposit of the given amount of BTC, in
/// satoshis.
pub fn calc_deposit_fee(amount: u64) -> u64 {
Expand Down Expand Up @@ -496,10 +508,7 @@ impl Bitcoin {
))
})?;

let regtest_mode = self.network() == bitcoin::Network::Regtest
&& _signatory_key.network == bitcoin::Network::Testnet;

if !regtest_mode && _signatory_key.network != self.network() {
if !matches_bitcoin_network(&_signatory_key.network) {
return Err(Error::Orga(orga::Error::App(
"Signatory key network does not match network".to_string(),
)));
Expand Down Expand Up @@ -603,7 +612,6 @@ impl Bitcoin {

let checkpoint = self.checkpoints.get(sigset_index)?;
let sigset = checkpoint.sigset.clone();

let dest_bytes = dest.commitment_bytes()?;
let expected_script =
sigset.output_script(&dest_bytes, self.checkpoints.config.sigset_threshold)?;
Expand Down Expand Up @@ -674,7 +682,9 @@ impl Bitcoin {
// TODO: keep in excess queue if full

let deposit_fee = nbtc.take(calc_deposit_fee(nbtc.amount.into()))?;
self.give_rewards(deposit_fee)?;
self.checkpoints
.building_mut()?
.insert_pending(Dest::Fee, deposit_fee)?;

let under_capacity = self.checkpoints.has_completed_checkpoint()?
&& self.value_locked()? < self.config.capacity_limit;
Expand Down
7 changes: 4 additions & 3 deletions src/bitcoin/recovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,18 @@ impl RecoveryTxs {
.output
.get(args.vout as usize)
.ok_or_else(|| Error::Signer("Invalid recovery tx vout".to_string()))?;
let commitment_bytes = args.dest.commitment_bytes()?;

let input = Input::new(
OutPoint::new(args.expired_tx.txid(), args.vout),
args.old_sigset,
&args.dest.commitment_bytes()?,
&commitment_bytes,
expired_output.value,
args.threshold,
)?;
let script_pubkey = args
.new_sigset
.output_script(args.dest.commitment_bytes()?.as_slice(), args.threshold)?;
.output_script(&commitment_bytes, args.threshold)?;
let output = TxOut {
value: expired_output.value,
script_pubkey,
Expand All @@ -74,7 +75,7 @@ impl RecoveryTxs {
tx.input.push_back(input)?;
tx.output.push_back(Adapter::new(output))?;

tx.deduct_fee(args.fee_rate * tx.vsize()?)?;
tx.deduct_fee(args.fee_rate * tx.est_vsize()?)?;

tx.populate_input_sig_message(0)?;

Expand Down
16 changes: 12 additions & 4 deletions src/bitcoin/relayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,8 +433,12 @@ impl Relayer {
)?;

let mut index = index.lock().await;
let receiver_addr = match dest.to_receiver_addr() {
Some(addr) => addr,
None => continue,
};
index.insert_deposit(
dest.to_receiver_addr(),
receiver_addr,
bitcoin_address,
Deposit::new(txid, vout as u32, output.value, None),
)
Expand Down Expand Up @@ -865,6 +869,10 @@ impl Relayer {
let txid = tx.txid();
let outpoint = (txid.into_inner(), output.vout);
let dest = output.dest.clone();
if dest.to_receiver_addr().is_none() {
return Ok(());
}
let receiver_addr = dest.to_receiver_addr().unwrap();
let vout = output.vout;
let contains_outpoint = app_client(&self.app_client_addr)
.query(|app| app.bitcoin.processed_outpoints.contains(outpoint))
Expand All @@ -877,13 +885,13 @@ impl Relayer {

if contains_outpoint {
let mut index = index.lock().await;
index.remove_deposit(dest.to_receiver_addr(), deposit_address, txid, vout)?;
index.remove_deposit(receiver_addr, deposit_address, txid, vout)?;
return Ok(());
}

let mut index_guard = index.lock().await;
index_guard.insert_deposit(
dest.to_receiver_addr(),
receiver_addr,
deposit_address.clone(),
Deposit::new(
txid,
Expand Down Expand Up @@ -1188,7 +1196,7 @@ impl WatchedScripts {
sigset: &SignatorySet,
threshold: (u64, u64),
) -> Result<::bitcoin::Script> {
sigset.output_script(dest.commitment_bytes()?.as_slice(), threshold)
sigset.output_script(&dest.commitment_bytes()?, threshold)
}
}

Expand Down
9 changes: 5 additions & 4 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,11 @@ pub fn make_std_tx(
pub fn generate_bitcoin_key(network: bitcoin::Network) -> Result<ExtendedPrivKey> {
let seed: [u8; 32] = rand::thread_rng().gen();

let network = if network == bitcoin::Network::Regtest {
bitcoin::Network::Testnet
} else {
network
let network = match network {
bitcoin::Network::Bitcoin => bitcoin::Network::Bitcoin,
bitcoin::Network::Testnet | bitcoin::Network::Signet | bitcoin::Network::Regtest => {
bitcoin::Network::Testnet
}
};

Ok(ExtendedPrivKey::new_master(network, seed.as_slice())?)
Expand Down
4 changes: 2 additions & 2 deletions tests/bitcoin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ async fn bitcoin_test() {
}
}
}
assert_eq!(signatory_balance, 49994239);
assert_eq!(signatory_balance, 49993057);

let funded_account_balances: Vec<_> = funded_accounts
.iter()
Expand All @@ -556,7 +556,7 @@ async fn bitcoin_test() {
})
.collect();

let expected_account_balances: Vec<u64> = vec![989980029, 0, 0, 0];
let expected_account_balances: Vec<u64> = vec![989976483, 0, 0, 0];
assert_eq!(funded_account_balances, expected_account_balances);

for (i, account) in funded_accounts[0..1].iter().enumerate() {
Expand Down

0 comments on commit 377c371

Please sign in to comment.