Skip to content

Commit

Permalink
Merge branch 'dev' into 'master'
Browse files Browse the repository at this point in the history
v0.1.2 - security patches to BTC-Relay and Staked Relayer Modules, Balances storage update,  substrate v2.0.0-alpha.7 version bump.

See merge request interlay/btc-parachain!127
  • Loading branch information
nud3l committed Jul 9, 2020
2 parents 45975af + b081ab9 commit 98e790e
Show file tree
Hide file tree
Showing 55 changed files with 2,634 additions and 1,623 deletions.
1,840 changes: 898 additions & 942 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
<p align="center">
<a href="https://gitlab.com/interlay/btc-parachain">
<img src="https://assets.gitlab-static.net/uploads/-/system/project/avatar/16523866/gitlab-impl-btc-parachain.png?width=64" alt="Logo" width="300">
</a>
<a href="https://web3.foundation/grants/">
<img src="/docs/web3_foundation_grants_badge_black.png" width="500">
<img src="/docs/polka_btc.png">
</a>


<h2 align="center">BTC-Parachain</h2>

<p align="center">
Expand Down Expand Up @@ -176,4 +172,10 @@ We would also like to thank the following teams for their continuous support:

* [Parity Technologies](https://www.parity.io/)

<p align="center">
<a href="https://web3.foundation/grants/">
<img src="/docs/web3_foundation_grants_badge_black.png">
</a>
</p>


14 changes: 9 additions & 5 deletions crates/bitcoin/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = 'bitcoin'
version = '0.1.0'
version = '0.1.1'
authors = ['Interlay Ltd <[email protected]>']
edition = '2018'

Expand All @@ -13,20 +13,20 @@ version = '1.0.101'
default-features = false
features = ['derive']
package = 'parity-scale-codec'
version = '1.0.0'
version = '1.3.0'

[dependencies.primitive-types]
default-features = false
version = '0.7.0'
version = '0.7.2'
features= ['codec']

[dependencies.sp-std]
default-features = false
version = '2.0.0-alpha.5'
version = '2.0.0-alpha.7'

[dependencies.sp-core]
default-features = false
version = '2.0.0-alpha.5'
version = '2.0.0-alpha.7'

[dependencies.sha2]
default-features = false
Expand All @@ -40,6 +40,10 @@ path = '../x-core'
default-features = false
version = '0.4.2'

[dependencies.bitcoin_hashes]
default-features = false
version = "0.7.3"

[dev-dependencies]
mocktopus = '0.7.0'

Expand Down
65 changes: 61 additions & 4 deletions crates/bitcoin/src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#[cfg(test)]
extern crate mocktopus;

extern crate bitcoin_hashes;

use bitcoin_hashes::Hash;

#[cfg(test)]
use mocktopus::macros::mockable;

Expand Down Expand Up @@ -387,7 +391,30 @@ fn parse_transaction_output(raw_output: &[u8]) -> Result<(TransactionOutput, usi
))
}

pub(crate) fn extract_address_hash(output_script: &[u8]) -> Result<Vec<u8>, Error> {
pub(crate) fn extract_address_hash_scriptsig(input_script: &[u8]) -> Result<Vec<u8>, Error> {
let mut parser = BytesParser::new(input_script);
let mut p2pkh = true;

// Multisig OBOE hack -> p2sh
if input_script[0] == OpCode::Op0 as u8 {
parser.parse::<u8>()?;
p2pkh = false;
}

let sig_size: u64 = parser.parse::<CompactUint>()?.value;
let _sig = parser.read(sig_size as usize)?;

let redeem_script_size: u64 = parser.parse::<CompactUint>()?.value;

// if not p2sh, redeem script is just 33-byte pubkey
if p2pkh && redeem_script_size != 33 {
return Err(Error::UnsupportedInputFormat);
}
let redeem_script = parser.read(redeem_script_size as usize)?;
return Ok(bitcoin_hashes::hash160::Hash::hash(&redeem_script).to_vec());
}

pub(crate) fn extract_address_hash_scriptpubkey(output_script: &[u8]) -> Result<Vec<u8>, Error> {
let script_len = output_script.len();
// Witness
if output_script[0] == 0 {
Expand Down Expand Up @@ -681,7 +708,7 @@ pub(crate) mod tests {

let p2pkh_address: [u8; 20] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

let extr_p2pkh = extract_address_hash(&p2pkh_script).unwrap();
let extr_p2pkh = extract_address_hash_scriptpubkey(&p2pkh_script).unwrap();

assert_eq!(&extr_p2pkh, &p2pkh_address);
}
Expand All @@ -692,17 +719,47 @@ pub(crate) mod tests {

let p2sh_address: [u8; 20] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

let extr_p2sh = extract_address_hash(&p2sh_script).unwrap();
let extr_p2sh = extract_address_hash_scriptpubkey(&p2sh_script).unwrap();

assert_eq!(&extr_p2sh, &p2sh_address);
}

#[test]
fn test_extract_address_hash_scriptsig() {
let raw_tx = "0100000001c15041a06deb6b3818b022fac558da4ce2097f0860c8f642105bbad9d29be02a010000006c493046022100cfd2a2d332b29adce119c55a9fadd3c073332024b7e272513e51623ca15993480221009b482d7f7b4d479aff62bdcdaea54667737d56f8d4d63dd03ec3ef651ed9a25401210325f8b039a11861659c9bf03f43fc4ea055f3a71cd60c7b1fd474ab578f9977faffffffff0290d94000000000001976a9148ed243a7be26080a1a8cf96b53270665f1b8dd2388ac4083086b000000001976a9147e7d94d0ddc21d83bfbcfc7798e4547edf0832aa88ac00000000";
let tx_bytes = hex::decode(&raw_tx).unwrap();
let transaction = parse_transaction(&tx_bytes).unwrap();

let address: [u8; 20] = [
126, 125, 148, 208, 221, 194, 29, 131, 191, 188, 252, 119, 152, 228, 84, 126, 223, 8,
50, 170,
];
let extr_address = extract_address_hash_scriptsig(&transaction.inputs[0].script).unwrap();

assert_eq!(&extr_address, &address);
}

#[test]
fn test_extract_address_hash_scriptsig_p2sh() {
let raw_tx = "0100000001c8cc2b56525e734ff63a13bc6ad06a9e5664df8c67632253a8e36017aee3ee40000000009000483045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51aefeffffff0120f40e00000000001976a9141d30342095961d951d306845ef98ac08474b36a088aca7270400";
let tx_bytes = hex::decode(&raw_tx).unwrap();
let transaction = parse_transaction(&tx_bytes).unwrap();

let address: [u8; 20] = [
233, 195, 221, 12, 7, 170, 199, 97, 121, 235, 199, 106, 108, 120, 212, 214, 124, 108,
22, 10,
];
let extr_address = extract_address_hash_scriptsig(&transaction.inputs[0].script).unwrap();

assert_eq!(&extr_address, &address);
}

/*
#[test]
fn test_extract_address_invalid_p2pkh_fails() {
let p2pkh_script = hex::decode(&sample_malformed_p2pkh_output()).unwrap();
assert_eq!(extract_address_hash(&p2pkh_script).err(), Some(Error::MalformedP2PKHOutput));
assert_eq!(extract_address_hash_scriptpubkey(&p2pkh_script).err(), Some(Error::MalformedP2PKHOutput));
}
*/
}
59 changes: 53 additions & 6 deletions crates/bitcoin/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ extern crate hex;
#[cfg(test)]
use mocktopus::macros::mockable;

use bitcoin_hashes::Hash;

use codec::alloc::string::String;
use codec::{Decode, Encode};
use primitive_types::{H256, U256};
Expand All @@ -13,7 +15,10 @@ use x_core::Error;

use crate::formatter::Formattable;
use crate::merkle::MerkleProof;
use crate::parser::{extract_address_hash, extract_op_return_data, FromLeBytes};
use crate::parser::{
extract_address_hash_scriptpubkey, extract_address_hash_scriptsig, extract_op_return_data,
FromLeBytes,
};
use crate::utils::{hash256_merkle_step, log2, reverse_endianness, sha256d_le};

pub(crate) const SERIALIZE_TRANSACTION_NO_WITNESS: i32 = 0x4000_0000;
Expand Down Expand Up @@ -304,6 +309,16 @@ impl TransactionInput {
pub fn with_witness(&mut self, witness: Vec<Vec<u8>>) {
self.witness = witness;
}

pub fn extract_address(&self) -> Result<Vec<u8>, Error> {
// Witness
if !self.witness.is_empty() {
return Ok(bitcoin_hashes::hash160::Hash::hash(&self.witness[1]).to_vec());
}

// P2PKH
extract_address_hash_scriptsig(&self.script)
}
}

/// Bitcoin script
Expand Down Expand Up @@ -367,10 +382,6 @@ impl Script {
self.bytes.extend(&value.format())
}

pub fn extract_address(&self) -> Result<Vec<u8>, Error> {
extract_address_hash(&self.bytes)
}

pub fn extract_op_return_data(&self) -> Result<Vec<u8>, Error> {
extract_op_return_data(&self.bytes)
}
Expand Down Expand Up @@ -435,6 +446,10 @@ impl TransactionOutput {
script: Script::op_return(return_content),
}
}

pub fn extract_address(&self) -> Result<Vec<u8>, Error> {
extract_address_hash_scriptpubkey(&self.script.bytes)
}
}

/// Bitcoin transaction
Expand Down Expand Up @@ -1000,7 +1015,7 @@ mod tests {
assert_eq!(transaction.outputs.len(), 2);
assert_eq!(transaction.outputs[0].value, 100);
assert_eq!(
transaction.outputs[0].script.extract_address().unwrap(),
transaction.outputs[0].extract_address().unwrap(),
address.as_bytes()
);
assert_eq!(transaction.outputs[1].value, 0);
Expand Down Expand Up @@ -1134,4 +1149,36 @@ mod tests {
let bytes = proof.format();
MerkleProof::parse(&bytes).unwrap();
}

#[test]
fn extract_witness_address_p2wpkh() {
let raw_tx = "0200000000010140d43a99926d43eb0e619bf0b3d83b4a31f60c176beecfb9d35bf45e54d0f7420100000017160014a4b4ca48de0b3fffc15404a1acdc8dbaae226955ffffffff0100e1f5050000000017a9144a1154d50b03292b3024370901711946cb7cccc387024830450221008604ef8f6d8afa892dee0f31259b6ce02dd70c545cfcfed8148179971876c54a022076d771d6e91bed212783c9b06e0de600fab2d518fad6f15a2b191d7fbd262a3e0121039d25ab79f41f75ceaf882411fd41fa670a4c672c23ffaf0e361a969cde0692e800000000";
let tx_bytes = hex::decode(&raw_tx).unwrap();
let transaction = parse_transaction(&tx_bytes).unwrap();

let address: [u8; 20] = [
164, 180, 202, 72, 222, 11, 63, 255, 193, 84, 4, 161, 172, 220, 141, 186, 174, 34, 105,
85,
];

let extr_address = transaction.inputs[0].extract_address().unwrap();

assert_eq!(&extr_address, &address);
}

#[test]
fn extract_witness_address_p2wsh() {
let raw_tx = "020000000001027113554199c88273f7f04d18a0dca69145ea863f31519a790b346579b9b55f090100000017160014d6ad6711da30f4349a0d8c387a515bff10ecd507fdffffff90a9eb7550a8308c629014f3f685d2d72e9e7de6bd199c3a9615b567206889430100000017160014cce6d8dffda77f56e237389f48417f10659c2e42fdffffff0228641c000000000017a914d980c4240e77b76d48051c791f68831d23ad3e8687400d03000000000017a914e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a870248304502210088b0fb4b40af9620f785f265c2e2f7436018391d9db34eee3bc1ebd796fbce96022015151182eaa595e090c8030d9f979b920aae276c385dfc66ac2d77160a27453b01210266dd88be116711227e2e953daa008cca45ce5cc0aa4b584c20ae6ddb9ce0212d0247304402204b2fdd767ab93b30a43042c3287ae78d06d1418084fe88350b0aaf06bebe02fe02202d850fc5887d948307fdade871de3714d867610643f6507e511d14dad86fe3ce012102593012612326b4c07e6f0234bac5ff62b5ed12afe77e2900474ca36b3bfa528075f50700";
let tx_bytes = hex::decode(&raw_tx).unwrap();
let transaction = parse_transaction(&tx_bytes).unwrap();

let address: [u8; 20] = [
214, 173, 103, 17, 218, 48, 244, 52, 154, 13, 140, 56, 122, 81, 91, 255, 16, 236, 213,
7,
];

let extr_address = transaction.inputs[0].extract_address().unwrap();

assert_eq!(&extr_address, &address);
}
}
22 changes: 11 additions & 11 deletions crates/btc-relay/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "btc-relay"
version = "0.1.0"
version = "2.0.0-alpha.7"
authors = ["Interlay Ltd"]
edition = "2018"

Expand All @@ -13,37 +13,37 @@ version = '1.0.101'
default-features = false
features = ['derive']
package = 'parity-scale-codec'
version = '1.0.0'
version = '1.3.0'

[dependencies.frame-support]
default-features = false
version = '2.0.0-alpha.5'
version = '2.0.0-alpha.7'

[dependencies.system]
default-features = false
package = 'frame-system'
version = '2.0.0-alpha.5'
version = '2.0.0-alpha.7'

[dependencies.sp-io]
default-features = false
version = '2.0.0-alpha.5'
version = '2.0.0-alpha.7'

[dependencies.sp-core]
default-features = false
version = '2.0.0-alpha.5'
version = '2.0.0-alpha.7'

[dependencies.timestamp]
default-features = false
package = 'pallet-timestamp'
version = '2.0.0-alpha.5'
version = '2.0.0-alpha.7'

[dependencies.sp-std]
default-features = false
version = '2.0.0-alpha.5'
version = '2.0.0-alpha.7'

[dependencies.primitive-types]
default-features = false
version = '0.7.0'
version = '0.7.2'
features= ['codec']

[dependencies.bitcoin]
Expand All @@ -60,14 +60,14 @@ path = '../security'

[dependencies.hex]
default-features = false
version = "0.4.0"
version = '0.4.2'

[dev-dependencies]
mocktopus = '0.7.0'

[dev-dependencies.sp-runtime]
default-features = false
version = '2.0.0-alpha.5'
version = '2.0.0-alpha.7'

[features]
default = ['std']
Expand Down
26 changes: 25 additions & 1 deletion crates/btc-relay/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use mocktopus::macros::mockable;

#[cfg_attr(test, mockable)]
pub(crate) mod security {
#[cfg(test)]
use security::types::ErrorCode;
use security::types::StatusCode;
use x_core::UnitResult;
use x_core::{Error, UnitResult};

pub fn _ensure_parachain_status_running<T: security::Trait>() -> UnitResult {
<security::Module<T>>::_ensure_parachain_status_running()
Expand All @@ -17,4 +19,26 @@ pub(crate) mod security {
pub fn _get_parachain_status<T: security::Trait>() -> StatusCode {
<security::Module<T>>::get_parachain_status()
}

pub fn _is_parachain_error_invalid_btcrelay<T: security::Trait>() -> bool {
<security::Module<T>>::_is_parachain_error_invalid_btcrelay()
}

pub fn _is_parachain_error_no_data_btcrelay<T: security::Trait>() -> bool {
<security::Module<T>>::_is_parachain_error_no_data_btcrelay()
}

pub fn recover_from_btc_relay_failure<T: security::Trait>() -> UnitResult {
<security::Module<T>>::recover_from_btc_relay_failure().map_err(|_e| Error::RuntimeError)
}

#[cfg(test)]
pub fn set_parachain_status<T: security::Trait>(status: StatusCode) -> () {
<security::Module<T>>::set_parachain_status(status)
}

#[cfg(test)]
pub fn insert_error<T: security::Trait>(error: ErrorCode) -> () {
<security::Module<T>>::insert_error(error)
}
}
Loading

0 comments on commit 98e790e

Please sign in to comment.