Skip to content

Commit

Permalink
chore: minor cleanups/refactorings
Browse files Browse the repository at this point in the history
  • Loading branch information
sander2 committed Jul 19, 2023
1 parent 6058758 commit 5e23bc6
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 115 deletions.
2 changes: 2 additions & 0 deletions crates/bitcoin/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ use serde::{Deserialize, Serialize};

pub(crate) const SERIALIZE_TRANSACTION_NO_WITNESS: i32 = 0x4000_0000;

/// We also check the coinbase proof in order to defend against the 'leaf-node weakness'.
/// See https://bitslog.com/2018/06/09/leaf-node-weakness-in-bitcoin-merkle-tree-design/ .
#[derive(Encode, Decode, Clone, TypeInfo, PartialEq)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct FullTransactionProof {
Expand Down
9 changes: 6 additions & 3 deletions crates/btc-relay/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ use mocktopus::macros::mockable;
#[cfg(feature = "runtime-benchmarks")]
use bitcoin::types::{BlockBuilder, TransactionBuilder, TransactionOutput};
use bitcoin::{
merkle::{PartialTransactionProof, ProofResult},
types::{BlockChain, BlockHeader, FullTransactionProof, H256Le, Transaction, Value},
merkle::ProofResult,
types::{BlockChain, BlockHeader, H256Le, Transaction, Value},
Error as BitcoinError, SetCompact,
};
use frame_support::{
Expand All @@ -72,7 +72,10 @@ use sp_std::{
prelude::*,
};

pub use bitcoin::{self, Address as BtcAddress, PublicKey as BtcPublicKey};
pub use bitcoin::{
self, merkle::PartialTransactionProof, types::FullTransactionProof, Address as BtcAddress,
PublicKey as BtcPublicKey,
};
pub use pallet::*;
pub use types::{OpReturnPaymentData, RichBlockHeader};

Expand Down
14 changes: 0 additions & 14 deletions crates/btc-relay/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1923,20 +1923,6 @@ fn sample_block_header() -> BlockHeader {
ret
}

//
//
// fn sample_unchecked_partial_proof() -> PartialTransactionProof {
// let merkle_proof = sample_merkle_proof();
// let outputs = vec![sample_valid_payment_output()];
// let transaction = sample_transaction_parsed(&outputs);
// let tx_encoded_len = 99999999;
// PartialTransactionProof {
// merkle_proof,
// transaction,
// tx_encoded_len,
// }
// }

fn sample_unchecked_transaction() -> FullTransactionProof {
let coinbase_tx_hex = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044b6d0b1a020b02ffffffff0100f2052a01000000434104e8e37f1556b53b557405fc7924c861e640c8f99ebb3feb09ae69a84bea1f125940309beec02fb815ea5e68782c32da123b4585bc2f23731f1f1c62c9727dba9dac00000000";
let raw_coinbase_tx = hex::decode(coinbase_tx_hex).unwrap();
Expand Down
67 changes: 31 additions & 36 deletions crates/issue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ pub mod types;
pub use crate::types::{DefaultIssueRequest, IssueRequest, IssueRequestStatus};

use crate::types::{BalanceOf, DefaultVaultId, Version};
use bitcoin::types::FullTransactionProof;
use bitcoin::{merkle::PartialTransactionProof, types::FullTransactionProof};
use btc_relay::{BtcAddress, BtcPublicKey};
use currency::Amount;
use frame_support::{dispatch::DispatchError, ensure, traits::Get, transactional, PalletId};
use frame_support::{dispatch::DispatchError, ensure, pallet_prelude::Weight, traits::Get, transactional, PalletId};
use frame_system::{ensure_root, ensure_signed};
pub use pallet::*;
use sp_core::H256;
Expand All @@ -44,6 +44,32 @@ use sp_std::vec::Vec;
use types::IssueRequestExt;
use vault_registry::{types::CurrencyId, CurrencySource, VaultStatus};

/// Complexity:
/// - `O(H + I + O + B)` where:
/// - `H` is the number of hashes in the merkle tree
/// - `I` is the number of transaction inputs
/// - `O` is the number of transaction outputs
/// - `B` is `transaction` size in bytes (length-fee-bounded)
fn weight_for_execute_issue<T: Config>(proof: &FullTransactionProof) -> Weight {
let partial_weight = |partial_proof: &PartialTransactionProof| {
let h = partial_proof.merkle_proof.hashes.len() as u32;
let i = partial_proof.transaction.inputs.len() as u32;
let o = partial_proof.transaction.outputs.len() as u32;
let b = partial_proof.tx_encoded_len;

<T as Config>::WeightInfo::execute_issue_underpayment(h, i, o, b)
.max(<T as Config>::WeightInfo::execute_issue_exact(h, i, o, b))
.max(<T as Config>::WeightInfo::execute_issue_overpayment(h, i, o, b))
.max(<T as Config>::WeightInfo::execute_expired_issue_underpayment(
h, i, o, b,
))
.max(<T as Config>::WeightInfo::execute_expired_issue_exact(h, i, o, b))
.max(<T as Config>::WeightInfo::execute_expired_issue_overpayment(h, i, o, b))
};

partial_weight(&proof.coinbase_proof).saturating_add(partial_weight(&proof.user_tx_proof))
}

#[frame_support::pallet]
pub mod pallet {
use super::*;
Expand Down Expand Up @@ -220,47 +246,16 @@ pub mod pallet {
/// * `tx_block_height` - block number of collateral chain
/// * `merkle_proof` - raw bytes
/// * `raw_tx` - raw bytes
///
/// ## Complexity:
/// - `O(H + I + O + B)` where:
/// - `H` is the number of hashes in the merkle tree
/// - `I` is the number of transaction inputs
/// - `O` is the number of transaction outputs
/// - `B` is `transaction` size in bytes (length-fee-bounded)
#[pallet::call_index(1)]
#[pallet::weight({
let h = transaction.user_tx_proof.merkle_proof.hashes.len() as u32;
let i = transaction.user_tx_proof.transaction.inputs.len() as u32;
let o = transaction.user_tx_proof.transaction.outputs.len() as u32;
let b = transaction.user_tx_proof.tx_encoded_len;
<T as Config>::WeightInfo::execute_issue_underpayment(h, i, o, b)
.max(<T as Config>::WeightInfo::execute_issue_exact(h, i, o, b))
.max(<T as Config>::WeightInfo::execute_issue_overpayment(h, i, o, b))
.max(<T as Config>::WeightInfo::execute_expired_issue_underpayment(h, i, o, b))
.max(<T as Config>::WeightInfo::execute_expired_issue_exact(h, i, o, b))
.max(<T as Config>::WeightInfo::execute_expired_issue_overpayment(h, i, o, b))
}.saturating_add({
let h = transaction.coinbase_proof.merkle_proof.hashes.len() as u32;
let i = transaction.coinbase_proof.transaction.inputs.len() as u32;
let o = transaction.coinbase_proof.transaction.outputs.len() as u32;
let b = transaction.coinbase_proof.tx_encoded_len;
<T as Config>::WeightInfo::execute_issue_underpayment(h, i, o, b)
.max(<T as Config>::WeightInfo::execute_issue_exact(h, i, o, b))
.max(<T as Config>::WeightInfo::execute_issue_overpayment(h, i, o, b))
.max(<T as Config>::WeightInfo::execute_expired_issue_underpayment(h, i, o, b))
.max(<T as Config>::WeightInfo::execute_expired_issue_exact(h, i, o, b))
.max(<T as Config>::WeightInfo::execute_expired_issue_overpayment(h, i, o, b))
}))]
#[pallet::weight(weight_for_execute_issue::<T>(unchecked_transaction))]
#[transactional]
pub fn execute_issue(
origin: OriginFor<T>,
issue_id: H256,
transaction: FullTransactionProof,
unchecked_transaction: FullTransactionProof,
) -> DispatchResultWithPostInfo {
let executor = ensure_signed(origin)?;
Self::_execute_issue(executor, issue_id, transaction)?;
Self::_execute_issue(executor, issue_id, unchecked_transaction)?;
Ok(().into())
}

Expand Down
48 changes: 27 additions & 21 deletions crates/redeem/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ use btc_relay::BtcAddress;
use currency::Amount;
use frame_support::{
dispatch::{DispatchError, DispatchResult},
ensure, transactional,
ensure,
pallet_prelude::Weight,
transactional,
};
use frame_system::{ensure_root, ensure_signed};
use oracle::OracleKey;
Expand All @@ -50,6 +52,27 @@ use vault_registry::{

pub use pallet::*;

/// Complexity:
/// - `O(H + I + O + B)` where:
/// - `H` is the number of hashes in the merkle tree
/// - `I` is the number of transaction inputs
/// - `O` is the number of transaction outputs
/// - `B` is `transaction` size in bytes (length-fee-bounded)
fn weight_for_execute_redeem<T: Config>(proof: &FullTransactionProof) -> Weight {
<T as Config>::WeightInfo::execute_redeem(
proof.user_tx_proof.merkle_proof.hashes.len() as u32, // H
proof.user_tx_proof.transaction.inputs.len() as u32, // I
proof.user_tx_proof.transaction.outputs.len() as u32, // O
proof.user_tx_proof.tx_encoded_len,
)
.saturating_add(<T as Config>::WeightInfo::execute_redeem(
proof.coinbase_proof.merkle_proof.hashes.len() as u32, // H
proof.coinbase_proof.transaction.inputs.len() as u32, // I
proof.coinbase_proof.transaction.outputs.len() as u32, // O
proof.coinbase_proof.tx_encoded_len,
))
}

#[frame_support::pallet]
pub mod pallet {
use super::*;
Expand Down Expand Up @@ -266,34 +289,17 @@ pub mod pallet {
/// * `tx_id` - transaction hash
/// * `merkle_proof` - membership proof
/// * `transaction` - tx containing payment
///
/// ## Complexity:
/// - `O(H + I + O + B)` where:
/// - `H` is the number of hashes in the merkle tree
/// - `I` is the number of transaction inputs
/// - `O` is the number of transaction outputs
/// - `B` is `transaction` size in bytes (length-fee-bounded)
#[pallet::call_index(2)]
#[pallet::weight(<T as Config>::WeightInfo::execute_redeem(
transaction.user_tx_proof.merkle_proof.hashes.len() as u32, // H
transaction.user_tx_proof.transaction.inputs.len() as u32, // I
transaction.user_tx_proof.transaction.outputs.len() as u32, // O
transaction.user_tx_proof.tx_encoded_len,
).saturating_add(<T as Config>::WeightInfo::execute_redeem(
transaction.coinbase_proof.merkle_proof.hashes.len() as u32, // H
transaction.coinbase_proof.transaction.inputs.len() as u32, // I
transaction.coinbase_proof.transaction.outputs.len() as u32, // O
transaction.coinbase_proof.tx_encoded_len,
)))]
#[pallet::weight(weight_for_execute_redeem::<T>(unchecked_transaction))]
#[transactional]
pub fn execute_redeem(
origin: OriginFor<T>,
redeem_id: H256,
transaction: FullTransactionProof,
unchecked_transaction: FullTransactionProof,
) -> DispatchResultWithPostInfo {
let _ = ensure_signed(origin)?;

Self::_execute_redeem(redeem_id, transaction)?;
Self::_execute_redeem(redeem_id, unchecked_transaction)?;

// Don't take tx fees on success. If the vault had to pay for this function, it would
// have been vulnerable to a griefing attack where users would redeem amounts just
Expand Down
53 changes: 29 additions & 24 deletions crates/replace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub use default_weights::WeightInfo;
use frame_support::{
dispatch::{DispatchError, DispatchResult},
ensure,
pallet_prelude::Weight,
traits::Get,
transactional,
};
Expand All @@ -45,6 +46,31 @@ use vault_registry::{types::CurrencyId, CurrencySource};

pub use pallet::*;

/// Complexity:
/// - `O(H + I + O + B)` where:
/// - `H` is the number of hashes in the merkle tree
/// - `I` is the number of transaction inputs
/// - `O` is the number of transaction outputs
/// - `B` is `transaction` size in bytes (length-fee-bounded)
fn weight_for_execute_replace<T: Config>(proof: &FullTransactionProof) -> Weight {
{
let h = proof.user_tx_proof.merkle_proof.hashes.len() as u32;
let i = proof.user_tx_proof.transaction.inputs.len() as u32;
let o = proof.user_tx_proof.transaction.outputs.len() as u32;
let b = proof.user_tx_proof.tx_encoded_len;
<T as Config>::WeightInfo::execute_pending_replace(h, i, o, b)
.max(<T as Config>::WeightInfo::execute_cancelled_replace(h, i, o, b))
}
.saturating_add({
let h = proof.coinbase_proof.merkle_proof.hashes.len() as u32;
let i = proof.coinbase_proof.transaction.inputs.len() as u32;
let o = proof.coinbase_proof.transaction.outputs.len() as u32;
let b = proof.coinbase_proof.tx_encoded_len;
<T as Config>::WeightInfo::execute_pending_replace(h, i, o, b)
.max(<T as Config>::WeightInfo::execute_cancelled_replace(h, i, o, b))
})
}

#[frame_support::pallet]
pub mod pallet {
use super::*;
Expand Down Expand Up @@ -266,38 +292,17 @@ pub mod pallet {
/// * `replace_id` - the ID of the replacement request
/// * 'merkle_proof' - the merkle root of the block
/// * `raw_tx` - the transaction id in bytes
///
/// ## Complexity:
/// - `O(H + I + O + B)` where:
/// - `H` is the number of hashes in the merkle tree
/// - `I` is the number of transaction inputs
/// - `O` is the number of transaction outputs
/// - `B` is `transaction` size in bytes (length-fee-bounded)
#[pallet::call_index(3)]
#[pallet::weight({
let h = transaction.user_tx_proof.merkle_proof.hashes.len() as u32;
let i = transaction.user_tx_proof.transaction.inputs.len() as u32;
let o = transaction.user_tx_proof.transaction.outputs.len() as u32;
let b = transaction.user_tx_proof.tx_encoded_len;
<T as Config>::WeightInfo::execute_pending_replace(h, i, o, b)
.max(<T as Config>::WeightInfo::execute_cancelled_replace(h, i, o, b))
}.saturating_add({
let h = transaction.coinbase_proof.merkle_proof.hashes.len() as u32;
let i = transaction.coinbase_proof.transaction.inputs.len() as u32;
let o = transaction.coinbase_proof.transaction.outputs.len() as u32;
let b = transaction.coinbase_proof.tx_encoded_len;
<T as Config>::WeightInfo::execute_pending_replace(h, i, o, b)
.max(<T as Config>::WeightInfo::execute_cancelled_replace(h, i, o, b))
}))]
#[pallet::weight(weight_for_execute_replace::<T>(unchecked_transaction))]
#[transactional]
pub fn execute_replace(
origin: OriginFor<T>,
replace_id: H256,
transaction: FullTransactionProof,
unchecked_transaction: FullTransactionProof,
) -> DispatchResultWithPostInfo {
let _ = ensure_signed(origin)?;

Self::_execute_replace(replace_id, transaction)?;
Self::_execute_replace(replace_id, unchecked_transaction)?;
Ok(().into())
}

Expand Down
6 changes: 3 additions & 3 deletions parachain/runtime/runtime-tests/src/parachain/issue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ fn integration_test_issue_wrapped_execute_succeeds() {
// alice executes the issue by confirming the btc transaction
assert_ok!(RuntimeCall::Issue(IssueCall::execute_issue {
issue_id: issue_id,
transaction
unchecked_transaction: transaction
})
.dispatch(origin_of(account_of(vault_proof_submitter))));
});
Expand Down Expand Up @@ -625,7 +625,7 @@ mod execute_pending_issue_tests {
assert_noop!(
RuntimeCall::Issue(IssueCall::execute_issue {
issue_id: issue_id,
transaction: unchecked_transaction
unchecked_transaction
})
.dispatch(origin_of(account_of(CAROL))),
BTCRelayError::InvalidTxid
Expand All @@ -650,7 +650,7 @@ mod execute_pending_issue_tests {
assert_noop!(
RuntimeCall::Issue(IssueCall::execute_issue {
issue_id: issue_id,
transaction
unchecked_transaction: transaction
})
.dispatch(origin_of(account_of(CAROL))),
BTCRelayError::BlockNotFound
Expand Down
Loading

0 comments on commit 5e23bc6

Please sign in to comment.