Skip to content

Commit 98e790e

Browse files
committed
Merge branch 'dev' into 'master'
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
2 parents 45975af + b081ab9 commit 98e790e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2634
-1623
lines changed

Cargo.lock

Lines changed: 898 additions & 942 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
<p align="center">
22
<a href="https://gitlab.com/interlay/btc-parachain">
3-
<img src="https://assets.gitlab-static.net/uploads/-/system/project/avatar/16523866/gitlab-impl-btc-parachain.png?width=64" alt="Logo" width="300">
4-
</a>
5-
<a href="https://web3.foundation/grants/">
6-
<img src="/docs/web3_foundation_grants_badge_black.png" width="500">
3+
<img src="/docs/polka_btc.png">
74
</a>
85

9-
106
<h2 align="center">BTC-Parachain</h2>
117

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

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

175+
<p align="center">
176+
<a href="https://web3.foundation/grants/">
177+
<img src="/docs/web3_foundation_grants_badge_black.png">
178+
</a>
179+
</p>
180+
179181

crates/bitcoin/Cargo.toml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = 'bitcoin'
3-
version = '0.1.0'
3+
version = '0.1.1'
44
authors = ['Interlay Ltd <dominik@interlay.io>']
55
edition = '2018'
66

@@ -13,20 +13,20 @@ version = '1.0.101'
1313
default-features = false
1414
features = ['derive']
1515
package = 'parity-scale-codec'
16-
version = '1.0.0'
16+
version = '1.3.0'
1717

1818
[dependencies.primitive-types]
1919
default-features = false
20-
version = '0.7.0'
20+
version = '0.7.2'
2121
features= ['codec']
2222

2323
[dependencies.sp-std]
2424
default-features = false
25-
version = '2.0.0-alpha.5'
25+
version = '2.0.0-alpha.7'
2626

2727
[dependencies.sp-core]
2828
default-features = false
29-
version = '2.0.0-alpha.5'
29+
version = '2.0.0-alpha.7'
3030

3131
[dependencies.sha2]
3232
default-features = false
@@ -40,6 +40,10 @@ path = '../x-core'
4040
default-features = false
4141
version = '0.4.2'
4242

43+
[dependencies.bitcoin_hashes]
44+
default-features = false
45+
version = "0.7.3"
46+
4347
[dev-dependencies]
4448
mocktopus = '0.7.0'
4549

crates/bitcoin/src/parser.rs

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#[cfg(test)]
22
extern crate mocktopus;
33

4+
extern crate bitcoin_hashes;
5+
6+
use bitcoin_hashes::Hash;
7+
48
#[cfg(test)]
59
use mocktopus::macros::mockable;
610

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

390-
pub(crate) fn extract_address_hash(output_script: &[u8]) -> Result<Vec<u8>, Error> {
394+
pub(crate) fn extract_address_hash_scriptsig(input_script: &[u8]) -> Result<Vec<u8>, Error> {
395+
let mut parser = BytesParser::new(input_script);
396+
let mut p2pkh = true;
397+
398+
// Multisig OBOE hack -> p2sh
399+
if input_script[0] == OpCode::Op0 as u8 {
400+
parser.parse::<u8>()?;
401+
p2pkh = false;
402+
}
403+
404+
let sig_size: u64 = parser.parse::<CompactUint>()?.value;
405+
let _sig = parser.read(sig_size as usize)?;
406+
407+
let redeem_script_size: u64 = parser.parse::<CompactUint>()?.value;
408+
409+
// if not p2sh, redeem script is just 33-byte pubkey
410+
if p2pkh && redeem_script_size != 33 {
411+
return Err(Error::UnsupportedInputFormat);
412+
}
413+
let redeem_script = parser.read(redeem_script_size as usize)?;
414+
return Ok(bitcoin_hashes::hash160::Hash::hash(&redeem_script).to_vec());
415+
}
416+
417+
pub(crate) fn extract_address_hash_scriptpubkey(output_script: &[u8]) -> Result<Vec<u8>, Error> {
391418
let script_len = output_script.len();
392419
// Witness
393420
if output_script[0] == 0 {
@@ -681,7 +708,7 @@ pub(crate) mod tests {
681708

682709
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];
683710

684-
let extr_p2pkh = extract_address_hash(&p2pkh_script).unwrap();
711+
let extr_p2pkh = extract_address_hash_scriptpubkey(&p2pkh_script).unwrap();
685712

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

693720
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];
694721

695-
let extr_p2sh = extract_address_hash(&p2sh_script).unwrap();
722+
let extr_p2sh = extract_address_hash_scriptpubkey(&p2sh_script).unwrap();
696723

697724
assert_eq!(&extr_p2sh, &p2sh_address);
698725
}
699726

727+
#[test]
728+
fn test_extract_address_hash_scriptsig() {
729+
let raw_tx = "0100000001c15041a06deb6b3818b022fac558da4ce2097f0860c8f642105bbad9d29be02a010000006c493046022100cfd2a2d332b29adce119c55a9fadd3c073332024b7e272513e51623ca15993480221009b482d7f7b4d479aff62bdcdaea54667737d56f8d4d63dd03ec3ef651ed9a25401210325f8b039a11861659c9bf03f43fc4ea055f3a71cd60c7b1fd474ab578f9977faffffffff0290d94000000000001976a9148ed243a7be26080a1a8cf96b53270665f1b8dd2388ac4083086b000000001976a9147e7d94d0ddc21d83bfbcfc7798e4547edf0832aa88ac00000000";
730+
let tx_bytes = hex::decode(&raw_tx).unwrap();
731+
let transaction = parse_transaction(&tx_bytes).unwrap();
732+
733+
let address: [u8; 20] = [
734+
126, 125, 148, 208, 221, 194, 29, 131, 191, 188, 252, 119, 152, 228, 84, 126, 223, 8,
735+
50, 170,
736+
];
737+
let extr_address = extract_address_hash_scriptsig(&transaction.inputs[0].script).unwrap();
738+
739+
assert_eq!(&extr_address, &address);
740+
}
741+
742+
#[test]
743+
fn test_extract_address_hash_scriptsig_p2sh() {
744+
let raw_tx = "0100000001c8cc2b56525e734ff63a13bc6ad06a9e5664df8c67632253a8e36017aee3ee40000000009000483045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51aefeffffff0120f40e00000000001976a9141d30342095961d951d306845ef98ac08474b36a088aca7270400";
745+
let tx_bytes = hex::decode(&raw_tx).unwrap();
746+
let transaction = parse_transaction(&tx_bytes).unwrap();
747+
748+
let address: [u8; 20] = [
749+
233, 195, 221, 12, 7, 170, 199, 97, 121, 235, 199, 106, 108, 120, 212, 214, 124, 108,
750+
22, 10,
751+
];
752+
let extr_address = extract_address_hash_scriptsig(&transaction.inputs[0].script).unwrap();
753+
754+
assert_eq!(&extr_address, &address);
755+
}
756+
700757
/*
701758
#[test]
702759
fn test_extract_address_invalid_p2pkh_fails() {
703760
let p2pkh_script = hex::decode(&sample_malformed_p2pkh_output()).unwrap();
704761
705-
assert_eq!(extract_address_hash(&p2pkh_script).err(), Some(Error::MalformedP2PKHOutput));
762+
assert_eq!(extract_address_hash_scriptpubkey(&p2pkh_script).err(), Some(Error::MalformedP2PKHOutput));
706763
}
707764
*/
708765
}

crates/bitcoin/src/types.rs

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ extern crate hex;
33
#[cfg(test)]
44
use mocktopus::macros::mockable;
55

6+
use bitcoin_hashes::Hash;
7+
68
use codec::alloc::string::String;
79
use codec::{Decode, Encode};
810
use primitive_types::{H256, U256};
@@ -13,7 +15,10 @@ use x_core::Error;
1315

1416
use crate::formatter::Formattable;
1517
use crate::merkle::MerkleProof;
16-
use crate::parser::{extract_address_hash, extract_op_return_data, FromLeBytes};
18+
use crate::parser::{
19+
extract_address_hash_scriptpubkey, extract_address_hash_scriptsig, extract_op_return_data,
20+
FromLeBytes,
21+
};
1722
use crate::utils::{hash256_merkle_step, log2, reverse_endianness, sha256d_le};
1823

1924
pub(crate) const SERIALIZE_TRANSACTION_NO_WITNESS: i32 = 0x4000_0000;
@@ -304,6 +309,16 @@ impl TransactionInput {
304309
pub fn with_witness(&mut self, witness: Vec<Vec<u8>>) {
305310
self.witness = witness;
306311
}
312+
313+
pub fn extract_address(&self) -> Result<Vec<u8>, Error> {
314+
// Witness
315+
if !self.witness.is_empty() {
316+
return Ok(bitcoin_hashes::hash160::Hash::hash(&self.witness[1]).to_vec());
317+
}
318+
319+
// P2PKH
320+
extract_address_hash_scriptsig(&self.script)
321+
}
307322
}
308323

309324
/// Bitcoin script
@@ -367,10 +382,6 @@ impl Script {
367382
self.bytes.extend(&value.format())
368383
}
369384

370-
pub fn extract_address(&self) -> Result<Vec<u8>, Error> {
371-
extract_address_hash(&self.bytes)
372-
}
373-
374385
pub fn extract_op_return_data(&self) -> Result<Vec<u8>, Error> {
375386
extract_op_return_data(&self.bytes)
376387
}
@@ -435,6 +446,10 @@ impl TransactionOutput {
435446
script: Script::op_return(return_content),
436447
}
437448
}
449+
450+
pub fn extract_address(&self) -> Result<Vec<u8>, Error> {
451+
extract_address_hash_scriptpubkey(&self.script.bytes)
452+
}
438453
}
439454

440455
/// Bitcoin transaction
@@ -1000,7 +1015,7 @@ mod tests {
10001015
assert_eq!(transaction.outputs.len(), 2);
10011016
assert_eq!(transaction.outputs[0].value, 100);
10021017
assert_eq!(
1003-
transaction.outputs[0].script.extract_address().unwrap(),
1018+
transaction.outputs[0].extract_address().unwrap(),
10041019
address.as_bytes()
10051020
);
10061021
assert_eq!(transaction.outputs[1].value, 0);
@@ -1134,4 +1149,36 @@ mod tests {
11341149
let bytes = proof.format();
11351150
MerkleProof::parse(&bytes).unwrap();
11361151
}
1152+
1153+
#[test]
1154+
fn extract_witness_address_p2wpkh() {
1155+
let raw_tx = "0200000000010140d43a99926d43eb0e619bf0b3d83b4a31f60c176beecfb9d35bf45e54d0f7420100000017160014a4b4ca48de0b3fffc15404a1acdc8dbaae226955ffffffff0100e1f5050000000017a9144a1154d50b03292b3024370901711946cb7cccc387024830450221008604ef8f6d8afa892dee0f31259b6ce02dd70c545cfcfed8148179971876c54a022076d771d6e91bed212783c9b06e0de600fab2d518fad6f15a2b191d7fbd262a3e0121039d25ab79f41f75ceaf882411fd41fa670a4c672c23ffaf0e361a969cde0692e800000000";
1156+
let tx_bytes = hex::decode(&raw_tx).unwrap();
1157+
let transaction = parse_transaction(&tx_bytes).unwrap();
1158+
1159+
let address: [u8; 20] = [
1160+
164, 180, 202, 72, 222, 11, 63, 255, 193, 84, 4, 161, 172, 220, 141, 186, 174, 34, 105,
1161+
85,
1162+
];
1163+
1164+
let extr_address = transaction.inputs[0].extract_address().unwrap();
1165+
1166+
assert_eq!(&extr_address, &address);
1167+
}
1168+
1169+
#[test]
1170+
fn extract_witness_address_p2wsh() {
1171+
let raw_tx = "020000000001027113554199c88273f7f04d18a0dca69145ea863f31519a790b346579b9b55f090100000017160014d6ad6711da30f4349a0d8c387a515bff10ecd507fdffffff90a9eb7550a8308c629014f3f685d2d72e9e7de6bd199c3a9615b567206889430100000017160014cce6d8dffda77f56e237389f48417f10659c2e42fdffffff0228641c000000000017a914d980c4240e77b76d48051c791f68831d23ad3e8687400d03000000000017a914e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a870248304502210088b0fb4b40af9620f785f265c2e2f7436018391d9db34eee3bc1ebd796fbce96022015151182eaa595e090c8030d9f979b920aae276c385dfc66ac2d77160a27453b01210266dd88be116711227e2e953daa008cca45ce5cc0aa4b584c20ae6ddb9ce0212d0247304402204b2fdd767ab93b30a43042c3287ae78d06d1418084fe88350b0aaf06bebe02fe02202d850fc5887d948307fdade871de3714d867610643f6507e511d14dad86fe3ce012102593012612326b4c07e6f0234bac5ff62b5ed12afe77e2900474ca36b3bfa528075f50700";
1172+
let tx_bytes = hex::decode(&raw_tx).unwrap();
1173+
let transaction = parse_transaction(&tx_bytes).unwrap();
1174+
1175+
let address: [u8; 20] = [
1176+
214, 173, 103, 17, 218, 48, 244, 52, 154, 13, 140, 56, 122, 81, 91, 255, 16, 236, 213,
1177+
7,
1178+
];
1179+
1180+
let extr_address = transaction.inputs[0].extract_address().unwrap();
1181+
1182+
assert_eq!(&extr_address, &address);
1183+
}
11371184
}

crates/btc-relay/Cargo.toml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "btc-relay"
3-
version = "0.1.0"
3+
version = "2.0.0-alpha.7"
44
authors = ["Interlay Ltd"]
55
edition = "2018"
66

@@ -13,37 +13,37 @@ version = '1.0.101'
1313
default-features = false
1414
features = ['derive']
1515
package = 'parity-scale-codec'
16-
version = '1.0.0'
16+
version = '1.3.0'
1717

1818
[dependencies.frame-support]
1919
default-features = false
20-
version = '2.0.0-alpha.5'
20+
version = '2.0.0-alpha.7'
2121

2222
[dependencies.system]
2323
default-features = false
2424
package = 'frame-system'
25-
version = '2.0.0-alpha.5'
25+
version = '2.0.0-alpha.7'
2626

2727
[dependencies.sp-io]
2828
default-features = false
29-
version = '2.0.0-alpha.5'
29+
version = '2.0.0-alpha.7'
3030

3131
[dependencies.sp-core]
3232
default-features = false
33-
version = '2.0.0-alpha.5'
33+
version = '2.0.0-alpha.7'
3434

3535
[dependencies.timestamp]
3636
default-features = false
3737
package = 'pallet-timestamp'
38-
version = '2.0.0-alpha.5'
38+
version = '2.0.0-alpha.7'
3939

4040
[dependencies.sp-std]
4141
default-features = false
42-
version = '2.0.0-alpha.5'
42+
version = '2.0.0-alpha.7'
4343

4444
[dependencies.primitive-types]
4545
default-features = false
46-
version = '0.7.0'
46+
version = '0.7.2'
4747
features= ['codec']
4848

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

6161
[dependencies.hex]
6262
default-features = false
63-
version = "0.4.0"
63+
version = '0.4.2'
6464

6565
[dev-dependencies]
6666
mocktopus = '0.7.0'
6767

6868
[dev-dependencies.sp-runtime]
6969
default-features = false
70-
version = '2.0.0-alpha.5'
70+
version = '2.0.0-alpha.7'
7171

7272
[features]
7373
default = ['std']

crates/btc-relay/src/ext.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ use mocktopus::macros::mockable;
33

44
#[cfg_attr(test, mockable)]
55
pub(crate) mod security {
6+
#[cfg(test)]
7+
use security::types::ErrorCode;
68
use security::types::StatusCode;
7-
use x_core::UnitResult;
9+
use x_core::{Error, UnitResult};
810

911
pub fn _ensure_parachain_status_running<T: security::Trait>() -> UnitResult {
1012
<security::Module<T>>::_ensure_parachain_status_running()
@@ -17,4 +19,26 @@ pub(crate) mod security {
1719
pub fn _get_parachain_status<T: security::Trait>() -> StatusCode {
1820
<security::Module<T>>::get_parachain_status()
1921
}
22+
23+
pub fn _is_parachain_error_invalid_btcrelay<T: security::Trait>() -> bool {
24+
<security::Module<T>>::_is_parachain_error_invalid_btcrelay()
25+
}
26+
27+
pub fn _is_parachain_error_no_data_btcrelay<T: security::Trait>() -> bool {
28+
<security::Module<T>>::_is_parachain_error_no_data_btcrelay()
29+
}
30+
31+
pub fn recover_from_btc_relay_failure<T: security::Trait>() -> UnitResult {
32+
<security::Module<T>>::recover_from_btc_relay_failure().map_err(|_e| Error::RuntimeError)
33+
}
34+
35+
#[cfg(test)]
36+
pub fn set_parachain_status<T: security::Trait>(status: StatusCode) -> () {
37+
<security::Module<T>>::set_parachain_status(status)
38+
}
39+
40+
#[cfg(test)]
41+
pub fn insert_error<T: security::Trait>(error: ErrorCode) -> () {
42+
<security::Module<T>>::insert_error(error)
43+
}
2044
}

0 commit comments

Comments
 (0)