Skip to content

Commit

Permalink
fix some part for bitcoin (paritytech#221)
Browse files Browse the repository at this point in the history
1. add revoke_withdraw for XGatewayCommon to support user revoke their withdraw request
2. let `set_withdrawal_state` in XGatewayRecords could set any state and add test
3. add `force_replace_proposal_tx` allow trustee could replace an existed withdrawal tx
  • Loading branch information
atenjin authored Sep 4, 2020
1 parent 66e7716 commit 3a4f009
Show file tree
Hide file tree
Showing 14 changed files with 359 additions and 86 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion xpallets/assets/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ benchmarks! {
}

set_balance {
let n in 1 .. AssetType::iterator().collect::<Vec<_>>().len() as u32;
let n in 1 .. AssetType::iter().collect::<Vec<_>>().len() as u32;

let user: T::AccountId = account("user", 0, SEED);
let user_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(user.clone());
Expand Down
65 changes: 65 additions & 0 deletions xpallets/gateway/bitcoin/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,56 @@ fn withdraw_tx() -> (Transaction, BtcRelayedTxInfo, Transaction) {
(withdraw, info, prev)
}

fn prepare_withdrawal<T: Trait>() -> Transaction {
// https://btc.com/62c389f1974b8a44737d76f92da0f5cd7f6f48d065e7af6ba368298361141270.rawhex
const RAW_TX: &'static str = "0100000001052ceda6cf9c93012a994f4ffa2a29c9e31ecf96f472b175eb8e602bfa2b2c5100000000fdfd000047304402200e4d732c456f4722d376252be16554edb27fc93c55db97859e16682bc62b014502202b9c4b01ad55daa1f76e6a564b7762cd0a81240c947806ab3f3b056f2e77c1da01483045022100c7cd680992de60da8c33fc3ef7f5ead85b204660822d9fbda2d85f9fadba732a022021fdc49b20a6007ea971a385732a4065d1d7c792ac9dc391034fb78aa9f5034b014c69522102df92e88c4380778c9c48268460a124a8f4e7da883f80477deaa644ced486efc6210244d81efeb4171b1a8a433b87dd202117f94e44c909c49e42e77b69b5a6ce7d0d2103a36339f413da869df12b1ab0def91749413a0dee87f0bfa85ba7196e6cdad10253aeffffffff03e0349500000000001976a91413256ff2dee6e80c275ddb877abc1ffe453a731488ace00f9700000000001976a914ea6e8dd56703ace584eb9dff0224629f8486672988acc88a02000000000017a914cb94110435d0635223eebe25ed2aaabc03781c458700000000";
let old_withdraw = Transaction::from(RAW_TX);
// https://btc.com/092684402f9b21abdb1d2d76511d5983bd1250d173ced171a3f76d03fcc43e97.rawhex
const ANOTHER_TX: &'static str =
"0100000001059ec66e2a2123364a56bd48f10f57d8a41ecf4082669e6fc85485637043879100000000fdfd00004830450221009fbe7b8f2f4ae771e8773cb5206b9f20286676e2c7cfa98a8e95368acfc3cb3c02203969727a276d7333d5f8815fa364307b8015783cfefbd53def28befdb81855fc0147304402205e5bbe039457d7657bb90dbe63ac30b9547242b44cc03e1f7a690005758e34aa02207208ed76a269d193f1e10583bd902561dbd02826d0486c33a4b1b1839a3d226f014c69522102df92e88c4380778c9c48268460a124a8f4e7da883f80477deaa644ced486efc6210244d81efeb4171b1a8a433b87dd202117f94e44c909c49e42e77b69b5a6ce7d0d2103a36339f413da869df12b1ab0def91749413a0dee87f0bfa85ba7196e6cdad10253aeffffffff04288e0300000000001976a914eb016d7998c88a79a50a0408dd7d5839b1ce1a6888aca0bb0d00000000001976a914646fe05e35369248c3f8deea436dc2b92c7dc86888ac50c30000000000001976a914d1a68d6e891a88d53d9bc3b88d172a3ff6b238c388ac20ee03020000000017a914cb94110435d0635223eebe25ed2aaabc03781c458700000000";
let tmp = Transaction::from(ANOTHER_TX);

let accounts = accounts::<T>();
let alice = accounts[0].clone();
let bob = accounts[1].clone();
let withdrawal_fee = XGatewayBitcoin::<T>::btc_withdrawal_fee();

let balance1 = (9778400 + withdrawal_fee).saturated_into();
let balance2 = (9900000 + withdrawal_fee).saturated_into();
XGatewayRecords::<T>::deposit(&alice, &ASSET_ID, balance1).unwrap();
XGatewayRecords::<T>::deposit(&bob, &ASSET_ID, balance2).unwrap();
// prepare withdraw info
XGatewayRecords::<T>::withdrawal(
&alice,
&ASSET_ID,
balance1,
b"12kEgqNShFw7BN27QCMQZCynQpSuV4x1Ax".to_vec(),
b"memo".to_vec().into(),
)
.unwrap();
XGatewayRecords::<T>::withdrawal(
&bob,
&ASSET_ID,
balance2,
b"1NNZZKR6pos2M4yiJhS76NjcRHxoJUATy4".to_vec(),
b"memo".to_vec().into(),
)
.unwrap();

let proposal = BtcWithdrawalProposal::<T::AccountId> {
sig_state: VoteResult::Finish,
withdrawal_id_list: vec![0, 1],
tx: old_withdraw.clone(),
trustee_list: vec![(alice, true), (bob, true)],
};
WithdrawalProposal::<T>::put(proposal);

// replace tx
let mut new_withdraw = old_withdraw;
new_withdraw.inputs = tmp.inputs; // replace inputs
new_withdraw
}

fn create_tx() -> Transaction {
Transaction::from("0100000001052ceda6cf9c93012a994f4ffa2a29c9e31ecf96f472b175eb8e602bfa2b2c5100000000b40047304402200e4d732c456f4722d376252be16554edb27fc93c55db97859e16682bc62b014502202b9c4b01ad55daa1f76e6a564b7762cd0a81240c947806ab3f3b056f2e77c1da014c69522102df92e88c4380778c9c48268460a124a8f4e7da883f80477deaa644ced486efc6210244d81efeb4171b1a8a433b87dd202117f94e44c909c49e42e77b69b5a6ce7d0d2103a36339f413da869df12b1ab0def91749413a0dee87f0bfa85ba7196e6cdad10253aeffffffff03e0349500000000001976a91413256ff2dee6e80c275ddb877abc1ffe453a731488ace00f9700000000001976a914ea6e8dd56703ace584eb9dff0224629f8486672988acc88a02000000000017a914cb94110435d0635223eebe25ed2aaabc03781c458700000000")
}
Expand Down Expand Up @@ -234,6 +284,17 @@ benchmarks! {
assert!(WithdrawalProposal::<T>::get().is_none());
}

force_replace_proposal_tx {
let l in 1 .. 1024 * 1024 * 500; // 500KB length

Verifier::put(BtcTxVerifier::Test);
let tx = prepare_withdrawal::<T>();
let raw = serialization::serialize(&tx);
}: _(RawOrigin::Root, raw.into())
verify {
assert_eq!(WithdrawalProposal::<T>::get().unwrap().tx, tx);
}

set_btc_withdrawal_fee {
let caller = common::accounts::<T>()[0].clone();
}: _(RawOrigin::Root, 2000000)
Expand Down Expand Up @@ -283,6 +344,10 @@ mod tests {
assert_ok!(test_benchmark_remove_pending::<Test>());
});

ExtBuilder::default().build().execute_with(|| {
assert_ok!(test_benchmark_force_replace_proposal_tx::<Test>());
});

ExtBuilder::default().build().execute_with(|| {
assert_ok!(test_benchmark_set_btc_withdrawal_fee::<Test>());
});
Expand Down
30 changes: 30 additions & 0 deletions xpallets/gateway/bitcoin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,9 @@ decl_module! {
Ok(post_info)
}

/// Trustee create a proposal for a withdrawal list. `tx` is the proposal withdrawal transaction.
/// The `tx` would have a sign for current creator or do not have sign. if creator do not sign
/// for this transaction, he could do `sign_withdraw_tx` later.
#[weight = <T as Trait>::WeightInfo::create_withdraw_tx()]
pub fn create_withdraw_tx(origin, withdrawal_id_list: Vec<u32>, tx: Vec<u8>) -> DispatchResult {
let from = ensure_signed(origin)?;
Expand All @@ -319,6 +322,9 @@ decl_module! {
Ok(())
}

/// Trustees sign a withdrawal proposal. If `tx` is None, means this trustee vote to reject
/// this proposal. If `tx` is Some(), the inner part must be a valid transaction with this
/// trustee signature.
#[weight = <T as Trait>::WeightInfo::sign_withdraw_tx()]
pub fn sign_withdraw_tx(origin, tx: Option<Vec<u8>>) -> DispatchResult {
let from = ensure_signed(origin)?;
Expand Down Expand Up @@ -351,6 +357,9 @@ decl_module! {
Ok(())
}

/// Allow root or trustees could remove pending deposits for an address and decide whether
/// deposit to an account id. if pass `None` to `who`, would just remove pendings, if pass
/// Some, would deposit to this account id.
#[weight = <T as Trait>::WeightInfo::remove_pending()]
pub fn remove_pending(origin, addr: BtcAddress, who: Option<T::AccountId>) -> DispatchResult {
T::TrusteeOrigin::try_origin(origin).map(|_| ()).or_else(ensure_root)?;
Expand All @@ -364,20 +373,41 @@ decl_module! {
Ok(())
}

/// Dangerous! remove current withdrawal proposal directly. Please check business logic before
/// do this operation.
#[weight = <T as Trait>::WeightInfo::remove_proposal()]
pub fn remove_proposal(origin) -> DispatchResult {
ensure_root(origin)?;
WithdrawalProposal::<T>::kill();
Ok(())
}

/// Dangerous! force replace current withdrawal proposal transaction. Please check business
/// logic before do this operation. Must make sure current proposal transaction is invalid
/// (e.g. when created a proposal, the inputs are not in double spend state, but after other
/// trustees finish signing, the inputs are in double spend due other case. Thus could create
/// a new valid transaction which outputs same to current proposal to replace current proposal
/// transaction.)
#[weight = <T as Trait>::WeightInfo::force_replace_proposal_tx()]
pub fn force_replace_proposal_tx(origin, tx: Vec<u8>) -> DispatchResult {
T::TrusteeOrigin::try_origin(origin).map(|_| ()).or_else(ensure_root)?;
let tx: Transaction = deserialize(Reader::new(tx.as_slice())).map_err(|_| Error::<T>::DeserializeErr)?;
native::debug!(
target: xpallet_support::RUNTIME_TARGET,
"[force_replace_proposal_tx]|new_tx:{:?}", tx,
);
Self::force_replace_withdraw_tx(tx)
}

/// Set bitcoin withdrawal fee
#[weight = <T as Trait>::WeightInfo::set_btc_withdrawal_fee()]
pub fn set_btc_withdrawal_fee(origin, #[compact] fee: u64) -> DispatchResult {
T::TrusteeOrigin::try_origin(origin).map(|_| ()).or_else(ensure_root)?;
BtcWithdrawalFee::put(fee);
Ok(())
}

/// Set bitcoin deposit limit
#[weight = <T as Trait>::WeightInfo::set_btc_deposit_limit()]
pub fn set_btc_deposit_limit(origin, #[compact] value: u64) -> DispatchResult {
T::TrusteeOrigin::try_origin(origin).map(|_| ()).or_else(ensure_root)?;
Expand Down
2 changes: 1 addition & 1 deletion xpallets/gateway/bitcoin/src/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ impl Trait for Test {
pub type System = frame_system::Module<Test>;
pub type Balances = pallet_balances::Module<Test>;
pub type XAssets = xpallet_assets::Module<Test>;
// pub type XGatewayRecords = xpallet_gateway_records::Module<Test>;
pub type XGatewayRecords = xpallet_gateway_records::Module<Test>;
pub type XGatewayCommon = xpallet_gateway_common::Module<Test>;
pub type XGatewayBitcoin = Module<Test>;
pub type XGatewayBitcoinErr = Error<Test>;
Expand Down
62 changes: 62 additions & 0 deletions xpallets/gateway/bitcoin/src/tests/trustee.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use super::common::*;

use frame_system::RawOrigin;
use sp_std::str::FromStr;

use light_bitcoin::crypto::dhash160;
use light_bitcoin::keys::{Public, Type};
use light_bitcoin::serialization;

use xpallet_gateway_common::traits::TrusteeForChain;

use crate::trustee::create_multi_address;
use crate::tx::validator::parse_and_check_signed_tx_impl;
use crate::types::VoteResult;

#[test]
pub fn test_check_trustee_entity() {
Expand Down Expand Up @@ -181,3 +184,62 @@ fn test_verify_tx_sign() {
assert_eq!(r, 1);
});
}

#[test]
fn force_replace_withdraw() {
ExtBuilder::default().build_and_execute(|| {
// test would ignore sign check and always return true
Verifier::put(BtcTxVerifier::Test);

// https://btc.com/62c389f1974b8a44737d76f92da0f5cd7f6f48d065e7af6ba368298361141270.rawhex
const RAW_TX: &'static str = "0100000001052ceda6cf9c93012a994f4ffa2a29c9e31ecf96f472b175eb8e602bfa2b2c5100000000fdfd000047304402200e4d732c456f4722d376252be16554edb27fc93c55db97859e16682bc62b014502202b9c4b01ad55daa1f76e6a564b7762cd0a81240c947806ab3f3b056f2e77c1da01483045022100c7cd680992de60da8c33fc3ef7f5ead85b204660822d9fbda2d85f9fadba732a022021fdc49b20a6007ea971a385732a4065d1d7c792ac9dc391034fb78aa9f5034b014c69522102df92e88c4380778c9c48268460a124a8f4e7da883f80477deaa644ced486efc6210244d81efeb4171b1a8a433b87dd202117f94e44c909c49e42e77b69b5a6ce7d0d2103a36339f413da869df12b1ab0def91749413a0dee87f0bfa85ba7196e6cdad10253aeffffffff03e0349500000000001976a91413256ff2dee6e80c275ddb877abc1ffe453a731488ace00f9700000000001976a914ea6e8dd56703ace584eb9dff0224629f8486672988acc88a02000000000017a914cb94110435d0635223eebe25ed2aaabc03781c458700000000";
let old_withdraw = Transaction::from(RAW_TX);
// https://btc.com/092684402f9b21abdb1d2d76511d5983bd1250d173ced171a3f76d03fcc43e97.rawhex
const ANOTHER_TX: &'static str =
"0100000001059ec66e2a2123364a56bd48f10f57d8a41ecf4082669e6fc85485637043879100000000fdfd00004830450221009fbe7b8f2f4ae771e8773cb5206b9f20286676e2c7cfa98a8e95368acfc3cb3c02203969727a276d7333d5f8815fa364307b8015783cfefbd53def28befdb81855fc0147304402205e5bbe039457d7657bb90dbe63ac30b9547242b44cc03e1f7a690005758e34aa02207208ed76a269d193f1e10583bd902561dbd02826d0486c33a4b1b1839a3d226f014c69522102df92e88c4380778c9c48268460a124a8f4e7da883f80477deaa644ced486efc6210244d81efeb4171b1a8a433b87dd202117f94e44c909c49e42e77b69b5a6ce7d0d2103a36339f413da869df12b1ab0def91749413a0dee87f0bfa85ba7196e6cdad10253aeffffffff04288e0300000000001976a914eb016d7998c88a79a50a0408dd7d5839b1ce1a6888aca0bb0d00000000001976a914646fe05e35369248c3f8deea436dc2b92c7dc86888ac50c30000000000001976a914d1a68d6e891a88d53d9bc3b88d172a3ff6b238c388ac20ee03020000000017a914cb94110435d0635223eebe25ed2aaabc03781c458700000000";
let tmp = Transaction::from(ANOTHER_TX);

let accounts = accounts::<Test>();
let alice = accounts[0].clone();
let bob = accounts[1].clone();
let withdrawal_fee = XGatewayBitcoin::btc_withdrawal_fee();

let balance1 = (9778400 + withdrawal_fee).into();
let balance2 = (9900000 + withdrawal_fee).into();
XGatewayRecords::deposit(
&alice,&X_BTC, balance1,).unwrap();
XGatewayRecords::deposit(
&bob,&X_BTC, balance2,).unwrap();
// prepare withdraw info
assert_ok!(XGatewayCommon::withdraw(
RawOrigin::Signed(alice.clone()).into(),
X_BTC,
balance1,
b"12kEgqNShFw7BN27QCMQZCynQpSuV4x1Ax".to_vec(),
b"memo".to_vec().into(),
));
assert_ok!(XGatewayCommon::withdraw(
RawOrigin::Signed(bob.clone()).into(),
X_BTC,
balance2,
b"1NNZZKR6pos2M4yiJhS76NjcRHxoJUATy4".to_vec(),
b"memo".to_vec().into(),
));

let proposal = BtcWithdrawalProposal::<AccountId> {
sig_state: VoteResult::Finish,
withdrawal_id_list: vec![0, 1],
tx: old_withdraw.clone(),
trustee_list: vec![(alice, true), (bob, true)],
};
WithdrawalProposal::<Test>::put(proposal);

// replace tx
let mut new_withdraw = old_withdraw;
new_withdraw.inputs = tmp.inputs; // replace inputs

let raw = serialization::serialize(&new_withdraw);
assert_ok!(XGatewayBitcoin::force_replace_proposal_tx(RawOrigin::Root.into(), raw.into()));
assert_eq!(XGatewayBitcoin::withdrawal_proposal().unwrap().tx, new_withdraw);
});
}
Loading

0 comments on commit 3a4f009

Please sign in to comment.