From 9a8b05235019d297a5e12a7479f4d55900e96269 Mon Sep 17 00:00:00 2001 From: jaupe Date: Sat, 4 Apr 2020 15:37:19 +0100 Subject: [PATCH 01/37] remove unneeded 'return' statements --- crates/bitcoin/src/utils.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bitcoin/src/utils.rs b/crates/bitcoin/src/utils.rs index 54d96e0a46..6f4e58fe01 100644 --- a/crates/bitcoin/src/utils.rs +++ b/crates/bitcoin/src/utils.rs @@ -52,9 +52,9 @@ pub fn reverse_endianness(bytes: &[u8]) -> Vec { // FIXME: maybe use sp_core sha2_256? pub fn sha256d_be(bytes: &[u8]) -> H256 { - return H256::from_slice(&sha256d(bytes)[..]); + H256::from_slice(&sha256d(bytes)[..]) } pub fn sha256d_le(bytes: &[u8]) -> H256Le { - return H256Le::from_bytes_le(&sha256d(bytes)); + H256Le::from_bytes_le(&sha256d(bytes)) } \ No newline at end of file From 9488210db15fc14e6167ab19887fd8cdeda2d6da Mon Sep 17 00:00:00 2001 From: jaupe Date: Sat, 4 Apr 2020 15:45:28 +0100 Subject: [PATCH 02/37] add literal seperators --- crates/bitcoin/src/merkle.rs | 2 +- crates/bitcoin/src/parser.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bitcoin/src/merkle.rs b/crates/bitcoin/src/merkle.rs index 3e719ec01b..c2a8f97053 100644 --- a/crates/bitcoin/src/merkle.rs +++ b/crates/bitcoin/src/merkle.rs @@ -8,7 +8,7 @@ extern crate mocktopus; use mocktopus::macros::mockable; /// Values taken from https://github.com/bitcoin/bitcoin/blob/78dae8caccd82cfbfd76557f1fb7d7557c7b5edb/src/consensus/consensus.h -const MAX_BLOCK_WEIGHT: u32 = 4000000; +const MAX_BLOCK_WEIGHT: u32 = 4_000_000; const WITNESS_SCALE_FACTOR: u32 = 4; const MIN_TRANSACTION_WEIGHT: u32 = WITNESS_SCALE_FACTOR * 60; const MAX_TRANSACTIONS_IN_PROOF: u32 = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_WEIGHT; diff --git a/crates/bitcoin/src/parser.rs b/crates/bitcoin/src/parser.rs index 27f57f3bf2..d25ba06cf7 100644 --- a/crates/bitcoin/src/parser.rs +++ b/crates/bitcoin/src/parser.rs @@ -7,7 +7,7 @@ extern crate mocktopus; #[cfg(test)] use mocktopus::macros::mockable; -const SERIALIZE_TRANSACTION_NO_WITNESS: i32 = 0x40000000; +const SERIALIZE_TRANSACTION_NO_WITNESS: i32 = 0x4000_0000; /// Type to be parsed from a bytes array @@ -246,7 +246,7 @@ pub fn parse_block_header(raw_header: RawBlockHeader) -> Result Result, Error> { } return Ok(output_script[2..(script_len-1)].to_vec()) } - return Err(Error::UnsupportedOutputFormat); + Err(Error::UnsupportedOutputFormat) } pub fn extract_op_return_data(output_script: &[u8]) -> Result, Error> { From 07dd0837c1b26757c69c12c8e9e402bd144ca589 Mon Sep 17 00:00:00 2001 From: jaupe Date: Sat, 4 Apr 2020 15:52:02 +0100 Subject: [PATCH 03/37] pass by value for for 1 byte args --- crates/btc-core/src/lib.rs | 2 +- crates/xclaim-core/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/btc-core/src/lib.rs b/crates/btc-core/src/lib.rs index 54e346df10..498457642e 100644 --- a/crates/btc-core/src/lib.rs +++ b/crates/btc-core/src/lib.rs @@ -36,7 +36,7 @@ pub enum Error { } impl Error { - pub fn message(&self) -> &'static str { + pub fn message(self) -> &'static str { match self { Error::AlreadyInitialized => "Already initialized", Error::MissingBlockHeight => "Missing the block at this height", diff --git a/crates/xclaim-core/src/lib.rs b/crates/xclaim-core/src/lib.rs index 383d883ba4..2a060c21eb 100644 --- a/crates/xclaim-core/src/lib.rs +++ b/crates/xclaim-core/src/lib.rs @@ -12,7 +12,7 @@ pub enum Error { } impl Error { - pub fn message(&self) -> &'static str { + pub fn message(self) -> &'static str { match self { Error::MissingExchangeRate => "Exchange rate not set", Error::InvalidOracleSource => "Invalid oracle account", From 2d08d3c6863a4d87f3bd82572b085745e7ee10a5 Mon Sep 17 00:00:00 2001 From: jaupe Date: Sat, 4 Apr 2020 15:52:33 +0100 Subject: [PATCH 04/37] unneeded unit return type --- crates/bitcoin/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bitcoin/src/types.rs b/crates/bitcoin/src/types.rs index 06e5a8b9c7..45b20c6241 100644 --- a/crates/bitcoin/src/types.rs +++ b/crates/bitcoin/src/types.rs @@ -65,7 +65,7 @@ pub struct TransactionInput { } impl TransactionInput { - pub fn with_witness(&mut self, witness: Vec) -> () { + pub fn with_witness(&mut self, witness: Vec) { self.witness = Some(witness); } } From 0b7edc094f426bab50fcdc03d278bcc7f3117e5d Mon Sep 17 00:00:00 2001 From: jaupe Date: Sat, 4 Apr 2020 16:14:35 +0100 Subject: [PATCH 05/37] redundant field names in struct initialization --- crates/bitcoin/src/merkle.rs | 10 +++++----- crates/bitcoin/src/parser.rs | 38 ++++++++++++++++++------------------ crates/bitcoin/src/types.rs | 8 ++++---- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/crates/bitcoin/src/merkle.rs b/crates/bitcoin/src/merkle.rs index c2a8f97053..7b4bfc1dea 100644 --- a/crates/bitcoin/src/merkle.rs +++ b/crates/bitcoin/src/merkle.rs @@ -149,7 +149,7 @@ impl MerkleProof { /// * `merkle_proof` - Raw bytes of the merkle proof pub fn parse(merkle_proof: &[u8]) -> Result { let mut proof_parser = BytesParser::new(merkle_proof); - let header = proof_parser.parse()?; + let block_header = proof_parser.parse()?; let transactions_count = proof_parser.parse()?; let hashes_count: CompactUint = proof_parser.parse()?; @@ -167,10 +167,10 @@ impl MerkleProof { } Ok(MerkleProof { - block_header: header, - transactions_count: transactions_count, - hashes: hashes, - flag_bits: flag_bits, + block_header, + transactions_count, + hashes, + flag_bits, }) } } diff --git a/crates/bitcoin/src/parser.rs b/crates/bitcoin/src/parser.rs index d25ba06cf7..df29110084 100644 --- a/crates/bitcoin/src/parser.rs +++ b/crates/bitcoin/src/parser.rs @@ -231,19 +231,19 @@ pub fn header_from_bytes(bytes: &[u8]) -> RawBlockHeader { pub fn parse_block_header(raw_header: RawBlockHeader) -> Result { let mut parser = BytesParser::new(&raw_header); let version: i32 = parser.parse()?; - let previous_block_hash: H256Le = parser.parse()?; + let hash_prev_block: H256Le = parser.parse()?; let merkle_root: H256Le = parser.parse()?; let timestamp: u32 = parser.parse()?; let target: U256 = parser.parse()?; let nonce: u32 = parser.parse()?; let block_header = BlockHeader { - merkle_root: merkle_root, - target: target, + merkle_root, + target, timestamp: timestamp as u64, - version: version, - nonce: nonce, - hash_prev_block: previous_block_hash, + version, + nonce, + hash_prev_block, }; Ok(block_header) @@ -322,11 +322,11 @@ pub fn parse_transaction(raw_transaction: &[u8]) -> Result { } Ok(Transaction { - version: version, - inputs: inputs, - outputs: outputs, - block_height: block_height, - locktime: locktime, + version, + inputs, + outputs, + block_height, + locktime, }) } @@ -337,14 +337,14 @@ pub fn parse_transaction_input( ) -> Result<(TransactionInput, usize), Error> { let mut parser = BytesParser::new(raw_input); let previous_hash: H256Le = parser.parse()?; - let pervious_index: u32 = parser.parse()?; + let previous_index: u32 = parser.parse()?; // coinbase input has no previous hash let is_coinbase = previous_hash == H256Le::zero(); // fail if transaction is coinbase and previous index is not 0xffffffff // previous_hash - if is_coinbase && pervious_index != u32::max_value() { + if is_coinbase && previous_index != u32::max_value() { return Err(Error::MalformedTransaction); } @@ -367,12 +367,12 @@ pub fn parse_transaction_input( Ok(( TransactionInput { - previous_hash: previous_hash, - previous_index: pervious_index, + previous_hash, + previous_index, coinbase: is_coinbase, - height: height, - script: script, - sequence: sequence, + height, + script, + sequence, witness: None, }, consumed_bytes, @@ -389,7 +389,7 @@ pub fn parse_transaction_output(raw_output: &[u8]) -> Result<(TransactionOutput, let script = parser.read(script_size.value as usize)?; Ok(( TransactionOutput { - value: value, + value, script: Vec::from(script), }, parser.position, diff --git a/crates/bitcoin/src/types.rs b/crates/bitcoin/src/types.rs index 45b20c6241..67843fb99c 100644 --- a/crates/bitcoin/src/types.rs +++ b/crates/bitcoin/src/types.rs @@ -111,8 +111,8 @@ impl RichBlockHeader { Ok(RichBlockHeader { block_hash: BlockHeader::block_hash_le(&raw_block_header), block_header: BlockHeader::from_le_bytes(&raw_block_header)?, - block_height: block_height, - chain_ref: chain_ref, + block_height, + chain_ref, }) } } @@ -146,7 +146,7 @@ impl H256Le { pub fn from_bytes_le(bytes: &[u8]) -> H256Le { let mut content: [u8; 32] = Default::default(); content.copy_from_slice(&bytes); - H256Le { content: content } + H256Le { content } } /// Creates a H256Le from big endian bytes @@ -154,7 +154,7 @@ impl H256Le { let bytes_le = reverse_endianness(bytes); let mut content: [u8; 32] = Default::default(); content.copy_from_slice(&bytes_le); - H256Le { content: content } + H256Le { content } } pub fn from_hex_le(hex: &str) -> H256Le { From 8a7b4d046ebf276c33347d2e05a76a40aceb0aef Mon Sep 17 00:00:00 2001 From: jaupe Date: Sat, 4 Apr 2020 16:16:18 +0100 Subject: [PATCH 06/37] remove unneeded clone call --- crates/bitcoin/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bitcoin/src/types.rs b/crates/bitcoin/src/types.rs index 67843fb99c..3aeccfc7ad 100644 --- a/crates/bitcoin/src/types.rs +++ b/crates/bitcoin/src/types.rs @@ -174,7 +174,7 @@ impl H256Le { /// Returns the content of the H256Le encoded in little endian pub fn to_bytes_le(&self) -> [u8; 32] { - self.content.clone() + self.content } /// Returns the content of the H256Le encoded in little endian hex From e7c72513388083064973cbcf27a82db9bcbc1cc7 Mon Sep 17 00:00:00 2001 From: jaupe Date: Sat, 4 Apr 2020 16:17:39 +0100 Subject: [PATCH 07/37] remove redundant struct initialization --- crates/bitcoin/src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bitcoin/src/parser.rs b/crates/bitcoin/src/parser.rs index df29110084..ad70b4348a 100644 --- a/crates/bitcoin/src/parser.rs +++ b/crates/bitcoin/src/parser.rs @@ -390,7 +390,7 @@ pub fn parse_transaction_output(raw_output: &[u8]) -> Result<(TransactionOutput, Ok(( TransactionOutput { value, - script: Vec::from(script), + script, }, parser.position, )) From 09f692f169078ab5b9fefb8bf7ff341ad00dcc54 Mon Sep 17 00:00:00 2001 From: jaupe Date: Sat, 4 Apr 2020 16:20:55 +0100 Subject: [PATCH 08/37] refactor length comparison to zero --- crates/bitcoin/src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bitcoin/src/parser.rs b/crates/bitcoin/src/parser.rs index ad70b4348a..9895f1b69f 100644 --- a/crates/bitcoin/src/parser.rs +++ b/crates/bitcoin/src/parser.rs @@ -296,7 +296,7 @@ pub fn parse_transaction(raw_transaction: &[u8]) -> Result { let mut inputs: Vec = parser.parse_with(version)?; let mut flags: u8 = 0; - if inputs.len() == 0 && allow_witness { + if inputs.is_empty() && allow_witness { flags = parser.parse()?; inputs = parser.parse_with(version)?; } From e38da893d35abd9b89d361271b88c40110eb77be Mon Sep 17 00:00:00 2001 From: jaupe Date: Sun, 5 Apr 2020 23:02:48 +0100 Subject: [PATCH 09/37] improve efficiency and readability --- crates/bitcoin/src/merkle.rs | 22 ++- crates/bitcoin/src/parser.rs | 68 ++++---- crates/bitcoin/src/types.rs | 49 +++--- crates/bitcoin/src/utils.rs | 12 +- crates/btc-core/src/lib.rs | 18 +- crates/btc-relay/src/lib.rs | 307 +++++++++++++++------------------- crates/security/src/lib.rs | 108 ++++++------ crates/xclaim-core/src/lib.rs | 1 - 8 files changed, 282 insertions(+), 303 deletions(-) diff --git a/crates/bitcoin/src/merkle.rs b/crates/bitcoin/src/merkle.rs index 7b4bfc1dea..7c4024a77f 100644 --- a/crates/bitcoin/src/merkle.rs +++ b/crates/bitcoin/src/merkle.rs @@ -1,5 +1,5 @@ use crate::parser::BytesParser; -use crate::types::{BlockHeader, Error, H256Le, CompactUint}; +use crate::types::{BlockHeader, CompactUint, Error, H256Le}; use crate::utils::hash256_merkle_step; #[cfg(test)] @@ -179,9 +179,9 @@ impl MerkleProof { mod tests { use super::*; + use mocktopus::mocking::*; use primitive_types::H256; use std::str::FromStr; - use mocktopus::mocking::*; // curl -s -H 'content-type: application/json' http://satoshi.doc.ic.ac.uk:8332 -d '{ // "jsonrpc": "1.0", @@ -195,9 +195,18 @@ mod tests { const PROOF_HEX: &str = "00000020ecf348128755dbeea5deb8eddf64566d9d4e59bc65d485000000000000000000901f0d92a66ee7dcefd02fa282ca63ce85288bab628253da31ef259b24abe8a0470a385a45960018e8d672f8a90a00000d0bdabada1fb6e3cef7f5c6e234621e3230a2f54efc1cba0b16375d9980ecbc023cbef3ba8d8632ea220927ec8f95190b30769eb35d87618f210382c9445f192504074f56951b772efa43b89320d9c430b0d156b93b7a1ff316471e715151a0619a39392657f25289eb713168818bd5b37476f1bc59b166deaa736d8a58756f9d7ce2aef46d8004c5fe3293d883838f87b5f1da03839878895b71530e9ff89338bb6d4578b3c3135ff3e8671f9a64d43b22e14c2893e8271cecd420f11d2359307403bb1f3128885b3912336045269ef909d64576b93e816fa522c8c027fe408700dd4bdee0254c069ccb728d3516fe1e27578b31d70695e3e35483da448f3a951273e018de7f2a8f657064b013c6ede75c74bbd7f98fdae1c2ac6789ee7b21a791aa29d60e89fff2d1d2b1ada50aa9f59f403823c8c58bb092dc58dc09b28158ca15447da9c3bedb0b160f3fe1668d5a27716e27661bcb75ddbf3468f5c76b7bed1004c6b4df4da2ce80b831a7c260b515e6355e1c306373d2233e8de6fda3674ed95d17a01a1f64b27ba88c3676024fbf8d5dd962ffc4d5e9f3b1700763ab88047f7d0000"; fn sample_valid_proof_result() -> ProofResult { - let tx_id = H256Le::from_bytes_le(&hex::decode("c8589f304d3b9df1d4d8b3d15eb6edaaa2af9d796e9d9ace12b31f293705c5e9".to_owned()).unwrap()); - let merkle_root = H256Le::from_bytes_le(&hex::decode("90d079ef103a8b7d3d9315126468f78b456690ba6628d1dcd5a16c9990fbe11e".to_owned()).unwrap()); - + let tx_id = H256Le::from_bytes_le( + &hex::decode( + "c8589f304d3b9df1d4d8b3d15eb6edaaa2af9d796e9d9ace12b31f293705c5e9".to_owned(), + ) + .unwrap(), + ); + let merkle_root = H256Le::from_bytes_le( + &hex::decode( + "90d079ef103a8b7d3d9315126468f78b456690ba6628d1dcd5a16c9990fbe11e".to_owned(), + ) + .unwrap(), + ); ProofResult { extracted_root: merkle_root, transaction_hash: tx_id, @@ -210,8 +219,7 @@ mod tests { let mock_proof_result = sample_valid_proof_result(); let proof = MerkleProof::parse(&hex::decode(&PROOF_HEX[..]).unwrap()).unwrap(); - MerkleProof::verify_proof. - mock_safe(move |_| MockResult::Return(Ok(mock_proof_result))); + MerkleProof::verify_proof.mock_safe(move |_| MockResult::Return(Ok(mock_proof_result))); let res = MerkleProof::verify_proof(&proof).unwrap(); assert_eq!(res, mock_proof_result); diff --git a/crates/bitcoin/src/parser.rs b/crates/bitcoin/src/parser.rs index 9895f1b69f..df546eeca0 100644 --- a/crates/bitcoin/src/parser.rs +++ b/crates/bitcoin/src/parser.rs @@ -9,7 +9,6 @@ use mocktopus::macros::mockable; const SERIALIZE_TRANSACTION_NO_WITNESS: i32 = 0x4000_0000; - /// Type to be parsed from a bytes array pub(crate) trait Parsable: Sized { fn parse(raw_bytes: &[u8], position: usize) -> Result<(Self, usize), Error>; @@ -93,7 +92,10 @@ impl Parsable for Vec { } } -impl ParsableMeta for Vec where T: ParsableMeta { +impl ParsableMeta for Vec +where + T: ParsableMeta, +{ fn parse_with(raw_bytes: &[u8], position: usize, extra: U) -> Result<(Vec, usize), Error> { let mut result: Vec = Vec::new(); let mut parser = BytesParser::new(&raw_bytes[position..]); @@ -137,7 +139,7 @@ impl Parsable for TransactionOutput { impl Parsable for U256 { fn parse(raw_bytes: &[u8], position: usize) -> Result<(U256, usize), Error> { if position + 4 > raw_bytes.len() { - return Err(Error::EOS) + return Err(Error::EOS); } let raw_exponent = raw_bytes[position + 3]; if raw_exponent < 3 { @@ -222,7 +224,6 @@ pub fn header_from_bytes(bytes: &[u8]) -> RawBlockHeader { result } - /// Parses the raw bitcoin header into a Rust struct /// /// # Arguments @@ -387,13 +388,7 @@ pub fn parse_transaction_output(raw_output: &[u8]) -> Result<(TransactionOutput, return Err(Error::MalformedTransaction); } let script = parser.read(script_size.value as usize)?; - Ok(( - TransactionOutput { - value, - script, - }, - parser.position, - )) + Ok((TransactionOutput { value, script }, parser.position)) } pub fn extract_value(raw_output: &[u8]) -> u64 { @@ -403,9 +398,7 @@ pub fn extract_value(raw_output: &[u8]) -> u64 { } pub fn extract_address_hash(output_script: &[u8]) -> Result, Error> { - let script_len = output_script.len(); - // Witness if output_script[0] == 0 { if script_len < 2 { @@ -422,22 +415,33 @@ pub fn extract_address_hash(output_script: &[u8]) -> Result, Error> { // 25 bytes // Format: // 0x76 (OP_DUP) - 0xa9 (OP_HASH160) - 0x14 (20 bytes len) - <20 bytes pubkey hash> - 0x88 (OP_EQUALVERIFY) - 0xac (OP_CHECKSIG) - if script_len as u32 == P2PKH_SCRIPT_SIZE && output_script[0..=2] == [OpCode::OpDup as u8, OpCode::OpHash160 as u8, HASH160_SIZE_HEX] { - if output_script[script_len - 2..] != [OpCode::OpEqualVerify as u8, OpCode::OpCheckSig as u8] { + if script_len as u32 == P2PKH_SCRIPT_SIZE + && output_script[0..=2] + == [ + OpCode::OpDup as u8, + OpCode::OpHash160 as u8, + HASH160_SIZE_HEX, + ] + { + if output_script[script_len - 2..] + != [OpCode::OpEqualVerify as u8, OpCode::OpCheckSig as u8] + { return Err(Error::MalformedP2PKHOutput); } - return Ok(output_script[3..script_len-2].to_vec()); + return Ok(output_script[3..script_len - 2].to_vec()); } // P2SH // 23 bytes - // Format: + // Format: // 0xa9 (OP_HASH160) - 0x14 (20 bytes hash) - <20 bytes script hash> - 0x87 (OP_EQUAL) - if script_len as u32 == P2SH_SCRIPT_SIZE && output_script[0..=1] == [OpCode::OpHash160 as u8, HASH160_SIZE_HEX] { - if output_script[script_len-1] != OpCode::OpEqual as u8 { - return Err(Error::MalformedP2SHOutput) + if script_len as u32 == P2SH_SCRIPT_SIZE + && output_script[0..=1] == [OpCode::OpHash160 as u8, HASH160_SIZE_HEX] + { + if output_script[script_len - 1] != OpCode::OpEqual as u8 { + return Err(Error::MalformedP2SHOutput); } - return Ok(output_script[2..(script_len-1)].to_vec()) + return Ok(output_script[2..(script_len - 1)].to_vec()); } Err(Error::UnsupportedOutputFormat) } @@ -455,14 +459,12 @@ pub fn extract_op_return_data(output_script: &[u8]) -> Result, Error> { Ok(output_script[2..].to_vec()) } - #[cfg(test)] mod tests { use super::*; // examples from https://bitcoin.org/en/developer-reference#block-headers - #[test] fn test_parse_block_header() { let hex_header = "02000000".to_owned() + // ............... Block version: 2 @@ -542,7 +544,7 @@ mod tests { "cbc20a7664f2f69e5355aa427045bc15" + "e7c6c772" + // PubKey hash "88" + // OP_EQUALVERIFY - "ac" // OP_CHECKSIG + "ac" // OP_CHECKSIG } fn sample_transaction() -> String { @@ -633,17 +635,23 @@ mod tests { assert_eq!(inputs[0].coinbase, true); assert_eq!(inputs[0].witness.is_some(), true); assert_eq!(outputs.len(), 2); - assert_eq!(&hex::encode(&outputs[0].script), "a91466c7060feb882664ae62ffad0051fe843e318e8587"); - assert_eq!(&hex::encode(&outputs[1].script), "6a24aa21a9ede5c17d15b8b1fa2811b7e6da66ffa5e1aaa05922c69068bf90cd585b95bb4675"); + assert_eq!( + &hex::encode(&outputs[0].script), + "a91466c7060feb882664ae62ffad0051fe843e318e8587" + ); + assert_eq!( + &hex::encode(&outputs[1].script), + "6a24aa21a9ede5c17d15b8b1fa2811b7e6da66ffa5e1aaa05922c69068bf90cd585b95bb4675" + ); assert_eq!(transaction.block_height, Some(0)); assert_eq!(transaction.locktime, None); } #[test] - fn test_extract_address_hash_valid_p2pkh(){ + fn test_extract_address_hash_valid_p2pkh() { let p2pkh_script = hex::decode(&sample_valid_p2pkh()).unwrap(); - 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 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(); @@ -651,10 +659,10 @@ mod tests { } #[test] - fn test_extract_address_hash_valid_p2sh(){ + fn test_extract_address_hash_valid_p2sh() { let p2sh_script = hex::decode(&sample_valid_p2sh()).unwrap(); - 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 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(); diff --git a/crates/bitcoin/src/types.rs b/crates/bitcoin/src/types.rs index 3aeccfc7ad..c9176b21fa 100644 --- a/crates/bitcoin/src/types.rs +++ b/crates/bitcoin/src/types.rs @@ -1,16 +1,15 @@ extern crate hex; -use primitive_types::{U256, H256}; -use codec::{Encode, Decode}; -use node_primitives::{Moment}; +use crate::parser::*; +use crate::utils::*; +use codec::{Decode, Encode}; +use node_primitives::Moment; +use primitive_types::{H256, U256}; use sp_std::collections::btree_map::BTreeMap; use sp_std::collections::btree_set::BTreeSet; -use crate::utils::*; -use crate::parser::*; /// Custom Types /// Bitcoin Raw Block Header type - pub type RawBlockHeader = [u8; 80]; // #[derive(Encode, Decode, Default, Copy, Clone, PartialEq)] @@ -38,16 +37,15 @@ pub struct BlockHeader { pub timestamp: Moment, pub version: i32, pub hash_prev_block: H256Le, - pub nonce: u32 + pub nonce: u32, } impl BlockHeader { - - pub fn block_hash_le(bytes: &[u8]) -> H256Le{ + pub fn block_hash_le(bytes: &[u8]) -> H256Le { sha256d_le(bytes) } - pub fn block_hash_be(bytes: &[u8]) -> H256{ + pub fn block_hash_be(bytes: &[u8]) -> H256 { sha256d_be(bytes) } } @@ -84,10 +82,9 @@ pub struct Transaction { pub inputs: Vec, pub outputs: Vec, pub block_height: Option, //FIXME: why is this optional? - pub locktime: Option, //FIXME: why is this optional? + pub locktime: Option, //FIXME: why is this optional? } - impl Transaction { pub fn tx_id(raw_tx: &[u8]) -> H256Le { sha256d_le(&raw_tx) @@ -105,9 +102,12 @@ pub struct RichBlockHeader { } impl RichBlockHeader { - // Creates a RichBlockHeader given a RawBlockHeader, Blockchain identifier and block height - pub fn construct_rich_block_header(raw_block_header: RawBlockHeader, chain_ref: u32, block_height: u32) -> Result { + pub fn construct_rich_block_header( + raw_block_header: RawBlockHeader, + chain_ref: u32, + block_height: u32, + ) -> Result { Ok(RichBlockHeader { block_hash: BlockHeader::block_hash_le(&raw_block_header), block_header: BlockHeader::from_le_bytes(&raw_block_header)?, @@ -122,7 +122,7 @@ impl RichBlockHeader { //#[cfg_attr(feature = "std", derive(Debug))] pub struct BlockChain { pub chain_id: u32, - pub chain: BTreeMap, + pub chain: BTreeMap, pub start_height: u32, pub max_height: u32, pub no_data: BTreeSet, @@ -133,7 +133,7 @@ pub struct BlockChain { #[derive(Encode, Decode, Default, PartialEq, Eq, Clone, Copy, Debug)] //#[cfg_attr(feature="std", derive(Debug))] pub struct H256Le { - content: [u8; 32] + content: [u8; 32], } impl H256Le { @@ -198,7 +198,7 @@ impl H256Le { } } -#[cfg(feature="std")] +#[cfg(feature = "std")] impl std::fmt::Display for H256Le { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "0x{}", self.to_hex_be()) @@ -211,7 +211,6 @@ impl std::fmt::LowerHex for H256Le { } } - /// Errors which can be returned by the bitcoin crate #[derive(Clone, Copy, PartialEq)] #[cfg_attr(feature = "std", derive(Debug))] @@ -222,7 +221,6 @@ pub enum Error { /// Format of the proof is not correct MalformedProof, - /// Malformed header MalformedHeader, @@ -246,10 +244,9 @@ pub enum Error { MalformedOpReturnOutput, // Output does not match format of supported output types (Witness, P2PKH, P2SH) - UnsupportedOutputFormat + UnsupportedOutputFormat, } - impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -262,7 +259,10 @@ impl std::fmt::Display for Error { Error::MalformedP2PKHOutput => write!(f, "invalid P2PKH output format"), Error::MalformedP2SHOutput => write!(f, "invalid P2SH output format"), Error::MalformedOpReturnOutput => write!(f, "invalid OP_RETURN output format"), - Error::UnsupportedOutputFormat => write!(f, "unsupported output type. Currently supported: Witness, P2PKH, P2SH") + Error::UnsupportedOutputFormat => write!( + f, + "unsupported output type. Currently supported: Witness, P2PKH, P2SH" + ), } } } @@ -272,9 +272,9 @@ pub enum OpCode { OpDup = 0x76, OpHash160 = 0xa9, OpEqualVerify = 0x88, - OpCheckSig = 0xac, + OpCheckSig = 0xac, OpEqual = 0x87, - OpReturn = 0x6a + OpReturn = 0x6a, } impl PartialEq for H256 { @@ -290,7 +290,6 @@ impl PartialEq for H256Le { } } - pub(crate) struct CompactUint { pub(crate) value: u64, } diff --git a/crates/bitcoin/src/utils.rs b/crates/bitcoin/src/utils.rs index 6f4e58fe01..545084f13c 100644 --- a/crates/bitcoin/src/utils.rs +++ b/crates/bitcoin/src/utils.rs @@ -1,14 +1,12 @@ - -use sha2::{Sha256, Digest}; use crate::types::H256Le; use primitive_types::H256; - +use sha2::{Digest, Sha256}; /// Computes Bitcoin's double SHA256 hash over a LE byte encoded input -/// +/// /// # Arguments /// * data: LE bytes encoded input -/// +/// /// # Returns /// * The double SHA256 hash encoded as LE bytes from data pub fn sha256d(bytes: &[u8]) -> [u8; 32] { @@ -37,7 +35,6 @@ pub fn hash256_merkle_step(a: &[u8], b: &[u8]) -> H256Le { H256Le::from_bytes_le(&sha256d(&res)) } - /// Reverses endianness of the value /// ``` /// let bytes = bitcoin::utils::reverse_endianness(&[1, 2, 3]); @@ -49,7 +46,6 @@ pub fn reverse_endianness(bytes: &[u8]) -> Vec { vec } - // FIXME: maybe use sp_core sha2_256? pub fn sha256d_be(bytes: &[u8]) -> H256 { H256::from_slice(&sha256d(bytes)[..]) @@ -57,4 +53,4 @@ pub fn sha256d_be(bytes: &[u8]) -> H256 { pub fn sha256d_le(bytes: &[u8]) -> H256Le { H256Le::from_bytes_le(&sha256d(bytes)) -} \ No newline at end of file +} diff --git a/crates/btc-core/src/lib.rs b/crates/btc-core/src/lib.rs index 498457642e..704e36c836 100644 --- a/crates/btc-core/src/lib.rs +++ b/crates/btc-core/src/lib.rs @@ -11,9 +11,9 @@ pub enum Error { LowDiff, DiffTargetHeader, // TODO: rename to self-explanatory MalformedTxid, - Confirmations, // TODO: rename to self-explanatory + Confirmations, // TODO: rename to self-explanatory InsufficientStableConfirmations, //not in spec - OngoingFork, //not in spec + OngoingFork, //not in spec InvalidMerkleProof, Invalid, Shutdown, @@ -25,14 +25,14 @@ pub enum Error { InvalidOpreturn, InvalidTxVersion, NotOpReturn, - UnknownErrorcode, // not in spec - ForkIdNotFound, // not in spec - BlockNotFound, // not in spec - AlreadyReported, // not in spec - UnauthorizedRelayer, // not in spec + UnknownErrorcode, // not in spec + ForkIdNotFound, // not in spec + BlockNotFound, // not in spec + AlreadyReported, // not in spec + UnauthorizedRelayer, // not in spec ChainCounterOverflow, // not in spec - BlockHeightOverflow, // not in spec - ChainsUnderflow, // not in spec + BlockHeightOverflow, // not in spec + ChainsUnderflow, // not in spec } impl Error { diff --git a/crates/btc-relay/src/lib.rs b/crates/btc-relay/src/lib.rs index e44618abb5..5da590eaa0 100644 --- a/crates/btc-relay/src/lib.rs +++ b/crates/btc-relay/src/lib.rs @@ -16,11 +16,8 @@ use mocktopus::macros::mockable; /// # BTC-Relay implementation /// This is the implementation of the BTC-Relay following the spec at: /// https://interlay.gitlab.io/polkabtc-spec/btcrelay-spec/ - // Substrate -use frame_support::{ - decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure -}; +use frame_support::{decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure}; use sp_core::{H160, U256}; use sp_std::collections::btree_map::BTreeMap; use sp_std::collections::btree_set::BTreeSet; @@ -29,14 +26,12 @@ use system::ensure_signed; // Crates use bitcoin::merkle::{MerkleProof, ProofResult}; use bitcoin::parser::{ - extract_address_hash, extract_op_return_data, - header_from_bytes, parse_block_header, parse_transaction, + extract_address_hash, extract_op_return_data, header_from_bytes, parse_block_header, + parse_transaction, }; use bitcoin::types::{ - BlockChain, BlockHeader, H256Le, - RawBlockHeader, RichBlockHeader, Transaction + BlockChain, BlockHeader, H256Le, RawBlockHeader, RichBlockHeader, Transaction, }; -use security; use security::ErrorCode; use btc_core::Error; @@ -55,7 +50,7 @@ pub trait Trait: system::Trait //+ security::Trait pub const DIFFICULTY_ADJUSTMENT_INTERVAL: u32 = 2016; /// Target Timespan -pub const TARGET_TIMESPAN: u32 = 1209600; +pub const TARGET_TIMESPAN: u32 = 1_209_600; // Used in Bitcoin's retarget algorithm pub const TARGET_TIMESPAN_DIVISOR: u32 = 4; @@ -66,7 +61,7 @@ pub const UNROUNDED_MAX_TARGET: U256 = U256([ ::max_value(), ::max_value(), ::max_value(), - 0x00000000ffffffffu64, + 0x0000_0000_ffff_ffffu64, ]); /// Main chain id @@ -132,7 +127,6 @@ decl_module! { // construct the BlockChain struct let blockchain = Self::initialize_blockchain( block_height, block_header_hash); - // Create rich block header let block_header = RichBlockHeader { block_hash: block_header_hash, @@ -256,7 +250,6 @@ decl_module! { // print!("Best block hash: {:?} \n", current_best_block); // print!("Current block hash: {:?} \n", block_header_hash); - if current_best_block == block_header_hash { // extends the main chain Self::deposit_event( @@ -284,13 +277,13 @@ decl_module! { /// # Arguments /// /// * `tx_id` - The hash of the transaction to check for - /// * `tx_block_height` - The height of the block in which the + /// * `tx_block_height` - The height of the block in which the /// transaction should be included - /// * `raw_merkle_proof` - The raw merkle proof as returned by + /// * `raw_merkle_proof` - The raw merkle proof as returned by /// bitcoin `gettxoutproof` - /// * `confirmations` - The number of confirmations needed to accept + /// * `confirmations` - The number of confirmations needed to accept /// the proof - /// * `insecure` - determines if checks against recommended global transaction confirmation are to be executed. Recommended: set to `true` + /// * `insecure` - determines if checks against recommended global transaction confirmation are to be executed. Recommended: set to `true` fn verify_transaction_inclusion( origin, tx_id: H256Le, @@ -307,7 +300,6 @@ decl_module! { ensure!(>::check_parachain_status(StatusCode::Running), Error::::Shutdown); */ - //let main_chain = Self::get_block_chain_from_id(MAIN_CHAIN_ID); let best_block_height = Self::get_best_block_height(); @@ -317,21 +309,19 @@ decl_module! { ).max_height; // fail if there is an ongoing fork - ensure!(best_block_height + ensure!(best_block_height >= next_best_fork_height + STABLE_TRANSACTION_CONFIRMATIONS, Error::OngoingFork); // This call fails if not enough confirmations Self::check_confirmations( - best_block_height, - confirmations, - block_height, + best_block_height, + confirmations, + block_height, insecure)?; - let proof_result = Self::verify_merkle_proof(&raw_merkle_proof)?; - let rich_header = Self::get_block_header_from_height( - &Self::get_block_chain_from_id(MAIN_CHAIN_ID), + &Self::get_block_chain_from_id(MAIN_CHAIN_ID), block_height )?; @@ -346,8 +336,8 @@ decl_module! { Ok(()) } - /// Validates a given raw Bitcoin transaction, according to the - /// supported transaction format (see + /// Validates a given raw Bitcoin transaction, according to the + /// supported transaction format (see /// https://interlay.gitlab.io/polkabtc-spec/btcrelay-spec/intro/ /// accepted-format.html) /// This DOES NOT check if the transaction is included in a block @@ -356,11 +346,11 @@ decl_module! { /// /// # Arguments /// * `raw_tx` - raw Bitcoin transaction - /// * `paymentValue` - value of BTC sent in the 1st / + /// * `paymentValue` - value of BTC sent in the 1st / /// payment UTXO of the transaction - /// * `recipientBtcAddress` - 20 byte Bitcoin address of recipient + /// * `recipientBtcAddress` - 20 byte Bitcoin address of recipient /// of the BTC in the 1st / payment UTXO - /// * `op_return_id` - 32 byte hash identifier expected in + /// * `op_return_id` - 32 byte hash identifier expected in /// OP_RETURN (replay protection) fn validate_transaction( origin, @@ -386,7 +376,7 @@ decl_module! { let extr_recipient_address = extract_address_hash( &transaction.outputs[0].script ).map_err(|_e| Error::InvalidOutputFormat)?; - ensure!(extr_recipient_address == recipient_btc_address, + ensure!(extr_recipient_address == recipient_btc_address, Error::WrongRecipient); // Check if 2nd / data UTXO has correct OP_RETURN value @@ -406,13 +396,13 @@ impl Module { // START: Storage getter functions // ******************************** - /// Get chain id from position (sorted by max block height) + /// Get chain id from position (sorted by max block height) fn get_chain_id_from_position(position: u32) -> u32 { ::get(position) } /// Get the position of the fork in Chains fn get_chain_position_from_chain_id(chain_id: u32) -> Result { - for (k,v) in ::enumerate() { + for (k, v) in ::enumerate() { if v == chain_id { return Ok(k); } @@ -440,7 +430,7 @@ impl Module { fn best_block_exists() -> bool { ::exists() } - /// get the best block height + /// get the best block height fn get_best_block_height() -> u32 { ::get() } @@ -453,18 +443,14 @@ impl Module { /// /// * `blockchain`: the blockchian struct to search in /// * `block_height`: the height if the block header - fn get_block_hash( - blockchain: &BlockChain, block_height: u32 - ) -> Result { + fn get_block_hash(blockchain: &BlockChain, block_height: u32) -> Result { match blockchain.chain.get(&block_height) { Some(hash) => Ok(*hash), - None => return Err(Error::MissingBlockHeight.into()), + None => Err(Error::MissingBlockHeight), } } /// Get a block header from its hash - fn get_block_header_from_hash( - block_hash: H256Le - ) -> Result { + fn get_block_header_from_hash(block_hash: H256Le) -> Result { if ::exists(block_hash) { return Ok(::get(block_hash)); } @@ -482,7 +468,6 @@ impl Module { let block_hash = Self::get_block_hash(blockchain, block_height)?; Self::get_block_header_from_hash(block_hash) } - /// Storage setter functions /// Set a new chain with position and id fn set_chain_from_position_and_id(position: u32, id: u32) { @@ -508,9 +493,9 @@ impl Module { fn set_block_chain_from_id(id: u32, chain: &BlockChain) { ::insert(id, &chain); } - /// Update a blockchain in ChainsIndex + /// Update a blockchain in ChainsIndex fn mutate_block_chain_from_id(id: u32, chain: BlockChain) { - ::mutate(id, |b| {*b = chain}); + ::mutate(id, |b| *b = chain); } /// Remove a blockchain element from chainindex fn remove_blockchain_from_chainindex(id: u32) { @@ -522,9 +507,7 @@ impl Module { } /// update the chain_ref of a block header fn mutate_block_header_from_chain_id(hash: &H256Le, chain_ref: u32) { - ::mutate(&hash, |header| { - header.chain_ref = chain_ref - }); + ::mutate(&hash, |header| header.chain_ref = chain_ref); } /// Set a new best block @@ -542,46 +525,36 @@ impl Module { new_counter } - /// Initialize the new main blockchain with a single block - fn initialize_blockchain( - block_height: u32, block_hash: H256Le - ) -> BlockChain { + fn initialize_blockchain(block_height: u32, block_hash: H256Le) -> BlockChain { let chain_id = MAIN_CHAIN_ID; // generate an empty blockchain Self::generate_blockchain(chain_id, block_height, block_hash) } /// Create a new blockchain element with a new chain id - fn create_blockchain( - block_height: u32, block_hash: H256Le - ) -> BlockChain { + fn create_blockchain(block_height: u32, block_hash: H256Le) -> BlockChain { // get a new chain id let chain_id: u32 = Self::increment_chain_counter(); // generate an empty blockchain Self::generate_blockchain(chain_id, block_height, block_hash) } - /// Generate the raw blockchain from a chain Id and with a single block - fn generate_blockchain( - chain_id: u32, - block_height: u32, - block_hash: H256Le, - ) -> BlockChain { + /// Generate the raw blockchain from a chain Id and with a single block + fn generate_blockchain(chain_id: u32, block_height: u32, block_hash: H256Le) -> BlockChain { // initialize an empty chain let mut chain = BTreeMap::new(); chain.insert(block_height, block_hash); - let blockchain = BlockChain { - chain_id: chain_id, - chain: chain, + BlockChain { + chain_id, + chain, start_height: block_height, max_height: block_height, no_data: BTreeSet::new(), invalid: BTreeSet::new(), - }; - blockchain + } } /// Add a new block header to an existing blockchain fn extend_blockchain( @@ -592,7 +565,7 @@ impl Module { let mut blockchain = prev_blockchain; if blockchain.chain.insert(block_height, *block_hash).is_some() { - return Err(Error::DuplicateBlock.into()); + return Err(Error::DuplicateBlock); } blockchain.max_height = block_height; @@ -608,18 +581,14 @@ impl Module { // END: Storage getter functions // ********************************* - // Wrapper functions around bitcoin lib for testing purposes - fn parse_transaction(raw_tx: &[u8]) -> Result { - parse_transaction(&raw_tx) - .map_err(|_e| Error::TxFormat) + parse_transaction(&raw_tx).map_err(|_e| Error::TxFormat) } fn verify_merkle_proof(raw_merkle_proof: &[u8]) -> Result { - - let merkle_proof = MerkleProof::parse(&raw_merkle_proof) - .map_err(|_e| Error::InvalidMerkleProof)?; + let merkle_proof = + MerkleProof::parse(&raw_merkle_proof).map_err(|_e| Error::InvalidMerkleProof)?; merkle_proof .verify_proof() @@ -635,7 +604,8 @@ impl Module { /// # Panics /// If ParachainStatus in Security module is not set to RUNNING fn verify_block_header(raw_block_header: RawBlockHeader) -> Result { - let basic_block_header = parse_block_header(raw_block_header).map_err(|_e| Error::InvalidHeaderSize)?; + let basic_block_header = + parse_block_header(raw_block_header).map_err(|_e| Error::InvalidHeaderSize)?; let block_header_hash = BlockHeader::block_hash_le(&raw_block_header); @@ -646,9 +616,9 @@ impl Module { ); // Check that the referenced previous block header exists in BTC-Relay - let prev_block_header = Self::get_block_header_from_hash( - basic_block_header.hash_prev_block) - .map_err(|_| Error::PrevBlock)?; + let prev_block_header = + Self::get_block_header_from_hash(basic_block_header.hash_prev_block) + .map_err(|_| Error::PrevBlock)?; // Check that the PoW hash satisfies the target set in the block header ensure!( block_header_hash.as_u256() < basic_block_header.target, @@ -658,59 +628,71 @@ impl Module { // Check that the diff. target is indeed correctly set in the block header, i.e., check for re-target. let block_height = prev_block_header.block_height + 1; - let expected_target = match block_height >= 2016 && block_height % DIFFICULTY_ADJUSTMENT_INTERVAL == 0 { - true => Self::compute_new_target( - &prev_block_header, - block_height)?, - false => prev_block_header.block_header.target - }; + let expected_target = + if block_height >= 2016 && block_height % DIFFICULTY_ADJUSTMENT_INTERVAL == 0 { + Self::compute_new_target(&prev_block_header, block_height)? + } else { + prev_block_header.block_header.target + }; - ensure!(basic_block_header.target == expected_target, Error::DiffTargetHeader); + ensure!( + basic_block_header.target == expected_target, + Error::DiffTargetHeader + ); Ok(basic_block_header) } - /// Computes Bitcoin's PoW retarget algorithm for a given block height /// # Arguments /// * `prev_block_header`: previous block header /// * `block_height` : block height of new target - fn compute_new_target(prev_block_header: &RichBlockHeader, block_height: u32) -> Result { - + fn compute_new_target( + prev_block_header: &RichBlockHeader, + block_height: u32, + ) -> Result { // get time of last retarget - let last_retarget_time = Self::get_last_retarget_time(prev_block_header.chain_ref, block_height)?; + let last_retarget_time = + Self::get_last_retarget_time(prev_block_header.chain_ref, block_height)?; // Compute new target - let actual_timespan = match ((prev_block_header.block_header.timestamp - last_retarget_time) as u32) < (TARGET_TIMESPAN / TARGET_TIMESPAN_DIVISOR) { - true => TARGET_TIMESPAN / TARGET_TIMESPAN_DIVISOR, - false => TARGET_TIMESPAN * TARGET_TIMESPAN_DIVISOR, + let actual_timespan = if ((prev_block_header.block_header.timestamp - last_retarget_time) + as u32) + < (TARGET_TIMESPAN / TARGET_TIMESPAN_DIVISOR) + { + TARGET_TIMESPAN / TARGET_TIMESPAN_DIVISOR + } else { + TARGET_TIMESPAN * TARGET_TIMESPAN_DIVISOR }; - let new_target = U256::from(actual_timespan) * prev_block_header.block_header.target / U256::from(TARGET_TIMESPAN); + let new_target = U256::from(actual_timespan) * prev_block_header.block_header.target + / U256::from(TARGET_TIMESPAN); // ensure target does not exceed max. target - match new_target > UNROUNDED_MAX_TARGET { - true => UNROUNDED_MAX_TARGET, - false => new_target - }; - - Ok(new_target) + Ok(if new_target > UNROUNDED_MAX_TARGET { + UNROUNDED_MAX_TARGET + } else { + new_target + }) } /// Returns the timestamp of the last difficulty retarget on the specified BlockChain, given the current block height - /// + /// /// # Arguments /// * `chain_ref` - BlockChain identifier /// * `block_height` - current block height fn get_last_retarget_time(chain_ref: u32, block_height: u32) -> Result { - let block_chain = Self::get_block_chain_from_id(chain_ref); - let last_retarget_header = Self::get_block_header_from_height(&block_chain, block_height - DIFFICULTY_ADJUSTMENT_INTERVAL)?; + let block_chain = Self::get_block_chain_from_id(chain_ref); + let last_retarget_header = Self::get_block_header_from_height( + &block_chain, + block_height - DIFFICULTY_ADJUSTMENT_INTERVAL, + )?; Ok(last_retarget_header.block_header.timestamp) } - /// Swap the main chain with a fork. This method takes the starting height + /// Swap the main chain with a fork. This method takes the starting height /// of the fork and replaces each block in the main chain with the blocks - /// in the fork. It moves the replaced blocks in the main chain to a new - /// fork. + /// in the fork. It moves the replaced blocks in the main chain to a new + /// fork. /// Last, it replaces the chain_ref of each block header in the new main /// chain to the MAIN_CHAIN_ID and each block header in the new fork to the /// new chain id. @@ -736,7 +718,8 @@ impl Module { // maybe split off the no data elements // check if there is a no_data block element // that is greater than start_height - let index_no_data = main_chain.no_data + let index_no_data = main_chain + .no_data .iter() .position(|&h| h >= start_height) .map(|v| v as u32); @@ -746,7 +729,8 @@ impl Module { }; // maybe split off the invalid elements - let index_invalid = main_chain.invalid + let index_invalid = main_chain + .invalid .iter() .position(|&h| h >= start_height) .map(|v| v as u32); @@ -758,12 +742,12 @@ impl Module { // store the main chain part that is going to be replaced by the new fork // into the forked_main_chain element let forked_main_chain: BlockChain = BlockChain { - chain_id: chain_id, + chain_id, chain: forked_chain.clone(), - start_height: start_height, + start_height, max_height: main_chain.max_height, - no_data: no_data, - invalid: invalid, + no_data, + invalid, }; // append the fork to the main chain @@ -785,7 +769,7 @@ impl Module { Self::set_block_chain_from_id(MAIN_CHAIN_ID, &main_chain); // Set BestBlock and BestBlockHeight to the submitted block - Self::set_best_block(best_block.clone()); + Self::set_best_block(*best_block); Self::set_best_block_height(main_chain.max_height); // remove the fork from storage @@ -793,8 +777,7 @@ impl Module { Self::remove_blockchain_from_chain(position)?; // store the forked main chain - Self::set_block_chain_from_id( - forked_main_chain.chain_id, &forked_main_chain); + Self::set_block_chain_from_id(forked_main_chain.chain_id, &forked_main_chain); // insert the reference to the forked main chain in Chains Self::insert_sorted(&forked_main_chain); @@ -802,8 +785,7 @@ impl Module { // get an iterator of all forked block headers // update all the forked block headers for (_height, block) in forked_chain.iter() { - Self::mutate_block_header_from_chain_id( - &block, forked_main_chain.chain_id); + Self::mutate_block_header_from_chain_id(&block, forked_main_chain.chain_id); } // get an iterator of all new main chain block headers @@ -829,8 +811,7 @@ impl Module { } // get the position of the fork in Chains - let fork_position: u32 = Self::get_chain_position_from_chain_id( - fork.chain_id)?; + let fork_position: u32 = Self::get_chain_position_from_chain_id(fork.chain_id)?; // print!("fork position {:?}\n", fork_position); // check if the previous element in Chains has a lower block_height let mut current_position = fork_position; @@ -841,11 +822,9 @@ impl Module { // get the previous position let prev_position = current_position - 1; // get the blockchain id - let prev_blockchain_id = Self::get_chain_id_from_position( - prev_position); + let prev_blockchain_id = Self::get_chain_id_from_position(prev_position); // get the previous blockchain height - let prev_height = Self::get_block_chain_from_id(prev_blockchain_id) - .max_height; + let prev_height = Self::get_block_chain_from_id(prev_blockchain_id).max_height; // swap elements if block height is greater // print!("curr height {:?}\n", current_height); // print!("prev height {:?}\n", prev_height); @@ -857,8 +836,7 @@ impl Module { // and the current height is more than the // STABLE_TRANSACTION_CONFIRMATIONS ahead // we are swapping the main chain - if prev_height + STABLE_TRANSACTION_CONFIRMATIONS - < current_height { + if prev_height + STABLE_TRANSACTION_CONFIRMATIONS < current_height { Self::swap_main_blockchain(&fork)?; // announce the new main chain @@ -875,9 +853,9 @@ impl Module { )); } else { Self::deposit_event(Event::ForkAheadOfMainChain( - prev_height, // main chain height + prev_height, // main chain height fork.max_height, // fork height - fork.chain_id, // fork id + fork.chain_id, // fork id )); } // break the while loop @@ -920,9 +898,7 @@ impl Module { // NOTE: we never want to insert a new main chain through this function for (curr_position, curr_chain_id) in chains.iter().skip(1) { // get the height of the current chain_id - let curr_height = Self::get_block_chain_from_id( - curr_chain_id.clone()) - .max_height; + let curr_height = Self::get_block_chain_from_id(*curr_chain_id).max_height; // if the height of the current blockchain is lower than // the new blockchain, it should be inserted at that position @@ -933,13 +909,12 @@ impl Module { } // insert the new fork into the chains element - Self::set_chain_from_position_and_id( - max_chain_element, blockchain.chain_id); + Self::set_chain_from_position_and_id(max_chain_element, blockchain.chain_id); // starting from the last element swap the positions until // the new blockchain is at the position_blockchain // print!("max element {:?}\n", max_chain_element); // print!("position blockchain {:?}\n", position_blockchain); - for curr_position in (position_blockchain+1..max_chain_element+1).rev() { + for curr_position in (position_blockchain + 1..max_chain_element + 1).rev() { // stop when the blockchain element is at it's // designated position // print!("current position {:?}\n", curr_position); @@ -952,15 +927,14 @@ impl Module { Self::swap_chain(curr_position, prev_position); } } - /// Flag an error in a block header. This function is called by the + /// Flag an error in a block header. This function is called by the /// security pallet. /// /// # Arguments /// /// * `block_hash` - the hash of the block header with the error /// * `error` - the error code for the block header - pub fn flag_block_error(block_hash: H256Le, error: ErrorCode) - -> Result<(), Error> { + pub fn flag_block_error(block_hash: H256Le, error: ErrorCode) -> Result<(), Error> { // Get the chain id of the block header let block_header = Self::get_block_header_from_hash(block_hash)?; let chain_id = block_header.chain_ref; @@ -971,12 +945,8 @@ impl Module { // Flag errors in the blockchain entry // Check which error we are dealing with let newly_flagged = match error { - ErrorCode::NoDataBTCRelay => blockchain - .no_data - .insert(block_header.block_height), - ErrorCode::InvalidBTCRelay => blockchain - .invalid - .insert(block_header.block_height), + ErrorCode::NoDataBTCRelay => blockchain.no_data.insert(block_header.block_height), + ErrorCode::InvalidBTCRelay => blockchain.invalid.insert(block_header.block_height), _ => return Err(Error::UnknownErrorcode), }; @@ -986,18 +956,17 @@ impl Module { Self::deposit_event(Event::FlagBlockError(block_hash, chain_id, error)); } - Ok (()) + Ok(()) } - /// Clear an error from a block header. This function is called by the + /// Clear an error from a block header. This function is called by the /// security pallet. /// /// # Arguments /// /// * `block_hash` - the hash of the block header being cleared /// * `error` - the error code for the block header - pub fn clear_block_error(block_hash: H256Le, error: ErrorCode) - -> Result<(), Error> { + pub fn clear_block_error(block_hash: H256Le, error: ErrorCode) -> Result<(), Error> { // Get the chain id of the block header let block_header = Self::get_block_header_from_hash(block_hash)?; let chain_id = block_header.chain_ref; @@ -1008,12 +977,8 @@ impl Module { // Clear errors in the blockchain entry // Check which error we are dealing with let block_exists = match error { - ErrorCode::NoDataBTCRelay => { - blockchain.no_data.remove(&block_header.block_height) - }, - ErrorCode::InvalidBTCRelay => { - blockchain.invalid.remove(&block_header.block_height) - }, + ErrorCode::NoDataBTCRelay => blockchain.no_data.remove(&block_header.block_height), + ErrorCode::InvalidBTCRelay => blockchain.invalid.remove(&block_header.block_height), _ => return Err(Error::UnknownErrorcode), }; @@ -1021,45 +986,49 @@ impl Module { // Store the updated blockchain entry Self::mutate_block_chain_from_id(chain_id, blockchain); - Self::deposit_event( - Event::ClearBlockError(block_hash, chain_id, error) - ); + Self::deposit_event(Event::ClearBlockError(block_hash, chain_id, error)); } - Ok (()) + Ok(()) } /// Checks if the given transaction confirmations are greater/equal to the /// requested confirmations (and/or the global k security parameter) - /// + /// /// # Arguments /// * `block_height` - current main chain block height /// * `req_confs` - confirmations requested by the caller /// * `tx_block_height` - block height of checked transaction - /// * `insecure` - determines if checks against recommended global transaction confirmation are to be executed. Recommended: set to `true` - /// - pub fn check_confirmations(main_chain_height: u32, req_confs: u32, tx_block_height: u32, insecure: bool) -> Result<(),Error> { + /// * `insecure` - determines if checks against recommended global transaction confirmation are to be executed. Recommended: set to `true` + /// + pub fn check_confirmations( + main_chain_height: u32, + req_confs: u32, + tx_block_height: u32, + insecure: bool, + ) -> Result<(), Error> { // insecure call: only checks against user parameter if insecure { - match tx_block_height + req_confs <= main_chain_height { - true => Ok(()), - false => Err(Error::Confirmations) + if tx_block_height + req_confs <= main_chain_height { + Ok(()) + } else { + Err(Error::Confirmations) } } else { // secure call: checks against max of user- and global security parameter let global_confs = Self::get_stable_transaction_confirmations(); if global_confs > req_confs { - match tx_block_height + global_confs <= main_chain_height { - true => Ok(()), - false => Err(Error::InsufficientStableConfirmations) + if tx_block_height + global_confs <= main_chain_height { + Ok(()) + } else { + Err(Error::InsufficientStableConfirmations) } + } else if tx_block_height + req_confs <= main_chain_height { + Ok(()) } else { - match tx_block_height + req_confs <= main_chain_height { - true => Ok(()), - false => Err(Error::Confirmations) - } - } + Err(Error::Confirmations) + } } } } diff --git a/crates/security/src/lib.rs b/crates/security/src/lib.rs index 27b91adde6..2995cf4afc 100644 --- a/crates/security/src/lib.rs +++ b/crates/security/src/lib.rs @@ -1,19 +1,19 @@ -#![deny(warnings)] +//#![deny(warnings)] #![cfg_attr(not(feature = "std"), no_std)] #[cfg(test)] mod tests; +use codec::alloc::string::String; +use codec::{Decode, Encode}; /// # Security module implementation /// This is the implementation of the BTC Parachain Security module following the spec at: /// https://interlay.gitlab.io/polkabtc-spec/spec/security /// -use frame_support::{decl_module, decl_storage, decl_event, decl_error}; -use codec::{Encode, Decode}; -use codec::alloc::string::{String}; -use node_primitives::{BlockNumber, AccountId}; -use sp_core::{U256}; -use sp_std::fmt::Debug; +use frame_support::{decl_error, decl_event, decl_module, decl_storage}; +use node_primitives::{AccountId, BlockNumber}; +use sp_core::U256; use sp_std::collections::btree_set::BTreeSet; +use sp_std::fmt::Debug; use bitcoin::types::*; @@ -21,7 +21,7 @@ use bitcoin::types::*; /// The pallet's configuration trait. pub trait Trait: system::Trait { /// The overarching event type. - type Event: From + Into<::Event>; + type Event: From + Into<::Event>; // Dot currency // FIXME: Check if correct. DOT currently emulated, until DOT bridge becomes available @@ -45,10 +45,12 @@ pub enum StatusCode { /// An error has occurred. See Errors for more details. Error = 1, /// BTC Parachain operation has been fully suspended - Shutdown = 2 + Shutdown = 2, } impl Default for StatusCode { - fn default() -> Self { StatusCode::Running } + fn default() -> Self { + StatusCode::Running + } } /// Enum specifying errors which lead to the Error status, tacked in Errors @@ -57,16 +59,18 @@ pub enum ErrorCode { /// No error. Used as default value None = 0, /// Missing transactional data for a block header submitted to BTC-Relay - NoDataBTCRelay = 1, + NoDataBTCRelay = 1, /// Invalid transaction was detected in a block header submitted to BTC-Relay InvalidBTCRelay = 2, /// The exchangeRateOracle experienced a liveness failure (no up-to-date exchange rate available) OracleOffline = 3, /// At least one Vault is being liquidated. Redeem requests paid out partially in collateral (DOT). - Liquidation = 4 + Liquidation = 4, } impl Default for ErrorCode { - fn default() -> Self { ErrorCode::None } + fn default() -> Self { + ErrorCode::None + } } // Indicates the state of a proposed StatusUpdate. @@ -78,17 +82,19 @@ pub enum ProposalStatus { /// StatusUpdate has been accepted Accepted = 1, /// StatusUpdate has been rejected - Rejected = 2 + Rejected = 2, } impl Default for ProposalStatus { - fn default() -> Self { ProposalStatus::Pending } + fn default() -> Self { + ProposalStatus::Pending + } } /// ## Structs /// Struct storing information on a proposed parachain status update #[derive(Encode, Decode, Default, Clone, PartialEq)] #[cfg_attr(feature = "std", derive(Debug))] -pub struct StatusUpdate{ +pub struct StatusUpdate { /// New status of the BTC Parachain. new_status_code: StatusCode, /// Previous status of the BTC Parachain. @@ -110,16 +116,15 @@ pub struct StatusUpdate{ /// Set of accounts which have voted FOR this status update. This can be either Staked Relayers or the Governance Mechanism. votes_yes: BTreeSet, /// Set of accounts which have voted AGAINST this status update. This can be either Staked Relayers or the Governance Mechanism. - votes_no: BTreeSet + votes_no: BTreeSet, } #[derive(Encode, Decode, Default, Clone, PartialEq)] #[cfg_attr(feature = "std", derive(Debug))] pub struct StakedRelayer { - stake: u64 + stake: u64, } - // This pallet's storage items. decl_storage! { trait Store for Module as SecurityModule { @@ -150,7 +155,6 @@ decl_storage! { } } - // The pallet's dispatchable functions. decl_module! { pub struct Module for enum Call where origin: T::Origin { @@ -158,18 +162,14 @@ decl_module! { } } - - - impl Module { - /// Checks if the ParachainStatus matches the provided StatusCode /// /// # Arguments /// /// * `status_code` - to-be-checked StatusCode enum pub fn check_parachain_status(status_code: StatusCode) -> bool { - return status_code == ::get(); + status_code == ::get() } /// Checks if the given ErrorCode is contains in Errors @@ -178,23 +178,23 @@ impl Module { /// /// * `error_code` - to-be-checked ErrorCode enum pub fn check_parachain_error(error_code: ErrorCode) -> bool { - return ::get().contains(&(error_code as u8)); + ::get().contains(&(error_code as u8)) + } + /// Checks if a staked relayer is registered + /// + /// # Arguments + /// + /// * `relayer` - account id of the relayer + pub fn check_relayer_registered(relayer: T::AccountId) -> bool { + >::exists(relayer) } - /// Checks if a staked relayer is registered - /// - /// # Arguments - /// - /// * `relayer` - account id of the relayer - pub fn check_relayer_registered(relayer: T::AccountId) -> bool { - return >::exists(relayer); - } } decl_event!( pub enum Event { - RegisterStakedRelayer(AccountId, u64), - DeRegisterStakedRelayer(AccountId), - StatusUpdateSuggested(u8, BTreeSet, BTreeSet, String, AccountId), + RegisterStakedRelayer(AccountId, u64), + DeRegisterStakedRelayer(AccountId), + StatusUpdateSuggested(u8, BTreeSet, BTreeSet, String, AccountId), VoteOnStatusUpdate(U256, AccountId, bool), ExecuteStatusUpdate(u8, BTreeSet, BTreeSet, String), RejectStatusUpdate(u8, BTreeSet, BTreeSet, String), @@ -205,21 +205,21 @@ decl_event!( ); decl_error! { - pub enum Error for Module { - AlreadyRegistered, - InsufficientStake, - NotRegistered, - GovernanceOnly, - StakedRelayersOnly, - StatusUpdateNotFound, - InsufficientYesVotes, - InsufficientNoVotes, - VaultAlreadyReported, - VaultNotFound, - VaultAlreadyLiquidated, - ValidRedeemOrReplace, - ValidMergeTransaction, - CollateralOk, - OracleOnline - } + pub enum Error for Module { + AlreadyRegistered, + InsufficientStake, + NotRegistered, + GovernanceOnly, + StakedRelayersOnly, + StatusUpdateNotFound, + InsufficientYesVotes, + InsufficientNoVotes, + VaultAlreadyReported, + VaultNotFound, + VaultAlreadyLiquidated, + ValidRedeemOrReplace, + ValidMergeTransaction, + CollateralOk, + OracleOnline + } } diff --git a/crates/xclaim-core/src/lib.rs b/crates/xclaim-core/src/lib.rs index 2a060c21eb..e01cf144e8 100644 --- a/crates/xclaim-core/src/lib.rs +++ b/crates/xclaim-core/src/lib.rs @@ -27,7 +27,6 @@ impl ToString for Error { } } - impl std::convert::From for DispatchError { fn from(error: Error) -> Self { DispatchError::Module { From 5a284e360d0b7c9cc14ff292c87208dd8a8c120f Mon Sep 17 00:00:00 2001 From: "alexei.zamyatin" Date: Mon, 6 Apr 2020 12:40:25 +0200 Subject: [PATCH 10/37] Updated gitignore to avoid target folder commit --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index 3af7788708..6872b7d438 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,14 @@ + +### Rust ### +# Generated by Cargo +# will have compiled files and executables +/target/ */target/* */*/target/* +# These are backup files generated by rustfmt +**/*.rs.bt + +### Editors ### .idea *.vscode From 84de69c58692dec37cf2d43dd2d5b396a144adda Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Mon, 6 Apr 2020 20:17:20 +0900 Subject: [PATCH 11/37] add treasury module --- crates/treasury/Cargo.toml | 53 ++++++++++++ crates/treasury/src/lib.rs | 154 +++++++++++++++++++++++++++++++++++ crates/treasury/src/mock.rs | 55 +++++++++++++ crates/treasury/src/tests.rs | 26 ++++++ 4 files changed, 288 insertions(+) create mode 100644 crates/treasury/Cargo.toml create mode 100644 crates/treasury/src/lib.rs create mode 100644 crates/treasury/src/mock.rs create mode 100644 crates/treasury/src/tests.rs diff --git a/crates/treasury/Cargo.toml b/crates/treasury/Cargo.toml new file mode 100644 index 0000000000..21513cdbe5 --- /dev/null +++ b/crates/treasury/Cargo.toml @@ -0,0 +1,53 @@ +[package] +authors = ['Interlay'] +description = 'Treasury module' +edition = '2018' +homepage = 'https://interlay.gitlab.io/polkabtc-spec/spec/treasury.html' +name = 'treasury' +version = '0.1.0' + +[features] +default = ['std'] +std = [ + 'codec/std', + 'frame-support/std', + 'safe-mix/std', + 'system/std', +] + +[dependencies.codec] +default-features = false +features = ['derive'] +package = 'parity-scale-codec' +version = '1.0.0' + +[dependencies.frame-support] +default-features = false +version = '2.0.0-alpha.5' + +[dependencies.safe-mix] +default-features = false +version = '1.0.0' + +[dependencies.sp-core] +default-features = false +version = '2.0.0-alpha.5' + +[dependencies.sp-io] +default-features = false +version = '2.0.0-alpha.5' + +[dependencies.sp-runtime] +default-features = false +version = '2.0.0-alpha.5' + +[dependencies.system] +default-features = false +package = 'frame-system' +version = '2.0.0-alpha.5' + +[dependencies.xclaim-core] +path = '../xclaim-core' + +[dev-dependencies] +mocktopus = "0.7.0" diff --git a/crates/treasury/src/lib.rs b/crates/treasury/src/lib.rs new file mode 100644 index 0000000000..92637f938e --- /dev/null +++ b/crates/treasury/src/lib.rs @@ -0,0 +1,154 @@ +// #![deny(warnings)] +#![cfg_attr(test, feature(proc_macro_hygiene))] +#![cfg_attr(not(feature = "std"), no_std)] +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[cfg(test)] +extern crate mocktopus; + +#[cfg(test)] +use mocktopus::macros::mockable; + +/// # PolkaBTC Treasury implementation +/// The Treasury module according to the specification at +/// https://interlay.gitlab.io/polkabtc-spec/spec/treasury.html + + +// Substrate +use frame_support::{ + decl_module, decl_storage, decl_event, + dispatch::DispatchResult, ensure +}; +use system::ensure_signed; +use frame_support::traits::{Currency, ReservableCurrency, ExistenceRequirement::KeepAlive}; +use sp_runtime::ModuleId; + + +use xclaim_core::Error; + +type BalanceOf = <::PolkaBTC as Currency<::AccountId>>::Balance; + +/// The treasury's module id, used for deriving its sovereign account ID. +const MODULE_ID: ModuleId = ModuleId(*b"ily/trsy"); + +/// The pallet's configuration trait. +pub trait Trait: system::Trait { + /// The PolkaBTC currency + type PolkaBTC: Currency + ReservableCurrency; + + /// The overarching event type. + type Event: From> + Into<::Event>; +} + +// This pallet's storage items. +decl_storage! { + trait Store for Module as Treasury { + // locked balances + // LockedBalances: map hasher(blake2_128_concat) T::AccountId => T::Currency; + } +} + +// The pallet's events +decl_event!( + pub enum Event where + AccountId = ::AccountId, + Balance = BalanceOf, + { + Transfer(AccountId, AccountId, Balance), + Mint(AccountId, Balance), + Lock(AccountId, Balance), + Burn(AccountId, Balance), + } +); + + +// The pallet's dispatchable functions. +decl_module! { + /// The module declaration. + pub struct Module for enum Call where origin: T::Origin { + // Initializing events + // this is needed only if you are using events in your pallet + fn deposit_event() = default; + + /// Transfer an amount of PolkaBTC (without fees) + /// + /// # Arguments + /// + /// * `origin` - sender of the transaction + /// * `receiver` - receiver of the transaction + /// * `amount` - amount of PolkaBTC + fn transfer(origin, receiver: T::AccountId, amount: BalanceOf) + -> DispatchResult + { + let sender = ensure_signed(origin)?; + + T::PolkaBTC::transfer(&sender, &receiver, amount, KeepAlive)?; + + Self::deposit_event(RawEvent::Transfer(sender, receiver, amount)); + Ok(()) + } + } +} + + +impl Module { + /// Total supply of PolkaBTC + pub fn total_supply() -> BalanceOf { + T::PolkaBTC::total_issuance() + } + /// Mint new tokens + /// + /// # Arguments + /// + /// * `requester` - PolkaBTC user requesting new tokens + /// * `amount` - to be issued amount of PolkaBTC + pub fn mint(requester: T::AccountId, amount: BalanceOf) { + // adds the amount to the total balance of tokens + let minted_tokens = T::PolkaBTC::issue(amount); + // adds the added amount to the requester's balance + T::PolkaBTC::resolve_creating(&requester, minted_tokens); + + Self::deposit_event(RawEvent::Mint(requester, amount)); + } + /// Lock PolkaBTC tokens to burn them + /// + /// # Arguments + /// + /// * `redeemer` - the account redeeming tokens + /// * `amount` - to be locked amount of PolkaBTC + pub fn lock(redeemer: T::AccountId, amount: BalanceOf) + -> Result<(), Error> + { + T::PolkaBTC::reserve(&redeemer, amount) + .map_err(|_| Error::InsufficientFunds)?; + + Self::deposit_event(RawEvent::Lock(redeemer, amount)); + Ok(()) + } + /// Burn a previously locked PolkaBTC tokens + /// + /// # Arguments + /// + /// * `redeemer` - the account redeeming tokens + /// * `amount` - the to be burned amount of PolkaBTC + pub fn burn(redeemer: T::AccountId, amount: BalanceOf) + -> Result<(), Error> + { + ensure!(T::PolkaBTC::reserved_balance(&redeemer) == amount, + Error::InsufficientLockedFunds); + + // burn the tokens from the global balance + let _burned_tokens = T::PolkaBTC::burn(amount); + // burn the tokens for the redeemer + let (_burned_tokens, _mismatch_tokens) = T::PolkaBTC::slash_reserved( + &redeemer, amount); + + Self::deposit_event(RawEvent::Burn(redeemer, amount)); + + Ok(()) + } +} diff --git a/crates/treasury/src/mock.rs b/crates/treasury/src/mock.rs new file mode 100644 index 0000000000..2ea81ffb45 --- /dev/null +++ b/crates/treasury/src/mock.rs @@ -0,0 +1,55 @@ +// Creating mock runtime here + +use crate::{Module, Trait}; +use sp_core::H256; +use frame_support::{impl_outer_origin, parameter_types, weights::Weight}; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, testing::Header, Perbill, +}; + +impl_outer_origin! { + pub enum Origin for Test {} +} + +// For testing the pallet, we construct most of a mock runtime. This means +// first constructing a configuration type (`Test`) which `impl`s each of the +// configuration traits of pallets we want to use. +#[derive(Clone, Eq, PartialEq)] +pub struct Test; +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); +} +impl system::Trait for Test { + type Origin = Origin; + type Call = (); + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + type ModuleToIndex = (); + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); +} +impl Trait for Test { + type Event = (); +} +pub type TemplateModule = Module; + +// This function basically just builds a genesis storage key/value store according to +// our desired mockup. +pub fn new_test_ext() -> sp_io::TestExternalities { + system::GenesisConfig::default().build_storage::().unwrap().into() +} diff --git a/crates/treasury/src/tests.rs b/crates/treasury/src/tests.rs new file mode 100644 index 0000000000..ec123a50c7 --- /dev/null +++ b/crates/treasury/src/tests.rs @@ -0,0 +1,26 @@ +// Tests to be written here + +use crate::{Error, mock::*}; +use frame_support::{assert_ok, assert_noop}; + +#[test] +fn it_works_for_default_value() { + new_test_ext().execute_with(|| { + // Just a dummy test for the dummy function `do_something` + // calling the `do_something` function with a value 42 + assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); + // asserting that the stored value is equal to what we stored + assert_eq!(TemplateModule::something(), Some(42)); + }); +} + +#[test] +fn correct_error_for_none_value() { + new_test_ext().execute_with(|| { + // Ensure the correct error is thrown on None value + assert_noop!( + TemplateModule::cause_error(Origin::signed(1)), + Error::::NoneValue + ); + }); +} From 643251dbb8fc9824c9f0613bb6b944b0857cd2f0 Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Mon, 6 Apr 2020 20:17:41 +0900 Subject: [PATCH 12/37] add blank collateral pallet --- crates/collateral/Cargo.toml | 47 +++++++++++++++ crates/collateral/src/lib.rs | 101 +++++++++++++++++++++++++++++++++ crates/collateral/src/mock.rs | 55 ++++++++++++++++++ crates/collateral/src/tests.rs | 26 +++++++++ 4 files changed, 229 insertions(+) create mode 100644 crates/collateral/Cargo.toml create mode 100644 crates/collateral/src/lib.rs create mode 100644 crates/collateral/src/mock.rs create mode 100644 crates/collateral/src/tests.rs diff --git a/crates/collateral/Cargo.toml b/crates/collateral/Cargo.toml new file mode 100644 index 0000000000..e7084223bc --- /dev/null +++ b/crates/collateral/Cargo.toml @@ -0,0 +1,47 @@ +[package] +authors = ['Interlay'] +description = 'Collateral module' +edition = '2018' +homepage = 'https://interlay.gitlab.io/polkabtc-spec/spec/treasury.html' +name = 'collateral' +version = '0.1.0' + +[features] +default = ['std'] +std = [ + 'codec/std', + 'frame-support/std', + 'safe-mix/std', + 'system/std', +] + +[dependencies.codec] +default-features = false +features = ['derive'] +package = 'parity-scale-codec' +version = '1.0.0' + +[dependencies.frame-support] +default-features = false +version = '2.0.0-alpha.5' + +[dependencies.safe-mix] +default-features = false +version = '1.0.0' + +[dependencies.sp-core] +default-features = false +version = '2.0.0-alpha.5' + +[dependencies.sp-io] +default-features = false +version = '2.0.0-alpha.5' + +[dependencies.sp-runtime] +default-features = false +version = '2.0.0-alpha.5' + +[dependencies.system] +default-features = false +package = 'frame-system' +version = '2.0.0-alpha.5' diff --git a/crates/collateral/src/lib.rs b/crates/collateral/src/lib.rs new file mode 100644 index 0000000000..9f927f4acc --- /dev/null +++ b/crates/collateral/src/lib.rs @@ -0,0 +1,101 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +/// The Treasury module according to the specification at +/// https://interlay.gitlab.io/polkabtc-spec/spec/treasury.html + +use frame_support::{decl_module, decl_storage, decl_event, decl_error, dispatch}; +use system::ensure_signed; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +/// The pallet's configuration trait. +pub trait Trait: system::Trait { + // Add other types and constants required to configure this pallet. + + /// The overarching event type. + type Event: From> + Into<::Event>; +} + +// This pallet's storage items. +decl_storage! { + // It is important to update your storage name so that your pallet's + // storage items are isolated from other pallets. + // ---------------------------------vvvvvvvvvvvvvv + trait Store for Module as TemplateModule { + // Just a dummy storage item. + // Here we are declaring a StorageValue, `Something` as a Option + // `get(fn something)` is the default getter which returns either the stored `u32` or `None` if nothing stored + Something get(fn something): Option; + } +} + +// The pallet's events +decl_event!( + pub enum Event where AccountId = ::AccountId { + /// Just a dummy event. + /// Event `Something` is declared with a parameter of the type `u32` and `AccountId` + /// To emit this event, we call the deposit function, from our runtime functions + SomethingStored(u32, AccountId), + } +); + +// The pallet's errors +decl_error! { + pub enum Error for Module { + /// Value was None + NoneValue, + /// Value reached maximum and cannot be incremented further + StorageOverflow, + } +} + +// The pallet's dispatchable functions. +decl_module! { + /// The module declaration. + pub struct Module for enum Call where origin: T::Origin { + // Initializing errors + // this includes information about your errors in the node's metadata. + // it is needed only if you are using errors in your pallet + type Error = Error; + + // Initializing events + // this is needed only if you are using events in your pallet + fn deposit_event() = default; + + /// Just a dummy entry point. + /// function that can be called by the external world as an extrinsics call + /// takes a parameter of the type `AccountId`, stores it, and emits an event + pub fn do_something(origin, something: u32) -> dispatch::DispatchResult { + // Check it was signed and get the signer. See also: ensure_root and ensure_none + let who = ensure_signed(origin)?; + + // Code to execute when something calls this. + // For example: the following line stores the passed in u32 in the storage + Something::put(something); + + // Here we are raising the Something event + Self::deposit_event(RawEvent::SomethingStored(something, who)); + Ok(()) + } + + /// Another dummy entry point. + /// takes no parameters, attempts to increment storage value, and possibly throws an error + pub fn cause_error(origin) -> dispatch::DispatchResult { + // Check it was signed and get the signer. See also: ensure_root and ensure_none + let _who = ensure_signed(origin)?; + + match Something::get() { + None => Err(Error::::NoneValue)?, + Some(old) => { + let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; + Something::put(new); + Ok(()) + }, + } + } + } +} diff --git a/crates/collateral/src/mock.rs b/crates/collateral/src/mock.rs new file mode 100644 index 0000000000..2ea81ffb45 --- /dev/null +++ b/crates/collateral/src/mock.rs @@ -0,0 +1,55 @@ +// Creating mock runtime here + +use crate::{Module, Trait}; +use sp_core::H256; +use frame_support::{impl_outer_origin, parameter_types, weights::Weight}; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, testing::Header, Perbill, +}; + +impl_outer_origin! { + pub enum Origin for Test {} +} + +// For testing the pallet, we construct most of a mock runtime. This means +// first constructing a configuration type (`Test`) which `impl`s each of the +// configuration traits of pallets we want to use. +#[derive(Clone, Eq, PartialEq)] +pub struct Test; +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); +} +impl system::Trait for Test { + type Origin = Origin; + type Call = (); + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + type ModuleToIndex = (); + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); +} +impl Trait for Test { + type Event = (); +} +pub type TemplateModule = Module; + +// This function basically just builds a genesis storage key/value store according to +// our desired mockup. +pub fn new_test_ext() -> sp_io::TestExternalities { + system::GenesisConfig::default().build_storage::().unwrap().into() +} diff --git a/crates/collateral/src/tests.rs b/crates/collateral/src/tests.rs new file mode 100644 index 0000000000..ec123a50c7 --- /dev/null +++ b/crates/collateral/src/tests.rs @@ -0,0 +1,26 @@ +// Tests to be written here + +use crate::{Error, mock::*}; +use frame_support::{assert_ok, assert_noop}; + +#[test] +fn it_works_for_default_value() { + new_test_ext().execute_with(|| { + // Just a dummy test for the dummy function `do_something` + // calling the `do_something` function with a value 42 + assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); + // asserting that the stored value is equal to what we stored + assert_eq!(TemplateModule::something(), Some(42)); + }); +} + +#[test] +fn correct_error_for_none_value() { + new_test_ext().execute_with(|| { + // Ensure the correct error is thrown on None value + assert_noop!( + TemplateModule::cause_error(Origin::signed(1)), + Error::::NoneValue + ); + }); +} From 9e2c4c080eceb7ffa08e89851f3ecab965454e1c Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Mon, 6 Apr 2020 20:18:03 +0900 Subject: [PATCH 13/37] add treasury error codes --- crates/xclaim-core/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/xclaim-core/src/lib.rs b/crates/xclaim-core/src/lib.rs index 383d883ba4..b00d5fd4db 100644 --- a/crates/xclaim-core/src/lib.rs +++ b/crates/xclaim-core/src/lib.rs @@ -5,6 +5,8 @@ use frame_support::dispatch::DispatchError; pub enum Error { MissingExchangeRate, InvalidOracleSource, + InsufficientFunds, + InsufficientLockedFunds, /// use only for errors which means something /// going very wrong and which do not match any other error @@ -16,6 +18,8 @@ impl Error { match self { Error::MissingExchangeRate => "Exchange rate not set", Error::InvalidOracleSource => "Invalid oracle account", + Error::InsufficientFunds => "The balance of this account is insufficient to complete the transaction.", + Error::InsufficientLockedFunds => "The locked token balance of this account is insufficient to burn the tokens.", Error::RuntimeError => "Runtim error", } } From f1afd53cfcec7752d32ff6849a18c37ce047ad23 Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Mon, 6 Apr 2020 20:18:48 +0900 Subject: [PATCH 14/37] ignore target folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3af7788708..40292207cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +target/* */target/* */*/target/* .idea From 7826a608a6b0a84614a094e507bcc29892c20756 Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Mon, 6 Apr 2020 20:19:14 +0900 Subject: [PATCH 15/37] include treasury and collateral module --- Cargo.lock | 921 ++++++++++++++++++++++++++++++++++++++++++++++------- Cargo.toml | 2 + 2 files changed, 811 insertions(+), 112 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe0761e876..6b3c86b678 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,10 +98,10 @@ dependencies = [ "mocktopus", "node-primitives", "parity-scale-codec", - "primitive-types", + "primitive-types 0.6.2", "sha2", - "sp-core", - "sp-std", + "sp-core 2.0.0", + "sp-std 2.0.0", "twox-hash", ] @@ -162,8 +162,8 @@ dependencies = [ name = "btc-core" version = "0.1.0" dependencies = [ - "frame-support", - "sp-runtime", + "frame-support 2.0.0", + "sp-runtime 2.0.0", ] [[package]] @@ -172,8 +172,8 @@ version = "0.0.1" dependencies = [ "bitcoin", "btc-core", - "frame-support", - "frame-system", + "frame-support 2.0.0", + "frame-system 2.0.0", "hex", "indexmap", "mocktopus", @@ -182,10 +182,10 @@ dependencies = [ "parity-scale-codec", "security", "serde", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", + "sp-core 2.0.0", + "sp-io 2.0.0", + "sp-runtime 2.0.0", + "sp-std 2.0.0", ] [[package]] @@ -236,6 +236,19 @@ dependencies = [ "bitflags", ] +[[package]] +name = "collateral" +version = "0.1.0" +dependencies = [ + "frame-support 2.0.0-alpha.5", + "frame-system 2.0.0-alpha.5", + "parity-scale-codec", + "safe-mix", + "sp-core 2.0.0-alpha.5", + "sp-io 2.0.0-alpha.5", + "sp-runtime 2.0.0-alpha.5", +] + [[package]] name = "const-random" version = "0.1.8" @@ -352,14 +365,14 @@ checksum = "516aa8d7a71cb00a1c4146f0798549b93d083d4f189b3ced8f3de6b8f11ee6c4" name = "exchange-rate-oracle" version = "0.0.1" dependencies = [ - "frame-support", - "frame-system", + "frame-support 2.0.0", + "frame-system 2.0.0", "mocktopus", "pallet-timestamp", "parity-scale-codec", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 2.0.0", + "sp-io 2.0.0", + "sp-runtime 2.0.0", "xclaim-core", ] @@ -404,6 +417,18 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixed-hash" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32529fc42e86ec06e5047092082aab9ad459b070c5d2a76b14f4f5ce70bf2e84" +dependencies = [ + "byteorder", + "rand 0.7.3", + "rustc-hex", + "static_assertions", +] + [[package]] name = "frame-metadata" version = "2.0.0" @@ -411,8 +436,45 @@ source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa8357 dependencies = [ "parity-scale-codec", "serde", - "sp-core", - "sp-std", + "sp-core 2.0.0", + "sp-std 2.0.0", +] + +[[package]] +name = "frame-metadata" +version = "11.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7083431304c527dea7559f6b262b186473f44d1c9819b7da74388d6487b2653f" +dependencies = [ + "parity-scale-codec", + "serde", + "sp-core 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", +] + +[[package]] +name = "frame-support" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "390a1a495b50001f75a2f4fe0602734ce61890d7acbd6aa7ddce0b60d9145a82" +dependencies = [ + "bitmask", + "frame-metadata 11.0.0-alpha.5", + "frame-support-procedural 2.0.0-alpha.5", + "impl-trait-for-tuples", + "log", + "once_cell 1.3.1", + "parity-scale-codec", + "paste", + "serde", + "sp-arithmetic 2.0.0-alpha.5", + "sp-core 2.0.0-alpha.5", + "sp-inherents 2.0.0-alpha.5", + "sp-io 2.0.0-alpha.5", + "sp-runtime 2.0.0-alpha.5", + "sp-state-machine 0.8.0-alpha.5", + "sp-std 2.0.0-alpha.5", + "tracing", ] [[package]] @@ -421,30 +483,55 @@ version = "2.0.0" source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa835790df63410a29676243fc54#3e651110aa06aa835790df63410a29676243fc54" dependencies = [ "bitmask", - "frame-metadata", - "frame-support-procedural", + "frame-metadata 2.0.0", + "frame-support-procedural 2.0.0", "impl-trait-for-tuples", "log", "once_cell 0.2.4", "parity-scale-codec", "paste", "serde", - "sp-arithmetic", - "sp-core", - "sp-inherents", - "sp-io", - "sp-runtime", - "sp-state-machine", - "sp-std", + "sp-arithmetic 2.0.0", + "sp-core 2.0.0", + "sp-inherents 2.0.0", + "sp-io 2.0.0", + "sp-runtime 2.0.0", + "sp-state-machine 2.0.0", + "sp-std 2.0.0", "tracing", ] +[[package]] +name = "frame-support-procedural" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e509284ec2b06c24d28ba18fda0c21f6ad69545a3da5e9fcb7ba1817686ffa" +dependencies = [ + "frame-support-procedural-tools 2.0.0-alpha.5", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "frame-support-procedural" version = "2.0.0" source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa835790df63410a29676243fc54#3e651110aa06aa835790df63410a29676243fc54" dependencies = [ - "frame-support-procedural-tools", + "frame-support-procedural-tools 2.0.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "frame-support-procedural-tools" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bf920148acb725b9ac1a6238b57a010ba660ecae7cd125f4b146c4a7d43192d" +dependencies = [ + "frame-support-procedural-tools-derive 2.0.0-alpha.5", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -455,13 +542,24 @@ name = "frame-support-procedural-tools" version = "2.0.0" source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa835790df63410a29676243fc54#3e651110aa06aa835790df63410a29676243fc54" dependencies = [ - "frame-support-procedural-tools-derive", + "frame-support-procedural-tools-derive 2.0.0", "proc-macro-crate", "proc-macro2", "quote", "syn", ] +[[package]] +name = "frame-support-procedural-tools-derive" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d277cb5e284309c165ac1cfd7e1077b0d66d4aa0a1043dd32329191b510c40" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "frame-support-procedural-tools-derive" version = "2.0.0" @@ -472,21 +570,38 @@ dependencies = [ "syn", ] +[[package]] +name = "frame-system" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e525321245fb95648e49a22ab1e8a53abd86dcc71e0f9474a7945afe2d7f50" +dependencies = [ + "frame-support 2.0.0-alpha.5", + "impl-trait-for-tuples", + "parity-scale-codec", + "serde", + "sp-core 2.0.0-alpha.5", + "sp-io 2.0.0-alpha.5", + "sp-runtime 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", + "sp-version 2.0.0-alpha.5", +] + [[package]] name = "frame-system" version = "2.0.0" source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa835790df63410a29676243fc54#3e651110aa06aa835790df63410a29676243fc54" dependencies = [ - "frame-support", + "frame-support 2.0.0", "impl-trait-for-tuples", "parity-scale-codec", "safe-mix", "serde", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "sp-version", + "sp-core 2.0.0", + "sp-io 2.0.0", + "sp-runtime 2.0.0", + "sp-std 2.0.0", + "sp-version 2.0.0", ] [[package]] @@ -495,6 +610,98 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +[[package]] +name = "futures" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" + +[[package]] +name = "futures-executor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" + +[[package]] +name = "futures-macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" + +[[package]] +name = "futures-task" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" + +[[package]] +name = "futures-util" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + [[package]] name = "generic-array" version = "0.12.3" @@ -550,6 +757,15 @@ dependencies = [ "autocfg 0.1.7", ] +[[package]] +name = "hermit-abi" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.2" @@ -723,7 +939,19 @@ dependencies = [ "ahash", "hash-db", "hashbrown 0.6.3", - "parity-util-mem", + "parity-util-mem 0.3.0", +] + +[[package]] +name = "memory-db" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58381b20ebe2c578e75dececd9da411414903415349548ccc46aac3209cdfbc" +dependencies = [ + "ahash", + "hash-db", + "hashbrown 0.6.3", + "parity-util-mem 0.6.0", ] [[package]] @@ -744,6 +972,18 @@ dependencies = [ "zeroize 1.1.0", ] +[[package]] +name = "merlin" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6feca46f4fa3443a01769d768727f10c10a20fdb65e52dc16a81f0c8269bb78" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.5.1", + "zeroize 1.1.0", +] + [[package]] name = "mocktopus" version = "0.7.5" @@ -769,8 +1009,8 @@ name = "node-primitives" version = "2.0.0" source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa835790df63410a29676243fc54#3e651110aa06aa835790df63410a29676243fc54" dependencies = [ - "sp-core", - "sp-runtime", + "sp-core 2.0.0", + "sp-runtime 2.0.0", ] [[package]] @@ -821,6 +1061,16 @@ dependencies = [ "autocfg 1.0.0", ] +[[package]] +name = "num_cpus" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "once_cell" version = "0.1.8" @@ -836,6 +1086,15 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d584f08c2d717d5c23a6414fc2822b71c651560713e54fa7eace675f758a355e" +[[package]] +name = "once_cell" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" +dependencies = [ + "parking_lot 0.9.0", +] + [[package]] name = "opaque-debug" version = "0.2.3" @@ -847,14 +1106,14 @@ name = "pallet-timestamp" version = "2.0.0" source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa835790df63410a29676243fc54#3e651110aa06aa835790df63410a29676243fc54" dependencies = [ - "frame-support", - "frame-system", + "frame-support 2.0.0", + "frame-system 2.0.0", "impl-trait-for-tuples", "parity-scale-codec", "serde", - "sp-inherents", - "sp-runtime", - "sp-std", + "sp-inherents 2.0.0", + "sp-runtime 2.0.0", + "sp-std 2.0.0", "sp-timestamp", ] @@ -894,6 +1153,31 @@ dependencies = [ "winapi", ] +[[package]] +name = "parity-util-mem" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e42755f26e5ea21a6a819d9e63cbd70713e9867a2b767ec2cc65ca7659532c5" +dependencies = [ + "cfg-if", + "impl-trait-for-tuples", + "parity-util-mem-derive", + "parking_lot 0.10.0", + "primitive-types 0.7.0", + "winapi", +] + +[[package]] +name = "parity-util-mem-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" +dependencies = [ + "proc-macro2", + "syn", + "synstructure", +] + [[package]] name = "parity-wasm" version = "0.41.0" @@ -921,6 +1205,16 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "parking_lot" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" +dependencies = [ + "lock_api 0.3.3", + "parking_lot_core 0.7.0", +] + [[package]] name = "parking_lot_core" version = "0.4.0" @@ -949,6 +1243,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "smallvec 1.2.0", + "winapi", +] + [[package]] name = "paste" version = "0.1.9" @@ -981,6 +1289,12 @@ dependencies = [ "crypto-mac", ] +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" + [[package]] name = "ppv-lite86" version = "0.2.6" @@ -993,7 +1307,19 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4336f4f5d5524fa60bcbd6fe626f9223d8142a50e7053e979acdf0da41ab975" dependencies = [ - "fixed-hash", + "fixed-hash 0.5.2", + "impl-codec", + "impl-serde 0.3.0", + "uint", +] + +[[package]] +name = "primitive-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5e4b9943a2da369aec5e96f7c10ebc74fcf434d39590d974b0a3460e6f67fbb" +dependencies = [ + "fixed-hash 0.6.0", "impl-codec", "impl-serde 0.3.0", "uint", @@ -1014,6 +1340,12 @@ version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" +[[package]] +name = "proc-macro-nested" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" + [[package]] name = "proc-macro2" version = "1.0.10" @@ -1224,6 +1556,12 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -1256,7 +1594,7 @@ checksum = "eacd8381b3c37840c9c9f40472af529e49975bdcbc24f83c31059fd6539023d3" dependencies = [ "curve25519-dalek 1.2.3", "failure", - "merlin", + "merlin 1.3.0", "rand 0.6.5", "rand_core 0.4.2", "rand_os", @@ -1265,6 +1603,24 @@ dependencies = [ "zeroize 0.9.3", ] +[[package]] +name = "schnorrkel" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" +dependencies = [ + "arrayref", + "arrayvec 0.5.1", + "curve25519-dalek 2.0.0", + "getrandom", + "merlin 2.0.0", + "rand 0.7.3", + "rand_core 0.5.1", + "sha2", + "subtle 2.2.2", + "zeroize 1.1.0", +] + [[package]] name = "scopeguard" version = "0.3.3" @@ -1282,16 +1638,16 @@ name = "security" version = "0.1.0" dependencies = [ "bitcoin", - "frame-support", - "frame-system", + "frame-support 2.0.0", + "frame-system 2.0.0", "node-primitives", "pallet-timestamp", "parity-scale-codec", "serde", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", + "sp-core 2.0.0", + "sp-io 2.0.0", + "sp-runtime 2.0.0", + "sp-std 2.0.0", ] [[package]] @@ -1341,6 +1697,12 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + [[package]] name = "smallvec" version = "0.6.13" @@ -1363,11 +1725,11 @@ source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa8357 dependencies = [ "parity-scale-codec", "sp-api-proc-macro", - "sp-core", - "sp-runtime", - "sp-state-machine", - "sp-std", - "sp-version", + "sp-core 2.0.0", + "sp-runtime 2.0.0", + "sp-state-machine 2.0.0", + "sp-std 2.0.0", + "sp-version 2.0.0", ] [[package]] @@ -1382,6 +1744,19 @@ dependencies = [ "syn", ] +[[package]] +name = "sp-application-crypto" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed68f0c283a01b5a8c768965b160fb4aa0a637a7e1b5e0d1168cba2f2310b348" +dependencies = [ + "parity-scale-codec", + "serde", + "sp-core 2.0.0-alpha.5", + "sp-io 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", +] + [[package]] name = "sp-application-crypto" version = "2.0.0" @@ -1389,9 +1764,23 @@ source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa8357 dependencies = [ "parity-scale-codec", "serde", - "sp-core", - "sp-io", - "sp-std", + "sp-core 2.0.0", + "sp-io 2.0.0", + "sp-std 2.0.0", +] + +[[package]] +name = "sp-arithmetic" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d1e32dfcd4c87069d6e48d7d4a873221a8c27161a0ef5ad6ff683b591e6f97" +dependencies = [ + "integer-sqrt", + "num-traits", + "parity-scale-codec", + "serde", + "sp-debug-derive 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", ] [[package]] @@ -1403,8 +1792,50 @@ dependencies = [ "num-traits", "parity-scale-codec", "serde", - "sp-debug-derive", - "sp-std", + "sp-debug-derive 2.0.0", + "sp-std 2.0.0", +] + +[[package]] +name = "sp-core" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a2938aefa827fbf6dbf5c3e8eea5cc6dedafe97a28bbfb733258ee99c82c67" +dependencies = [ + "base58", + "blake2-rfc", + "byteorder", + "ed25519-dalek", + "futures", + "hash-db", + "hash256-std-hasher", + "hex", + "impl-serde 0.3.0", + "lazy_static", + "libsecp256k1", + "log", + "num-traits", + "parity-scale-codec", + "parity-util-mem 0.6.0", + "parking_lot 0.10.0", + "primitive-types 0.7.0", + "rand 0.7.3", + "regex", + "rustc-hex", + "schnorrkel 0.9.1", + "serde", + "sha2", + "sp-debug-derive 2.0.0-alpha.5", + "sp-externalities 0.8.0-alpha.5", + "sp-runtime-interface 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", + "sp-storage 2.0.0-alpha.5", + "substrate-bip39 0.4.1", + "tiny-bip39 0.7.3", + "tiny-keccak", + "twox-hash", + "wasmi", + "zeroize 1.1.0", ] [[package]] @@ -1426,26 +1857,37 @@ dependencies = [ "num-traits", "parity-scale-codec", "parking_lot 0.9.0", - "primitive-types", + "primitive-types 0.6.2", "rand 0.7.3", "regex", "rustc-hex", - "schnorrkel", + "schnorrkel 0.8.5", "serde", "sha2", - "sp-debug-derive", - "sp-externalities", - "sp-runtime-interface", - "sp-std", - "sp-storage", - "substrate-bip39", - "tiny-bip39", + "sp-debug-derive 2.0.0", + "sp-externalities 2.0.0", + "sp-runtime-interface 2.0.0", + "sp-std 2.0.0", + "sp-storage 2.0.0", + "substrate-bip39 0.3.1", + "tiny-bip39 0.6.2", "tiny-keccak", "twox-hash", "wasmi", "zeroize 1.1.0", ] +[[package]] +name = "sp-debug-derive" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "124f3ffa2d897139864715cc624811ca997ca92be8880229143c6dee801b5ab2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sp-debug-derive" version = "2.0.0" @@ -1456,14 +1898,38 @@ dependencies = [ "syn", ] +[[package]] +name = "sp-externalities" +version = "0.8.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b3aa6665b2a1a9df50a5514597e96a7d08d69e0e7ff90d238380fb266e14622" +dependencies = [ + "environmental", + "sp-std 2.0.0-alpha.5", + "sp-storage 2.0.0-alpha.5", +] + [[package]] name = "sp-externalities" version = "2.0.0" source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa835790df63410a29676243fc54#3e651110aa06aa835790df63410a29676243fc54" dependencies = [ "environmental", - "sp-std", - "sp-storage", + "sp-std 2.0.0", + "sp-storage 2.0.0", +] + +[[package]] +name = "sp-inherents" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d5ea2312969d929d617f852f9728644b98591b503a641106ee444acea4394fc" +dependencies = [ + "derive_more", + "parity-scale-codec", + "parking_lot 0.10.0", + "sp-core 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", ] [[package]] @@ -1474,8 +1940,27 @@ dependencies = [ "derive_more", "parity-scale-codec", "parking_lot 0.9.0", - "sp-core", - "sp-std", + "sp-core 2.0.0", + "sp-std 2.0.0", +] + +[[package]] +name = "sp-io" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ed12cd1b0eddf5250703fff43da9e76be6cce32c492b2e2a71b4f6d9a12f49" +dependencies = [ + "hash-db", + "libsecp256k1", + "log", + "parity-scale-codec", + "sp-core 2.0.0-alpha.5", + "sp-externalities 0.8.0-alpha.5", + "sp-runtime-interface 2.0.0-alpha.5", + "sp-state-machine 0.8.0-alpha.5", + "sp-std 2.0.0-alpha.5", + "sp-trie 2.0.0-alpha.5", + "sp-wasm-interface 2.0.0-alpha.5", ] [[package]] @@ -1487,12 +1972,22 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", - "sp-core", - "sp-externalities", - "sp-runtime-interface", - "sp-state-machine", - "sp-std", - "sp-trie", + "sp-core 2.0.0", + "sp-externalities 2.0.0", + "sp-runtime-interface 2.0.0", + "sp-state-machine 2.0.0", + "sp-std 2.0.0", + "sp-trie 2.0.0", +] + +[[package]] +name = "sp-panic-handler" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643ae9f2dc119551342422394cdfa8bfe0a230d1adc9891fcb08cf15fdf0f703" +dependencies = [ + "backtrace", + "log", ] [[package]] @@ -1504,6 +1999,28 @@ dependencies = [ "log", ] +[[package]] +name = "sp-runtime" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2eb5d07f847c7420070d9dc28d810d405dc6316cd58f58548a41f0aeeca84e8" +dependencies = [ + "hash256-std-hasher", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "parity-util-mem 0.6.0", + "paste", + "rand 0.7.3", + "serde", + "sp-application-crypto 2.0.0-alpha.5", + "sp-arithmetic 2.0.0-alpha.5", + "sp-core 2.0.0-alpha.5", + "sp-inherents 2.0.0-alpha.5", + "sp-io 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", +] + [[package]] name = "sp-runtime" version = "2.0.0" @@ -1515,12 +2032,27 @@ dependencies = [ "paste", "rand 0.7.3", "serde", - "sp-application-crypto", - "sp-arithmetic", - "sp-core", - "sp-inherents", - "sp-io", - "sp-std", + "sp-application-crypto 2.0.0", + "sp-arithmetic 2.0.0", + "sp-core 2.0.0", + "sp-inherents 2.0.0", + "sp-io 2.0.0", + "sp-std 2.0.0", +] + +[[package]] +name = "sp-runtime-interface" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d25229ba01740b13368f743e866d8ee155826932c9f2c4390e4ceb7730df214" +dependencies = [ + "parity-scale-codec", + "primitive-types 0.7.0", + "sp-externalities 0.8.0-alpha.5", + "sp-runtime-interface-proc-macro 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", + "sp-wasm-interface 2.0.0-alpha.5", + "static_assertions", ] [[package]] @@ -1530,14 +2062,27 @@ source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa8357 dependencies = [ "environmental", "parity-scale-codec", - "primitive-types", - "sp-externalities", - "sp-runtime-interface-proc-macro", - "sp-std", - "sp-wasm-interface", + "primitive-types 0.6.2", + "sp-externalities 2.0.0", + "sp-runtime-interface-proc-macro 2.0.0", + "sp-std 2.0.0", + "sp-wasm-interface 2.0.0", "static_assertions", ] +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f1d9e32fa5db2f3dd89affbd3c97959432272c9e52e4e2610dad32dd4705784" +dependencies = [ + "Inflector", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sp-runtime-interface-proc-macro" version = "2.0.0" @@ -1550,6 +2095,26 @@ dependencies = [ "syn", ] +[[package]] +name = "sp-state-machine" +version = "0.8.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e52a17e293be8e7a518ac6aebfc7fdafbe531b6c808a83a754e4a8730f139521" +dependencies = [ + "hash-db", + "log", + "num-traits", + "parity-scale-codec", + "parking_lot 0.10.0", + "rand 0.7.3", + "sp-core 2.0.0-alpha.5", + "sp-externalities 0.8.0-alpha.5", + "sp-panic-handler 2.0.0-alpha.5", + "sp-trie 2.0.0-alpha.5", + "trie-db 0.20.0", + "trie-root 0.16.0", +] + [[package]] name = "sp-state-machine" version = "2.0.0" @@ -1561,19 +2126,37 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.9.0", "rand 0.7.3", - "sp-core", - "sp-externalities", - "sp-panic-handler", - "sp-trie", - "trie-db", - "trie-root", + "sp-core 2.0.0", + "sp-externalities 2.0.0", + "sp-panic-handler 2.0.0", + "sp-trie 2.0.0", + "trie-db 0.18.1", + "trie-root 0.15.2", ] +[[package]] +name = "sp-std" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "752e038359704226bb5737531fb91df2e4ab33214e0be6eb6f32ad688a71b411" + [[package]] name = "sp-std" version = "2.0.0" source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa835790df63410a29676243fc54#3e651110aa06aa835790df63410a29676243fc54" +[[package]] +name = "sp-storage" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c389a75ddd45ba771b20c4caed1011d23004069e436b73eca058d2f894585069" +dependencies = [ + "impl-serde 0.2.3", + "serde", + "sp-debug-derive 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", +] + [[package]] name = "sp-storage" version = "2.0.0" @@ -1581,8 +2164,8 @@ source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa8357 dependencies = [ "impl-serde 0.2.3", "serde", - "sp-debug-derive", - "sp-std", + "sp-debug-derive 2.0.0", + "sp-std 2.0.0", ] [[package]] @@ -1593,9 +2176,24 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "sp-api", - "sp-inherents", - "sp-runtime", - "sp-std", + "sp-inherents 2.0.0", + "sp-runtime 2.0.0", + "sp-std 2.0.0", +] + +[[package]] +name = "sp-trie" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f417a60d0d1222f92733deef4dffc73b21180b0cf44ec335ac73fc871198721" +dependencies = [ + "hash-db", + "memory-db 0.20.0", + "parity-scale-codec", + "sp-core 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", + "trie-db 0.20.0", + "trie-root 0.16.0", ] [[package]] @@ -1604,12 +2202,25 @@ version = "2.0.0" source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa835790df63410a29676243fc54#3e651110aa06aa835790df63410a29676243fc54" dependencies = [ "hash-db", - "memory-db", + "memory-db 0.18.1", + "parity-scale-codec", + "sp-core 2.0.0", + "sp-std 2.0.0", + "trie-db 0.18.1", + "trie-root 0.15.2", +] + +[[package]] +name = "sp-version" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f7ded62b3fd6346dc7e96dcfc55f8137653809e09cfa3f0da8052efd35c875" +dependencies = [ + "impl-serde 0.2.3", "parity-scale-codec", - "sp-core", - "sp-std", - "trie-db", - "trie-root", + "serde", + "sp-runtime 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", ] [[package]] @@ -1620,8 +2231,20 @@ dependencies = [ "impl-serde 0.2.3", "parity-scale-codec", "serde", - "sp-runtime", - "sp-std", + "sp-runtime 2.0.0", + "sp-std 2.0.0", +] + +[[package]] +name = "sp-wasm-interface" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9dec817ad8e5eed83a3579da8638703d7559be5da5342312c8effee6a70aa" +dependencies = [ + "impl-trait-for-tuples", + "parity-scale-codec", + "sp-std 2.0.0-alpha.5", + "wasmi", ] [[package]] @@ -1647,7 +2270,19 @@ checksum = "3be511be555a3633e71739a79e4ddff6a6aaa6579fa6114182a51d72c3eb93c5" dependencies = [ "hmac", "pbkdf2", - "schnorrkel", + "schnorrkel 0.8.5", + "sha2", +] + +[[package]] +name = "substrate-bip39" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c004e8166d6e0aa3a9d5fa673e5b7098ff25f930de1013a21341988151e681bb" +dependencies = [ + "hmac", + "pbkdf2", + "schnorrkel 0.9.1", "sha2", ] @@ -1710,6 +2345,22 @@ dependencies = [ "sha2", ] +[[package]] +name = "tiny-bip39" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0165e045cc2ae1660270ca65e1676dbaab60feb0f91b10f7d0665e9b47e31f2" +dependencies = [ + "failure", + "hmac", + "once_cell 1.3.1", + "pbkdf2", + "rand 0.7.3", + "rustc-hash", + "sha2", + "unicode-normalization", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -1758,6 +2409,21 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "treasury" +version = "0.1.0" +dependencies = [ + "frame-support 2.0.0-alpha.5", + "frame-system 2.0.0-alpha.5", + "mocktopus", + "parity-scale-codec", + "safe-mix", + "sp-core 2.0.0-alpha.5", + "sp-io 2.0.0-alpha.5", + "sp-runtime 2.0.0-alpha.5", + "xclaim-core", +] + [[package]] name = "trie-db" version = "0.18.1" @@ -1771,6 +2437,19 @@ dependencies = [ "smallvec 1.2.0", ] +[[package]] +name = "trie-db" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de9222c50cc325855621271157c973da27a0dcd26fa06f8edf81020bd2333df0" +dependencies = [ + "hash-db", + "hashbrown 0.6.3", + "log", + "rustc-hex", + "smallvec 1.2.0", +] + [[package]] name = "trie-root" version = "0.15.2" @@ -1780,6 +2459,15 @@ dependencies = [ "hash-db", ] +[[package]] +name = "trie-root" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "652931506d2c1244d7217a70b99f56718a7b4161b37f04e7cd868072a99f68cd" +dependencies = [ + "hash-db", +] + [[package]] name = "twox-hash" version = "1.5.0" @@ -1807,6 +2495,15 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "unicode-normalization" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" +dependencies = [ + "smallvec 1.2.0", +] + [[package]] name = "unicode-xid" version = "0.2.0" @@ -1868,8 +2565,8 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" name = "xclaim-core" version = "0.1.0" dependencies = [ - "frame-support", - "sp-runtime", + "frame-support 2.0.0", + "sp-runtime 2.0.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 7e8083c47f..50150729cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,6 @@ members = [ "crates/btc-relay", "crates/security", "crates/exchange-rate-oracle", + "crates/treasury", + "crates/collateral", ] From 6e57aa967e65296356f1dadabbe39cc2db55698b Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Mon, 6 Apr 2020 21:19:32 +0900 Subject: [PATCH 16/37] update link to collateral spec --- crates/collateral/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/collateral/Cargo.toml b/crates/collateral/Cargo.toml index e7084223bc..c9ccd1cb39 100644 --- a/crates/collateral/Cargo.toml +++ b/crates/collateral/Cargo.toml @@ -2,7 +2,7 @@ authors = ['Interlay'] description = 'Collateral module' edition = '2018' -homepage = 'https://interlay.gitlab.io/polkabtc-spec/spec/treasury.html' +homepage = 'https://interlay.gitlab.io/polkabtc-spec/spec/collateral.html' name = 'collateral' version = '0.1.0' From 56bcb6e6a604428e84ddf2bbd0bca13f523760aa Mon Sep 17 00:00:00 2001 From: jaupe Date: Mon, 6 Apr 2020 21:03:42 +0100 Subject: [PATCH 17/37] remove build from git --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3af7788708..579af04baf 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ */*/target/* .idea *.vscode +/target/* From fc7ad69e12424aa4f14f34ebcf62c9f995ae9ae5 Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Tue, 7 Apr 2020 16:19:01 +0900 Subject: [PATCH 18/37] adding test WARNING: does not compile --- crates/treasury/Cargo.toml | 7 +++ crates/treasury/src/lib.rs | 27 +++++------ crates/treasury/src/mock.rs | 90 +++++++++++++++++++++++++++++++----- crates/treasury/src/tests.rs | 64 +++++++++++++++++-------- 4 files changed, 144 insertions(+), 44 deletions(-) diff --git a/crates/treasury/Cargo.toml b/crates/treasury/Cargo.toml index 21513cdbe5..e04417d833 100644 --- a/crates/treasury/Cargo.toml +++ b/crates/treasury/Cargo.toml @@ -13,6 +13,7 @@ std = [ 'frame-support/std', 'safe-mix/std', 'system/std', + 'pallet-balances/std', ] [dependencies.codec] @@ -46,8 +47,14 @@ default-features = false package = 'frame-system' version = '2.0.0-alpha.5' +[dependencies.pallet-balances] +default-features = false +package = 'pallet-balances' +version = '2.0.0-alpha.5' + [dependencies.xclaim-core] path = '../xclaim-core' [dev-dependencies] mocktopus = "0.7.0" + diff --git a/crates/treasury/src/lib.rs b/crates/treasury/src/lib.rs index 92637f938e..d99565fc2e 100644 --- a/crates/treasury/src/lib.rs +++ b/crates/treasury/src/lib.rs @@ -20,7 +20,7 @@ use mocktopus::macros::mockable; // Substrate use frame_support::{ - decl_module, decl_storage, decl_event, + decl_module, decl_event, dispatch::DispatchResult, ensure }; use system::ensure_signed; @@ -33,24 +33,22 @@ use xclaim_core::Error; type BalanceOf = <::PolkaBTC as Currency<::AccountId>>::Balance; /// The treasury's module id, used for deriving its sovereign account ID. -const MODULE_ID: ModuleId = ModuleId(*b"ily/trsy"); +const _MODULE_ID: ModuleId = ModuleId(*b"ily/trsy"); /// The pallet's configuration trait. pub trait Trait: system::Trait { /// The PolkaBTC currency type PolkaBTC: Currency + ReservableCurrency; - + /// The overarching event type. type Event: From> + Into<::Event>; } // This pallet's storage items. -decl_storage! { - trait Store for Module as Treasury { - // locked balances - // LockedBalances: map hasher(blake2_128_concat) T::AccountId => T::Currency; - } -} +// decl_storage! { +// trait Store for Module as Treasury { +// } +// } // The pallet's events decl_event!( @@ -86,10 +84,13 @@ decl_module! { { let sender = ensure_signed(origin)?; - T::PolkaBTC::transfer(&sender, &receiver, amount, KeepAlive)?; - - Self::deposit_event(RawEvent::Transfer(sender, receiver, amount)); - Ok(()) + match T::PolkaBTC::transfer(&sender, &receiver, amount, KeepAlive) { + Err(_) => return Err(Error::InsufficientFunds), + _ => { + Self::deposit_event(RawEvent::Transfer(sender, receiver, amount)); + return Ok(()); + } + } } } } diff --git a/crates/treasury/src/mock.rs b/crates/treasury/src/mock.rs index 2ea81ffb45..b1ab1a31fd 100644 --- a/crates/treasury/src/mock.rs +++ b/crates/treasury/src/mock.rs @@ -1,19 +1,38 @@ -// Creating mock runtime here - +/// Mocking the test environment use crate::{Module, Trait}; use sp_core::H256; -use frame_support::{impl_outer_origin, parameter_types, weights::Weight}; +use frame_support::{impl_outer_origin, impl_outer_event, + parameter_types, weights::Weight}; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, testing::Header, Perbill, }; +use pallet_balances as balances; + +use mocktopus::mocking::clear_mocks; impl_outer_origin! { pub enum Origin for Test {} } +mod test_events { + pub use crate::Event; +} + +impl_outer_event! { + pub enum TestEvent for Test { + system, + test_events, + balances, + } +} + // For testing the pallet, we construct most of a mock runtime. This means // first constructing a configuration type (`Test`) which `impl`s each of the // configuration traits of pallets we want to use. + +pub type AccountId = u64; +pub type Balance = u64; + #[derive(Clone, Eq, PartialEq)] pub struct Test; parameter_types! { @@ -29,27 +48,74 @@ impl system::Trait for Test { type BlockNumber = u64; type Hash = H256; type Hashing = BlakeTwo256; - type AccountId = u64; + type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; - type Event = (); + type Event = TestEvent; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; type MaximumBlockLength = MaximumBlockLength; type AvailableBlockRatio = AvailableBlockRatio; type Version = (); type ModuleToIndex = (); - type AccountData = (); + type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); } +parameter_types! { + pub const ExistentialDeposit: u64 = 1; +} +impl pallet_balances::Trait for Test { + type Balance = Balance; + type Event = TestEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; +} + impl Trait for Test { - type Event = (); + type PolkaBTC = Balances; + type Event = TestEvent; +} + +pub type Error = crate::Error; + +pub type System = system::Module; +pub type Balances = pallet_balances::Module; +pub type Treasury = Module; + +pub const ALICE: AccountId = 1; +pub const BOB: AccountId = 2; +pub const ALICE_BALANCE: u64 = 1_000_000; +pub const BOB_BALANCE: u64 = 1_000_000; + +pub struct ExtBuilder; + +impl ExtBuilder { + pub fn build() -> sp_io::TestExternalities { + let mut storage = system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + (ALICE, ALICE_BALANCE), + (BOB, BOB_BALANCE), + ] + } + .assimilate_storage(&mut storage) + .unwrap(); + + storage.into() + + // sp_io::TestExternalities::from(storage) + } } -pub type TemplateModule = Module; -// This function basically just builds a genesis storage key/value store according to -// our desired mockup. -pub fn new_test_ext() -> sp_io::TestExternalities { - system::GenesisConfig::default().build_storage::().unwrap().into() +pub fn run_test(test: T) -> () +where + T: FnOnce() -> (), +{ + clear_mocks(); + ExtBuilder::build().execute_with(test); } diff --git a/crates/treasury/src/tests.rs b/crates/treasury/src/tests.rs index ec123a50c7..52a29b1652 100644 --- a/crates/treasury/src/tests.rs +++ b/crates/treasury/src/tests.rs @@ -1,26 +1,52 @@ -// Tests to be written here +/// Tests for Treasury +use crate::mock::*; +use crate::RawEvent; +use frame_support::{assert_err, assert_ok}; -use crate::{Error, mock::*}; -use frame_support::{assert_ok, assert_noop}; +use mocktopus::mocking::*; #[test] -fn it_works_for_default_value() { - new_test_ext().execute_with(|| { - // Just a dummy test for the dummy function `do_something` - // calling the `do_something` function with a value 42 - assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); - // asserting that the stored value is equal to what we stored - assert_eq!(TemplateModule::something(), Some(42)); - }); +fn test_transfer_succeeds() { + run_test(|| { + let sender = Origin::signed(ALICE); + let receiver = BOB; + let amount: Balance = 3; + + let init_balance_alice = Balances::free_balance(ALICE); + let init_balance_bob = Balances::free_balance(BOB); + + assert_ok!(Treasury::transfer(sender, receiver, amount)); + let transfer_event = TestEvent::test_events( + RawEvent::Transfer(ALICE, BOB, amount)); + + assert!(System::events().iter().any(|a| a.event == transfer_event)); + + let balance_alice = Balances::free_balance(ALICE); + let balance_bob = Balances::free_balance(BOB); + + assert_eq!(balance_alice, init_balance_alice - amount); + assert_eq!(balance_bob, init_balance_bob + amount); + }) } #[test] -fn correct_error_for_none_value() { - new_test_ext().execute_with(|| { - // Ensure the correct error is thrown on None value - assert_noop!( - TemplateModule::cause_error(Origin::signed(1)), - Error::::NoneValue - ); - }); +fn test_transfer_fails() { + run_test(|| { + let sender = Origin::signed(ALICE); + let receiver = BOB; + let amount = ALICE_BALANCE + 10; + + let init_balance_alice = Balances::free_balance(ALICE); + let init_balance_bob = Balances::free_balance(BOB); + + assert_err!(Treasury::transfer(sender, receiver, amount), + Error::InsufficientFunds); + + let balance_alice = Balances::free_balance(ALICE); + let balance_bob = Balances::free_balance(BOB); + + assert_eq!(balance_alice, init_balance_alice); + assert_eq!(balance_bob, init_balance_bob); + }) } + From dfa78993885f66e3d931974316ba93dfd8256260 Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Tue, 7 Apr 2020 17:41:04 +0900 Subject: [PATCH 19/37] bump version to 2.0.0-alpha.5 --- Cargo.lock | 174 +++++++++++++++++++++++++++++++++- crates/treasury/Cargo.toml | 8 ++ crates/treasury/src/lib.rs | 13 ++- crates/xclaim-core/Cargo.toml | 14 +-- 4 files changed, 192 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b3c86b678..c943e9f776 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,6 +28,26 @@ dependencies = [ "memchr", ] +[[package]] +name = "alga" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f823d037a7ec6ea2197046bafd4ae150e6bc36f9ca347404f46a46823fa84f2" +dependencies = [ + "approx", + "num-complex", + "num-traits", +] + +[[package]] +name = "approx" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" +dependencies = [ + "num-traits", +] + [[package]] name = "arrayref" version = "0.3.6" @@ -429,6 +449,23 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "frame-benchmarking" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712481345c6430a3a9a9369871d74e10c8afd64e5191b8d233f43aca5d9df955" +dependencies = [ + "frame-support 2.0.0-alpha.5", + "frame-system 2.0.0-alpha.5", + "linregress", + "parity-scale-codec", + "sp-api 2.0.0-alpha.5", + "sp-io 2.0.0-alpha.5", + "sp-runtime 2.0.0-alpha.5", + "sp-runtime-interface 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", +] + [[package]] name = "frame-metadata" version = "2.0.0" @@ -864,6 +901,12 @@ version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" +[[package]] +name = "libm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" + [[package]] name = "libsecp256k1" version = "0.3.5" @@ -880,6 +923,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "linregress" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9290cf6f928576eeb9c096c6fad9d8d452a0a1a70a2bbffa6e36064eedc0aac9" +dependencies = [ + "failure", + "nalgebra", + "statrs", +] + [[package]] name = "lock_api" version = "0.1.5" @@ -918,6 +972,15 @@ dependencies = [ "synstructure", ] +[[package]] +name = "matrixmultiply" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4f7ec66360130972f34830bfad9ef05c6610a43938a467bcc9ab9369ab3478f" +dependencies = [ + "rawpointer", +] + [[package]] name = "maybe-uninit" version = "2.0.0" @@ -1004,6 +1067,23 @@ dependencies = [ "syn", ] +[[package]] +name = "nalgebra" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaa9fddbc34c8c35dd2108515587b8ce0cab396f17977b8c738568e4edb521a2" +dependencies = [ + "alga", + "approx", + "generic-array", + "matrixmultiply", + "num-complex", + "num-rational", + "num-traits", + "rand 0.6.5", + "typenum", +] + [[package]] name = "node-primitives" version = "2.0.0" @@ -1030,6 +1110,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg 1.0.0", + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.42" @@ -1059,6 +1149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" dependencies = [ "autocfg 1.0.0", + "libm", ] [[package]] @@ -1101,6 +1192,22 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +[[package]] +name = "pallet-balances" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4190f97ea53bebe7a5ae2c089a43e72561d9166968d28d0911eed2cea878d5dd" +dependencies = [ + "frame-benchmarking", + "frame-support 2.0.0-alpha.5", + "frame-system 2.0.0-alpha.5", + "parity-scale-codec", + "serde", + "sp-io 2.0.0-alpha.5", + "sp-runtime 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", +] + [[package]] name = "pallet-timestamp" version = "2.0.0" @@ -1370,6 +1477,19 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" +[[package]] +name = "rand" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "winapi", +] + [[package]] name = "rand" version = "0.6.5" @@ -1517,6 +1637,12 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rdrand" version = "0.4.0" @@ -1718,13 +1844,29 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" +[[package]] +name = "sp-api" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4312c5081652e14f9c87fe6f8c765bbe63ac0ae69daeba48c2e5f7e7b7b25b" +dependencies = [ + "hash-db", + "parity-scale-codec", + "sp-api-proc-macro 2.0.0-alpha.5", + "sp-core 2.0.0-alpha.5", + "sp-runtime 2.0.0-alpha.5", + "sp-state-machine 0.8.0-alpha.5", + "sp-std 2.0.0-alpha.5", + "sp-version 2.0.0-alpha.5", +] + [[package]] name = "sp-api" version = "2.0.0" source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa835790df63410a29676243fc54#3e651110aa06aa835790df63410a29676243fc54" dependencies = [ "parity-scale-codec", - "sp-api-proc-macro", + "sp-api-proc-macro 2.0.0", "sp-core 2.0.0", "sp-runtime 2.0.0", "sp-state-machine 2.0.0", @@ -1732,6 +1874,19 @@ dependencies = [ "sp-version 2.0.0", ] +[[package]] +name = "sp-api-proc-macro" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73a94ac1f228f99fb5279d7983f6bcde83bf1fe5824f9a56e5f7a81cc8a7069c" +dependencies = [ + "blake2-rfc", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sp-api-proc-macro" version = "2.0.0" @@ -2175,7 +2330,7 @@ source = "git+https://github.com/paritytech/substrate.git?rev=3e651110aa06aa8357 dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", - "sp-api", + "sp-api 2.0.0", "sp-inherents 2.0.0", "sp-runtime 2.0.0", "sp-std 2.0.0", @@ -2262,6 +2417,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "statrs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10102ac8d55e35db2b3fafc26f81ba8647da2e15879ab686a67e6d19af2685e8" +dependencies = [ + "rand 0.5.6", +] + [[package]] name = "substrate-bip39" version = "0.3.1" @@ -2416,11 +2580,13 @@ dependencies = [ "frame-support 2.0.0-alpha.5", "frame-system 2.0.0-alpha.5", "mocktopus", + "pallet-balances", "parity-scale-codec", "safe-mix", "sp-core 2.0.0-alpha.5", "sp-io 2.0.0-alpha.5", "sp-runtime 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", "xclaim-core", ] @@ -2565,8 +2731,8 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" name = "xclaim-core" version = "0.1.0" dependencies = [ - "frame-support 2.0.0", - "sp-runtime 2.0.0", + "frame-support 2.0.0-alpha.5", + "sp-runtime 2.0.0-alpha.5", ] [[package]] diff --git a/crates/treasury/Cargo.toml b/crates/treasury/Cargo.toml index e04417d833..13e30bd39d 100644 --- a/crates/treasury/Cargo.toml +++ b/crates/treasury/Cargo.toml @@ -11,8 +11,12 @@ default = ['std'] std = [ 'codec/std', 'frame-support/std', + 'sp-runtime/std', + 'sp-io/std', + 'sp-core/std', 'safe-mix/std', 'system/std', + 'sp-std/std', 'pallet-balances/std', ] @@ -42,6 +46,10 @@ version = '2.0.0-alpha.5' default-features = false version = '2.0.0-alpha.5' +[dependencies.sp-std] +default-features = false +version = '2.0.0-alpha.5' + [dependencies.system] default-features = false package = 'frame-system' diff --git a/crates/treasury/src/lib.rs b/crates/treasury/src/lib.rs index d99565fc2e..c79fe14742 100644 --- a/crates/treasury/src/lib.rs +++ b/crates/treasury/src/lib.rs @@ -84,13 +84,12 @@ decl_module! { { let sender = ensure_signed(origin)?; - match T::PolkaBTC::transfer(&sender, &receiver, amount, KeepAlive) { - Err(_) => return Err(Error::InsufficientFunds), - _ => { - Self::deposit_event(RawEvent::Transfer(sender, receiver, amount)); - return Ok(()); - } - } + T::PolkaBTC::transfer(&sender, &receiver, amount, KeepAlive) + .map_err(|_| Error::InsufficientFunds)?; + + Self::deposit_event(RawEvent::Transfer(sender, receiver, amount)); + + Ok(()) } } } diff --git a/crates/xclaim-core/Cargo.toml b/crates/xclaim-core/Cargo.toml index fb6ef0982f..7656c5e087 100644 --- a/crates/xclaim-core/Cargo.toml +++ b/crates/xclaim-core/Cargo.toml @@ -13,12 +13,14 @@ std = [ [dependencies.sp-runtime] default-features = false -git = 'https://github.com/paritytech/substrate.git' -rev = '3e651110aa06aa835790df63410a29676243fc54' -version = '2.0.0' +version = '2.0.0-alpha.5' +# git = 'https://github.com/paritytech/substrate.git' +# rev = '3e651110aa06aa835790df63410a29676243fc54' +# version = '2.0.0' [dependencies.frame-support] default-features = false -git = 'https://github.com/paritytech/substrate.git' -rev = '3e651110aa06aa835790df63410a29676243fc54' -version = '2.0.0' +version = '2.0.0-alpha.5' +# git = 'https://github.com/paritytech/substrate.git' +# rev = '3e651110aa06aa835790df63410a29676243fc54' +# version = '2.0.0' From c242717a8788ecebbea719d62a6f5651418c2deb Mon Sep 17 00:00:00 2001 From: Daniel Perez Date: Tue, 7 Apr 2020 18:10:40 +0100 Subject: [PATCH 20/37] Fix blockchain structure to avoid loading all blocks --- crates/bitcoin/src/types.rs | 3 -- crates/btc-relay/src/lib.rs | 68 +++++++++++++++++++++-------------- crates/btc-relay/src/tests.rs | 36 ++++++++----------- 3 files changed, 55 insertions(+), 52 deletions(-) diff --git a/crates/bitcoin/src/types.rs b/crates/bitcoin/src/types.rs index fe90242f50..5cfcf26e28 100644 --- a/crates/bitcoin/src/types.rs +++ b/crates/bitcoin/src/types.rs @@ -5,7 +5,6 @@ use crate::utils::*; use codec::{Decode, Encode}; use node_primitives::Moment; use primitive_types::{H256, U256}; -use sp_std::collections::btree_map::BTreeMap; use sp_std::collections::btree_set::BTreeSet; use btc_core::Error; @@ -125,7 +124,6 @@ impl RichBlockHeader { //#[cfg_attr(feature = "std", derive(Debug))] pub struct BlockChain { pub chain_id: u32, - pub chain: BTreeMap, pub start_height: u32, pub max_height: u32, pub no_data: BTreeSet, @@ -214,7 +212,6 @@ impl std::fmt::LowerHex for H256Le { } } - // Bitcoin Script OpCodes pub enum OpCode { OpDup = 0x76, diff --git a/crates/btc-relay/src/lib.rs b/crates/btc-relay/src/lib.rs index 241e4357aa..4478e4cb0d 100644 --- a/crates/btc-relay/src/lib.rs +++ b/crates/btc-relay/src/lib.rs @@ -19,7 +19,6 @@ use mocktopus::macros::mockable; // Substrate use frame_support::{decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure}; use sp_core::{H160, U256}; -use sp_std::collections::btree_map::BTreeMap; use sp_std::collections::btree_set::BTreeSet; use system::ensure_signed; @@ -83,6 +82,9 @@ decl_storage! { /// Store the index for each tracked blockchain ChainsIndex: map u32 => BlockChain; + /// Stores a mapping from (chain_index, block height) to block hash + ChainsHashes: double_map u32, blake2_256(u32) => H256Le; + /// Store the current blockchain tip BestBlock: H256Le; @@ -440,14 +442,15 @@ impl Module { /// Get a block hash from a blockchain /// # Arguments /// - /// * `blockchain`: the blockchian struct to search in + /// * `chain_id`: the id of the blockchain to search in /// * `block_height`: the height if the block header - fn get_block_hash(blockchain: &BlockChain, block_height: u32) -> Result { - match blockchain.chain.get(&block_height) { - Some(hash) => Ok(*hash), - None => Err(Error::MissingBlockHeight), + fn get_block_hash(chain_id: u32, block_height: u32) -> Result { + if !Self::block_exists(chain_id, block_height) { + return Err(Error::MissingBlockHeight); } + Ok(::get(chain_id, block_height)) } + /// Get a block header from its hash fn get_block_header_from_hash(block_hash: H256Le) -> Result { if ::exists(block_hash) { @@ -464,7 +467,7 @@ impl Module { blockchain: &BlockChain, block_height: u32, ) -> Result { - let block_hash = Self::get_block_hash(blockchain, block_height)?; + let block_hash = Self::get_block_hash(blockchain.chain_id, block_height)?; Self::get_block_header_from_hash(block_hash) } /// Storage setter functions @@ -542,19 +545,34 @@ impl Module { /// Generate the raw blockchain from a chain Id and with a single block fn generate_blockchain(chain_id: u32, block_height: u32, block_hash: H256Le) -> BlockChain { // initialize an empty chain - let mut chain = BTreeMap::new(); - chain.insert(block_height, block_hash); + Self::insert_block_hash(chain_id, block_height, block_hash); BlockChain { chain_id, - chain, start_height: block_height, max_height: block_height, no_data: BTreeSet::new(), invalid: BTreeSet::new(), } } + + fn insert_block_hash(chain_id: u32, block_height: u32, block_hash: H256Le) { + ::insert(chain_id, block_height, block_hash); + } + + fn remove_block_hash(chain_id: u32, block_height: u32) { + ::remove(chain_id, block_height); + } + + fn block_exists(chain_id: u32, block_height: u32) -> bool { + ::exists(chain_id, block_height) + } + + fn _blocks_count(chain_id: u32) -> usize { + ::iter_prefix(chain_id).count() + } + /// Add a new block header to an existing blockchain fn extend_blockchain( block_height: u32, @@ -563,9 +581,10 @@ impl Module { ) -> Result { let mut blockchain = prev_blockchain; - if blockchain.chain.insert(block_height, *block_hash).is_some() { + if Self::block_exists(blockchain.chain_id, block_height) { return Err(Error::DuplicateBlock); } + Self::insert_block_hash(blockchain.chain_id, block_height, *block_hash); blockchain.max_height = block_height; @@ -706,9 +725,6 @@ impl Module { // generate a chain id let chain_id = Self::increment_chain_counter(); - // split off the chain - let forked_chain = main_chain.chain.split_off(&start_height); - // maybe split off the no data elements // check if there is a no_data block element // that is greater than start_height @@ -737,24 +753,18 @@ impl Module { // into the forked_main_chain element let forked_main_chain: BlockChain = BlockChain { chain_id, - chain: forked_chain.clone(), start_height, max_height: main_chain.max_height, no_data, invalid, }; - // append the fork to the main chain - main_chain.chain.append(&mut fork.chain.clone()); main_chain.max_height = fork.max_height; main_chain.no_data.append(&mut fork.no_data.clone()); main_chain.invalid.append(&mut fork.invalid.clone()); // get the best block hash - let best_block = match main_chain.chain.get(&main_chain.max_height) { - Some(block) => block, - None => return Err(Error::BlockNotFound), - }; + let best_block = Self::get_block_hash(fork.chain_id, fork.max_height)?; // get the position of the fork in Chains let position: u32 = Self::get_chain_position_from_chain_id(fork.chain_id)?; @@ -763,7 +773,7 @@ impl Module { Self::set_block_chain_from_id(MAIN_CHAIN_ID, &main_chain); // Set BestBlock and BestBlockHeight to the submitted block - Self::set_best_block(*best_block); + Self::set_best_block(best_block); Self::set_best_block_height(main_chain.max_height); // remove the fork from storage @@ -776,17 +786,21 @@ impl Module { // insert the reference to the forked main chain in Chains Self::insert_sorted(&forked_main_chain); - // get an iterator of all forked block headers // update all the forked block headers - for (_height, block) in forked_chain.iter() { - Self::mutate_block_header_from_chain_id(&block, forked_main_chain.chain_id); + for height in fork.start_height..=forked_main_chain.max_height { + let block_hash = Self::get_block_hash(main_chain.chain_id, height)?; + Self::insert_block_hash(forked_main_chain.chain_id, height, block_hash); + Self::mutate_block_header_from_chain_id(&block_hash, forked_main_chain.chain_id); + Self::remove_block_hash(MAIN_CHAIN_ID, height); } - // get an iterator of all new main chain block headers // update all new main chain block headers - for (_height, block) in fork.chain.iter() { + for height in fork.start_height..=fork.max_height { + let block = Self::get_block_hash(fork.chain_id, height)?; Self::mutate_block_header_from_chain_id(&block, MAIN_CHAIN_ID); + Self::insert_block_hash(MAIN_CHAIN_ID, height, block); } + ::remove_prefix(fork.chain_id); Ok(()) } diff --git a/crates/btc-relay/src/tests.rs b/crates/btc-relay/src/tests.rs index 570e9193cf..25a0085ff3 100644 --- a/crates/btc-relay/src/tests.rs +++ b/crates/btc-relay/src/tests.rs @@ -6,7 +6,6 @@ use bitcoin::parser::*; use bitcoin::types::*; use frame_support::{assert_err, assert_ok}; use security::ErrorCode; -use sp_std::collections::btree_map::BTreeMap; use sp_std::collections::btree_set::BTreeSet; use mocktopus::mocking::*; @@ -491,19 +490,14 @@ fn swap_main_blockchain_succeeds() { // swap the main and fork assert_ok!(BTCRelay::swap_main_blockchain(&fork)); - let mut main_chain_map = main.chain.clone(); - for (height, hash) in fork.chain.iter() { - main_chain_map.insert(height.clone(), hash.clone()); - } + // check that the new main chain is correct let new_main = BTCRelay::get_block_chain_from_id(main_chain_ref); assert_eq!(fork_height, new_main.max_height); assert_eq!(main_start, new_main.start_height); assert_eq!(main_chain_ref, new_main.chain_id); - assert_eq!(main_chain_map.len(), new_main.chain.len()); - for (height, _hash) in new_main.chain.iter() { - assert_eq!(main_chain_map.get(height), new_main.chain.get(height)); - } + assert_eq!(fork_height + 1, BTCRelay::_blocks_count(main_chain_ref) as u32); + assert_eq!(main.no_data, new_main.no_data); assert_eq!(main.invalid, new_main.invalid); @@ -516,30 +510,31 @@ fn swap_main_blockchain_succeeds() { assert_eq!(main_height, old_main.max_height); assert_eq!(fork_start, old_main.start_height); assert_eq!(old_main_ref, old_main.chain_id); - assert_eq!(main_height - fork_start + 1, old_main.chain.len() as u32); - for (height, _hash) in old_main.chain.iter() { - assert_eq!(main.chain.get(height), old_main.chain.get(height)); - } + let old_main_length = BTCRelay::_blocks_count(old_main.chain_id); + assert_eq!(main_height - fork_start + 1, old_main_length as u32); + assert_eq!(main.no_data, old_main.no_data); assert_eq!(main.invalid, old_main.invalid); // check that the best block is set assert_eq!( - fork.chain.get(&fork_height), - Some(&BTCRelay::get_best_block()) + BTCRelay::get_block_hash(new_main.chain_id, fork_height).unwrap(), + BTCRelay::get_best_block() ); // check that the best block height is correct assert_eq!(fork_height, BTCRelay::get_best_block_height()); // check that all fork headers are updated - for (_height, hash) in fork.chain.iter() { - let header = BTCRelay::get_block_header_from_hash(hash.clone()).unwrap(); + for height in fork_start..=fork_height { + let block_hash = BTCRelay::get_block_hash(main_chain_ref, height).unwrap(); + let header = BTCRelay::get_block_header_from_hash(block_hash).unwrap(); assert_eq!(header.chain_ref, main_chain_ref); } // check that all main headers are updated - for (_height, hash) in main.chain.iter().skip(fork_start as usize) { - let header = BTCRelay::get_block_header_from_hash(hash.clone()).unwrap(); + for height in fork_start..=main_height { + let block_hash = BTCRelay::get_block_hash(old_main_ref, height).unwrap(); + let header = BTCRelay::get_block_header_from_hash(block_hash).unwrap(); assert_eq!(header.chain_ref, old_main_ref); } }) @@ -1423,11 +1418,8 @@ fn get_empty_block_chain_from_chain_id_and_height( start_height: u32, block_height: u32, ) -> BlockChain { - let chain = BTreeMap::new(); - let blockchain = BlockChain { chain_id: chain_id, - chain: chain, start_height: start_height, max_height: block_height, no_data: BTreeSet::new(), From eb57497c933889f6f4cff5fc0103cb0424a2cf76 Mon Sep 17 00:00:00 2001 From: Daniel Perez Date: Tue, 7 Apr 2020 18:35:40 +0100 Subject: [PATCH 21/37] Add editor configuration and enforce formattiong --- .editorconfig | 17 ++ .gitignore | 1 - .gitlab-ci.yml | 35 +-- .vscode/settings.json | 6 + crates/bitcoin/examples/parse-transaction.rs | 5 +- crates/bitcoin/src/merkle.rs | 3 +- crates/bitcoin/src/parser.rs | 1 - crates/bitcoin/src/types.rs | 1 - crates/btc-relay/src/tests.rs | 16 +- crates/exchange-rate-oracle/src/mock.rs | 2 +- crates/security/src/lib.rs | 266 +++++++++---------- crates/security/src/tests.rs | 63 ++--- 12 files changed, 220 insertions(+), 196 deletions(-) create mode 100644 .editorconfig create mode 100644 .vscode/settings.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..479bca0f81 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*] +end_of_line = lf +charset = utf-8 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.rs] +indent_size = 4 + +[*.toml] +indent_size = 2 + +[*.{yml,yaml}] +indent_size = 4 diff --git a/.gitignore b/.gitignore index 5d3d9792ce..5a0fcbbb10 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,5 @@ ### Editors ### .idea -*.vscode /target/* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 49189f3f1d..1a1adc037f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,15 +4,15 @@ image: "rust:latest" # Install a C compiler, cmake and git into the container. before_script: - - apt-get -y update - - apt-get install -y build-essential cmake pkg-config libssl-dev clang libclang-dev llvm - - rustc --version && cargo --version # Print version info for debugging + - apt-get -y update + - apt-get install -y build-essential cmake pkg-config libssl-dev clang libclang-dev llvm + - rustc --version && cargo --version # Print version info for debugging # Declare stages stages: - - build # for crates and pallets - - test # for tests in dev - - deploy # for deployment in master + - build # for crates and pallets + - test # for tests in dev + - deploy # for deployment in master # # master branch # btc-parachain-test: @@ -58,14 +58,15 @@ stages: # pallets and crates test-pallets-and-crates: - stage: test - image: rustlang/rust:nightly - script: - - cargo build --release --verbose - - cargo test --all --release - cache: - key: build-cache - paths: - - target - only: - - merge_requests + stage: test + image: rustlang/rust:nightly + script: + - cargo build --release --verbose + - cargo fmt -- --check + - cargo test --all --release + cache: + key: build-cache + paths: + - target + only: + - merge_requests diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..e153e3a12c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "editor.formatOnSave": true, + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust" + } +} diff --git a/crates/bitcoin/examples/parse-transaction.rs b/crates/bitcoin/examples/parse-transaction.rs index 5694e0e8de..92e15521f4 100644 --- a/crates/bitcoin/examples/parse-transaction.rs +++ b/crates/bitcoin/examples/parse-transaction.rs @@ -8,7 +8,10 @@ use bitcoin::parser::parse_transaction; fn main() { let raw_tx = hex::decode(RAW_TRANSACTION).unwrap(); let tx = parse_transaction(&raw_tx).unwrap(); - println!("height {}", hex::encode(&tx.inputs[0].height.as_ref().unwrap())); + println!( + "height {}", + hex::encode(&tx.inputs[0].height.as_ref().unwrap()) + ); println!("ouptut 1 script {}", hex::encode(&tx.outputs[0].script)); println!("ouptut 2 script {}", hex::encode(&tx.outputs[1].script)); } diff --git a/crates/bitcoin/src/merkle.rs b/crates/bitcoin/src/merkle.rs index e4376bc576..0ec22ba0fd 100644 --- a/crates/bitcoin/src/merkle.rs +++ b/crates/bitcoin/src/merkle.rs @@ -6,10 +6,9 @@ use mocktopus::macros::mockable; use btc_core::Error; use crate::parser::BytesParser; -use crate::types::{BlockHeader, H256Le, CompactUint}; +use crate::types::{BlockHeader, CompactUint, H256Le}; use crate::utils::hash256_merkle_step; - /// Values taken from https://github.com/bitcoin/bitcoin/blob/78dae8caccd82cfbfd76557f1fb7d7557c7b5edb/src/consensus/consensus.h const MAX_BLOCK_WEIGHT: u32 = 4_000_000; const WITNESS_SCALE_FACTOR: u32 = 4; diff --git a/crates/bitcoin/src/parser.rs b/crates/bitcoin/src/parser.rs index 8c7d31bed8..a7e173e5a3 100644 --- a/crates/bitcoin/src/parser.rs +++ b/crates/bitcoin/src/parser.rs @@ -7,7 +7,6 @@ extern crate mocktopus; #[cfg(test)] use mocktopus::macros::mockable; - use btc_core::Error; const SERIALIZE_TRANSACTION_NO_WITNESS: i32 = 0x4000_0000; diff --git a/crates/bitcoin/src/types.rs b/crates/bitcoin/src/types.rs index fe90242f50..d5513464d1 100644 --- a/crates/bitcoin/src/types.rs +++ b/crates/bitcoin/src/types.rs @@ -214,7 +214,6 @@ impl std::fmt::LowerHex for H256Le { } } - // Bitcoin Script OpCodes pub enum OpCode { OpDup = 0x76, diff --git a/crates/btc-relay/src/tests.rs b/crates/btc-relay/src/tests.rs index 570e9193cf..3a28d0517c 100644 --- a/crates/btc-relay/src/tests.rs +++ b/crates/btc-relay/src/tests.rs @@ -582,7 +582,8 @@ fn test_verify_block_header_correct_retarget_increase_succeeds() { retarget_headers[1], chain_ref, block_height, - ).unwrap(); + ) + .unwrap(); let curr_block_header = BlockHeader::from_le_bytes(&retarget_headers[2]).unwrap(); // Prev block exists @@ -612,7 +613,8 @@ fn test_verify_block_header_correct_retarget_decrease_succeeds() { retarget_headers[1], chain_ref, block_height, - ).unwrap(); + ) + .unwrap(); let curr_block_header = BlockHeader::from_le_bytes(&retarget_headers[2]).unwrap(); // Prev block exists @@ -641,7 +643,8 @@ fn test_verify_block_header_missing_retarget_succeeds() { retarget_headers[1], chain_ref, block_height, - ).unwrap(); + ) + .unwrap(); let curr_block_header = BlockHeader::from_le_bytes(&retarget_headers[2]).unwrap(); // Prev block exists @@ -667,9 +670,12 @@ fn test_compute_new_target() { let block_height: u32 = 2016; let retarget_headers = sample_retarget_interval_increase(); - let last_retarget_time = BlockHeader::from_le_bytes(&retarget_headers[0]).unwrap().timestamp; + let last_retarget_time = BlockHeader::from_le_bytes(&retarget_headers[0]) + .unwrap() + .timestamp; let prev_block_header = - RichBlockHeader::construct_rich_block_header(retarget_headers[1], chain_ref, block_height).unwrap(); + RichBlockHeader::construct_rich_block_header(retarget_headers[1], chain_ref, block_height) + .unwrap(); let curr_block_header = BlockHeader::from_le_bytes(&retarget_headers[2]).unwrap(); diff --git a/crates/exchange-rate-oracle/src/mock.rs b/crates/exchange-rate-oracle/src/mock.rs index e52d99d0b0..2e1a603c7d 100644 --- a/crates/exchange-rate-oracle/src/mock.rs +++ b/crates/exchange-rate-oracle/src/mock.rs @@ -1,13 +1,13 @@ /// Mocking the test environment use crate::{Module, Trait}; use frame_support::{impl_outer_event, impl_outer_origin, parameter_types, weights::Weight}; +use mocktopus::mocking::clear_mocks; use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, Perbill, }; -use mocktopus::mocking::clear_mocks; impl_outer_origin! { pub enum Origin for Test {} diff --git a/crates/security/src/lib.rs b/crates/security/src/lib.rs index 2995cf4afc..ae5c948eef 100644 --- a/crates/security/src/lib.rs +++ b/crates/security/src/lib.rs @@ -20,12 +20,12 @@ use bitcoin::types::*; /// ## Configuration /// The pallet's configuration trait. pub trait Trait: system::Trait { - /// The overarching event type. - type Event: From + Into<::Event>; + /// The overarching event type. + type Event: From + Into<::Event>; - // Dot currency - // FIXME: Check if correct. DOT currently emulated, until DOT bridge becomes available - // type DotBalance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + MaybeSerializeDeserialize + Debug + From; + // Dot currency + // FIXME: Check if correct. DOT currently emulated, until DOT bridge becomes available + // type DotBalance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + MaybeSerializeDeserialize + Debug + From; } /// ## Constants @@ -40,54 +40,54 @@ pub const STAKED_RELAYER_STAKE: u64 = 10; #[derive(Encode, Decode, Clone, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] pub enum StatusCode { - /// BTC Parachain is fully operational - Running = 0, - /// An error has occurred. See Errors for more details. - Error = 1, - /// BTC Parachain operation has been fully suspended - Shutdown = 2, + /// BTC Parachain is fully operational + Running = 0, + /// An error has occurred. See Errors for more details. + Error = 1, + /// BTC Parachain operation has been fully suspended + Shutdown = 2, } impl Default for StatusCode { - fn default() -> Self { - StatusCode::Running - } + fn default() -> Self { + StatusCode::Running + } } /// Enum specifying errors which lead to the Error status, tacked in Errors #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)] pub enum ErrorCode { - /// No error. Used as default value - None = 0, - /// Missing transactional data for a block header submitted to BTC-Relay - NoDataBTCRelay = 1, - /// Invalid transaction was detected in a block header submitted to BTC-Relay - InvalidBTCRelay = 2, - /// The exchangeRateOracle experienced a liveness failure (no up-to-date exchange rate available) - OracleOffline = 3, - /// At least one Vault is being liquidated. Redeem requests paid out partially in collateral (DOT). - Liquidation = 4, + /// No error. Used as default value + None = 0, + /// Missing transactional data for a block header submitted to BTC-Relay + NoDataBTCRelay = 1, + /// Invalid transaction was detected in a block header submitted to BTC-Relay + InvalidBTCRelay = 2, + /// The exchangeRateOracle experienced a liveness failure (no up-to-date exchange rate available) + OracleOffline = 3, + /// At least one Vault is being liquidated. Redeem requests paid out partially in collateral (DOT). + Liquidation = 4, } impl Default for ErrorCode { - fn default() -> Self { - ErrorCode::None - } + fn default() -> Self { + ErrorCode::None + } } // Indicates the state of a proposed StatusUpdate. #[derive(Encode, Decode, Clone, PartialEq)] #[cfg_attr(feature = "std", derive(Debug))] pub enum ProposalStatus { - /// StatusUpdate is current under review and is being voted upon - Pending = 0, - /// StatusUpdate has been accepted - Accepted = 1, - /// StatusUpdate has been rejected - Rejected = 2, + /// StatusUpdate is current under review and is being voted upon + Pending = 0, + /// StatusUpdate has been accepted + Accepted = 1, + /// StatusUpdate has been rejected + Rejected = 2, } impl Default for ProposalStatus { - fn default() -> Self { - ProposalStatus::Pending - } + fn default() -> Self { + ProposalStatus::Pending + } } /// ## Structs @@ -95,131 +95,131 @@ impl Default for ProposalStatus { #[derive(Encode, Decode, Default, Clone, PartialEq)] #[cfg_attr(feature = "std", derive(Debug))] pub struct StatusUpdate { - /// New status of the BTC Parachain. - new_status_code: StatusCode, - /// Previous status of the BTC Parachain. - old_status_code: StatusCode, - /// If new_status_code is Error, specifies which errors are to be added to Errors - // FIXME: will need casting to ErrorCode enum - add_errors: BTreeSet, - /// Indicates which ErrorCode entries are to be removed from Errors (recovery). - // FIXME: will need casting to ErrorCode enum - remove_errors: BTreeSet, - /// Parachain block number at which this status update was suggested. - time: BlockNumber, - /// Status of the proposed status update. See ProposalStatus. - proposal_status: ProposalStatus, - /// Message providing more details on the change of status (detailed error message or recovery reason). - msg: String, - /// LE Block hash of the Bitcoin block where the error was detected, if related to BTC-Relay. - btc_block_hash: H256Le, - /// Set of accounts which have voted FOR this status update. This can be either Staked Relayers or the Governance Mechanism. - votes_yes: BTreeSet, - /// Set of accounts which have voted AGAINST this status update. This can be either Staked Relayers or the Governance Mechanism. - votes_no: BTreeSet, + /// New status of the BTC Parachain. + new_status_code: StatusCode, + /// Previous status of the BTC Parachain. + old_status_code: StatusCode, + /// If new_status_code is Error, specifies which errors are to be added to Errors + // FIXME: will need casting to ErrorCode enum + add_errors: BTreeSet, + /// Indicates which ErrorCode entries are to be removed from Errors (recovery). + // FIXME: will need casting to ErrorCode enum + remove_errors: BTreeSet, + /// Parachain block number at which this status update was suggested. + time: BlockNumber, + /// Status of the proposed status update. See ProposalStatus. + proposal_status: ProposalStatus, + /// Message providing more details on the change of status (detailed error message or recovery reason). + msg: String, + /// LE Block hash of the Bitcoin block where the error was detected, if related to BTC-Relay. + btc_block_hash: H256Le, + /// Set of accounts which have voted FOR this status update. This can be either Staked Relayers or the Governance Mechanism. + votes_yes: BTreeSet, + /// Set of accounts which have voted AGAINST this status update. This can be either Staked Relayers or the Governance Mechanism. + votes_no: BTreeSet, } #[derive(Encode, Decode, Default, Clone, PartialEq)] #[cfg_attr(feature = "std", derive(Debug))] pub struct StakedRelayer { - stake: u64, + stake: u64, } // This pallet's storage items. decl_storage! { - trait Store for Module as SecurityModule { + trait Store for Module as SecurityModule { - /// Integer/Enum defining the current state of the BTC-Parachain - ParachainStatus get(parachain_status): StatusCode; + /// Integer/Enum defining the current state of the BTC-Parachain + ParachainStatus get(parachain_status): StatusCode; - /// Set of ErrorCodes, indicating the reason for an "Error" ParachainStatus - /// FIXME: type casting to enum necessary! - Errors get(fn error): BTreeSet; + /// Set of ErrorCodes, indicating the reason for an "Error" ParachainStatus + /// FIXME: type casting to enum necessary! + Errors get(fn error): BTreeSet; - /// Integer increment-only counter used to track status updates. - StatusCounter get(fn status_counter): U256; + /// Integer increment-only counter used to track status updates. + StatusCounter get(fn status_counter): U256; - /// Integer increment-only counter, used to prevent collisions when generating identifiers - /// for e.g. issue, redeem or replace requests (for OP_RETURN field in Bitcoin). - Nonce get(fn nonce): U256; + /// Integer increment-only counter, used to prevent collisions when generating identifiers + /// for e.g. issue, redeem or replace requests (for OP_RETURN field in Bitcoin). + Nonce get(fn nonce): U256; - /// Mapping from accounts of staked relayers to the StakedRelayer struct - StakedRelayers get(fn staked_relayer): map T::AccountId => StakedRelayer; + /// Mapping from accounts of staked relayers to the StakedRelayer struct + StakedRelayers get(fn staked_relayer): map T::AccountId => StakedRelayer; - /// Map of StatusUpdates, identified by an integer key - StatusUpdates get(fn status_update): map U256 => StatusUpdate; + /// Map of StatusUpdates, identified by an integer key + StatusUpdates get(fn status_update): map U256 => StatusUpdate; - /// Mapping of Bitcoin transaction identifiers (SHA256 hashes) to account - /// identifiers of Vaults accused of theft - TheftReports get(fn theft_report): map H256Le => BTreeSet; - } + /// Mapping of Bitcoin transaction identifiers (SHA256 hashes) to account + /// identifiers of Vaults accused of theft + TheftReports get(fn theft_report): map H256Le => BTreeSet; + } } // The pallet's dispatchable functions. decl_module! { - pub struct Module for enum Call where origin: T::Origin { + pub struct Module for enum Call where origin: T::Origin { - } + } } impl Module { - /// Checks if the ParachainStatus matches the provided StatusCode - /// - /// # Arguments - /// - /// * `status_code` - to-be-checked StatusCode enum - pub fn check_parachain_status(status_code: StatusCode) -> bool { - status_code == ::get() - } - - /// Checks if the given ErrorCode is contains in Errors - /// - /// # Arguments - /// - /// * `error_code` - to-be-checked ErrorCode enum - pub fn check_parachain_error(error_code: ErrorCode) -> bool { - ::get().contains(&(error_code as u8)) - } - /// Checks if a staked relayer is registered - /// - /// # Arguments - /// - /// * `relayer` - account id of the relayer - pub fn check_relayer_registered(relayer: T::AccountId) -> bool { - >::exists(relayer) - } + /// Checks if the ParachainStatus matches the provided StatusCode + /// + /// # Arguments + /// + /// * `status_code` - to-be-checked StatusCode enum + pub fn check_parachain_status(status_code: StatusCode) -> bool { + status_code == ::get() + } + + /// Checks if the given ErrorCode is contains in Errors + /// + /// # Arguments + /// + /// * `error_code` - to-be-checked ErrorCode enum + pub fn check_parachain_error(error_code: ErrorCode) -> bool { + ::get().contains(&(error_code as u8)) + } + /// Checks if a staked relayer is registered + /// + /// # Arguments + /// + /// * `relayer` - account id of the relayer + pub fn check_relayer_registered(relayer: T::AccountId) -> bool { + >::exists(relayer) + } } decl_event!( - pub enum Event { - RegisterStakedRelayer(AccountId, u64), - DeRegisterStakedRelayer(AccountId), - StatusUpdateSuggested(u8, BTreeSet, BTreeSet, String, AccountId), - VoteOnStatusUpdate(U256, AccountId, bool), - ExecuteStatusUpdate(u8, BTreeSet, BTreeSet, String), - RejectStatusUpdate(u8, BTreeSet, BTreeSet, String), - ForceStatusUpdate(u8, BTreeSet, BTreeSet, String), - SlashStakedRelayer(AccountId), - ReportVaultTheft(AccountId), - } + pub enum Event { + RegisterStakedRelayer(AccountId, u64), + DeRegisterStakedRelayer(AccountId), + StatusUpdateSuggested(u8, BTreeSet, BTreeSet, String, AccountId), + VoteOnStatusUpdate(U256, AccountId, bool), + ExecuteStatusUpdate(u8, BTreeSet, BTreeSet, String), + RejectStatusUpdate(u8, BTreeSet, BTreeSet, String), + ForceStatusUpdate(u8, BTreeSet, BTreeSet, String), + SlashStakedRelayer(AccountId), + ReportVaultTheft(AccountId), + } ); decl_error! { - pub enum Error for Module { - AlreadyRegistered, - InsufficientStake, - NotRegistered, - GovernanceOnly, - StakedRelayersOnly, - StatusUpdateNotFound, - InsufficientYesVotes, - InsufficientNoVotes, - VaultAlreadyReported, - VaultNotFound, - VaultAlreadyLiquidated, - ValidRedeemOrReplace, - ValidMergeTransaction, - CollateralOk, - OracleOnline - } + pub enum Error for Module { + AlreadyRegistered, + InsufficientStake, + NotRegistered, + GovernanceOnly, + StakedRelayersOnly, + StatusUpdateNotFound, + InsufficientYesVotes, + InsufficientNoVotes, + VaultAlreadyReported, + VaultNotFound, + VaultAlreadyLiquidated, + ValidRedeemOrReplace, + ValidMergeTransaction, + CollateralOk, + OracleOnline + } } diff --git a/crates/security/src/tests.rs b/crates/security/src/tests.rs index 5640e6352a..ea0b68af28 100644 --- a/crates/security/src/tests.rs +++ b/crates/security/src/tests.rs @@ -1,14 +1,15 @@ /// Tests for Security Module - -use crate::{Trait}; -use sp_core::{H256}; -use frame_support::{impl_outer_origin, impl_outer_event, parameter_types, weights::Weight}; +use crate::Trait; +use frame_support::{impl_outer_event, impl_outer_origin, parameter_types, weights::Weight}; +use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, testing::Header, Perbill, + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, }; impl_outer_origin! { - pub enum Origin for Test {} + pub enum Origin for Test {} } mod test_events { @@ -27,32 +28,32 @@ impl_outer_event! { #[derive(Clone, Eq, PartialEq)] pub struct Test; parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: Weight = 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); } impl system::Trait for Test { - type Origin = Origin; - type Call = (); - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = TestEvent; - type BlockHashCount = BlockHashCount; - type MaximumBlockWeight = MaximumBlockWeight; - type MaximumBlockLength = MaximumBlockLength; - type AvailableBlockRatio = AvailableBlockRatio; - type Version = (); - type ModuleToIndex = (); + type Origin = Origin; + type Call = (); + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = TestEvent; + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + type ModuleToIndex = (); } impl Trait for Test { - type Event = TestEvent; + type Event = TestEvent; } // pub type System = system::Module; @@ -69,19 +70,13 @@ impl ExtBuilder { } } - // fn ExtBuilder::build() -> sp_io::TestExternalities { // system::GenesisConfig::default().build_storage::().unwrap().into() // } - /// Initialize Function #[test] fn dummy_test() { - ExtBuilder::build().execute_with(|| { - }); + ExtBuilder::build().execute_with(|| {}); } - - - From b8969d28c351290ff956e1ebcf2859a06133318a Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Wed, 8 Apr 2020 14:30:21 +0900 Subject: [PATCH 22/37] bump oracle to 2.0.0-alpha5 --- crates/exchange-rate-oracle/Cargo.toml | 24 ++++++------------------ crates/exchange-rate-oracle/src/mock.rs | 4 ++++ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/crates/exchange-rate-oracle/Cargo.toml b/crates/exchange-rate-oracle/Cargo.toml index dc4df5debb..edd971e6af 100644 --- a/crates/exchange-rate-oracle/Cargo.toml +++ b/crates/exchange-rate-oracle/Cargo.toml @@ -24,41 +24,29 @@ version = '1.0.0' [dependencies.sp-runtime] default-features = false -git = 'https://github.com/paritytech/substrate.git' -rev = '3e651110aa06aa835790df63410a29676243fc54' -version = '2.0.0' +version = '2.0.0-alpha.5' [dependencies.frame-support] default-features = false -git = 'https://github.com/paritytech/substrate.git' -rev = '3e651110aa06aa835790df63410a29676243fc54' -version = '2.0.0' +version = '2.0.0-alpha.5' [dependencies.system] default-features = false -git = 'https://github.com/paritytech/substrate.git' package = 'frame-system' -rev = '3e651110aa06aa835790df63410a29676243fc54' -version = '2.0.0' +version = '2.0.0-alpha.5' [dependencies.sp-io] default-features = false -git = 'https://github.com/paritytech/substrate.git' -rev = '3e651110aa06aa835790df63410a29676243fc54' -version = '2.0.0' +version = '2.0.0-alpha.5' [dependencies.sp-core] default-features = false -git = 'https://github.com/paritytech/substrate.git' -rev = '3e651110aa06aa835790df63410a29676243fc54' -version = '2.0.0' +version = '2.0.0-alpha.5' [dependencies.timestamp] default-features = false -git = 'https://github.com/paritytech/substrate.git' package = 'pallet-timestamp' -rev = '3e651110aa06aa835790df63410a29676243fc54' -version = '2.0.0' +version = '2.0.0-alpha.5' [dependencies.xclaim-core] path = '../xclaim-core' diff --git a/crates/exchange-rate-oracle/src/mock.rs b/crates/exchange-rate-oracle/src/mock.rs index e52d99d0b0..d24a376c2c 100644 --- a/crates/exchange-rate-oracle/src/mock.rs +++ b/crates/exchange-rate-oracle/src/mock.rs @@ -19,6 +19,7 @@ mod test_events { impl_outer_event! { pub enum TestEvent for Test { + system, test_events, } } @@ -51,6 +52,9 @@ impl system::Trait for Test { type AvailableBlockRatio = AvailableBlockRatio; type Version = (); type ModuleToIndex = (); + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); } impl Trait for Test { From 3d0216d563c57eeb70fa90ab429376355d570aa5 Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Wed, 8 Apr 2020 14:32:23 +0900 Subject: [PATCH 23/37] deny warnings --- crates/treasury/Cargo.toml | 3 +-- crates/treasury/src/lib.rs | 6 +++--- crates/treasury/src/tests.rs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/treasury/Cargo.toml b/crates/treasury/Cargo.toml index 13e30bd39d..a582c2c9bf 100644 --- a/crates/treasury/Cargo.toml +++ b/crates/treasury/Cargo.toml @@ -2,7 +2,6 @@ authors = ['Interlay'] description = 'Treasury module' edition = '2018' -homepage = 'https://interlay.gitlab.io/polkabtc-spec/spec/treasury.html' name = 'treasury' version = '0.1.0' @@ -24,7 +23,7 @@ std = [ default-features = false features = ['derive'] package = 'parity-scale-codec' -version = '1.0.0' +version = '1.3.0' [dependencies.frame-support] default-features = false diff --git a/crates/treasury/src/lib.rs b/crates/treasury/src/lib.rs index c79fe14742..5ae264db87 100644 --- a/crates/treasury/src/lib.rs +++ b/crates/treasury/src/lib.rs @@ -1,4 +1,4 @@ -// #![deny(warnings)] +#![deny(warnings)] #![cfg_attr(test, feature(proc_macro_hygiene))] #![cfg_attr(not(feature = "std"), no_std)] #[cfg(test)] @@ -10,8 +10,8 @@ mod tests; #[cfg(test)] extern crate mocktopus; -#[cfg(test)] -use mocktopus::macros::mockable; +// #[cfg(test)] +// use mocktopus::macros::mockable; /// # PolkaBTC Treasury implementation /// The Treasury module according to the specification at diff --git a/crates/treasury/src/tests.rs b/crates/treasury/src/tests.rs index 52a29b1652..93b769d17b 100644 --- a/crates/treasury/src/tests.rs +++ b/crates/treasury/src/tests.rs @@ -3,7 +3,7 @@ use crate::mock::*; use crate::RawEvent; use frame_support::{assert_err, assert_ok}; -use mocktopus::mocking::*; +// use mocktopus::mocking::*; #[test] fn test_transfer_succeeds() { From 08029ceea73b1904815f19fe58b29044fe9ade7f Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Wed, 8 Apr 2020 14:32:57 +0900 Subject: [PATCH 24/37] bump xlcaim-core to 2.0.0-alpha5 --- Cargo.lock | 164 ++++++++++++++++++++++++++++++++-- crates/xclaim-core/Cargo.toml | 6 -- 2 files changed, 155 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c943e9f776..913e8cc6e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -198,7 +198,7 @@ dependencies = [ "indexmap", "mocktopus", "node-primitives", - "pallet-timestamp", + "pallet-timestamp 2.0.0", "parity-scale-codec", "security", "serde", @@ -208,6 +208,12 @@ dependencies = [ "sp-std 2.0.0", ] +[[package]] +name = "bumpalo" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" + [[package]] name = "byte-slice-cast" version = "0.3.5" @@ -385,14 +391,14 @@ checksum = "516aa8d7a71cb00a1c4146f0798549b93d083d4f189b3ced8f3de6b8f11ee6c4" name = "exchange-rate-oracle" version = "0.0.1" dependencies = [ - "frame-support 2.0.0", - "frame-system 2.0.0", + "frame-support 2.0.0-alpha.5", + "frame-system 2.0.0-alpha.5", "mocktopus", - "pallet-timestamp", + "pallet-timestamp 2.0.0-alpha.5", "parity-scale-codec", - "sp-core 2.0.0", - "sp-io 2.0.0", - "sp-runtime 2.0.0", + "sp-core 2.0.0-alpha.5", + "sp-io 2.0.0-alpha.5", + "sp-runtime 2.0.0-alpha.5", "xclaim-core", ] @@ -883,6 +889,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f65877bf7d44897a473350b1046277941cee20b263397e90869c50b6e766088b" +[[package]] +name = "js-sys" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a27d435371a2fa5b6d2b028a74bbdb1234f308da363226a2854ca3ff8ba7055" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "keccak" version = "0.1.0" @@ -1208,6 +1223,24 @@ dependencies = [ "sp-std 2.0.0-alpha.5", ] +[[package]] +name = "pallet-timestamp" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec68fe57dc24af2869f5447f406de1de4dc105b11fbab59ae94f580cd2787aa" +dependencies = [ + "frame-benchmarking", + "frame-support 2.0.0-alpha.5", + "frame-system 2.0.0-alpha.5", + "impl-trait-for-tuples", + "parity-scale-codec", + "serde", + "sp-inherents 2.0.0-alpha.5", + "sp-runtime 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", + "sp-timestamp 2.0.0-alpha.5", +] + [[package]] name = "pallet-timestamp" version = "2.0.0" @@ -1221,7 +1254,7 @@ dependencies = [ "sp-inherents 2.0.0", "sp-runtime 2.0.0", "sp-std 2.0.0", - "sp-timestamp", + "sp-timestamp 2.0.0", ] [[package]] @@ -1767,7 +1800,7 @@ dependencies = [ "frame-support 2.0.0", "frame-system 2.0.0", "node-primitives", - "pallet-timestamp", + "pallet-timestamp 2.0.0", "parity-scale-codec", "serde", "sp-core 2.0.0", @@ -1791,6 +1824,12 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "send_wrapper" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4" + [[package]] name = "serde" version = "1.0.105" @@ -2323,6 +2362,21 @@ dependencies = [ "sp-std 2.0.0", ] +[[package]] +name = "sp-timestamp" +version = "2.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990bc28e4e7fd31a13f5e61fd30ef0aa3ba5747b64ab3560df5285abbd879f6c" +dependencies = [ + "impl-trait-for-tuples", + "parity-scale-codec", + "sp-api 2.0.0-alpha.5", + "sp-inherents 2.0.0-alpha.5", + "sp-runtime 2.0.0-alpha.5", + "sp-std 2.0.0-alpha.5", + "wasm-timer", +] + [[package]] name = "sp-timestamp" version = "2.0.0" @@ -2682,6 +2736,88 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasm-bindgen" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc57ce05287f8376e998cbddfb4c8cb43b84a7ec55cf4551d7c00eef317a47f" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967d37bf6c16cca2973ca3af071d0a2523392e4a594548155d89a678f4237cd" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7add542ea1ac7fdaa9dc25e031a6af33b7d63376292bd24140c637d00d1c312a" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd151b63e1ea881bb742cd20e1d6127cef28399558f3b5d415289bc41eee3a4" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf76fe7d25ac79748a37538b7daeed1c7a6867c92d3245c12c6222e4a20d639" + +[[package]] +name = "wasm-timer" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "324c5e65a08699c9c4334ba136597ab22b85dccd4b65dd1e36ccf8f723a95b54" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.9.0", + "pin-utils", + "send_wrapper", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wasmi" version = "0.6.2" @@ -2705,6 +2841,16 @@ dependencies = [ "parity-wasm", ] +[[package]] +name = "web-sys" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6f51648d8c56c366144378a33290049eafdd784071077f6fe37dae64c1c4cb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.8" diff --git a/crates/xclaim-core/Cargo.toml b/crates/xclaim-core/Cargo.toml index 7656c5e087..0ecd7c7547 100644 --- a/crates/xclaim-core/Cargo.toml +++ b/crates/xclaim-core/Cargo.toml @@ -14,13 +14,7 @@ std = [ [dependencies.sp-runtime] default-features = false version = '2.0.0-alpha.5' -# git = 'https://github.com/paritytech/substrate.git' -# rev = '3e651110aa06aa835790df63410a29676243fc54' -# version = '2.0.0' [dependencies.frame-support] default-features = false version = '2.0.0-alpha.5' -# git = 'https://github.com/paritytech/substrate.git' -# rev = '3e651110aa06aa835790df63410a29676243fc54' -# version = '2.0.0' From 8e1d4a87f40d5540e92b8dab146897cf6e54c61b Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Wed, 8 Apr 2020 15:08:11 +0900 Subject: [PATCH 25/37] rustfmt --- crates/btc-relay/src/lib.rs | 259 +++++++++++------------- crates/btc-relay/src/tests.rs | 16 +- crates/collateral/src/lib.rs | 144 ++++++------- crates/collateral/src/mock.rs | 61 +++--- crates/collateral/src/tests.rs | 32 +-- crates/exchange-rate-oracle/src/mock.rs | 8 +- crates/treasury/src/lib.rs | 85 ++++---- crates/treasury/src/mock.rs | 68 +++---- crates/treasury/src/tests.rs | 22 +- crates/xclaim-core/src/lib.rs | 9 +- 10 files changed, 342 insertions(+), 362 deletions(-) diff --git a/crates/btc-relay/src/lib.rs b/crates/btc-relay/src/lib.rs index e44618abb5..abf88f3051 100644 --- a/crates/btc-relay/src/lib.rs +++ b/crates/btc-relay/src/lib.rs @@ -16,11 +16,8 @@ use mocktopus::macros::mockable; /// # BTC-Relay implementation /// This is the implementation of the BTC-Relay following the spec at: /// https://interlay.gitlab.io/polkabtc-spec/btcrelay-spec/ - // Substrate -use frame_support::{ - decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure -}; +use frame_support::{decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure}; use sp_core::{H160, U256}; use sp_std::collections::btree_map::BTreeMap; use sp_std::collections::btree_set::BTreeSet; @@ -29,12 +26,11 @@ use system::ensure_signed; // Crates use bitcoin::merkle::{MerkleProof, ProofResult}; use bitcoin::parser::{ - extract_address_hash, extract_op_return_data, - header_from_bytes, parse_block_header, parse_transaction, + extract_address_hash, extract_op_return_data, header_from_bytes, parse_block_header, + parse_transaction, }; use bitcoin::types::{ - BlockChain, BlockHeader, H256Le, - RawBlockHeader, RichBlockHeader, Transaction + BlockChain, BlockHeader, H256Le, RawBlockHeader, RichBlockHeader, Transaction, }; use security; use security::ErrorCode; @@ -132,7 +128,7 @@ decl_module! { // construct the BlockChain struct let blockchain = Self::initialize_blockchain( block_height, block_header_hash); - + // Create rich block header let block_header = RichBlockHeader { block_hash: block_header_hash, @@ -256,7 +252,7 @@ decl_module! { // print!("Best block hash: {:?} \n", current_best_block); // print!("Current block hash: {:?} \n", block_header_hash); - + if current_best_block == block_header_hash { // extends the main chain Self::deposit_event( @@ -284,13 +280,13 @@ decl_module! { /// # Arguments /// /// * `tx_id` - The hash of the transaction to check for - /// * `tx_block_height` - The height of the block in which the + /// * `tx_block_height` - The height of the block in which the /// transaction should be included - /// * `raw_merkle_proof` - The raw merkle proof as returned by + /// * `raw_merkle_proof` - The raw merkle proof as returned by /// bitcoin `gettxoutproof` - /// * `confirmations` - The number of confirmations needed to accept + /// * `confirmations` - The number of confirmations needed to accept /// the proof - /// * `insecure` - determines if checks against recommended global transaction confirmation are to be executed. Recommended: set to `true` + /// * `insecure` - determines if checks against recommended global transaction confirmation are to be executed. Recommended: set to `true` fn verify_transaction_inclusion( origin, tx_id: H256Le, @@ -307,7 +303,7 @@ decl_module! { ensure!(>::check_parachain_status(StatusCode::Running), Error::::Shutdown); */ - + //let main_chain = Self::get_block_chain_from_id(MAIN_CHAIN_ID); let best_block_height = Self::get_best_block_height(); @@ -317,21 +313,21 @@ decl_module! { ).max_height; // fail if there is an ongoing fork - ensure!(best_block_height + ensure!(best_block_height >= next_best_fork_height + STABLE_TRANSACTION_CONFIRMATIONS, Error::OngoingFork); // This call fails if not enough confirmations Self::check_confirmations( - best_block_height, - confirmations, - block_height, + best_block_height, + confirmations, + block_height, insecure)?; - + let proof_result = Self::verify_merkle_proof(&raw_merkle_proof)?; - + let rich_header = Self::get_block_header_from_height( - &Self::get_block_chain_from_id(MAIN_CHAIN_ID), + &Self::get_block_chain_from_id(MAIN_CHAIN_ID), block_height )?; @@ -346,8 +342,8 @@ decl_module! { Ok(()) } - /// Validates a given raw Bitcoin transaction, according to the - /// supported transaction format (see + /// Validates a given raw Bitcoin transaction, according to the + /// supported transaction format (see /// https://interlay.gitlab.io/polkabtc-spec/btcrelay-spec/intro/ /// accepted-format.html) /// This DOES NOT check if the transaction is included in a block @@ -356,11 +352,11 @@ decl_module! { /// /// # Arguments /// * `raw_tx` - raw Bitcoin transaction - /// * `paymentValue` - value of BTC sent in the 1st / + /// * `paymentValue` - value of BTC sent in the 1st / /// payment UTXO of the transaction - /// * `recipientBtcAddress` - 20 byte Bitcoin address of recipient + /// * `recipientBtcAddress` - 20 byte Bitcoin address of recipient /// of the BTC in the 1st / payment UTXO - /// * `op_return_id` - 32 byte hash identifier expected in + /// * `op_return_id` - 32 byte hash identifier expected in /// OP_RETURN (replay protection) fn validate_transaction( origin, @@ -386,7 +382,7 @@ decl_module! { let extr_recipient_address = extract_address_hash( &transaction.outputs[0].script ).map_err(|_e| Error::InvalidOutputFormat)?; - ensure!(extr_recipient_address == recipient_btc_address, + ensure!(extr_recipient_address == recipient_btc_address, Error::WrongRecipient); // Check if 2nd / data UTXO has correct OP_RETURN value @@ -406,13 +402,13 @@ impl Module { // START: Storage getter functions // ******************************** - /// Get chain id from position (sorted by max block height) + /// Get chain id from position (sorted by max block height) fn get_chain_id_from_position(position: u32) -> u32 { ::get(position) } /// Get the position of the fork in Chains fn get_chain_position_from_chain_id(chain_id: u32) -> Result { - for (k,v) in ::enumerate() { + for (k, v) in ::enumerate() { if v == chain_id { return Ok(k); } @@ -440,7 +436,7 @@ impl Module { fn best_block_exists() -> bool { ::exists() } - /// get the best block height + /// get the best block height fn get_best_block_height() -> u32 { ::get() } @@ -453,18 +449,14 @@ impl Module { /// /// * `blockchain`: the blockchian struct to search in /// * `block_height`: the height if the block header - fn get_block_hash( - blockchain: &BlockChain, block_height: u32 - ) -> Result { + fn get_block_hash(blockchain: &BlockChain, block_height: u32) -> Result { match blockchain.chain.get(&block_height) { Some(hash) => Ok(*hash), None => return Err(Error::MissingBlockHeight.into()), } } /// Get a block header from its hash - fn get_block_header_from_hash( - block_hash: H256Le - ) -> Result { + fn get_block_header_from_hash(block_hash: H256Le) -> Result { if ::exists(block_hash) { return Ok(::get(block_hash)); } @@ -482,7 +474,7 @@ impl Module { let block_hash = Self::get_block_hash(blockchain, block_height)?; Self::get_block_header_from_hash(block_hash) } - + /// Storage setter functions /// Set a new chain with position and id fn set_chain_from_position_and_id(position: u32, id: u32) { @@ -508,9 +500,9 @@ impl Module { fn set_block_chain_from_id(id: u32, chain: &BlockChain) { ::insert(id, &chain); } - /// Update a blockchain in ChainsIndex + /// Update a blockchain in ChainsIndex fn mutate_block_chain_from_id(id: u32, chain: BlockChain) { - ::mutate(id, |b| {*b = chain}); + ::mutate(id, |b| *b = chain); } /// Remove a blockchain element from chainindex fn remove_blockchain_from_chainindex(id: u32) { @@ -522,9 +514,7 @@ impl Module { } /// update the chain_ref of a block header fn mutate_block_header_from_chain_id(hash: &H256Le, chain_ref: u32) { - ::mutate(&hash, |header| { - header.chain_ref = chain_ref - }); + ::mutate(&hash, |header| header.chain_ref = chain_ref); } /// Set a new best block @@ -542,32 +532,24 @@ impl Module { new_counter } - + /// Initialize the new main blockchain with a single block - fn initialize_blockchain( - block_height: u32, block_hash: H256Le - ) -> BlockChain { + fn initialize_blockchain(block_height: u32, block_hash: H256Le) -> BlockChain { let chain_id = MAIN_CHAIN_ID; // generate an empty blockchain Self::generate_blockchain(chain_id, block_height, block_hash) } /// Create a new blockchain element with a new chain id - fn create_blockchain( - block_height: u32, block_hash: H256Le - ) -> BlockChain { + fn create_blockchain(block_height: u32, block_hash: H256Le) -> BlockChain { // get a new chain id let chain_id: u32 = Self::increment_chain_counter(); // generate an empty blockchain Self::generate_blockchain(chain_id, block_height, block_hash) } - /// Generate the raw blockchain from a chain Id and with a single block - fn generate_blockchain( - chain_id: u32, - block_height: u32, - block_hash: H256Le, - ) -> BlockChain { + /// Generate the raw blockchain from a chain Id and with a single block + fn generate_blockchain(chain_id: u32, block_height: u32, block_hash: H256Le) -> BlockChain { // initialize an empty chain let mut chain = BTreeMap::new(); @@ -608,18 +590,15 @@ impl Module { // END: Storage getter functions // ********************************* - // Wrapper functions around bitcoin lib for testing purposes - + fn parse_transaction(raw_tx: &[u8]) -> Result { - parse_transaction(&raw_tx) - .map_err(|_e| Error::TxFormat) + parse_transaction(&raw_tx).map_err(|_e| Error::TxFormat) } fn verify_merkle_proof(raw_merkle_proof: &[u8]) -> Result { - - let merkle_proof = MerkleProof::parse(&raw_merkle_proof) - .map_err(|_e| Error::InvalidMerkleProof)?; + let merkle_proof = + MerkleProof::parse(&raw_merkle_proof).map_err(|_e| Error::InvalidMerkleProof)?; merkle_proof .verify_proof() @@ -635,7 +614,8 @@ impl Module { /// # Panics /// If ParachainStatus in Security module is not set to RUNNING fn verify_block_header(raw_block_header: RawBlockHeader) -> Result { - let basic_block_header = parse_block_header(raw_block_header).map_err(|_e| Error::InvalidHeaderSize)?; + let basic_block_header = + parse_block_header(raw_block_header).map_err(|_e| Error::InvalidHeaderSize)?; let block_header_hash = BlockHeader::block_hash_le(&raw_block_header); @@ -646,9 +626,9 @@ impl Module { ); // Check that the referenced previous block header exists in BTC-Relay - let prev_block_header = Self::get_block_header_from_hash( - basic_block_header.hash_prev_block) - .map_err(|_| Error::PrevBlock)?; + let prev_block_header = + Self::get_block_header_from_hash(basic_block_header.hash_prev_block) + .map_err(|_| Error::PrevBlock)?; // Check that the PoW hash satisfies the target set in the block header ensure!( block_header_hash.as_u256() < basic_block_header.target, @@ -658,59 +638,70 @@ impl Module { // Check that the diff. target is indeed correctly set in the block header, i.e., check for re-target. let block_height = prev_block_header.block_height + 1; - let expected_target = match block_height >= 2016 && block_height % DIFFICULTY_ADJUSTMENT_INTERVAL == 0 { - true => Self::compute_new_target( - &prev_block_header, - block_height)?, - false => prev_block_header.block_header.target - }; + let expected_target = + match block_height >= 2016 && block_height % DIFFICULTY_ADJUSTMENT_INTERVAL == 0 { + true => Self::compute_new_target(&prev_block_header, block_height)?, + false => prev_block_header.block_header.target, + }; - ensure!(basic_block_header.target == expected_target, Error::DiffTargetHeader); + ensure!( + basic_block_header.target == expected_target, + Error::DiffTargetHeader + ); Ok(basic_block_header) } - /// Computes Bitcoin's PoW retarget algorithm for a given block height /// # Arguments /// * `prev_block_header`: previous block header /// * `block_height` : block height of new target - fn compute_new_target(prev_block_header: &RichBlockHeader, block_height: u32) -> Result { - + fn compute_new_target( + prev_block_header: &RichBlockHeader, + block_height: u32, + ) -> Result { // get time of last retarget - let last_retarget_time = Self::get_last_retarget_time(prev_block_header.chain_ref, block_height)?; + let last_retarget_time = + Self::get_last_retarget_time(prev_block_header.chain_ref, block_height)?; // Compute new target - let actual_timespan = match ((prev_block_header.block_header.timestamp - last_retarget_time) as u32) < (TARGET_TIMESPAN / TARGET_TIMESPAN_DIVISOR) { + let actual_timespan = match ((prev_block_header.block_header.timestamp - last_retarget_time) + as u32) + < (TARGET_TIMESPAN / TARGET_TIMESPAN_DIVISOR) + { true => TARGET_TIMESPAN / TARGET_TIMESPAN_DIVISOR, false => TARGET_TIMESPAN * TARGET_TIMESPAN_DIVISOR, }; - let new_target = U256::from(actual_timespan) * prev_block_header.block_header.target / U256::from(TARGET_TIMESPAN); + let new_target = U256::from(actual_timespan) * prev_block_header.block_header.target + / U256::from(TARGET_TIMESPAN); // ensure target does not exceed max. target match new_target > UNROUNDED_MAX_TARGET { true => UNROUNDED_MAX_TARGET, - false => new_target + false => new_target, }; Ok(new_target) } /// Returns the timestamp of the last difficulty retarget on the specified BlockChain, given the current block height - /// + /// /// # Arguments /// * `chain_ref` - BlockChain identifier /// * `block_height` - current block height fn get_last_retarget_time(chain_ref: u32, block_height: u32) -> Result { - let block_chain = Self::get_block_chain_from_id(chain_ref); - let last_retarget_header = Self::get_block_header_from_height(&block_chain, block_height - DIFFICULTY_ADJUSTMENT_INTERVAL)?; + let block_chain = Self::get_block_chain_from_id(chain_ref); + let last_retarget_header = Self::get_block_header_from_height( + &block_chain, + block_height - DIFFICULTY_ADJUSTMENT_INTERVAL, + )?; Ok(last_retarget_header.block_header.timestamp) } - /// Swap the main chain with a fork. This method takes the starting height + /// Swap the main chain with a fork. This method takes the starting height /// of the fork and replaces each block in the main chain with the blocks - /// in the fork. It moves the replaced blocks in the main chain to a new - /// fork. + /// in the fork. It moves the replaced blocks in the main chain to a new + /// fork. /// Last, it replaces the chain_ref of each block header in the new main /// chain to the MAIN_CHAIN_ID and each block header in the new fork to the /// new chain id. @@ -736,7 +727,8 @@ impl Module { // maybe split off the no data elements // check if there is a no_data block element // that is greater than start_height - let index_no_data = main_chain.no_data + let index_no_data = main_chain + .no_data .iter() .position(|&h| h >= start_height) .map(|v| v as u32); @@ -746,7 +738,8 @@ impl Module { }; // maybe split off the invalid elements - let index_invalid = main_chain.invalid + let index_invalid = main_chain + .invalid .iter() .position(|&h| h >= start_height) .map(|v| v as u32); @@ -793,8 +786,7 @@ impl Module { Self::remove_blockchain_from_chain(position)?; // store the forked main chain - Self::set_block_chain_from_id( - forked_main_chain.chain_id, &forked_main_chain); + Self::set_block_chain_from_id(forked_main_chain.chain_id, &forked_main_chain); // insert the reference to the forked main chain in Chains Self::insert_sorted(&forked_main_chain); @@ -802,8 +794,7 @@ impl Module { // get an iterator of all forked block headers // update all the forked block headers for (_height, block) in forked_chain.iter() { - Self::mutate_block_header_from_chain_id( - &block, forked_main_chain.chain_id); + Self::mutate_block_header_from_chain_id(&block, forked_main_chain.chain_id); } // get an iterator of all new main chain block headers @@ -829,8 +820,7 @@ impl Module { } // get the position of the fork in Chains - let fork_position: u32 = Self::get_chain_position_from_chain_id( - fork.chain_id)?; + let fork_position: u32 = Self::get_chain_position_from_chain_id(fork.chain_id)?; // print!("fork position {:?}\n", fork_position); // check if the previous element in Chains has a lower block_height let mut current_position = fork_position; @@ -841,11 +831,9 @@ impl Module { // get the previous position let prev_position = current_position - 1; // get the blockchain id - let prev_blockchain_id = Self::get_chain_id_from_position( - prev_position); + let prev_blockchain_id = Self::get_chain_id_from_position(prev_position); // get the previous blockchain height - let prev_height = Self::get_block_chain_from_id(prev_blockchain_id) - .max_height; + let prev_height = Self::get_block_chain_from_id(prev_blockchain_id).max_height; // swap elements if block height is greater // print!("curr height {:?}\n", current_height); // print!("prev height {:?}\n", prev_height); @@ -857,8 +845,7 @@ impl Module { // and the current height is more than the // STABLE_TRANSACTION_CONFIRMATIONS ahead // we are swapping the main chain - if prev_height + STABLE_TRANSACTION_CONFIRMATIONS - < current_height { + if prev_height + STABLE_TRANSACTION_CONFIRMATIONS < current_height { Self::swap_main_blockchain(&fork)?; // announce the new main chain @@ -875,9 +862,9 @@ impl Module { )); } else { Self::deposit_event(Event::ForkAheadOfMainChain( - prev_height, // main chain height + prev_height, // main chain height fork.max_height, // fork height - fork.chain_id, // fork id + fork.chain_id, // fork id )); } // break the while loop @@ -920,9 +907,7 @@ impl Module { // NOTE: we never want to insert a new main chain through this function for (curr_position, curr_chain_id) in chains.iter().skip(1) { // get the height of the current chain_id - let curr_height = Self::get_block_chain_from_id( - curr_chain_id.clone()) - .max_height; + let curr_height = Self::get_block_chain_from_id(curr_chain_id.clone()).max_height; // if the height of the current blockchain is lower than // the new blockchain, it should be inserted at that position @@ -933,13 +918,12 @@ impl Module { } // insert the new fork into the chains element - Self::set_chain_from_position_and_id( - max_chain_element, blockchain.chain_id); + Self::set_chain_from_position_and_id(max_chain_element, blockchain.chain_id); // starting from the last element swap the positions until // the new blockchain is at the position_blockchain // print!("max element {:?}\n", max_chain_element); // print!("position blockchain {:?}\n", position_blockchain); - for curr_position in (position_blockchain+1..max_chain_element+1).rev() { + for curr_position in (position_blockchain + 1..max_chain_element + 1).rev() { // stop when the blockchain element is at it's // designated position // print!("current position {:?}\n", curr_position); @@ -952,15 +936,14 @@ impl Module { Self::swap_chain(curr_position, prev_position); } } - /// Flag an error in a block header. This function is called by the + /// Flag an error in a block header. This function is called by the /// security pallet. /// /// # Arguments /// /// * `block_hash` - the hash of the block header with the error /// * `error` - the error code for the block header - pub fn flag_block_error(block_hash: H256Le, error: ErrorCode) - -> Result<(), Error> { + pub fn flag_block_error(block_hash: H256Le, error: ErrorCode) -> Result<(), Error> { // Get the chain id of the block header let block_header = Self::get_block_header_from_hash(block_hash)?; let chain_id = block_header.chain_ref; @@ -971,12 +954,8 @@ impl Module { // Flag errors in the blockchain entry // Check which error we are dealing with let newly_flagged = match error { - ErrorCode::NoDataBTCRelay => blockchain - .no_data - .insert(block_header.block_height), - ErrorCode::InvalidBTCRelay => blockchain - .invalid - .insert(block_header.block_height), + ErrorCode::NoDataBTCRelay => blockchain.no_data.insert(block_header.block_height), + ErrorCode::InvalidBTCRelay => blockchain.invalid.insert(block_header.block_height), _ => return Err(Error::UnknownErrorcode), }; @@ -986,18 +965,17 @@ impl Module { Self::deposit_event(Event::FlagBlockError(block_hash, chain_id, error)); } - Ok (()) + Ok(()) } - /// Clear an error from a block header. This function is called by the + /// Clear an error from a block header. This function is called by the /// security pallet. /// /// # Arguments /// /// * `block_hash` - the hash of the block header being cleared /// * `error` - the error code for the block header - pub fn clear_block_error(block_hash: H256Le, error: ErrorCode) - -> Result<(), Error> { + pub fn clear_block_error(block_hash: H256Le, error: ErrorCode) -> Result<(), Error> { // Get the chain id of the block header let block_header = Self::get_block_header_from_hash(block_hash)?; let chain_id = block_header.chain_ref; @@ -1008,12 +986,8 @@ impl Module { // Clear errors in the blockchain entry // Check which error we are dealing with let block_exists = match error { - ErrorCode::NoDataBTCRelay => { - blockchain.no_data.remove(&block_header.block_height) - }, - ErrorCode::InvalidBTCRelay => { - blockchain.invalid.remove(&block_header.block_height) - }, + ErrorCode::NoDataBTCRelay => blockchain.no_data.remove(&block_header.block_height), + ErrorCode::InvalidBTCRelay => blockchain.invalid.remove(&block_header.block_height), _ => return Err(Error::UnknownErrorcode), }; @@ -1021,29 +995,32 @@ impl Module { // Store the updated blockchain entry Self::mutate_block_chain_from_id(chain_id, blockchain); - Self::deposit_event( - Event::ClearBlockError(block_hash, chain_id, error) - ); + Self::deposit_event(Event::ClearBlockError(block_hash, chain_id, error)); } - Ok (()) + Ok(()) } /// Checks if the given transaction confirmations are greater/equal to the /// requested confirmations (and/or the global k security parameter) - /// + /// /// # Arguments /// * `block_height` - current main chain block height /// * `req_confs` - confirmations requested by the caller /// * `tx_block_height` - block height of checked transaction - /// * `insecure` - determines if checks against recommended global transaction confirmation are to be executed. Recommended: set to `true` - /// - pub fn check_confirmations(main_chain_height: u32, req_confs: u32, tx_block_height: u32, insecure: bool) -> Result<(),Error> { + /// * `insecure` - determines if checks against recommended global transaction confirmation are to be executed. Recommended: set to `true` + /// + pub fn check_confirmations( + main_chain_height: u32, + req_confs: u32, + tx_block_height: u32, + insecure: bool, + ) -> Result<(), Error> { // insecure call: only checks against user parameter if insecure { - match tx_block_height + req_confs <= main_chain_height { + match tx_block_height + req_confs <= main_chain_height { true => Ok(()), - false => Err(Error::Confirmations) + false => Err(Error::Confirmations), } } else { // secure call: checks against max of user- and global security parameter @@ -1052,14 +1029,14 @@ impl Module { if global_confs > req_confs { match tx_block_height + global_confs <= main_chain_height { true => Ok(()), - false => Err(Error::InsufficientStableConfirmations) + false => Err(Error::InsufficientStableConfirmations), } } else { match tx_block_height + req_confs <= main_chain_height { true => Ok(()), - false => Err(Error::Confirmations) + false => Err(Error::Confirmations), } - } + } } } } diff --git a/crates/btc-relay/src/tests.rs b/crates/btc-relay/src/tests.rs index 081371b1ff..192e50b798 100644 --- a/crates/btc-relay/src/tests.rs +++ b/crates/btc-relay/src/tests.rs @@ -582,7 +582,8 @@ fn test_verify_block_header_correct_retarget_increase_succeeds() { retarget_headers[1], chain_ref, block_height, - ).unwrap(); + ) + .unwrap(); let curr_block_header = BlockHeader::from_le_bytes(&retarget_headers[2]).unwrap(); // Prev block exists @@ -612,7 +613,8 @@ fn test_verify_block_header_correct_retarget_decrease_succeeds() { retarget_headers[1], chain_ref, block_height, - ).unwrap(); + ) + .unwrap(); let curr_block_header = BlockHeader::from_le_bytes(&retarget_headers[2]).unwrap(); // Prev block exists @@ -641,7 +643,8 @@ fn test_verify_block_header_missing_retarget_succeeds() { retarget_headers[1], chain_ref, block_height, - ).unwrap(); + ) + .unwrap(); let curr_block_header = BlockHeader::from_le_bytes(&retarget_headers[2]).unwrap(); // Prev block exists @@ -667,9 +670,12 @@ fn test_compute_new_target() { let block_height: u32 = 2016; let retarget_headers = sample_retarget_interval_increase(); - let last_retarget_time = BlockHeader::from_le_bytes(&retarget_headers[0]).unwrap().timestamp; + let last_retarget_time = BlockHeader::from_le_bytes(&retarget_headers[0]) + .unwrap() + .timestamp; let prev_block_header = - RichBlockHeader::construct_rich_block_header(retarget_headers[1], chain_ref, block_height).unwrap(); + RichBlockHeader::construct_rich_block_header(retarget_headers[1], chain_ref, block_height) + .unwrap(); let curr_block_header = BlockHeader::from_le_bytes(&retarget_headers[2]).unwrap(); diff --git a/crates/collateral/src/lib.rs b/crates/collateral/src/lib.rs index 9f927f4acc..b1400607a5 100644 --- a/crates/collateral/src/lib.rs +++ b/crates/collateral/src/lib.rs @@ -1,9 +1,8 @@ #![cfg_attr(not(feature = "std"), no_std)] -/// The Treasury module according to the specification at -/// https://interlay.gitlab.io/polkabtc-spec/spec/treasury.html - -use frame_support::{decl_module, decl_storage, decl_event, decl_error, dispatch}; +/// The Collateral module according to the specification at +/// https://interlay.gitlab.io/polkabtc-spec/spec/collateral.html +use frame_support::{decl_error, decl_event, decl_module, decl_storage, dispatch}; use system::ensure_signed; #[cfg(test)] @@ -14,88 +13,91 @@ mod tests; /// The pallet's configuration trait. pub trait Trait: system::Trait { - // Add other types and constants required to configure this pallet. + // Add other types and constants required to configure this pallet. - /// The overarching event type. - type Event: From> + Into<::Event>; + /// The overarching event type. + type Event: From> + Into<::Event>; } // This pallet's storage items. decl_storage! { - // It is important to update your storage name so that your pallet's - // storage items are isolated from other pallets. - // ---------------------------------vvvvvvvvvvvvvv - trait Store for Module as TemplateModule { - // Just a dummy storage item. - // Here we are declaring a StorageValue, `Something` as a Option - // `get(fn something)` is the default getter which returns either the stored `u32` or `None` if nothing stored - Something get(fn something): Option; - } + // It is important to update your storage name so that your pallet's + // storage items are isolated from other pallets. + // ---------------------------------vvvvvvvvvvvvvv + trait Store for Module as TemplateModule { + // Just a dummy storage item. + // Here we are declaring a StorageValue, `Something` as a Option + // `get(fn something)` is the default getter which returns either the stored `u32` or `None` if nothing stored + Something get(fn something): Option; + } } // The pallet's events decl_event!( - pub enum Event where AccountId = ::AccountId { - /// Just a dummy event. - /// Event `Something` is declared with a parameter of the type `u32` and `AccountId` - /// To emit this event, we call the deposit function, from our runtime functions - SomethingStored(u32, AccountId), - } + pub enum Event + where + AccountId = ::AccountId, + { + /// Just a dummy event. + /// Event `Something` is declared with a parameter of the type `u32` and `AccountId` + /// To emit this event, we call the deposit function, from our runtime functions + SomethingStored(u32, AccountId), + } ); // The pallet's errors decl_error! { - pub enum Error for Module { - /// Value was None - NoneValue, - /// Value reached maximum and cannot be incremented further - StorageOverflow, - } + pub enum Error for Module { + /// Value was None + NoneValue, + /// Value reached maximum and cannot be incremented further + StorageOverflow, + } } // The pallet's dispatchable functions. decl_module! { - /// The module declaration. - pub struct Module for enum Call where origin: T::Origin { - // Initializing errors - // this includes information about your errors in the node's metadata. - // it is needed only if you are using errors in your pallet - type Error = Error; - - // Initializing events - // this is needed only if you are using events in your pallet - fn deposit_event() = default; - - /// Just a dummy entry point. - /// function that can be called by the external world as an extrinsics call - /// takes a parameter of the type `AccountId`, stores it, and emits an event - pub fn do_something(origin, something: u32) -> dispatch::DispatchResult { - // Check it was signed and get the signer. See also: ensure_root and ensure_none - let who = ensure_signed(origin)?; - - // Code to execute when something calls this. - // For example: the following line stores the passed in u32 in the storage - Something::put(something); - - // Here we are raising the Something event - Self::deposit_event(RawEvent::SomethingStored(something, who)); - Ok(()) - } - - /// Another dummy entry point. - /// takes no parameters, attempts to increment storage value, and possibly throws an error - pub fn cause_error(origin) -> dispatch::DispatchResult { - // Check it was signed and get the signer. See also: ensure_root and ensure_none - let _who = ensure_signed(origin)?; - - match Something::get() { - None => Err(Error::::NoneValue)?, - Some(old) => { - let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; - Something::put(new); - Ok(()) - }, - } - } - } + /// The module declaration. + pub struct Module for enum Call where origin: T::Origin { + // Initializing errors + // this includes information about your errors in the node's metadata. + // it is needed only if you are using errors in your pallet + type Error = Error; + + // Initializing events + // this is needed only if you are using events in your pallet + fn deposit_event() = default; + + /// Just a dummy entry point. + /// function that can be called by the external world as an extrinsics call + /// takes a parameter of the type `AccountId`, stores it, and emits an event + pub fn do_something(origin, something: u32) -> dispatch::DispatchResult { + // Check it was signed and get the signer. See also: ensure_root and ensure_none + let who = ensure_signed(origin)?; + + // Code to execute when something calls this. + // For example: the following line stores the passed in u32 in the storage + Something::put(something); + + // Here we are raising the Something event + Self::deposit_event(RawEvent::SomethingStored(something, who)); + Ok(()) + } + + /// Another dummy entry point. + /// takes no parameters, attempts to increment storage value, and possibly throws an error + pub fn cause_error(origin) -> dispatch::DispatchResult { + // Check it was signed and get the signer. See also: ensure_root and ensure_none + let _who = ensure_signed(origin)?; + + match Something::get() { + None => Err(Error::::NoneValue)?, + Some(old) => { + let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; + Something::put(new); + Ok(()) + }, + } + } + } } diff --git a/crates/collateral/src/mock.rs b/crates/collateral/src/mock.rs index 2ea81ffb45..2b896f8ded 100644 --- a/crates/collateral/src/mock.rs +++ b/crates/collateral/src/mock.rs @@ -1,14 +1,16 @@ // Creating mock runtime here use crate::{Module, Trait}; -use sp_core::H256; use frame_support::{impl_outer_origin, parameter_types, weights::Weight}; +use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, testing::Header, Perbill, + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, }; impl_outer_origin! { - pub enum Origin for Test {} + pub enum Origin for Test {} } // For testing the pallet, we construct most of a mock runtime. This means @@ -17,39 +19,42 @@ impl_outer_origin! { #[derive(Clone, Eq, PartialEq)] pub struct Test; parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: Weight = 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); } impl system::Trait for Test { - type Origin = Origin; - type Call = (); - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = (); - type BlockHashCount = BlockHashCount; - type MaximumBlockWeight = MaximumBlockWeight; - type MaximumBlockLength = MaximumBlockLength; - type AvailableBlockRatio = AvailableBlockRatio; - type Version = (); - type ModuleToIndex = (); - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); + type Origin = Origin; + type Call = (); + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + type ModuleToIndex = (); + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); } impl Trait for Test { - type Event = (); + type Event = (); } pub type TemplateModule = Module; // This function basically just builds a genesis storage key/value store according to // our desired mockup. pub fn new_test_ext() -> sp_io::TestExternalities { - system::GenesisConfig::default().build_storage::().unwrap().into() + system::GenesisConfig::default() + .build_storage::() + .unwrap() + .into() } diff --git a/crates/collateral/src/tests.rs b/crates/collateral/src/tests.rs index ec123a50c7..46957f4b8c 100644 --- a/crates/collateral/src/tests.rs +++ b/crates/collateral/src/tests.rs @@ -1,26 +1,26 @@ // Tests to be written here -use crate::{Error, mock::*}; -use frame_support::{assert_ok, assert_noop}; +use crate::{mock::*, Error}; +use frame_support::{assert_noop, assert_ok}; #[test] fn it_works_for_default_value() { - new_test_ext().execute_with(|| { - // Just a dummy test for the dummy function `do_something` - // calling the `do_something` function with a value 42 - assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); - // asserting that the stored value is equal to what we stored - assert_eq!(TemplateModule::something(), Some(42)); - }); + new_test_ext().execute_with(|| { + // Just a dummy test for the dummy function `do_something` + // calling the `do_something` function with a value 42 + assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); + // asserting that the stored value is equal to what we stored + assert_eq!(TemplateModule::something(), Some(42)); + }); } #[test] fn correct_error_for_none_value() { - new_test_ext().execute_with(|| { - // Ensure the correct error is thrown on None value - assert_noop!( - TemplateModule::cause_error(Origin::signed(1)), - Error::::NoneValue - ); - }); + new_test_ext().execute_with(|| { + // Ensure the correct error is thrown on None value + assert_noop!( + TemplateModule::cause_error(Origin::signed(1)), + Error::::NoneValue + ); + }); } diff --git a/crates/exchange-rate-oracle/src/mock.rs b/crates/exchange-rate-oracle/src/mock.rs index d24a376c2c..d0cfb7b4de 100644 --- a/crates/exchange-rate-oracle/src/mock.rs +++ b/crates/exchange-rate-oracle/src/mock.rs @@ -1,13 +1,13 @@ /// Mocking the test environment use crate::{Module, Trait}; use frame_support::{impl_outer_event, impl_outer_origin, parameter_types, weights::Weight}; +use mocktopus::mocking::clear_mocks; use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, Perbill, }; -use mocktopus::mocking::clear_mocks; impl_outer_origin! { pub enum Origin for Test {} @@ -52,9 +52,9 @@ impl system::Trait for Test { type AvailableBlockRatio = AvailableBlockRatio; type Version = (); type ModuleToIndex = (); - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); } impl Trait for Test { diff --git a/crates/treasury/src/lib.rs b/crates/treasury/src/lib.rs index 5ae264db87..1f6f23ec5d 100644 --- a/crates/treasury/src/lib.rs +++ b/crates/treasury/src/lib.rs @@ -13,20 +13,14 @@ extern crate mocktopus; // #[cfg(test)] // use mocktopus::macros::mockable; +use frame_support::traits::{Currency, ExistenceRequirement::KeepAlive, ReservableCurrency}; /// # PolkaBTC Treasury implementation /// The Treasury module according to the specification at /// https://interlay.gitlab.io/polkabtc-spec/spec/treasury.html - - // Substrate -use frame_support::{ - decl_module, decl_event, - dispatch::DispatchResult, ensure -}; -use system::ensure_signed; -use frame_support::traits::{Currency, ReservableCurrency, ExistenceRequirement::KeepAlive}; +use frame_support::{decl_event, decl_module, dispatch::DispatchResult, ensure}; use sp_runtime::ModuleId; - +use system::ensure_signed; use xclaim_core::Error; @@ -38,10 +32,10 @@ const _MODULE_ID: ModuleId = ModuleId(*b"ily/trsy"); /// The pallet's configuration trait. pub trait Trait: system::Trait { /// The PolkaBTC currency - type PolkaBTC: Currency + ReservableCurrency; - - /// The overarching event type. - type Event: From> + Into<::Event>; + type PolkaBTC: Currency + ReservableCurrency; + + /// The overarching event type. + type Event: From> + Into<::Event>; } // This pallet's storage items. @@ -52,49 +46,48 @@ pub trait Trait: system::Trait { // The pallet's events decl_event!( - pub enum Event where + pub enum Event + where AccountId = ::AccountId, Balance = BalanceOf, { - Transfer(AccountId, AccountId, Balance), + Transfer(AccountId, AccountId, Balance), Mint(AccountId, Balance), Lock(AccountId, Balance), Burn(AccountId, Balance), - } + } ); - // The pallet's dispatchable functions. decl_module! { - /// The module declaration. - pub struct Module for enum Call where origin: T::Origin { - // Initializing events - // this is needed only if you are using events in your pallet - fn deposit_event() = default; - + /// The module declaration. + pub struct Module for enum Call where origin: T::Origin { + // Initializing events + // this is needed only if you are using events in your pallet + fn deposit_event() = default; + /// Transfer an amount of PolkaBTC (without fees) /// /// # Arguments - /// + /// /// * `origin` - sender of the transaction /// * `receiver` - receiver of the transaction /// * `amount` - amount of PolkaBTC - fn transfer(origin, receiver: T::AccountId, amount: BalanceOf) - -> DispatchResult + fn transfer(origin, receiver: T::AccountId, amount: BalanceOf) + -> DispatchResult { let sender = ensure_signed(origin)?; - + T::PolkaBTC::transfer(&sender, &receiver, amount, KeepAlive) .map_err(|_| Error::InsufficientFunds)?; - + Self::deposit_event(RawEvent::Transfer(sender, receiver, amount)); - + Ok(()) } - } + } } - impl Module { /// Total supply of PolkaBTC pub fn total_supply() -> BalanceOf { @@ -103,7 +96,7 @@ impl Module { /// Mint new tokens /// /// # Arguments - /// + /// /// * `requester` - PolkaBTC user requesting new tokens /// * `amount` - to be issued amount of PolkaBTC pub fn mint(requester: T::AccountId, amount: BalanceOf) { @@ -120,34 +113,30 @@ impl Module { /// /// * `redeemer` - the account redeeming tokens /// * `amount` - to be locked amount of PolkaBTC - pub fn lock(redeemer: T::AccountId, amount: BalanceOf) - -> Result<(), Error> - { - T::PolkaBTC::reserve(&redeemer, amount) - .map_err(|_| Error::InsufficientFunds)?; - + pub fn lock(redeemer: T::AccountId, amount: BalanceOf) -> Result<(), Error> { + T::PolkaBTC::reserve(&redeemer, amount).map_err(|_| Error::InsufficientFunds)?; + Self::deposit_event(RawEvent::Lock(redeemer, amount)); Ok(()) - } + } /// Burn a previously locked PolkaBTC tokens /// /// # Arguments /// /// * `redeemer` - the account redeeming tokens /// * `amount` - the to be burned amount of PolkaBTC - pub fn burn(redeemer: T::AccountId, amount: BalanceOf) - -> Result<(), Error> - { - ensure!(T::PolkaBTC::reserved_balance(&redeemer) == amount, - Error::InsufficientLockedFunds); - + pub fn burn(redeemer: T::AccountId, amount: BalanceOf) -> Result<(), Error> { + ensure!( + T::PolkaBTC::reserved_balance(&redeemer) == amount, + Error::InsufficientLockedFunds + ); + // burn the tokens from the global balance let _burned_tokens = T::PolkaBTC::burn(amount); // burn the tokens for the redeemer - let (_burned_tokens, _mismatch_tokens) = T::PolkaBTC::slash_reserved( - &redeemer, amount); + let (_burned_tokens, _mismatch_tokens) = T::PolkaBTC::slash_reserved(&redeemer, amount); - Self::deposit_event(RawEvent::Burn(redeemer, amount)); + Self::deposit_event(RawEvent::Burn(redeemer, amount)); Ok(()) } diff --git a/crates/treasury/src/mock.rs b/crates/treasury/src/mock.rs index b1ab1a31fd..91fdac7fb0 100644 --- a/crates/treasury/src/mock.rs +++ b/crates/treasury/src/mock.rs @@ -1,17 +1,18 @@ /// Mocking the test environment use crate::{Module, Trait}; +use frame_support::{impl_outer_event, impl_outer_origin, parameter_types, weights::Weight}; +use pallet_balances as balances; use sp_core::H256; -use frame_support::{impl_outer_origin, impl_outer_event, - parameter_types, weights::Weight}; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, testing::Header, Perbill, + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, }; -use pallet_balances as balances; use mocktopus::mocking::clear_mocks; impl_outer_origin! { - pub enum Origin for Test {} + pub enum Origin for Test {} } mod test_events { @@ -36,34 +37,34 @@ pub type Balance = u64; #[derive(Clone, Eq, PartialEq)] pub struct Test; parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: Weight = 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); } impl system::Trait for Test { - type Origin = Origin; - type Call = (); - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type Event = TestEvent; - type BlockHashCount = BlockHashCount; - type MaximumBlockWeight = MaximumBlockWeight; - type MaximumBlockLength = MaximumBlockLength; - type AvailableBlockRatio = AvailableBlockRatio; - type Version = (); - type ModuleToIndex = (); - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); + type Origin = Origin; + type Call = (); + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type Event = TestEvent; + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + type ModuleToIndex = (); + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); } parameter_types! { - pub const ExistentialDeposit: u64 = 1; + pub const ExistentialDeposit: u64 = 1; } impl pallet_balances::Trait for Test { type Balance = Balance; @@ -75,7 +76,7 @@ impl pallet_balances::Trait for Test { impl Trait for Test { type PolkaBTC = Balances; - type Event = TestEvent; + type Event = TestEvent; } pub type Error = crate::Error; @@ -96,12 +97,9 @@ impl ExtBuilder { let mut storage = system::GenesisConfig::default() .build_storage::() .unwrap(); - + pallet_balances::GenesisConfig:: { - balances: vec![ - (ALICE, ALICE_BALANCE), - (BOB, BOB_BALANCE), - ] + balances: vec![(ALICE, ALICE_BALANCE), (BOB, BOB_BALANCE)], } .assimilate_storage(&mut storage) .unwrap(); diff --git a/crates/treasury/src/tests.rs b/crates/treasury/src/tests.rs index 93b769d17b..93b43e7cca 100644 --- a/crates/treasury/src/tests.rs +++ b/crates/treasury/src/tests.rs @@ -1,4 +1,4 @@ -/// Tests for Treasury +/// Tests for Treasury use crate::mock::*; use crate::RawEvent; use frame_support::{assert_err, assert_ok}; @@ -11,16 +11,15 @@ fn test_transfer_succeeds() { let sender = Origin::signed(ALICE); let receiver = BOB; let amount: Balance = 3; - + let init_balance_alice = Balances::free_balance(ALICE); let init_balance_bob = Balances::free_balance(BOB); assert_ok!(Treasury::transfer(sender, receiver, amount)); - let transfer_event = TestEvent::test_events( - RawEvent::Transfer(ALICE, BOB, amount)); - + let transfer_event = TestEvent::test_events(RawEvent::Transfer(ALICE, BOB, amount)); + assert!(System::events().iter().any(|a| a.event == transfer_event)); - + let balance_alice = Balances::free_balance(ALICE); let balance_bob = Balances::free_balance(BOB); @@ -35,13 +34,15 @@ fn test_transfer_fails() { let sender = Origin::signed(ALICE); let receiver = BOB; let amount = ALICE_BALANCE + 10; - + let init_balance_alice = Balances::free_balance(ALICE); let init_balance_bob = Balances::free_balance(BOB); - assert_err!(Treasury::transfer(sender, receiver, amount), - Error::InsufficientFunds); - + assert_err!( + Treasury::transfer(sender, receiver, amount), + Error::InsufficientFunds + ); + let balance_alice = Balances::free_balance(ALICE); let balance_bob = Balances::free_balance(BOB); @@ -49,4 +50,3 @@ fn test_transfer_fails() { assert_eq!(balance_bob, init_balance_bob); }) } - diff --git a/crates/xclaim-core/src/lib.rs b/crates/xclaim-core/src/lib.rs index b00d5fd4db..8dc198518b 100644 --- a/crates/xclaim-core/src/lib.rs +++ b/crates/xclaim-core/src/lib.rs @@ -18,8 +18,12 @@ impl Error { match self { Error::MissingExchangeRate => "Exchange rate not set", Error::InvalidOracleSource => "Invalid oracle account", - Error::InsufficientFunds => "The balance of this account is insufficient to complete the transaction.", - Error::InsufficientLockedFunds => "The locked token balance of this account is insufficient to burn the tokens.", + Error::InsufficientFunds => { + "The balance of this account is insufficient to complete the transaction." + } + Error::InsufficientLockedFunds => { + "The locked token balance of this account is insufficient to burn the tokens." + } Error::RuntimeError => "Runtim error", } } @@ -31,7 +35,6 @@ impl ToString for Error { } } - impl std::convert::From for DispatchError { fn from(error: Error) -> Self { DispatchError::Module { From a181918583761e5fbcf31b32c0aad4fdef974ce3 Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Wed, 8 Apr 2020 15:18:42 +0900 Subject: [PATCH 26/37] rust fmt --- crates/btc-relay/src/tests.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/btc-relay/src/tests.rs b/crates/btc-relay/src/tests.rs index b919229f04..a113a9ede3 100644 --- a/crates/btc-relay/src/tests.rs +++ b/crates/btc-relay/src/tests.rs @@ -496,7 +496,10 @@ fn swap_main_blockchain_succeeds() { assert_eq!(fork_height, new_main.max_height); assert_eq!(main_start, new_main.start_height); assert_eq!(main_chain_ref, new_main.chain_id); - assert_eq!(fork_height + 1, BTCRelay::_blocks_count(main_chain_ref) as u32); + assert_eq!( + fork_height + 1, + BTCRelay::_blocks_count(main_chain_ref) as u32 + ); assert_eq!(main.no_data, new_main.no_data); assert_eq!(main.invalid, new_main.invalid); From c1478d4c7b97774cab4af12d30e8edec3d233867 Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Thu, 9 Apr 2020 14:30:25 +0900 Subject: [PATCH 27/37] add tests for mint, lock, burn --- crates/treasury/src/lib.rs | 10 ++- crates/treasury/src/tests.rs | 157 +++++++++++++++++++++++++++++++++-- 2 files changed, 158 insertions(+), 9 deletions(-) diff --git a/crates/treasury/src/lib.rs b/crates/treasury/src/lib.rs index 1f6f23ec5d..a7a20ca029 100644 --- a/crates/treasury/src/lib.rs +++ b/crates/treasury/src/lib.rs @@ -90,9 +90,17 @@ decl_module! { impl Module { /// Total supply of PolkaBTC - pub fn total_supply() -> BalanceOf { + pub fn get_total_supply() -> BalanceOf { T::PolkaBTC::total_issuance() } + /// Balance of an account (wrapper) + pub fn get_balance_from_account(account: T::AccountId) -> BalanceOf { + T::PolkaBTC::free_balance(&account) + } + /// Locked balance of an account (wrapper) + pub fn get_locked_balance_from_account(account: T::AccountId) -> BalanceOf { + T::PolkaBTC::reserved_balance(&account) + } /// Mint new tokens /// /// # Arguments diff --git a/crates/treasury/src/tests.rs b/crates/treasury/src/tests.rs index 93b43e7cca..d450fa1f6e 100644 --- a/crates/treasury/src/tests.rs +++ b/crates/treasury/src/tests.rs @@ -4,7 +4,19 @@ use crate::RawEvent; use frame_support::{assert_err, assert_ok}; // use mocktopus::mocking::*; +/// Total supply +#[test] +fn test_total_supply_correct() { + run_test(|| { + // initial supply + let desired_total_supply = ALICE_BALANCE + BOB_BALANCE; + let total_supply = Treasury::get_total_supply(); + assert_eq!(desired_total_supply, total_supply); + }) +} + +/// Transfer #[test] fn test_transfer_succeeds() { run_test(|| { @@ -12,19 +24,22 @@ fn test_transfer_succeeds() { let receiver = BOB; let amount: Balance = 3; - let init_balance_alice = Balances::free_balance(ALICE); - let init_balance_bob = Balances::free_balance(BOB); + let init_balance_alice = Treasury::get_balance_from_account(ALICE); + let init_balance_bob = Treasury::get_balance_from_account(BOB); + let init_total_supply = Treasury::get_total_supply(); assert_ok!(Treasury::transfer(sender, receiver, amount)); let transfer_event = TestEvent::test_events(RawEvent::Transfer(ALICE, BOB, amount)); assert!(System::events().iter().any(|a| a.event == transfer_event)); - let balance_alice = Balances::free_balance(ALICE); - let balance_bob = Balances::free_balance(BOB); + let balance_alice = Treasury::get_balance_from_account(ALICE); + let balance_bob = Treasury::get_balance_from_account(BOB); + let total_supply = Treasury::get_total_supply(); assert_eq!(balance_alice, init_balance_alice - amount); assert_eq!(balance_bob, init_balance_bob + amount); + assert_eq!(total_supply, init_total_supply); }) } @@ -35,18 +50,144 @@ fn test_transfer_fails() { let receiver = BOB; let amount = ALICE_BALANCE + 10; - let init_balance_alice = Balances::free_balance(ALICE); - let init_balance_bob = Balances::free_balance(BOB); + let init_balance_alice = Treasury::get_balance_from_account(ALICE); + let init_balance_bob = Treasury::get_balance_from_account(BOB); + let init_total_supply = Treasury::get_total_supply(); assert_err!( Treasury::transfer(sender, receiver, amount), Error::InsufficientFunds ); - let balance_alice = Balances::free_balance(ALICE); - let balance_bob = Balances::free_balance(BOB); + let balance_alice = Treasury::get_balance_from_account(ALICE); + let balance_bob = Treasury::get_balance_from_account(BOB); + let total_supply = Treasury::get_total_supply(); assert_eq!(balance_alice, init_balance_alice); assert_eq!(balance_bob, init_balance_bob); + assert_eq!(total_supply, init_total_supply); + }) +} + +/// Mint +#[test] +fn test_mint_succeeds() { + run_test(|| { + let requester = ALICE; + let amount: Balance = 5; + + let init_balance_alice = Treasury::get_balance_from_account(ALICE); + let init_total_supply = Treasury::get_total_supply(); + + Treasury::mint(requester, amount); + let mint_event = TestEvent::test_events(RawEvent::Mint(ALICE, amount)); + + assert!(System::events().iter().any(|a| a.event == mint_event)); + + let balance_alice = Treasury::get_balance_from_account(ALICE); + let total_supply = Treasury::get_total_supply(); + + assert_eq!(balance_alice, init_balance_alice + amount); + assert_eq!(total_supply, init_total_supply + amount); + }) +} + +/// Lock +#[test] +fn test_lock_succeeds() { + run_test(|| { + let redeemer = ALICE; + let amount = ALICE_BALANCE; + + let init_balance = Treasury::get_balance_from_account(ALICE); + let init_locked_balance = Treasury::get_locked_balance_from_account(ALICE); + let init_total_supply = Treasury::get_total_supply(); + + assert_ok!(Treasury::lock(redeemer, amount)); + let lock_event = TestEvent::test_events(RawEvent::Lock(ALICE, amount)); + + assert!(System::events().iter().any(|a| a.event == lock_event)); + + let balance = Treasury::get_balance_from_account(ALICE); + let locked_balance = Treasury::get_locked_balance_from_account(ALICE); + let total_supply = Treasury::get_total_supply(); + + assert_eq!(balance, init_balance - amount); + assert_eq!(locked_balance, init_locked_balance + amount); + assert_eq!(total_supply, init_total_supply); + }) +} + +#[test] +fn test_lock_fails() { + run_test(|| { + let redeemer = ALICE; + let amount = ALICE_BALANCE + 5; + + let init_balance = Treasury::get_balance_from_account(ALICE); + let init_locked_balance = Treasury::get_locked_balance_from_account(ALICE); + let init_total_supply = Treasury::get_total_supply(); + + assert_err!(Treasury::lock(redeemer, amount), Error::InsufficientFunds); + + let balance = Treasury::get_balance_from_account(ALICE); + let locked_balance = Treasury::get_locked_balance_from_account(ALICE); + let total_supply = Treasury::get_total_supply(); + + assert_eq!(balance, init_balance); + assert_eq!(locked_balance, init_locked_balance); + assert_eq!(total_supply, init_total_supply); + }) +} + +/// Burn +#[test] +fn test_burn_succeeds() { + run_test(|| { + let redeemer = ALICE; + let amount = ALICE_BALANCE; + + let init_balance = Treasury::get_balance_from_account(ALICE); + let init_locked_balance = Treasury::get_locked_balance_from_account(ALICE); + let init_total_supply = Treasury::get_total_supply(); + + assert_ok!(Treasury::lock(redeemer, amount)); + assert_ok!(Treasury::burn(redeemer, amount)); + let burn_event = TestEvent::test_events(RawEvent::Burn(ALICE, amount)); + + assert!(System::events().iter().any(|a| a.event == burn_event)); + + let balance = Treasury::get_balance_from_account(ALICE); + let locked_balance = Treasury::get_locked_balance_from_account(ALICE); + let total_supply = Treasury::get_total_supply(); + + assert_eq!(balance, init_balance - amount); + assert_eq!(locked_balance, init_locked_balance); + assert_eq!(total_supply, init_total_supply - amount); + }) +} + +#[test] +fn test_burn_fails() { + run_test(|| { + let redeemer = ALICE; + let amount = ALICE_BALANCE; + + let init_balance = Treasury::get_balance_from_account(ALICE); + let init_locked_balance = Treasury::get_locked_balance_from_account(ALICE); + let init_total_supply = Treasury::get_total_supply(); + + assert_err!( + Treasury::burn(redeemer, amount), + Error::InsufficientLockedFunds + ); + + let balance = Treasury::get_balance_from_account(ALICE); + let locked_balance = Treasury::get_locked_balance_from_account(ALICE); + let total_supply = Treasury::get_total_supply(); + + assert_eq!(balance, init_balance); + assert_eq!(locked_balance, init_locked_balance); + assert_eq!(total_supply, init_total_supply); }) } From d484338bef770e0ead368a8b9fdd942ee592ff3a Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Thu, 9 Apr 2020 19:08:30 +0900 Subject: [PATCH 28/37] add collateral module errors --- crates/xclaim-core/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/xclaim-core/src/lib.rs b/crates/xclaim-core/src/lib.rs index 0fb9094069..b236a04b46 100644 --- a/crates/xclaim-core/src/lib.rs +++ b/crates/xclaim-core/src/lib.rs @@ -7,6 +7,7 @@ pub enum Error { InvalidOracleSource, InsufficientFunds, InsufficientLockedFunds, + InsufficientCollateralAvailable, /// use only for errors which means something /// going very wrong and which do not match any other error @@ -24,7 +25,10 @@ impl Error { Error::InsufficientLockedFunds => { "The locked token balance of this account is insufficient to burn the tokens." } - Error::RuntimeError => "Runtim error", + Error::InsufficientCollateralAvailable => { + "The sender’s collateral balance is below the requested amount." + } + Error::RuntimeError => "Runtime error", } } } From ea9b9fa0bc8bdba4d6d69e512c16e951a5b35a2d Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Thu, 9 Apr 2020 19:33:03 +0900 Subject: [PATCH 29/37] add collateral module and tests --- Cargo.lock | 2 + crates/collateral/Cargo.toml | 17 ++- crates/collateral/src/lib.rs | 184 ++++++++++++++++++++----------- crates/collateral/src/mock.rs | 84 +++++++++++--- crates/collateral/src/tests.rs | 195 ++++++++++++++++++++++++++++++--- 5 files changed, 378 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5c1d7dbc5..01a4157ab8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -269,11 +269,13 @@ version = "0.1.0" dependencies = [ "frame-support 2.0.0-alpha.5", "frame-system 2.0.0-alpha.5", + "pallet-balances", "parity-scale-codec", "safe-mix", "sp-core 2.0.0-alpha.5", "sp-io 2.0.0-alpha.5", "sp-runtime 2.0.0-alpha.5", + "xclaim-core", ] [[package]] diff --git a/crates/collateral/Cargo.toml b/crates/collateral/Cargo.toml index c9ccd1cb39..8706284280 100644 --- a/crates/collateral/Cargo.toml +++ b/crates/collateral/Cargo.toml @@ -9,10 +9,11 @@ version = '0.1.0' [features] default = ['std'] std = [ - 'codec/std', - 'frame-support/std', - 'safe-mix/std', - 'system/std', + 'codec/std', + 'frame-support/std', + 'safe-mix/std', + 'system/std', + 'pallet-balances/std', ] [dependencies.codec] @@ -45,3 +46,11 @@ version = '2.0.0-alpha.5' default-features = false package = 'frame-system' version = '2.0.0-alpha.5' + +[dependencies.pallet-balances] +default-features = false +package = 'pallet-balances' +version = '2.0.0-alpha.5' + +[dependencies.xclaim-core] +path = '../xclaim-core' diff --git a/crates/collateral/src/lib.rs b/crates/collateral/src/lib.rs index b1400607a5..2f1f8bbc43 100644 --- a/crates/collateral/src/lib.rs +++ b/crates/collateral/src/lib.rs @@ -1,19 +1,29 @@ +#![deny(warnings)] +#![cfg_attr(test, feature(proc_macro_hygiene))] #![cfg_attr(not(feature = "std"), no_std)] - -/// The Collateral module according to the specification at -/// https://interlay.gitlab.io/polkabtc-spec/spec/collateral.html -use frame_support::{decl_error, decl_event, decl_module, decl_storage, dispatch}; -use system::ensure_signed; - #[cfg(test)] mod mock; #[cfg(test)] mod tests; +use frame_support::traits::{Currency, ReservableCurrency}; +/// The Collateral module according to the specification at +/// https://interlay.gitlab.io/polkabtc-spec/spec/collateral.html +use frame_support::{decl_event, decl_module, decl_storage, ensure}; +use sp_runtime::ModuleId; + +use xclaim_core::Error; + +type BalanceOf = <::DOT as Currency<::AccountId>>::Balance; + +/// The collateral's module id, used for deriving its sovereign account ID. +const _MODULE_ID: ModuleId = ModuleId(*b"ily/cltl"); + /// The pallet's configuration trait. pub trait Trait: system::Trait { - // Add other types and constants required to configure this pallet. + /// The DOT currency + type DOT: Currency + ReservableCurrency; /// The overarching event type. type Event: From> + Into<::Event>; @@ -21,14 +31,13 @@ pub trait Trait: system::Trait { // This pallet's storage items. decl_storage! { - // It is important to update your storage name so that your pallet's - // storage items are isolated from other pallets. - // ---------------------------------vvvvvvvvvvvvvv - trait Store for Module as TemplateModule { - // Just a dummy storage item. - // Here we are declaring a StorageValue, `Something` as a Option - // `get(fn something)` is the default getter which returns either the stored `u32` or `None` if nothing stored - Something get(fn something): Option; + trait Store for Module as Collateral { + /// ## Storage + /// Note that account's balances and locked balances are handled + /// through the Balances module. + /// + /// Total locked DOT collateral + TotalCollateral: BalanceOf; } } @@ -37,67 +46,108 @@ decl_event!( pub enum Event where AccountId = ::AccountId, + Balance = BalanceOf, { - /// Just a dummy event. - /// Event `Something` is declared with a parameter of the type `u32` and `AccountId` - /// To emit this event, we call the deposit function, from our runtime functions - SomethingStored(u32, AccountId), + LockCollateral(AccountId, Balance), + ReleaseCollateral(AccountId, Balance), + SlashCollateral(AccountId, AccountId, Balance), } ); -// The pallet's errors -decl_error! { - pub enum Error for Module { - /// Value was None - NoneValue, - /// Value reached maximum and cannot be incremented further - StorageOverflow, - } -} - -// The pallet's dispatchable functions. decl_module! { /// The module declaration. pub struct Module for enum Call where origin: T::Origin { - // Initializing errors - // this includes information about your errors in the node's metadata. - // it is needed only if you are using errors in your pallet - type Error = Error; - // Initializing events - // this is needed only if you are using events in your pallet fn deposit_event() = default; + } +} + +impl Module { + /// Total supply of DOT + pub fn get_total_supply() -> BalanceOf { + T::DOT::total_issuance() + } + /// Total locked DOT collateral + pub fn get_total_collateral() -> BalanceOf { + >::get() + } + /// Increase the locked collateral + pub fn increase_total_collateral(amount: BalanceOf) { + let new_collateral = Self::get_total_collateral() + amount; + >::put(new_collateral); + } + /// Decrease the locked collateral + pub fn decrease_total_collateral(amount: BalanceOf) { + let new_collateral = Self::get_total_collateral() - amount; + >::put(new_collateral); + } + /// Locked balance of account + pub fn get_collateral_from_account(account: T::AccountId) -> BalanceOf { + T::DOT::reserved_balance(&account) + } + /// Lock DOT collateral + /// + /// # Arguments + /// + /// * `sender` - the account locking tokens + /// * `amount` - to be locked amount of DOT + pub fn lock_collateral(sender: T::AccountId, amount: BalanceOf) -> Result<(), Error> { + T::DOT::reserve(&sender, amount).map_err(|_| Error::InsufficientFunds)?; + + Self::increase_total_collateral(amount); + + Self::deposit_event(RawEvent::LockCollateral(sender, amount)); + Ok(()) + } + /// Release DOT collateral + /// + /// # Arguments + /// + /// * `sender` - the account releasing tokens + /// * `amount` - the to be released amount of DOT + pub fn release_collateral(sender: T::AccountId, amount: BalanceOf) -> Result<(), Error> { + ensure!( + T::DOT::reserved_balance(&sender) == amount, + Error::InsufficientCollateralAvailable + ); + T::DOT::unreserve(&sender, amount); + + Self::decrease_total_collateral(amount); + + Self::deposit_event(RawEvent::ReleaseCollateral(sender, amount)); + + Ok(()) + } + /// Slash DOT collateral and assign to a receiver. Can only fail if + /// the sender account has too low collateral. + /// + /// # Arguments + /// + /// * `sender` - the account being slashed + /// * `receiver` - the receiver of the amount + /// * `amount` - the to be slashed amount + pub fn slash_collateral( + sender: T::AccountId, + receiver: T::AccountId, + amount: BalanceOf, + ) -> Result<(), Error> { + ensure!( + T::DOT::reserved_balance(&sender) == amount, + Error::InsufficientCollateralAvailable + ); + + // slash the sender's collateral + // remainder should always be 0 and is checked above + let (slashed, _remainder) = T::DOT::slash_reserved(&sender, amount); + + // add slashed amount to receiver and create account if it does not exists + T::DOT::resolve_creating(&receiver, slashed); + + // reserve the created amount for the receiver + T::DOT::reserve(&receiver, amount).map_err(|_| Error::InsufficientFunds)?; + + Self::deposit_event(RawEvent::SlashCollateral(sender, receiver, amount)); - /// Just a dummy entry point. - /// function that can be called by the external world as an extrinsics call - /// takes a parameter of the type `AccountId`, stores it, and emits an event - pub fn do_something(origin, something: u32) -> dispatch::DispatchResult { - // Check it was signed and get the signer. See also: ensure_root and ensure_none - let who = ensure_signed(origin)?; - - // Code to execute when something calls this. - // For example: the following line stores the passed in u32 in the storage - Something::put(something); - - // Here we are raising the Something event - Self::deposit_event(RawEvent::SomethingStored(something, who)); - Ok(()) - } - - /// Another dummy entry point. - /// takes no parameters, attempts to increment storage value, and possibly throws an error - pub fn cause_error(origin) -> dispatch::DispatchResult { - // Check it was signed and get the signer. See also: ensure_root and ensure_none - let _who = ensure_signed(origin)?; - - match Something::get() { - None => Err(Error::::NoneValue)?, - Some(old) => { - let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; - Something::put(new); - Ok(()) - }, - } - } + Ok(()) } } diff --git a/crates/collateral/src/mock.rs b/crates/collateral/src/mock.rs index 2b896f8ded..4c1cac09d4 100644 --- a/crates/collateral/src/mock.rs +++ b/crates/collateral/src/mock.rs @@ -1,7 +1,7 @@ -// Creating mock runtime here - +/// Mocking the test environment use crate::{Module, Trait}; -use frame_support::{impl_outer_origin, parameter_types, weights::Weight}; +use frame_support::{impl_outer_event, impl_outer_origin, parameter_types, weights::Weight}; +use pallet_balances as balances; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -13,9 +13,25 @@ impl_outer_origin! { pub enum Origin for Test {} } +mod test_events { + pub use crate::Event; +} + +impl_outer_event! { + pub enum TestEvent for Test { + system, + test_events, + balances, + } +} + // For testing the pallet, we construct most of a mock runtime. This means // first constructing a configuration type (`Test`) which `impl`s each of the // configuration traits of pallets we want to use. + +pub type AccountId = u64; +pub type Balance = u64; + #[derive(Clone, Eq, PartialEq)] pub struct Test; parameter_types! { @@ -31,30 +47,68 @@ impl system::Trait for Test { type BlockNumber = u64; type Hash = H256; type Hashing = BlakeTwo256; - type AccountId = u64; + type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; - type Event = (); + type Event = TestEvent; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; type MaximumBlockLength = MaximumBlockLength; type AvailableBlockRatio = AvailableBlockRatio; type Version = (); type ModuleToIndex = (); - type AccountData = (); + type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); } +parameter_types! { + pub const ExistentialDeposit: u64 = 1; +} +impl pallet_balances::Trait for Test { + type Balance = Balance; + type Event = TestEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; +} + impl Trait for Test { - type Event = (); + type DOT = Balances; + type Event = TestEvent; +} + +pub type Error = crate::Error; + +pub type System = system::Module; +pub type Balances = pallet_balances::Module; +pub type Collateral = Module; + +pub const ALICE: AccountId = 1; +pub const BOB: AccountId = 2; +pub const ALICE_BALANCE: u64 = 1_000_000; +pub const BOB_BALANCE: u64 = 1_000_000; + +pub struct ExtBuilder; + +impl ExtBuilder { + pub fn build() -> sp_io::TestExternalities { + let mut storage = system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(ALICE, ALICE_BALANCE), (BOB, BOB_BALANCE)], + } + .assimilate_storage(&mut storage) + .unwrap(); + + storage.into() + } } -pub type TemplateModule = Module; -// This function basically just builds a genesis storage key/value store according to -// our desired mockup. -pub fn new_test_ext() -> sp_io::TestExternalities { - system::GenesisConfig::default() - .build_storage::() - .unwrap() - .into() +pub fn run_test(test: T) -> () +where + T: FnOnce() -> (), +{ + ExtBuilder::build().execute_with(test); } diff --git a/crates/collateral/src/tests.rs b/crates/collateral/src/tests.rs index 46957f4b8c..3a73a9f315 100644 --- a/crates/collateral/src/tests.rs +++ b/crates/collateral/src/tests.rs @@ -1,26 +1,185 @@ -// Tests to be written here +/// Tests for Collateral +use crate::mock::*; +use crate::RawEvent; +use frame_support::{assert_err, assert_ok}; -use crate::{mock::*, Error}; -use frame_support::{assert_noop, assert_ok}; +/// Total supply +#[test] +fn test_total_supply_correct() { + run_test(|| { + // initial supply + let desired_total = ALICE_BALANCE + BOB_BALANCE; + let total = Collateral::get_total_supply(); + + assert_eq!(desired_total, total); + }) +} + +/// Total collateral +#[test] +fn test_total_collateral_correct() { + run_test(|| { + // initial supply + let desired_total_collateral = 0; + let increase_amount: Balance = 5; + let decrease_amount: Balance = 3; + + let total_collateral = Collateral::get_total_collateral(); + assert_eq!(desired_total_collateral, total_collateral); + + Collateral::increase_total_collateral(increase_amount); + let increased_collateral = Collateral::get_total_collateral(); + assert_eq!(total_collateral + increase_amount, increased_collateral); + + Collateral::decrease_total_collateral(decrease_amount); + let decreased_collateral = Collateral::get_total_collateral(); + assert_eq!(increased_collateral - decrease_amount, decreased_collateral); + }) +} + +/// Lock collateral +#[test] +fn test_lock_collateral_succeeds() { + run_test(|| { + let sender = ALICE; + let amount: Balance = 5; + + let init_collateral = Collateral::get_collateral_from_account(ALICE); + let init_total = Collateral::get_total_collateral(); + + assert_ok!(Collateral::lock_collateral(sender, amount)); + let lock_event = TestEvent::test_events(RawEvent::LockCollateral(ALICE, amount)); + + assert!(System::events().iter().any(|a| a.event == lock_event)); + + let collateral = Collateral::get_collateral_from_account(ALICE); + let total = Collateral::get_total_collateral(); + + assert_eq!(collateral, init_collateral + amount); + assert_eq!(total, init_total + amount); + }) +} + +#[test] +fn test_lock_collateral_fails() { + run_test(|| { + let sender = ALICE; + let amount = ALICE_BALANCE + 5; + + let init_collateral = Collateral::get_collateral_from_account(ALICE); + let init_total = Collateral::get_total_collateral(); + + assert_err!( + Collateral::lock_collateral(sender, amount), + Error::InsufficientFunds + ); + + let collateral = Collateral::get_collateral_from_account(ALICE); + let total = Collateral::get_total_collateral(); + + assert_eq!(collateral, init_collateral); + assert_eq!(total, init_total); + }) +} + +/// Release collateral +#[test] +fn test_release_collateral_succeeds() { + run_test(|| { + let sender = ALICE; + let amount = ALICE_BALANCE; + + assert_ok!(Collateral::lock_collateral(sender, amount)); + + let init_collateral = Collateral::get_collateral_from_account(ALICE); + let init_total = Collateral::get_total_collateral(); + + assert_ok!(Collateral::release_collateral(sender, amount)); + let release_event = TestEvent::test_events(RawEvent::ReleaseCollateral(ALICE, amount)); + + assert!(System::events().iter().any(|a| a.event == release_event)); + + let collateral = Collateral::get_collateral_from_account(ALICE); + let total = Collateral::get_total_collateral(); + + assert_eq!(collateral, init_collateral - amount); + assert_eq!(total, init_total - amount); + }) +} + +#[test] +fn test_release_collateral_fails() { + run_test(|| { + let sender = ALICE; + let lock_amount = ALICE_BALANCE; + + let init_collateral = Collateral::get_collateral_from_account(ALICE); + let init_total = Collateral::get_total_collateral(); + + assert_err!( + Collateral::release_collateral(sender, lock_amount), + Error::InsufficientCollateralAvailable + ); + let collateral = Collateral::get_collateral_from_account(ALICE); + let total = Collateral::get_total_collateral(); + + assert_eq!(collateral, init_collateral); + assert_eq!(total, init_total); + }) +} + +/// Slash collateral #[test] -fn it_works_for_default_value() { - new_test_ext().execute_with(|| { - // Just a dummy test for the dummy function `do_something` - // calling the `do_something` function with a value 42 - assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); - // asserting that the stored value is equal to what we stored - assert_eq!(TemplateModule::something(), Some(42)); - }); +fn test_slash_collateral_succeeds() { + run_test(|| { + let sender = ALICE; + let receiver = BOB; + let amount = ALICE_BALANCE; + + assert_ok!(Collateral::lock_collateral(sender, amount)); + + let init_collateral_alice = Collateral::get_collateral_from_account(ALICE); + let init_collateral_bob = Collateral::get_collateral_from_account(BOB); + let init_total = Collateral::get_total_collateral(); + + assert_ok!(Collateral::slash_collateral(sender, receiver, amount)); + let slash_event = TestEvent::test_events(RawEvent::SlashCollateral(ALICE, BOB, amount)); + + assert!(System::events().iter().any(|a| a.event == slash_event)); + + let collateral_alice = Collateral::get_collateral_from_account(ALICE); + let collateral_bob = Collateral::get_collateral_from_account(BOB); + let total = Collateral::get_total_collateral(); + + assert_eq!(collateral_alice, init_collateral_alice - amount); + assert_eq!(collateral_bob, init_collateral_bob + amount); + assert_eq!(total, init_total); + }) } #[test] -fn correct_error_for_none_value() { - new_test_ext().execute_with(|| { - // Ensure the correct error is thrown on None value - assert_noop!( - TemplateModule::cause_error(Origin::signed(1)), - Error::::NoneValue +fn test_slash_collateral_fails() { + run_test(|| { + let sender = ALICE; + let receiver = BOB; + let amount = ALICE_BALANCE; + + let init_collateral_alice = Collateral::get_collateral_from_account(ALICE); + let init_collateral_bob = Collateral::get_collateral_from_account(BOB); + let init_total = Collateral::get_total_collateral(); + + assert_err!( + Collateral::slash_collateral(sender, receiver, amount), + Error::InsufficientCollateralAvailable ); - }); + + let collateral_alice = Collateral::get_collateral_from_account(ALICE); + let collateral_bob = Collateral::get_collateral_from_account(BOB); + let total = Collateral::get_total_collateral(); + + assert_eq!(collateral_alice, init_collateral_alice); + assert_eq!(collateral_bob, init_collateral_bob); + assert_eq!(total, init_total); + }) } From 05a4748601bac5680a53a86a64d6ce8f5f213e8c Mon Sep 17 00:00:00 2001 From: Daniel Perez Date: Sat, 4 Apr 2020 01:59:16 +0100 Subject: [PATCH 30/37] Unify type for raw block headers --- crates/bitcoin/src/parser.rs | 35 +++----- crates/bitcoin/src/types.rs | 79 ++++++++++++------ crates/btc-relay/src/lib.rs | 26 +++--- crates/btc-relay/src/tests.rs | 146 +++++++++++++++------------------- 4 files changed, 138 insertions(+), 148 deletions(-) diff --git a/crates/bitcoin/src/parser.rs b/crates/bitcoin/src/parser.rs index a7e173e5a3..0de816a1f9 100644 --- a/crates/bitcoin/src/parser.rs +++ b/crates/bitcoin/src/parser.rs @@ -64,8 +64,8 @@ impl Parsable for BlockHeader { if position + 80 > raw_bytes.len() { return Err(Error::EOS); } - let header_bytes = header_from_bytes(&raw_bytes[position..position + 80]); - let block_header = parse_block_header(header_bytes)?; + let header_bytes = RawBlockHeader::from_bytes(&raw_bytes[position..position + 80])?; + let block_header = parse_block_header(&header_bytes)?; Ok((block_header, 80)) } } @@ -211,28 +211,17 @@ pub trait FromLeBytes: Sized { impl FromLeBytes for BlockHeader { fn from_le_bytes(bytes: &[u8]) -> Result { - parse_block_header(header_from_bytes(bytes)) + parse_block_header(&RawBlockHeader::from_bytes(bytes)?) } } -/// Returns a raw block header from a bytes slice -/// -/// # Arguments -/// -/// * `bytes` - A slice containing the header -pub fn header_from_bytes(bytes: &[u8]) -> RawBlockHeader { - let mut result: RawBlockHeader = [0; 80]; - result.copy_from_slice(&bytes); - result -} - /// Parses the raw bitcoin header into a Rust struct /// /// # Arguments /// /// * `header` - An 80-byte Bitcoin header -pub fn parse_block_header(raw_header: RawBlockHeader) -> Result { - let mut parser = BytesParser::new(&raw_header); +pub fn parse_block_header(raw_header: &RawBlockHeader) -> Result { + let mut parser = BytesParser::new(raw_header.as_slice()); let version: i32 = parser.parse()?; let hash_prev_block: H256Le = parser.parse()?; let merkle_root: H256Le = parser.parse()?; @@ -334,7 +323,7 @@ pub fn parse_transaction(raw_transaction: &[u8]) -> Result { } /// Parses a transaction input -pub fn parse_transaction_input( +fn parse_transaction_input( raw_input: &[u8], version: i32, ) -> Result<(TransactionInput, usize), Error> { @@ -382,7 +371,7 @@ pub fn parse_transaction_input( )) } -pub fn parse_transaction_output(raw_output: &[u8]) -> Result<(TransactionOutput, usize), Error> { +fn parse_transaction_output(raw_output: &[u8]) -> Result<(TransactionOutput, usize), Error> { let mut parser = BytesParser::new(raw_output); let value: i64 = parser.parse()?; let script_size: CompactUint = parser.parse()?; @@ -393,12 +382,6 @@ pub fn parse_transaction_output(raw_output: &[u8]) -> Result<(TransactionOutput, Ok((TransactionOutput { value, script }, parser.position)) } -pub fn extract_value(raw_output: &[u8]) -> u64 { - let mut arr: [u8; 8] = Default::default(); - arr.copy_from_slice(&raw_output[..8]); - u64::from_le_bytes(arr) -} - pub fn extract_address_hash(output_script: &[u8]) -> Result, Error> { let script_len = output_script.len(); // Witness @@ -477,8 +460,8 @@ mod tests { "24d95a54" + // ........................... Unix time: 1415239972 "30c31b18" + // ........................... Target: 0x1bc330 * 256**(0x18-3) "fe9f0864"; - let raw_header = hex::decode(&hex_header[..]).unwrap(); - let parsed_header = parse_block_header(header_from_bytes(&raw_header)).unwrap(); + let raw_header = RawBlockHeader::from_hex(&hex_header).unwrap(); + let parsed_header = parse_block_header(&raw_header).unwrap(); assert_eq!(parsed_header.version, 2); assert_eq!(parsed_header.timestamp, 1415239972); assert_eq!( diff --git a/crates/bitcoin/src/types.rs b/crates/bitcoin/src/types.rs index 5cfcf26e28..8d93490422 100644 --- a/crates/bitcoin/src/types.rs +++ b/crates/bitcoin/src/types.rs @@ -12,16 +12,58 @@ use btc_core::Error; /// Custom Types /// Bitcoin Raw Block Header type -pub type RawBlockHeader = [u8; 80]; +#[derive(Encode, Decode, Copy, Clone)] +pub struct RawBlockHeader([u8; 80]); + +impl RawBlockHeader { + /// Returns a raw block header from a bytes slice + /// + /// # Arguments + /// + /// * `bytes` - A slice containing the header + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != 80 { + return Err(Error::InvalidHeaderSize); + } + let mut result: [u8; 80] = [0; 80]; + result.copy_from_slice(&bytes); + Ok(RawBlockHeader(result)) + } -// #[derive(Encode, Decode, Default, Copy, Clone, PartialEq)] -// struct RawBlockHeader(pub [u8; 32]); + /// Returns a raw block header from a bytes slice + /// + /// # Arguments + /// + /// * `bytes` - A slice containing the header + pub fn from_hex>(hex_string: T) -> Result { + let bytes = hex::decode(hex_string).map_err(|_e| Error::MalformedHeader)?; + Self::from_bytes(&bytes) + } -// impl RawBlockHeader { -// fn hash(&self) -> H256Le { + /// Returns the hash of the block header using Bitcoin's double sha256 + pub fn hash(&self) -> H256Le { + H256Le::from_bytes_le(&sha256d(self.as_slice())) + } + + /// Returns the block header as a slice + pub fn as_slice(&self) -> &[u8] { + &self.0 + } +} + +impl PartialEq for RawBlockHeader { + fn eq(&self, other: &Self) -> bool { + let self_bytes = &self.0[..]; + let other_bytes = &other.0[..]; + self_bytes == other_bytes + } +} -// } -// } +impl std::fmt::Debug for RawBlockHeader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_list().entries(self.0.iter()).finish() + } +} // Constants pub const P2PKH_SCRIPT_SIZE: u32 = 25; @@ -42,16 +84,6 @@ pub struct BlockHeader { pub nonce: u32, } -impl BlockHeader { - pub fn block_hash_le(bytes: &[u8]) -> H256Le { - sha256d_le(bytes) - } - - pub fn block_hash_be(bytes: &[u8]) -> H256 { - sha256d_be(bytes) - } -} - /// Bitcoin transaction input #[derive(PartialEq, Clone, Debug)] pub struct TransactionInput { @@ -95,7 +127,6 @@ impl Transaction { /// Bitcoin Enriched Block Headers #[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Debug)] -// #[cfg_attr(feature = "std", derive(Debug))] pub struct RichBlockHeader { pub block_hash: H256Le, pub block_header: BlockHeader, @@ -105,23 +136,22 @@ pub struct RichBlockHeader { impl RichBlockHeader { // Creates a RichBlockHeader given a RawBlockHeader, Blockchain identifier and block height - pub fn construct_rich_block_header( + pub fn construct( raw_block_header: RawBlockHeader, chain_ref: u32, block_height: u32, ) -> Result { Ok(RichBlockHeader { - block_hash: BlockHeader::block_hash_le(&raw_block_header), - block_header: BlockHeader::from_le_bytes(&raw_block_header)?, - block_height, - chain_ref, + block_hash: raw_block_header.hash(), + block_header: BlockHeader::from_le_bytes(raw_block_header.as_slice())?, + block_height: block_height, + chain_ref: chain_ref, }) } } /// Representation of a Bitcoin blockchain #[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] -//#[cfg_attr(feature = "std", derive(Debug))] pub struct BlockChain { pub chain_id: u32, pub start_height: u32, @@ -132,7 +162,6 @@ pub struct BlockChain { /// Represents a bitcoin 32 bytes hash digest encoded in little-endian #[derive(Encode, Decode, Default, PartialEq, Eq, Clone, Copy, Debug)] -//#[cfg_attr(feature="std", derive(Debug))] pub struct H256Le { content: [u8; 32], } diff --git a/crates/btc-relay/src/lib.rs b/crates/btc-relay/src/lib.rs index 0160175f55..37eb104899 100644 --- a/crates/btc-relay/src/lib.rs +++ b/crates/btc-relay/src/lib.rs @@ -25,8 +25,7 @@ use system::ensure_signed; // Crates use bitcoin::merkle::{MerkleProof, ProofResult}; use bitcoin::parser::{ - extract_address_hash, extract_op_return_data, header_from_bytes, parse_block_header, - parse_transaction, + extract_address_hash, extract_op_return_data, parse_block_header, parse_transaction, }; use bitcoin::types::{ BlockChain, BlockHeader, H256Le, RawBlockHeader, RichBlockHeader, Transaction, @@ -112,7 +111,7 @@ decl_module! { /// block header. fn initialize( origin, - block_header_bytes: Vec, + raw_block_header: RawBlockHeader, block_height: u32) -> DispatchResult { @@ -122,14 +121,12 @@ decl_module! { ensure!(!Self::best_block_exists(), Error::AlreadyInitialized); // Parse the block header bytes to extract the required info - let raw_block_header = header_from_bytes(&block_header_bytes); - let basic_block_header = parse_block_header(raw_block_header)?; - let block_header_hash = BlockHeader::block_hash_le(&raw_block_header); + let basic_block_header = parse_block_header(&raw_block_header)?; + let block_header_hash = raw_block_header.hash(); // construct the BlockChain struct let blockchain = Self::initialize_blockchain( block_height, block_header_hash); - // Create rich block header let block_header = RichBlockHeader { block_hash: block_header_hash, @@ -165,9 +162,9 @@ decl_module! { /// /// # Arguments /// - /// * `block_header_bytes` - 80 byte raw Bitcoin block header. + /// * `raw_block_header` - 80 byte raw Bitcoin block header. fn store_block_header( - origin, block_header_bytes: Vec + origin, raw_block_header: RawBlockHeader ) -> DispatchResult { let _ = ensure_signed(origin)?; // Check if BTC _Parachain is in shutdown state.+ @@ -179,9 +176,8 @@ decl_module! { // ); // Parse the block header bytes to extract the required info - let raw_block_header = header_from_bytes(&block_header_bytes); - let basic_block_header = Self::verify_block_header(raw_block_header)?; - let block_header_hash = BlockHeader::block_hash_le(&raw_block_header); + let basic_block_header = Self::verify_block_header(&raw_block_header)?; + let block_header_hash = raw_block_header.hash(); let prev_header = Self::get_block_header_from_hash( basic_block_header.hash_prev_block @@ -620,10 +616,10 @@ impl Module { /// /// # Panics /// If ParachainStatus in Security module is not set to RUNNING - fn verify_block_header(raw_block_header: RawBlockHeader) -> Result { - let basic_block_header = parse_block_header(raw_block_header)?; + fn verify_block_header(raw_block_header: &RawBlockHeader) -> Result { + let basic_block_header = parse_block_header(&raw_block_header)?; - let block_header_hash = BlockHeader::block_hash_le(&raw_block_header); + let block_header_hash = raw_block_header.hash(); // Check that the block header is not yet stored in BTC-Relay ensure!( diff --git a/crates/btc-relay/src/tests.rs b/crates/btc-relay/src/tests.rs index a113a9ede3..92a2693230 100644 --- a/crates/btc-relay/src/tests.rs +++ b/crates/btc-relay/src/tests.rs @@ -39,7 +39,7 @@ fn get_block_header_from_hash_succeeds() { run_test(|| { let chain_ref: u32 = 2; let block_height: u32 = 100; - let block_header = hex::decode(sample_block_header()).unwrap(); + let block_header = hex::decode(sample_block_header_hex()).unwrap(); let rich_header = RichBlockHeader { block_hash: H256Le::zero(), @@ -94,8 +94,8 @@ fn get_block_chain_from_id_succeeds() { fn initialize_once_succeeds() { run_test(|| { let block_height: u32 = 1; - let block_header = hex::decode(sample_block_header()).unwrap(); - let block_header_hash = BlockHeader::block_hash_le(&block_header); + let block_header = RawBlockHeader::from_hex(sample_block_header_hex()).unwrap(); + let block_header_hash = block_header.hash(); BTCRelay::best_block_exists.mock_safe(|| MockResult::Return(false)); assert_ok!(BTCRelay::initialize( @@ -114,12 +114,12 @@ fn initialize_once_succeeds() { fn initialize_best_block_already_set_fails() { run_test(|| { let block_height: u32 = 1; - let block_header = hex::decode(sample_block_header()).unwrap(); + let raw_block_header = RawBlockHeader::from_hex(sample_block_header_hex()).unwrap(); BTCRelay::best_block_exists.mock_safe(|| MockResult::Return(true)); assert_err!( - BTCRelay::initialize(Origin::signed(3), block_header, block_height), + BTCRelay::initialize(Origin::signed(3), raw_block_header, block_height), Error::AlreadyInitialized ); }) @@ -129,18 +129,19 @@ fn initialize_best_block_already_set_fails() { #[test] fn store_block_header_on_mainchain_succeeds() { run_test(|| { - BTCRelay::verify_block_header - .mock_safe(|h| MockResult::Return(Ok(BlockHeader::from_le_bytes(&h).unwrap()))); + BTCRelay::verify_block_header.mock_safe(|h| { + MockResult::Return(Ok(BlockHeader::from_le_bytes(h.as_slice()).unwrap())) + }); BTCRelay::block_header_exists.mock_safe(|_| MockResult::Return(true)); let chain_ref: u32 = 0; let start_height: u32 = 0; let block_height: u32 = 100; - let block_header = hex::decode(sample_block_header()).unwrap(); + let block_header = RawBlockHeader::from_hex(sample_block_header_hex()).unwrap(); let rich_header = RichBlockHeader { block_hash: H256Le::zero(), - block_header: BlockHeader::from_le_bytes(&block_header).unwrap(), + block_header: parse_block_header(&block_header).unwrap(), block_height: block_height, chain_ref: chain_ref, }; @@ -153,7 +154,7 @@ fn store_block_header_on_mainchain_succeeds() { BTCRelay::get_block_chain_from_id .mock_safe(move |_: u32| MockResult::Return(prev_blockchain.clone())); - let block_header_hash = BlockHeader::block_hash_le(&block_header); + let block_header_hash = block_header.hash(); assert_ok!(BTCRelay::store_block_header( Origin::signed(3), block_header @@ -170,18 +171,17 @@ fn store_block_header_on_mainchain_succeeds() { #[test] fn store_block_header_on_fork_succeeds() { run_test(|| { - BTCRelay::verify_block_header - .mock_safe(|h| MockResult::Return(Ok(BlockHeader::from_le_bytes(&h).unwrap()))); + BTCRelay::verify_block_header.mock_safe(|h| MockResult::Return(parse_block_header(&h))); BTCRelay::block_header_exists.mock_safe(|_| MockResult::Return(true)); let chain_ref: u32 = 1; let start_height: u32 = 20; let block_height: u32 = 100; - let block_header = hex::decode(sample_block_header()).unwrap(); + let block_header = RawBlockHeader::from_hex(sample_block_header_hex()).unwrap(); let rich_header = RichBlockHeader { block_hash: H256Le::zero(), - block_header: BlockHeader::from_le_bytes(&block_header).unwrap(), + block_header: parse_block_header(&block_header).unwrap(), block_height: block_height - 1, chain_ref: chain_ref, }; @@ -193,7 +193,7 @@ fn store_block_header_on_fork_succeeds() { BTCRelay::get_block_chain_from_id .mock_safe(move |_: u32| MockResult::Return(prev_blockchain.clone())); - let block_header_hash = BlockHeader::block_hash_le(&block_header); + let block_header_hash = block_header.hash(); assert_ok!(BTCRelay::store_block_header( Origin::signed(3), block_header @@ -543,7 +543,7 @@ fn swap_main_blockchain_succeeds() { }) } -/// verify_block_header +/// verify_block_header #[test] fn test_verify_block_header_no_retarget_succeeds() { run_test(|| { @@ -552,8 +552,7 @@ fn test_verify_block_header_no_retarget_succeeds() { let block_height: u32 = 100; let genesis_header = sample_parsed_genesis_header(chain_ref, block_height); - let raw_first_header = - header_from_bytes(&(hex::decode(sample_raw_first_header()).unwrap())); + let raw_first_header = RawBlockHeader::from_hex(sample_raw_first_header()).unwrap(); let rich_first_header = sample_parsed_first_block(chain_ref, block_height + 1); // Prev block is genesis @@ -562,7 +561,7 @@ fn test_verify_block_header_no_retarget_succeeds() { // Not duplicate block BTCRelay::block_header_exists.mock_safe(move |_| MockResult::Return(false)); - let verified_header = BTCRelay::verify_block_header(raw_first_header).unwrap(); + let verified_header = BTCRelay::verify_block_header(&raw_first_header).unwrap(); assert_eq!(verified_header, rich_first_header.block_header) }) } @@ -576,14 +575,10 @@ fn test_verify_block_header_correct_retarget_increase_succeeds() { // Sample interval with INCREASING target let retarget_headers = sample_retarget_interval_increase(); - let prev_block_header_rich = RichBlockHeader::construct_rich_block_header( - retarget_headers[1], - chain_ref, - block_height, - ) - .unwrap(); + let prev_block_header_rich = + RichBlockHeader::construct(retarget_headers[1], chain_ref, block_height).unwrap(); - let curr_block_header = BlockHeader::from_le_bytes(&retarget_headers[2]).unwrap(); + let curr_block_header = parse_block_header(&retarget_headers[2]).unwrap(); // Prev block exists BTCRelay::get_block_header_from_hash .mock_safe(move |_| MockResult::Return(Ok(prev_block_header_rich))); @@ -593,7 +588,7 @@ fn test_verify_block_header_correct_retarget_increase_succeeds() { BTCRelay::compute_new_target .mock_safe(move |_, _| MockResult::Return(Ok(curr_block_header.target))); - let verified_header = BTCRelay::verify_block_header(retarget_headers[2]).unwrap(); + let verified_header = BTCRelay::verify_block_header(&retarget_headers[2]).unwrap(); assert_eq!(verified_header, curr_block_header) }) } @@ -607,14 +602,10 @@ fn test_verify_block_header_correct_retarget_decrease_succeeds() { // Sample interval with DECREASING target let retarget_headers = sample_retarget_interval_decrease(); - let prev_block_header_rich = RichBlockHeader::construct_rich_block_header( - retarget_headers[1], - chain_ref, - block_height, - ) - .unwrap(); + let prev_block_header_rich = + RichBlockHeader::construct(retarget_headers[1], chain_ref, block_height).unwrap(); - let curr_block_header = BlockHeader::from_le_bytes(&retarget_headers[2]).unwrap(); + let curr_block_header = parse_block_header(&retarget_headers[2]).unwrap(); // Prev block exists BTCRelay::get_block_header_from_hash .mock_safe(move |_| MockResult::Return(Ok(prev_block_header_rich))); @@ -624,7 +615,7 @@ fn test_verify_block_header_correct_retarget_decrease_succeeds() { BTCRelay::compute_new_target .mock_safe(move |_, _| MockResult::Return(Ok(curr_block_header.target))); - let verified_header = BTCRelay::verify_block_header(retarget_headers[2]).unwrap(); + let verified_header = BTCRelay::verify_block_header(&retarget_headers[2]).unwrap(); assert_eq!(verified_header, curr_block_header) }) } @@ -637,14 +628,10 @@ fn test_verify_block_header_missing_retarget_succeeds() { let block_height: u32 = 2015; let retarget_headers = sample_retarget_interval_increase(); - let prev_block_header_rich = RichBlockHeader::construct_rich_block_header( - retarget_headers[1], - chain_ref, - block_height, - ) - .unwrap(); + let prev_block_header_rich = + RichBlockHeader::construct(retarget_headers[1], chain_ref, block_height).unwrap(); - let curr_block_header = BlockHeader::from_le_bytes(&retarget_headers[2]).unwrap(); + let curr_block_header = parse_block_header(&retarget_headers[2]).unwrap(); // Prev block exists BTCRelay::get_block_header_from_hash .mock_safe(move |_| MockResult::Return(Ok(prev_block_header_rich))); @@ -655,7 +642,7 @@ fn test_verify_block_header_missing_retarget_succeeds() { .mock_safe(move |_, _| MockResult::Return(Ok(curr_block_header.target + 1))); assert_err!( - BTCRelay::verify_block_header(retarget_headers[2]), + BTCRelay::verify_block_header(&retarget_headers[2]), Error::DiffTargetHeader ); }) @@ -668,14 +655,11 @@ fn test_compute_new_target() { let block_height: u32 = 2016; let retarget_headers = sample_retarget_interval_increase(); - let last_retarget_time = BlockHeader::from_le_bytes(&retarget_headers[0]) - .unwrap() - .timestamp; + let last_retarget_time = parse_block_header(&retarget_headers[0]).unwrap().timestamp; let prev_block_header = - RichBlockHeader::construct_rich_block_header(retarget_headers[1], chain_ref, block_height) - .unwrap(); + RichBlockHeader::construct(retarget_headers[1], chain_ref, block_height).unwrap(); - let curr_block_header = BlockHeader::from_le_bytes(&retarget_headers[2]).unwrap(); + let curr_block_header = parse_block_header(&retarget_headers[2]).unwrap(); BTCRelay::get_last_retarget_time .mock_safe(move |_, _| MockResult::Return(Ok(last_retarget_time))); @@ -704,10 +688,9 @@ fn test_verify_block_header_duplicate_fails() { MockResult::Return(true) }); - let raw_first_header = - header_from_bytes(&(hex::decode(sample_raw_first_header()).unwrap())); + let raw_first_header = RawBlockHeader::from_hex(sample_raw_first_header()).unwrap(); assert_err!( - BTCRelay::verify_block_header(raw_first_header), + BTCRelay::verify_block_header(&raw_first_header), Error::DuplicateBlock ); }) @@ -722,10 +705,9 @@ fn test_verify_block_header_no_prev_block_fails() { // submitted block does not yet exist BTCRelay::block_header_exists.mock_safe(move |_| MockResult::Return(false)); - let raw_first_header = - header_from_bytes(&(hex::decode(sample_raw_first_header()).unwrap())); + let raw_first_header = RawBlockHeader::from_hex(sample_raw_first_header()).unwrap(); assert_err!( - BTCRelay::verify_block_header(raw_first_header), + BTCRelay::verify_block_header(&raw_first_header), Error::PrevBlock ); }) @@ -741,7 +723,7 @@ fn test_verify_block_header_low_diff_fails() { // block header with high target but weak hash let raw_first_header_weak = - header_from_bytes(&(hex::decode(sample_raw_first_header_low_diff()).unwrap())); + RawBlockHeader::from_hex(sample_raw_first_header_low_diff()).unwrap(); // Prev block is genesis BTCRelay::get_block_header_from_hash @@ -750,7 +732,7 @@ fn test_verify_block_header_low_diff_fails() { BTCRelay::block_header_exists.mock_safe(move |_| MockResult::Return(false)); assert_err!( - BTCRelay::verify_block_header(raw_first_header_weak), + BTCRelay::verify_block_header(&raw_first_header_weak), Error::LowDiff ); }); @@ -930,7 +912,7 @@ fn test_flag_block_error_succeeds() { let chain_ref: u32 = 1; let start_height: u32 = 10; let block_height: u32 = 100; - let block_header = hex::decode(sample_block_header()).unwrap(); + let block_header = hex::decode(sample_block_header_hex()).unwrap(); let rich_header = RichBlockHeader { block_hash: H256Le::zero(), @@ -975,7 +957,7 @@ fn test_flag_block_error_fails() { let chain_ref: u32 = 1; let start_height: u32 = 20; let block_height: u32 = 100; - let block_header = hex::decode(sample_block_header()).unwrap(); + let block_header = hex::decode(sample_block_header_hex()).unwrap(); let rich_header = RichBlockHeader { block_hash: H256Le::zero(), @@ -1007,7 +989,7 @@ fn test_clear_block_error_succeeds() { let chain_ref: u32 = 1; let start_height: u32 = 15; let block_height: u32 = 100; - let block_header = hex::decode(sample_block_header()).unwrap(); + let block_header = hex::decode(sample_block_header_hex()).unwrap(); let rich_header = RichBlockHeader { block_hash: H256Le::zero(), @@ -1055,7 +1037,7 @@ fn test_clear_block_error_fails() { let chain_ref: u32 = 1; let start_height: u32 = 20; let block_height: u32 = 100; - let block_header = hex::decode(sample_block_header()).unwrap(); + let block_header = hex::decode(sample_block_header_hex()).unwrap(); let rich_header = RichBlockHeader { block_hash: H256Le::zero(), @@ -1448,7 +1430,7 @@ fn store_blockchain_and_random_headers( // create and insert main chain headers for height in chain.start_height..chain.max_height + 1 { - let block_header = hex::decode(sample_block_header()).unwrap(); + let block_header = hex::decode(sample_block_header_hex()).unwrap(); let mut fake_block = height.to_be_bytes().repeat(7); fake_block.append(&mut id.to_be_bytes().to_vec()); let block_hash = H256Le::from_bytes_be(fake_block.as_slice()); @@ -1475,21 +1457,21 @@ fn sample_raw_genesis_header() -> String { } fn sample_parsed_genesis_header(chain_ref: u32, block_height: u32) -> RichBlockHeader { - let genesis_header = hex::decode(sample_raw_genesis_header()).unwrap(); + let genesis_header = RawBlockHeader::from_hex(sample_raw_genesis_header()).unwrap(); RichBlockHeader { - block_hash: BlockHeader::block_hash_le(&genesis_header), - block_header: BlockHeader::from_le_bytes(&genesis_header).unwrap(), + block_hash: genesis_header.hash(), + block_header: parse_block_header(&genesis_header).unwrap(), block_height: block_height, chain_ref: chain_ref, } } fn sample_raw_first_header_low_diff() -> String { - "01000000".to_owned() + + "01000000".to_owned() + "cb60e68ead74025dcfd4bf4673f3f71b1e678be9c6e6585f4544c79900000000" + - "c7f42be7f83eddf2005272412b01204352a5fddbca81942c115468c3c4ec2fff" + - "827ad949" + - "413b1417" + // high target + "c7f42be7f83eddf2005272412b01204352a5fddbca81942c115468c3c4ec2fff" + + "827ad949" + + "413b1417" + // high target "21e05e45" } @@ -1498,10 +1480,10 @@ fn sample_raw_first_header() -> String { } fn sample_parsed_first_block(chain_ref: u32, block_height: u32) -> RichBlockHeader { - let block_header = hex::decode(sample_raw_first_header()).unwrap(); + let block_header = RawBlockHeader::from_hex(sample_raw_first_header()).unwrap(); RichBlockHeader { - block_hash: BlockHeader::block_hash_le(&block_header), - block_header: BlockHeader::from_le_bytes(&block_header).unwrap(), + block_hash: block_header.hash(), + block_header: parse_block_header(&block_header).unwrap(), block_height: block_height, chain_ref: chain_ref, } @@ -1509,22 +1491,22 @@ fn sample_parsed_first_block(chain_ref: u32, block_height: u32) -> RichBlockHead fn sample_retarget_interval_increase() -> [RawBlockHeader; 3] { // block height 66528 - let last_retarget_header = header_from_bytes(&hex::decode("01000000".to_owned() + "4e8e5cf3c4e4b8f63a9cf88beb2dbaba1949182101ae4e5cf54ad100000000009f2a2344e8112b0d7bd8089414106ee5f17bb6cd64078883e1b661fa251aac6bed1d3c4cf4a3051c4dcd2b02").unwrap()); + let last_retarget_header = RawBlockHeader::from_hex("01000000".to_owned() + "4e8e5cf3c4e4b8f63a9cf88beb2dbaba1949182101ae4e5cf54ad100000000009f2a2344e8112b0d7bd8089414106ee5f17bb6cd64078883e1b661fa251aac6bed1d3c4cf4a3051c4dcd2b02").unwrap(); // block height 66543 - let prev_block_header = header_from_bytes(&hex::decode("01000000".to_owned() + "1e321d88cb25946c4ca521eece3752803c021f9403fc4e0171203a0500000000317057f8b50414848a5a3a26d9eb8ace3d6f5495df456d0104dd1421159faf5029293c4cf4a3051c73199005").unwrap()); + let prev_block_header = RawBlockHeader::from_hex("01000000".to_owned() + "1e321d88cb25946c4ca521eece3752803c021f9403fc4e0171203a0500000000317057f8b50414848a5a3a26d9eb8ace3d6f5495df456d0104dd1421159faf5029293c4cf4a3051c73199005").unwrap(); // block height 68544 - let curr_header = header_from_bytes(&hex::decode("01000000".to_owned() + "fb57c71ccd211b3de4ccc2e23b50a7cdb72aab91e60737b3a2bfdf030000000088a88ad9df68925e880e5d52b7e50cef225871c68b40a2cd0bca1084cd436037f388404cfd68011caeb1f801").unwrap()); + let curr_header = RawBlockHeader::from_hex("01000000".to_owned() + "fb57c71ccd211b3de4ccc2e23b50a7cdb72aab91e60737b3a2bfdf030000000088a88ad9df68925e880e5d52b7e50cef225871c68b40a2cd0bca1084cd436037f388404cfd68011caeb1f801").unwrap(); [last_retarget_header, prev_block_header, curr_header] } fn sample_retarget_interval_decrease() -> [RawBlockHeader; 3] { // block height 558432 - let last_retarget_header = header_from_bytes(&hex::decode("00c0ff2f".to_owned() + "6550b5dae76559589e3e3e135237072b6bc498949da6280000000000000000005988783435f506d2ccfbadb484e56d6f1d5dfdd480650acae1e3b43d3464ea73caf13b5c33d62f171d508fdb").unwrap()); + let last_retarget_header = RawBlockHeader::from_hex("00c0ff2f".to_owned() + "6550b5dae76559589e3e3e135237072b6bc498949da6280000000000000000005988783435f506d2ccfbadb484e56d6f1d5dfdd480650acae1e3b43d3464ea73caf13b5c33d62f171d508fdb").unwrap(); // block height 560447 - let prev_block_header = header_from_bytes(&hex::decode("00000020".to_owned() + "d8e8e54ca5e33522b94fbba5de736efc55ff75e832cf2300000000000000000007b395f80858ee022c9c3c2f0f5cee4bd807039f0729b0559ae4326c3ba77d6b209f4e5c33d62f1746ee356d").unwrap()); + let prev_block_header = RawBlockHeader::from_hex("00000020".to_owned() + "d8e8e54ca5e33522b94fbba5de736efc55ff75e832cf2300000000000000000007b395f80858ee022c9c3c2f0f5cee4bd807039f0729b0559ae4326c3ba77d6b209f4e5c33d62f1746ee356d").unwrap(); // block height 560448 - let curr_header = header_from_bytes(&hex::decode("00000020".to_owned() + "6b05bd2c4a06b3d8503a033c2593396a25a79e1dcadb140000000000000000001b08df3d42cd9a38d8b66adf9dc5eb464f503633bd861085ffff723634531596a1a24e5c35683017bf67b72a").unwrap()); + let curr_header = RawBlockHeader::from_hex("00000020".to_owned() + "6b05bd2c4a06b3d8503a033c2593396a25a79e1dcadb140000000000000000001b08df3d42cd9a38d8b66adf9dc5eb464f503633bd861085ffff723634531596a1a24e5c35683017bf67b72a").unwrap(); [last_retarget_header, prev_block_header, curr_header] } @@ -1533,7 +1515,7 @@ fn sample_accepted_transaction() -> String { "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0502cb000101ffffffff02400606950000000017a91466c7060feb882664ae62ffad0051fe843e318e85870000000000000000266a24aa21a9ede5c17d15b8b1fa2811b7e6da66ffa5e1aaa05922c69068bf90cd585b95bb46750120000000000000000000000000000000000000000000000000000000000000000000000000".to_owned() } -fn sample_block_header() -> String { +fn sample_block_header_hex() -> String { "02000000".to_owned() + // ............... Block version: 2 "b6ff0b1b1680a2862a30ca44d346d9e8" + // "910d334beb48ca0c0000000000000000" + // ... Hash of previous block's header @@ -1545,10 +1527,10 @@ fn sample_block_header() -> String { } fn sample_rich_tx_block_header(chain_ref: u32, block_height: u32) -> RichBlockHeader { - let raw_header = hex::decode("0000003096cb3d93696c4f56c10da153963d35abf4692c07b2b3bf0702fb4cb32a8682211ee1fb90996ca1d5dcd12866ba9066458bf768641215933d7d8b3a10ef79d090e8a13a5effff7f2005000000".to_owned()).unwrap(); + let raw_header = RawBlockHeader::from_hex("0000003096cb3d93696c4f56c10da153963d35abf4692c07b2b3bf0702fb4cb32a8682211ee1fb90996ca1d5dcd12866ba9066458bf768641215933d7d8b3a10ef79d090e8a13a5effff7f2005000000".to_owned()).unwrap(); RichBlockHeader { - block_hash: BlockHeader::block_hash_le(&raw_header), - block_header: BlockHeader::from_le_bytes(&raw_header).unwrap(), + block_hash: raw_header.hash(), + block_header: parse_block_header(&raw_header).unwrap(), block_height: block_height, chain_ref: chain_ref, } From 52830de2a3d540477cec1b20e90e7387c2ece211 Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Mon, 13 Apr 2020 16:16:00 +0900 Subject: [PATCH 31/37] modify to allow partial release and slash and add tests --- crates/collateral/src/lib.rs | 4 +-- crates/collateral/src/tests.rs | 56 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/crates/collateral/src/lib.rs b/crates/collateral/src/lib.rs index 2f1f8bbc43..6a89522ac6 100644 --- a/crates/collateral/src/lib.rs +++ b/crates/collateral/src/lib.rs @@ -107,7 +107,7 @@ impl Module { /// * `amount` - the to be released amount of DOT pub fn release_collateral(sender: T::AccountId, amount: BalanceOf) -> Result<(), Error> { ensure!( - T::DOT::reserved_balance(&sender) == amount, + T::DOT::reserved_balance(&sender) >= amount, Error::InsufficientCollateralAvailable ); T::DOT::unreserve(&sender, amount); @@ -132,7 +132,7 @@ impl Module { amount: BalanceOf, ) -> Result<(), Error> { ensure!( - T::DOT::reserved_balance(&sender) == amount, + T::DOT::reserved_balance(&sender) >= amount, Error::InsufficientCollateralAvailable ); diff --git a/crates/collateral/src/tests.rs b/crates/collateral/src/tests.rs index 3a73a9f315..64482bfec1 100644 --- a/crates/collateral/src/tests.rs +++ b/crates/collateral/src/tests.rs @@ -129,6 +129,32 @@ fn test_release_collateral_fails() { }) } +#[test] +fn test_release_collateral_partially_succeeds() { + run_test(|| { + let sender = ALICE; + let amount = ALICE_BALANCE; + let release_amount = ALICE_BALANCE - 10; + + assert_ok!(Collateral::lock_collateral(sender, amount)); + + let init_collateral = Collateral::get_collateral_from_account(ALICE); + let init_total = Collateral::get_total_collateral(); + + assert_ok!(Collateral::release_collateral(sender, release_amount)); + let release_event = + TestEvent::test_events(RawEvent::ReleaseCollateral(ALICE, release_amount)); + + assert!(System::events().iter().any(|a| a.event == release_event)); + + let collateral = Collateral::get_collateral_from_account(ALICE); + let total = Collateral::get_total_collateral(); + + assert_eq!(collateral, init_collateral - release_amount); + assert_eq!(total, init_total - release_amount); + }) +} + /// Slash collateral #[test] fn test_slash_collateral_succeeds() { @@ -183,3 +209,33 @@ fn test_slash_collateral_fails() { assert_eq!(total, init_total); }) } + +#[test] +fn test_slash_collateral_partially_succeeds() { + run_test(|| { + let sender = ALICE; + let receiver = BOB; + let amount = ALICE_BALANCE; + let slash_amount = ALICE_BALANCE; + + assert_ok!(Collateral::lock_collateral(sender, amount)); + + let init_collateral_alice = Collateral::get_collateral_from_account(ALICE); + let init_collateral_bob = Collateral::get_collateral_from_account(BOB); + let init_total = Collateral::get_total_collateral(); + + assert_ok!(Collateral::slash_collateral(sender, receiver, slash_amount)); + let slash_event = + TestEvent::test_events(RawEvent::SlashCollateral(ALICE, BOB, slash_amount)); + + assert!(System::events().iter().any(|a| a.event == slash_event)); + + let collateral_alice = Collateral::get_collateral_from_account(ALICE); + let collateral_bob = Collateral::get_collateral_from_account(BOB); + let total = Collateral::get_total_collateral(); + + assert_eq!(collateral_alice, init_collateral_alice - slash_amount); + assert_eq!(collateral_bob, init_collateral_bob + slash_amount); + assert_eq!(total, init_total); + }) +} From 8af57d7020ae2a217c89c4d2f7a902af554de7f3 Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Mon, 13 Apr 2020 16:44:00 +0900 Subject: [PATCH 32/37] handle partial burn --- crates/treasury/src/lib.rs | 44 +++++++++++++++++++++++++++--------- crates/treasury/src/tests.rs | 28 +++++++++++++++++++++++ 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/crates/treasury/src/lib.rs b/crates/treasury/src/lib.rs index a7a20ca029..d6879510ac 100644 --- a/crates/treasury/src/lib.rs +++ b/crates/treasury/src/lib.rs @@ -18,7 +18,7 @@ use frame_support::traits::{Currency, ExistenceRequirement::KeepAlive, Reservabl /// The Treasury module according to the specification at /// https://interlay.gitlab.io/polkabtc-spec/spec/treasury.html // Substrate -use frame_support::{decl_event, decl_module, dispatch::DispatchResult, ensure}; +use frame_support::{decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure}; use sp_runtime::ModuleId; use system::ensure_signed; @@ -39,10 +39,16 @@ pub trait Trait: system::Trait { } // This pallet's storage items. -// decl_storage! { -// trait Store for Module as Treasury { -// } -// } +decl_storage! { + trait Store for Module as Treasury { + /// ## Storage + /// Note that account's balances and locked balances are handled + /// through the Balances module. + /// + /// Total locked PolkaDOT + TotalLocked: BalanceOf; + } +} // The pallet's events decl_event!( @@ -101,6 +107,16 @@ impl Module { pub fn get_locked_balance_from_account(account: T::AccountId) -> BalanceOf { T::PolkaBTC::reserved_balance(&account) } + /// Increase the supply of locked PolkaBTC + pub fn increase_total_locked(amount: BalanceOf) { + let new_locked = >::get() + amount; + >::put(new_locked); + } + /// Decrease the supply of locked PolkaBTC + pub fn decrease_total_locked(amount: BalanceOf) { + let new_locked = >::get() - amount; + >::put(new_locked); + } /// Mint new tokens /// /// # Arguments @@ -115,7 +131,8 @@ impl Module { Self::deposit_event(RawEvent::Mint(requester, amount)); } - /// Lock PolkaBTC tokens to burn them + /// Lock PolkaBTC tokens to burn them. Note: this removes them from the + /// free balance of PolkaBTC and adds them to the locked supply of PolkaBTC. /// /// # Arguments /// @@ -124,10 +141,13 @@ impl Module { pub fn lock(redeemer: T::AccountId, amount: BalanceOf) -> Result<(), Error> { T::PolkaBTC::reserve(&redeemer, amount).map_err(|_| Error::InsufficientFunds)?; + // update total locked balance + Self::increase_total_locked(amount); + Self::deposit_event(RawEvent::Lock(redeemer, amount)); Ok(()) } - /// Burn a previously locked PolkaBTC tokens + /// Burn previously locked PolkaBTC tokens /// /// # Arguments /// @@ -135,14 +155,16 @@ impl Module { /// * `amount` - the to be burned amount of PolkaBTC pub fn burn(redeemer: T::AccountId, amount: BalanceOf) -> Result<(), Error> { ensure!( - T::PolkaBTC::reserved_balance(&redeemer) == amount, + T::PolkaBTC::reserved_balance(&redeemer) >= amount, Error::InsufficientLockedFunds ); - // burn the tokens from the global balance - let _burned_tokens = T::PolkaBTC::burn(amount); + // burn the tokens from the locked balance + Self::decrease_total_locked(amount); + // burn the tokens for the redeemer - let (_burned_tokens, _mismatch_tokens) = T::PolkaBTC::slash_reserved(&redeemer, amount); + // remainder should always be 0 and is checked above + let (_burned_tokens, _remainder) = T::PolkaBTC::slash_reserved(&redeemer, amount); Self::deposit_event(RawEvent::Burn(redeemer, amount)); diff --git a/crates/treasury/src/tests.rs b/crates/treasury/src/tests.rs index d450fa1f6e..5fb145a43e 100644 --- a/crates/treasury/src/tests.rs +++ b/crates/treasury/src/tests.rs @@ -191,3 +191,31 @@ fn test_burn_fails() { assert_eq!(total_supply, init_total_supply); }) } + +#[test] +fn test_burn_partially_succeeds() { + run_test(|| { + let redeemer = ALICE; + let amount = ALICE_BALANCE; + let burn_amount = amount - 10; + + let init_balance = Treasury::get_balance_from_account(ALICE); + let init_locked_balance = Treasury::get_locked_balance_from_account(ALICE); + let init_total_supply = Treasury::get_total_supply(); + + assert_ok!(Treasury::lock(redeemer, amount)); + assert_ok!(Treasury::burn(redeemer, burn_amount)); + let burn_event = TestEvent::test_events(RawEvent::Burn(ALICE, burn_amount)); + + assert!(System::events().iter().any(|a| a.event == burn_event)); + + let balance = Treasury::get_balance_from_account(ALICE); + let locked_balance = Treasury::get_locked_balance_from_account(ALICE); + let total_supply = Treasury::get_total_supply(); + + assert_eq!(balance, init_balance - amount); // balance is locked + // part of the balance is still locked + assert_eq!(locked_balance, init_locked_balance + (amount - burn_amount)); + assert_eq!(total_supply, init_total_supply - burn_amount); + }) +} From 8cb5c5439bc0984aa108ae5ce13bd06dcbbeb0a5 Mon Sep 17 00:00:00 2001 From: Dominik Harz Date: Mon, 13 Apr 2020 16:46:08 +0900 Subject: [PATCH 33/37] add description to balances --- crates/treasury/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/treasury/src/lib.rs b/crates/treasury/src/lib.rs index d6879510ac..d9c118ba98 100644 --- a/crates/treasury/src/lib.rs +++ b/crates/treasury/src/lib.rs @@ -30,6 +30,11 @@ type BalanceOf = <::PolkaBTC as Currency<::Ac const _MODULE_ID: ModuleId = ModuleId(*b"ily/trsy"); /// The pallet's configuration trait. +/// Instantiation of this pallet requires the existence of a module that +/// implements Currency and ReservableCurrency. The Balances module can be used +/// for this. The Balances module then gives functions for total supply, balances +/// of accounts, and any function defined by the Currency and ReservableCurrency +/// traits. pub trait Trait: system::Trait { /// The PolkaBTC currency type PolkaBTC: Currency + ReservableCurrency; From a33ae222b88d18e1dacf6a3ef9b22fb03d14f883 Mon Sep 17 00:00:00 2001 From: Alexei Zamyatin Date: Tue, 14 Apr 2020 11:44:22 +0000 Subject: [PATCH 34/37] Added btc-relay description to Readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ae19666fa3..982c2b903c 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,8 @@ The Substrate runtime makes use of various custom pallets and crates that are fo ### Development Progess -- [bitcoin](crates/bitcoin): [Beta] library for Bitcoin type, parsing and verification functions. +- [bitcoin](crates/bitcoin): [Beta] Library for Bitcoin type, parsing and verification functions. +- [btc-relay](creates/btc-relay): [Beta] Stateful SPV client for Bitcoin. Stores Bitcoin main chain, tracks forks, verifies Merkle proofs and validates specific transaction formats. - [btc-core](crates/btc-core): [Beta] Error types used in BTC-Relay and Bitcoin. - [priority-map](crates/priority-map): [WIP] Priority queue based on a mapping. Used to efficiently track ongoing forks and handle re-orgs. - [exchange-rate-oracle](crates/exchange-rate-oracle): [Beta] Exchange rate oracle. Integration with external provider pending. From 0a9a72c5891ca6fc867cc4328e897da04203d56a Mon Sep 17 00:00:00 2001 From: Alexei Zamyatin Date: Tue, 14 Apr 2020 11:44:52 +0000 Subject: [PATCH 35/37] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 982c2b903c..c0d98791ff 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ The Substrate runtime makes use of various custom pallets and crates that are fo ### Development Progess - [bitcoin](crates/bitcoin): [Beta] Library for Bitcoin type, parsing and verification functions. -- [btc-relay](creates/btc-relay): [Beta] Stateful SPV client for Bitcoin. Stores Bitcoin main chain, tracks forks, verifies Merkle proofs and validates specific transaction formats. +- [btc-relay](crates/btc-relay): [Beta] Stateful SPV client for Bitcoin. Stores Bitcoin main chain, tracks forks, verifies Merkle proofs and validates specific transaction formats. - [btc-core](crates/btc-core): [Beta] Error types used in BTC-Relay and Bitcoin. - [priority-map](crates/priority-map): [WIP] Priority queue based on a mapping. Used to efficiently track ongoing forks and handle re-orgs. - [exchange-rate-oracle](crates/exchange-rate-oracle): [Beta] Exchange rate oracle. Integration with external provider pending. From 399c1fd6c21f3c604068ced5bf10befb5070b8e1 Mon Sep 17 00:00:00 2001 From: Alexei Zamyatin Date: Tue, 14 Apr 2020 17:14:28 +0000 Subject: [PATCH 36/37] Removed left-over comment (remainder is not always 0 since partial slashing is allowed now) --- crates/collateral/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/collateral/src/lib.rs b/crates/collateral/src/lib.rs index 6a89522ac6..ecbe884a9a 100644 --- a/crates/collateral/src/lib.rs +++ b/crates/collateral/src/lib.rs @@ -137,7 +137,6 @@ impl Module { ); // slash the sender's collateral - // remainder should always be 0 and is checked above let (slashed, _remainder) = T::DOT::slash_reserved(&sender, amount); // add slashed amount to receiver and create account if it does not exists From 7e3026d18ced6da0fc47c5c8b7fb556724c2c122 Mon Sep 17 00:00:00 2001 From: Alexei Zamyatin Date: Wed, 15 Apr 2020 14:28:25 +0000 Subject: [PATCH 37/37] [vault-registry] Data model and public getters --- .gitignore | 2 + .gitlab-ci.yml | 6 +- .vscode/launch.json | 18 +++ Cargo.lock | 17 +++ Cargo.toml | 1 + crates/btc-relay/.vscode/launch.json | 28 +++++ crates/vault-registry/.gitattributes | 2 + crates/vault-registry/.gitignore | 2 + crates/vault-registry/Cargo.toml | 68 +++++++++++ crates/vault-registry/README.md | 58 +++++++++ crates/vault-registry/src/lib.rs | 175 +++++++++++++++++++++++++++ crates/vault-registry/src/mock.rs | 105 ++++++++++++++++ crates/vault-registry/src/tests.rs | 37 ++++++ 13 files changed, 517 insertions(+), 2 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 crates/btc-relay/.vscode/launch.json create mode 100644 crates/vault-registry/.gitattributes create mode 100644 crates/vault-registry/.gitignore create mode 100644 crates/vault-registry/Cargo.toml create mode 100644 crates/vault-registry/README.md create mode 100644 crates/vault-registry/src/lib.rs create mode 100644 crates/vault-registry/src/mock.rs create mode 100644 crates/vault-registry/src/tests.rs diff --git a/.gitignore b/.gitignore index 5a0fcbbb10..a1f6014f9b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ .idea /target/* +*/launch.json + diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1a1adc037f..59ac997ed7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,7 +6,10 @@ image: "rust:latest" before_script: - apt-get -y update - apt-get install -y build-essential cmake pkg-config libssl-dev clang libclang-dev llvm - - rustc --version && cargo --version # Print version info for debugging + - rustup toolchain install nightly-2020-03-01 # rustc version 1.43.0-nightly + - rustup default nightly-2020-03-01 + - rustup component add rustfmt + - rustc --version && rustfmt --version && cargo --version # Print version info for debugging # Declare stages stages: @@ -59,7 +62,6 @@ stages: # pallets and crates test-pallets-and-crates: stage: test - image: rustlang/rust:nightly script: - cargo build --release --verbose - cargo fmt -- --check diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..0f406d2f0b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug", + "program": "${workspaceRoot}/target/debug/${workspaceRootFolderName}", + "args": [], + "cwd": "${workspaceRoot}", + "sourceLanguages": ["rust"] + } + + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index e5c1d7dbc5..99c632c080 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2731,6 +2731,23 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +[[package]] +name = "vault-registry" +version = "0.0.1" +dependencies = [ + "frame-support 2.0.0-alpha.5", + "frame-system 2.0.0-alpha.5", + "mocktopus", + "node-primitives", + "pallet-balances", + "pallet-timestamp 2.0.0-alpha.5", + "parity-scale-codec", + "sp-core 2.0.0-alpha.5", + "sp-io 2.0.0-alpha.5", + "sp-runtime 2.0.0-alpha.5", + "xclaim-core", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 50150729cf..1069fcaeed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "crates/btc-relay", "crates/security", "crates/exchange-rate-oracle", + "crates/vault-registry", "crates/treasury", "crates/collateral", ] diff --git a/crates/btc-relay/.vscode/launch.json b/crates/btc-relay/.vscode/launch.json new file mode 100644 index 0000000000..58f00a5168 --- /dev/null +++ b/crates/btc-relay/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'btc-relay'", + "cargo": { + "args": [ + "test", + "test_validate_transaction_insufficient_payment_value_fails", + "--no-run", + "--lib", + "--package=btc-relay" + ], + "filter": { + "name": "btc-relay", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/crates/vault-registry/.gitattributes b/crates/vault-registry/.gitattributes new file mode 100644 index 0000000000..dfe0770424 --- /dev/null +++ b/crates/vault-registry/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/crates/vault-registry/.gitignore b/crates/vault-registry/.gitignore new file mode 100644 index 0000000000..53eaa21960 --- /dev/null +++ b/crates/vault-registry/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/crates/vault-registry/Cargo.toml b/crates/vault-registry/Cargo.toml new file mode 100644 index 0000000000..55454c235e --- /dev/null +++ b/crates/vault-registry/Cargo.toml @@ -0,0 +1,68 @@ +[package] +name = "vault-registry" +version = "0.0.1" +authors = ["Interlay Ltd"] +edition = "2018" + +[features] +default = ['std'] +std = [ + 'codec/std', + 'frame-support/std', + 'sp-runtime/std', + 'sp-io/std', + 'system/std', + 'timestamp/std', + 'sp-core/std', + 'pallet-balances/std', + 'node-primitives/std' +] + +[dependencies.codec] +default-features = false +features = ['derive'] +package = 'parity-scale-codec' +version = '1.0.0' + +[dependencies.sp-runtime] +default-features = false +version = '2.0.0-alpha.5' + +[dependencies.frame-support] +default-features = false +version = '2.0.0-alpha.5' + +[dependencies.system] +default-features = false +package = 'frame-system' +version = '2.0.0-alpha.5' + +[dependencies.sp-io] +default-features = false +version = '2.0.0-alpha.5' + +[dependencies.sp-core] +default-features = false +version = '2.0.0-alpha.5' + +[dependencies.timestamp] +default-features = false +package = 'pallet-timestamp' +version = '2.0.0-alpha.5' + +[dependencies.pallet-balances] +default-features = false +package = 'pallet-balances' +version = '2.0.0-alpha.5' + +[dependencies.node-primitives] +default-features = false +version = '2.0.0' +git = 'https://github.com/paritytech/substrate.git' +rev = '3e651110aa06aa835790df63410a29676243fc54' + +[dependencies.xclaim-core] +path = '../xclaim-core' + +[dev-dependencies] +mocktopus = "0.7.0" diff --git a/crates/vault-registry/README.md b/crates/vault-registry/README.md new file mode 100644 index 0000000000..c0af09b9cb --- /dev/null +++ b/crates/vault-registry/README.md @@ -0,0 +1,58 @@ +# Vault Registry + +Based on the Vault Registry specification [https://interlay.gitlab.io/polkabtc-spec/spec/vaultregistry.html](https://interlay.gitlab.io/polkabtc-spec/spec/vaultregistry.html). + +## Installation + +Run `cargo build` from the root folder of this directory. + +## Testing + +Run `cargo test` from the root folder of this directory. + + +## Integration into Runtimes + +### Runtime `Cargo.toml` + +To add this pallet to your runtime, simply include the following to your runtime's `Cargo.toml` file: + +```TOML +[dependencies.btc-relay] +default_features = false +git = '../creates/vault-registry' +``` + +and update your runtime's `std` feature to include this pallet: + +```TOML +std = [ + # --snip-- + 'vault-registry/std', +] +``` + +### Runtime `lib.rs` + +You should implement it's trait like so: + +```rust +/// Used for test_module +impl VaultRegistry::Trait for Runtime { + type Event = Event; +} +``` + +and include it in your `construct_runtime!` macro: + +```rust +VaultRegistry: vault-registry::{Module, Call, Storage, Event}, +``` + +## Reference Docs + +You can view the reference docs for this pallet by running: + +``` +cargo doc --open +``` diff --git a/crates/vault-registry/src/lib.rs b/crates/vault-registry/src/lib.rs new file mode 100644 index 0000000000..4865b3b93e --- /dev/null +++ b/crates/vault-registry/src/lib.rs @@ -0,0 +1,175 @@ +#![deny(warnings)] +#![cfg_attr(test, feature(proc_macro_hygiene))] +#![cfg_attr(not(feature = "std"), no_std)] +#[cfg(test)] +mod tests; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +extern crate mocktopus; + +#[cfg(test)] +use mocktopus::macros::mockable; + +/// # Vault Registry implementation +/// This is the implementation of the Vault Registry following the spec at: +/// https://interlay.gitlab.io/polkabtc-spec/spec/vaultregistry.html +// Substrate +use frame_support::{decl_event, decl_module, decl_storage /*, ensure */}; +// use std::time::SystemTime; +// use system::ensure_signed; +// use frame_support::dispatch::DispatchResult; +use codec::{Decode, Encode}; +use frame_support::traits::{Currency, ReservableCurrency}; +use node_primitives::{AccountId, Balance, BlockNumber}; +use sp_core::H160; + +use xclaim_core::Error; + +// FIXME: for mocking purposes PolkaBTC is declared here. This should be imported +// from the Treasury module in the future. +type BalanceOf = <::PolkaBTC as Currency<::AccountId>>::Balance; + +/// ## Configuration and Constants +/// The pallet's configuration trait. +pub trait Trait: system::Trait { + /// The overarching event type. + type Event: From> + Into<::Event>; + /// The DOT currency + type DOT: Currency + ReservableCurrency; + /// The PolkaBTC currency + type PolkaBTC: Currency + ReservableCurrency; +} + +/// Granularity of `SecureCollateralThreshold`, `AuctionCollateralThreshold`, +/// `LiquidationCollateralThreshold`, and `PunishmentFee` +pub const GRANULARITY: u128 = 5; + +#[derive(Encode, Decode, Default, Clone, PartialEq)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct Vault { + // Account identifier of the Vault + vault: AccountId, + // Number of PolkaBTC tokens pending issue + to_be_issued_tokens: Balance, + // Number of issued PolkaBTC tokens + issued_tokens: Balance, + // Number of PolkaBTC tokens pending redeem + to_be_redeemed_tokens: Balance, + // DOT collateral locked by this Vault + collateral: Balance, + // Bitcoin address of this Vault (P2PKH, P2SH, P2PKH, P2WSH) + btc_address: H160, + // Block height until which this Vault is banned from being + // used for Issue, Redeem (except during automatic liquidation) and Replace . + banned_until: BlockNumber, +} + +// This pallet's storage items. +decl_storage! { + trait Store for Module as VaultRegistry { + /// ## Storage + /// The minimum collateral (DOT) a Vault needs to provide + /// to participate in the issue process. + MinimumCollateralVault: BalanceOf; + + /// If a Vault misbehaves in either the redeem or replace protocol by + /// failing to prove that it sent the correct amount of BTC to the + /// correct address within the time limit, a vault is punished. + /// The punishment is the equivalent value of BTC in DOT + /// (valued at the current exchange rate via `getExchangeRate`) plus a + /// fixed `PunishmentFee` that is added as a percentage on top + /// to compensate the damaged party for its loss. + /// For example, if the `PunishmentFee` is set to 50000, + /// it is equivalent to 50%. + PunishmentFee: u128; + + /// If a Vault fails to execute a correct redeem or replace, + /// it is temporarily banned from further issue, redeem or replace requests. + PunishmentDelay: T::BlockNumber; + + /// If a Vault is running low on collateral and falls below + /// `PremiumRedeemThreshold`, users are allocated a premium in DOT + /// when redeeming with the Vault - as defined by this parameter. + /// For example, if the RedeemPremiumFee is set to 5000, it is equivalent to 5%. + RedeemPremiumFee: u128; + + /// Determines the over-collareralization rate for DOT collateral locked + /// by Vaults, necessary for issuing PolkaBTC. Must to be strictly + /// greater than 100000 and LiquidationCollateralThreshold. + SecureCollateralThreshold: u128; + + /// Determines the rate for the collateral rate of Vaults, at which the + /// BTC backed by the Vault are opened up for auction to other Vaults + AuctionCollateralThreshold: u128; + + /// Determines the rate for the collateral rate of Vaults, + /// at which users receive a premium in DOT, allocated from the + /// Vault’s collateral, when performing a redeem with this Vault. + /// Must to be strictly greater than 100000 and LiquidationCollateralThreshold. + PremiumRedeemThreshold: u128; + + /// Determines the lower bound for the collateral rate in PolkaBTC. + /// Must be strictly greater than 100000. If a Vault’s collateral rate + /// drops below this, automatic liquidation (forced Redeem) is triggered. + LiquidationCollateralThreshold: u128; + + /// Account identifier of an artificial Vault maintained by the VaultRegistry + /// to handle polkaBTC balances and DOT collateral of liquidated Vaults. + /// That is, when a Vault is liquidated, its balances are transferred to + /// LiquidationVault and claims are later handled via the LiquidationVault. + LiquidationVault: T::AccountId; + + /// Mapping of Vaults, using the respective Vault account identifier as key. + Vaults: map hasher(blake2_128_concat) AccountId => Vault; + } +} + +// The pallet's dispatchable functions. +decl_module! { + pub struct Module for enum Call where origin: T::Origin { + // Initializing events + fn deposit_event() = default; + } +} + +#[cfg_attr(test, mockable)] +impl Module { + /// Public getters + + pub fn get_vault_from_id(id: AccountId) -> Vault { + ::get(id) + } + + pub fn mutate_vault_from_id(id: AccountId, vault: Vault) { + ::mutate(id, |v| *v = vault) + } + + pub fn insert_vault(id: AccountId, vault: Vault) { + ::insert(id, vault) + } + /// Private getters and setters + + /// Other helpers + /// Returns an error if the parachain is not in running state + fn _ensure_parachain_running() -> Result<(), Error> { + // TODO: integrate security module + // ensure!( + // !>::check_parachain_status( + // StatusCode::Shutdown), + // Error::Shutdown + // ); + Ok(()) + } +} + +decl_event! { + /// ## Events + pub enum Event where + AccountId = ::AccountId, + Balance = BalanceOf { + RegisterVault(AccountId, Balance), + } +} diff --git a/crates/vault-registry/src/mock.rs b/crates/vault-registry/src/mock.rs new file mode 100644 index 0000000000..29253dbe1e --- /dev/null +++ b/crates/vault-registry/src/mock.rs @@ -0,0 +1,105 @@ +/// Mocking the test environment +use crate::{Module, Trait}; +use frame_support::{impl_outer_event, impl_outer_origin, parameter_types, weights::Weight}; +use mocktopus::mocking::clear_mocks; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, +}; + +impl_outer_origin! { + pub enum Origin for Test {} +} + +mod test_events { + pub use crate::Event; +} + +impl_outer_event! { + pub enum TestEvent for Test { + system, + test_events, + pallet_balances, + } +} + +// For testing the pallet, we construct most of a mock runtime. This means +// first constructing a configuration type (`Test`) which `impl`s each of the +// configuration traits of modules we want to use. +#[derive(Clone, Eq, PartialEq)] +pub struct Test; +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); +} +impl system::Trait for Test { + type Origin = Origin; + type Call = (); + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = TestEvent; + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + type ModuleToIndex = (); + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); +} + +pub type Balance = u64; + +parameter_types! { + pub const ExistentialDeposit: u64 = 1; +} + +impl pallet_balances::Trait for Test { + type Balance = Balance; + type Event = TestEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; +} + +impl Trait for Test { + type Event = TestEvent; + type PolkaBTC = Balances; + type DOT = Balances; +} + +pub type Balances = pallet_balances::Module; + +// pub type Error = crate::Error; + +pub type System = system::Module; +pub type _VaultRegistry = Module; + +pub struct ExtBuilder; + +impl ExtBuilder { + pub fn build() -> sp_io::TestExternalities { + let storage = system::GenesisConfig::default() + .build_storage::() + .unwrap(); + sp_io::TestExternalities::from(storage) + } +} + +pub fn run_test(test: T) -> () +where + T: FnOnce() -> (), +{ + clear_mocks(); + ExtBuilder::build().execute_with(test); +} diff --git a/crates/vault-registry/src/tests.rs b/crates/vault-registry/src/tests.rs new file mode 100644 index 0000000000..582915b066 --- /dev/null +++ b/crates/vault-registry/src/tests.rs @@ -0,0 +1,37 @@ +// use crate::mock::{run_test, Origin, System, Test, TestEvent, VaultRegistry}; +use crate::mock::run_test; +// use crate::Error; + +// use frame_support::{assert_err, assert_ok}; +// use mocktopus::mocking::*; + +// type Event = crate::Event; + +// // use macro to avoid messing up stack trace +// macro_rules! assert_emitted { +// ($event:expr) => { +// let test_event = TestEvent::test_events($event); +// assert!(System::events().iter().any(|a| a.event == test_event)); +// }; +// } + +// macro_rules! assert_not_emitted { +// ($event:expr) => { +// let test_event = TestEvent::test_events($event); +// assert!(!System::events().iter().any(|a| a.event == test_event)); +// }; +// } + +#[test] +fn set_exchange_rate_success() { + run_test(|| { + // VaultRegistry::get_authorized_oracle.mock_safe(|| MockResult::Return(3)); + // let result = ExchangeRateOracle::set_exchange_rate(Origin::signed(3), 100); + // assert_ok!(result); + + // let exchange_rate = ExchangeRateOracle::get_exchange_rate().unwrap(); + // assert_eq!(exchange_rate, 100); + + // assert_emitted!(Event::SetExchangeRate(3, 100)); + }); +}