diff --git a/Cargo.toml b/Cargo.toml index 761266a203..7877d1bcd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ exclude = [ "ring", "native-nostd-hasher", "standalone/pruntime", + "crates/pink/examples/mqproxy", ] members = [ @@ -30,6 +31,7 @@ members = [ "crates/phala-async-executor", "crates/phala-allocator", "crates/pink", + "crates/pink/pink-extension", "pallets/phala", "pallets/phala/mq-runtime-api", "pallets/bridge", diff --git a/crates/phactory/src/contracts/assets.rs b/crates/phactory/src/contracts/assets.rs index 305de3bfa0..3b1b3232ff 100644 --- a/crates/phactory/src/contracts/assets.rs +++ b/crates/phactory/src/contracts/assets.rs @@ -131,7 +131,7 @@ impl contracts::NativeContract for Assets { self.assets.insert(id, accounts); self.next_id += 1; - Ok(()) + Ok(Default::default()) } else { Err(TransactionError::SymbolExist) } @@ -144,7 +144,7 @@ impl contracts::NativeContract for Assets { self.metadata.remove(&id); self.assets.remove(&id); - Ok(()) + Ok(Default::default()) } else { Err(TransactionError::NotAssetOwner) } @@ -203,7 +203,7 @@ impl contracts::NativeContract for Assets { info!(" pushed history (dest)"); } - Ok(()) + Ok(Default::default()) } else { Err(TransactionError::InsufficientBalance) } diff --git a/crates/phactory/src/contracts/balances.rs b/crates/phactory/src/contracts/balances.rs index c89d4ac2eb..6768ae7598 100644 --- a/crates/phactory/src/contracts/balances.rs +++ b/crates/phactory/src/contracts/balances.rs @@ -99,7 +99,7 @@ impl contracts::NativeContract for Balances { info!(" src: {:>20} -> {:>20}", src0, src0 - value); info!(" dest: {:>20} -> {:>20}", dest0, dest0 + value); - Ok(()) + Ok(Default::default()) } else { Err(TransactionError::InsufficientBalance) } @@ -127,7 +127,7 @@ impl contracts::NativeContract for Balances { amount: value, }; context.mq().push_message(&data); - Ok(()) + Ok(Default::default()) } else { Err(TransactionError::InsufficientBalance) } @@ -152,7 +152,7 @@ impl contracts::NativeContract for Balances { info!(" value: {:>20} -> {:>20}", 0, amount); } self.total_issuance += amount; - Ok(()) + Ok(Default::default()) } } } diff --git a/crates/phactory/src/contracts/btc_lottery.rs b/crates/phactory/src/contracts/btc_lottery.rs index 2a2a1ae43f..a00675bbb4 100644 --- a/crates/phactory/src/contracts/btc_lottery.rs +++ b/crates/phactory/src/contracts/btc_lottery.rs @@ -443,7 +443,7 @@ impl BtcLottery { }; round_utxo.insert(btc_address, utxo); } - Ok(()) + Ok(Default::default()) } LotteryUserCommand::SetAdmin { new_admin } => { // TODO: listen to some specific privileged account instead of ALICE @@ -452,7 +452,7 @@ impl BtcLottery { if self.admin == sender { self.admin = new_admin; } - Ok(()) + Ok(Default::default()) } else { Err(TransactionError::InvalidAccount) } @@ -483,6 +483,6 @@ impl BtcLottery { btc_address, } => Self::open_lottery(self, context.mq(), round_id, token_id, btc_address), } - Ok(()) + Ok(Default::default()) } } diff --git a/crates/phactory/src/contracts/data_plaza.rs b/crates/phactory/src/contracts/data_plaza.rs index 2ee7d88ece..94e6dc54e4 100644 --- a/crates/phactory/src/contracts/data_plaza.rs +++ b/crates/phactory/src/contracts/data_plaza.rs @@ -278,7 +278,7 @@ impl contracts::NativeContract for DataPlaza { seller: address_hex, details, }); - Ok(()) + Ok(Default::default()) } Command::OpenOrder(details) => { self.orders.push(Order { @@ -294,7 +294,7 @@ impl contracts::NativeContract for DataPlaza { result_path: String::new(), }, }); - Ok(()) + Ok(Default::default()) } } } diff --git a/crates/phactory/src/contracts/geolocation.rs b/crates/phactory/src/contracts/geolocation.rs index 5be7e0ca36..884f3968f1 100644 --- a/crates/phactory/src/contracts/geolocation.rs +++ b/crates/phactory/src/contracts/geolocation.rs @@ -124,7 +124,7 @@ impl contracts::NativeContract for Geolocation { ); }; - Ok(()) + Ok(Default::default()) } } } diff --git a/crates/phactory/src/contracts/mod.rs b/crates/phactory/src/contracts/mod.rs index 34e0ec2c5e..dc2f4011fa 100644 --- a/crates/phactory/src/contracts/mod.rs +++ b/crates/phactory/src/contracts/mod.rs @@ -31,6 +31,11 @@ fn account_id_from_hex(s: &str) -> Result { pub use support::*; mod support { + use phala_crypto::ecdh::EcdhPublicKey; + use phala_mq::traits::MessageChannel; + use ::pink::runtime::ExecSideEffects; + use runtime::BlockNumber; + use super::pink::group::GroupKeeper; use super::*; use crate::types::BlockInfo; @@ -42,13 +47,14 @@ mod support { pub struct NativeContext<'a> { pub block: &'a BlockInfo<'a>, - mq: &'a SignedMessageChannel, - #[allow(unused)] // TODO.kevin: remove this. - secret_mq: SecretMessageChannel<'a, SignedMessageChannel>, + pub mq: &'a SignedMessageChannel, + pub secret_mq: SecretMessageChannel<'a, SignedMessageChannel>, pub contract_groups: &'a mut GroupKeeper, } pub struct QueryContext<'a> { + pub block_number: BlockNumber, + pub now_ms: u64, pub contract_groups: &'a mut GroupKeeper, } @@ -66,7 +72,16 @@ mod support { req: OpaqueQuery, context: &mut QueryContext, ) -> Result; - fn process_messages(&mut self, env: &mut ExecuteEnv); + fn group_id(&self) -> Option; + fn process_next_message(&mut self, env: &mut ExecuteEnv) -> Option; + fn on_block_end(&mut self, env: &mut ExecuteEnv) -> TransactionResult; + fn push_message(&self, payload: Vec, topic: Vec); + fn push_osp_message( + &self, + payload: Vec, + topic: Vec, + remote_pubkey: Option<&EcdhPublicKey>, + ); } pub trait NativeContract { @@ -75,13 +90,16 @@ mod support { type QResp: Encode + Debug; fn id(&self) -> ContractId; + fn group_id(&self) -> Option { + None + } fn handle_command( &mut self, _origin: MessageOrigin, _cmd: Self::Cmd, _context: &mut NativeContext, ) -> TransactionResult { - Ok(()) + Ok(Default::default()) } fn handle_query( &mut self, @@ -148,19 +166,24 @@ mod support { self.contract.id() } + fn group_id(&self) -> Option { + self.contract.group_id() + } + fn handle_query( &mut self, origin: Option<&runtime::AccountId>, req: OpaqueQuery, context: &mut QueryContext, ) -> Result { + debug!(target: "contract", "Contract {:?} handling query", self.id()); let response = self .contract .handle_query(origin, deopaque_query(req)?, context); Ok(response.encode()) } - fn process_messages(&mut self, env: &mut ExecuteEnv) { + fn process_next_message(&mut self, env: &mut ExecuteEnv) -> Option { let secret_mq = SecretMessageChannel::new(&self.ecdh_key, &self.send_mq); let mut context = NativeContext { block: env.block, @@ -168,25 +191,46 @@ mod support { secret_mq, contract_groups: &mut env.contract_groups, }; - loop { - let ok = phala_mq::select! { - next_cmd = self.cmd_rcv_mq => match next_cmd { - Ok((_, cmd, origin)) => { - let status = self.contract.handle_command(origin, cmd, &mut context); - if let Err(err) = status { - log::error!("Contract {:?} handle command error: {:?}", self.id(), err); - } - } - Err(e) => { - error!("Read command failed [{}]: {:?}", self.id(), e); - } - }, - }; - if ok.is_none() { - break; - } + + phala_mq::select! { + next_cmd = self.cmd_rcv_mq => match next_cmd { + Ok((_, cmd, origin)) => { + info!(target: "contract", "Contract {:?} handling command", self.id()); + self.contract.handle_command(origin, cmd, &mut context) + } + Err(e) => { + Err(TransactionError::ChannelError) + } + }, } - self.contract.on_block_end(&mut context) + } + + fn on_block_end(&mut self, env: &mut ExecuteEnv) -> TransactionResult { + let secret_mq = SecretMessageChannel::new(&self.ecdh_key, &self.send_mq); + let mut context = NativeContext { + block: env.block, + mq: &self.send_mq, + secret_mq, + contract_groups: &mut env.contract_groups, + }; + self.contract.on_block_end(&mut context); + Ok(Default::default()) + } + + fn push_message(&self, payload: Vec, topic: Vec) { + self.send_mq.push_data(payload, topic) + } + + fn push_osp_message( + &self, + payload: Vec, + topic: Vec, + remote_pubkey: Option<&EcdhPublicKey>, + ) { + let secret_mq = SecretMessageChannel::new(&self.ecdh_key, &self.send_mq); + secret_mq + .bind_remote_key(remote_pubkey) + .push_data(payload, topic) } } } diff --git a/crates/phactory/src/contracts/pink.rs b/crates/phactory/src/contracts/pink.rs index 4dd14b926c..a37e7e3c1e 100644 --- a/crates/phactory/src/contracts/pink.rs +++ b/crates/phactory/src/contracts/pink.rs @@ -3,7 +3,8 @@ use crate::system::{TransactionError, TransactionResult}; use anyhow::{anyhow, Result}; use parity_scale_codec::{Decode, Encode}; use phala_mq::{ContractGroupId, ContractId, MessageOrigin}; -use runtime::AccountId; +use pink::runtime::ExecSideEffects; +use runtime::{AccountId, BlockNumber}; #[derive(Debug, Encode, Decode)] pub enum Command { @@ -39,12 +40,27 @@ impl Pink { wasm_bin: Vec, input_data: Vec, salt: Vec, - ) -> Result { - let instance = pink::Contract::new(storage, origin.clone(), wasm_bin, input_data, salt) - .map_err( - |err| anyhow!("Instantiate contract failed: {:?} origin={:?}", err, origin,), - )?; - Ok(Self { group, instance }) + block_number: BlockNumber, + now: u64, + ) -> Result<(Self, ExecSideEffects)> { + let (instance, effects) = pink::Contract::new( + storage, + origin.clone(), + wasm_bin, + input_data, + salt, + block_number, + now, + ) + .map_err(|err| anyhow!("Instantiate contract failed: {:?} origin={:?}", err, origin,))?; + Ok((Self { group, instance }, effects)) + } + + pub fn from_address(address: AccountId, group: ContractGroupId) -> Self { + Self { + instance: pink::Contract::from_address(address), + group, + } } } @@ -60,6 +76,10 @@ impl contracts::NativeContract for Pink { inner.into() } + fn group_id(&self) -> Option { + Some(self.group.clone()) + } + fn handle_query( &mut self, origin: Option<&AccountId>, @@ -71,9 +91,17 @@ impl contracts::NativeContract for Pink { Query::InkMessage(input_data) => { let storage = group_storage(&mut context.contract_groups, &self.group) .expect("Pink group should always exists!"); - let ret = self + + let (ret, _messages) = self .instance - .bare_call(storage, origin.clone(), input_data, true) + .bare_call( + storage, + origin.clone(), + input_data, + true, + context.block_number, + context.now_ms, + ) .map_err(|err| { log::error!("Pink [{:?}] query exec error: {:?}", self.id(), err); QueryError::RuntimeError(format!("Call contract method failed: {:?}", err)) @@ -99,18 +127,26 @@ impl contracts::NativeContract for Pink { let storage = group_storage(&mut context.contract_groups, &self.group) .expect("Pink group should always exists!"); - let ret = self + let (ret, effects) = self .instance - .bare_call(storage, origin.clone(), message, false) + .bare_call( + storage, + origin.clone(), + message, + false, + context.block.block_number, + context.block.now_ms, + ) .map_err(|err| { log::error!("Pink [{:?}] command exec error: {:?}", self.id(), err); TransactionError::Other(format!("Call contract method failed: {:?}", err)) })?; - // TODO.kevin: report the output to the chain? + + // TODO.kevin: store the output to some where. let _ = ret; + Ok(effects) } } - Ok(()) } } @@ -126,23 +162,18 @@ fn group_storage<'a>( pub mod group { use super::Pink; - use crate::contracts::support::NativeContract as _; use anyhow::Result; - use phala_mq::{ContractGroupId, ContractId}; - use pink::types::AccountId; + use sp_core::sr25519; + use runtime::BlockNumber; use std::collections::{BTreeMap, BTreeSet}; + use phala_mq::{ContractGroupId, ContractId}; + use pink::{runtime::ExecSideEffects, types::AccountId}; #[derive(Default)] pub struct GroupKeeper { groups: BTreeMap, } - #[derive(Default)] - pub struct Group { - storage: pink::Storage, - contracts: BTreeSet, - } - impl GroupKeeper { pub fn instantiate_contract( &mut self, @@ -151,18 +182,29 @@ pub mod group { wasm_bin: Vec, input_data: Vec, salt: Vec, - ) -> Result { - let group = self.groups.entry(group_id.clone()).or_default(); - let pink = Pink::instantiate( + contract_key: &sr25519::Pair, + block_number: BlockNumber, + now: u64, + ) -> Result { + let group = self + .groups + .entry(group_id.clone()) + .or_insert_with(|| Group { + storage: Default::default(), + contracts: Default::default(), + key: contract_key.clone(), + }); + let (_, effects) = Pink::instantiate( group_id, &mut group.storage, origin, wasm_bin, input_data, salt, + block_number, + now, )?; - group.contracts.insert(pink.id().clone()); - Ok(pink) + Ok(effects) } pub fn get_group_storage_mut( @@ -171,6 +213,26 @@ pub mod group { ) -> Option<&mut pink::Storage> { Some(&mut self.groups.get_mut(group_id)?.storage) } + + pub fn get_group_mut(&mut self, group_id: &ContractGroupId) -> Option<&mut Group> { + self.groups.get_mut(group_id) + } + } + + pub struct Group { + storage: pink::Storage, + contracts: BTreeSet, + key: sr25519::Pair, + } + + impl Group { + pub fn add_contract(&mut self, address: ContractId) { + self.contracts.insert(address); + } + + pub fn key(&self) -> &sr25519::Pair { + &self.key + } } } @@ -181,7 +243,7 @@ pub mod messaging { use phala_types::WorkerPublicKey; use pink::types::AccountId; - pub use phala_types::messaging::{ContractInfo, WorkerPinkReport}; + pub use phala_types::messaging::WorkerPinkReport; bind_topic!(WorkerPinkRequest, b"phala/pink/worker/request"); #[derive(Encode, Decode, Debug)] diff --git a/crates/phactory/src/contracts/substrate_kitties.rs b/crates/phactory/src/contracts/substrate_kitties.rs index 4b19d840a8..40db1f7f52 100644 --- a/crates/phactory/src/contracts/substrate_kitties.rs +++ b/crates/phactory/src/contracts/substrate_kitties.rs @@ -216,7 +216,7 @@ impl contracts::NativeContract for SubstrateKitties { self.left_kitties.clear(); } // Returns Ok(()) to indicate a successful transaction - Ok(()) + Ok(Default::default()) } Command::Transfer { dest, blind_box_id } => { // TODO: check owner & dest not overflow & sender not underflow @@ -248,7 +248,7 @@ impl contracts::NativeContract for SubstrateKitties { self.owned_boxes.insert(reciever, new_owned_list); } // Returns Ok(()) to indicate a successful transaction - Ok(()) + Ok(Default::default()) } Command::Open { blind_box_id } => { let sender = origin.account()?; @@ -272,7 +272,7 @@ impl contracts::NativeContract for SubstrateKitties { self.opend_boxes.push(blind_box_id.clone()); context.mq().push_message(&data); } - Ok(()) + Ok(Default::default()) } Command::Created(dest, kitty_id) => { if !origin.is_pallet() { @@ -287,7 +287,7 @@ impl contracts::NativeContract for SubstrateKitties { }; self.kitties.insert(new_kitty_id.to_vec(), new_kitty); self.left_kitties.push(new_kitty_id.to_vec()); - Ok(()) + Ok(Default::default()) } } } diff --git a/crates/phactory/src/contracts/web3analytics.rs b/crates/phactory/src/contracts/web3analytics.rs index c4839b5feb..28b2a46bb4 100644 --- a/crates/phactory/src/contracts/web3analytics.rs +++ b/crates/phactory/src/contracts/web3analytics.rs @@ -907,7 +907,7 @@ impl contracts::NativeContract for Web3Analytics { self.no_tracking.remove(&o); } - Ok(()) + Ok(Default::default()) } }; diff --git a/crates/phactory/src/prpc_service.rs b/crates/phactory/src/prpc_service.rs index e36a236db3..66a158c1f4 100644 --- a/crates/phactory/src/prpc_service.rs +++ b/crates/phactory/src/prpc_service.rs @@ -213,6 +213,7 @@ impl Phactory { let mut last_block = 0; for block in blocks.into_iter() { + info!("Dispatching block: {}", block.block_header.number); let state = self.runtime_state()?; state .storage_synchronizer diff --git a/crates/phactory/src/system/mod.rs b/crates/phactory/src/system/mod.rs index 4a4a40e106..9c021aa217 100644 --- a/crates/phactory/src/system/mod.rs +++ b/crates/phactory/src/system/mod.rs @@ -6,18 +6,20 @@ use crate::{ benchmark, contracts::{ pink::{ - group::GroupKeeper, + group::Group, messaging::{WorkerPinkReport, WorkerPinkRequest}, }, ExecuteEnv, NativeContract, }, - pink::messaging::ContractInfo, + pink::{group::GroupKeeper, Pink}, secret_channel::{PeelingReceiver, SecretReceiver}, types::{BlockInfo, OpaqueError, OpaqueQuery, OpaqueReply}, }; use anyhow::Result; use core::fmt; use log::info; +use pink::runtime::ExecSideEffects; +use runtime::BlockNumber; use std::collections::BTreeMap; use crate::contracts; @@ -45,7 +47,7 @@ use phala_types::{ use side_tasks::geo_probe; use sp_core::{hashing::blake2_256, sr25519, Pair, U256}; -pub type TransactionResult = Result<(), TransactionError>; +pub type TransactionResult = Result; #[derive(Encode, Decode, Debug, Clone)] pub enum TransactionError { @@ -66,6 +68,7 @@ pub enum TransactionError { FailedToSign, BadDecimal, DestroyNotAllowed, + ChannelError, // for pdiem BadAccountInfo, BadLedgerInfo, @@ -379,6 +382,10 @@ pub struct System { pub(crate) contracts: ContractMap, contract_groups: GroupKeeper, + + // Cached for query + block_number: BlockNumber, + now_ms: u64, } impl System { @@ -418,6 +425,8 @@ impl System { gatekeeper: None, contracts, contract_groups: Default::default(), + block_number: 0, + now_ms: 0, } } @@ -432,12 +441,17 @@ impl System { .get_mut(contract_id) .ok_or(OpaqueError::ContractNotFound)?; let mut context = contracts::QueryContext { + block_number: self.block_number, + now_ms: self.now_ms, contract_groups: &mut self.contract_groups, }; contract.handle_query(origin, req, &mut context) } pub fn process_messages(&mut self, block: &mut BlockInfo) -> anyhow::Result<()> { + self.block_number = block.block_number; + self.now_ms = block.now_ms; + if self.enable_geoprobing { geo_probe::process_block( block.block_number, @@ -482,13 +496,56 @@ impl System { gatekeeper.emit_random_number(block.block_number); } - let mut env = ExecuteEnv { - block: block, - contract_groups: &mut self.contract_groups, - }; - - for contract in self.contracts.values_mut() { - contract.process_messages(&mut env); + // Iterate over all contracts to handle their incoming commands. + // + // Since the wasm contracts can instantiate new contracts, it means that it will mutate the `self.contracts`. + // So we can not directly itrate over the self.contracts.values_mut() which would keep borrowing on `self.contracts` + // in the scope of entire `for loop` body. + let contract_ids: Vec<_> = self.contracts.keys().cloned().collect(); + 'outer: for key in contract_ids { + // Inner loop to handle commands. One command per iteration and apply the command side-effects to make it + // availabe for next command. + loop { + let contract = match self.contracts.get_mut(&key) { + None => continue 'outer, + Some(v) => v, + }; + let group_id = contract.group_id(); + let mut env = ExecuteEnv { + block: block, + contract_groups: &mut self.contract_groups, + }; + let result = match contract.process_next_message(&mut env) { + Some(result) => result, + None => break, + }; + handle_contract_command_result( + result, + group_id, + &mut self.contracts, + &mut self.contract_groups, + block, + &self.egress, + ); + } + let mut env = ExecuteEnv { + block: block, + contract_groups: &mut self.contract_groups, + }; + let contract = match self.contracts.get_mut(&key) { + None => continue 'outer, + Some(v) => v, + }; + let result = contract.on_block_end(&mut env); + let group_id = contract.group_id(); + handle_contract_command_result( + result, + group_id, + &mut self.contracts, + &mut self.contract_groups, + block, + &self.egress, + ); } Ok(()) @@ -717,29 +774,18 @@ impl System { return; } - let result: Result<(ContractId, EcdhPublicKey), String> = { - let owner = owner.clone(); - let contracts = &mut self.contracts; - let contract_groups = &mut self.contract_groups; - let group_id = group_id.clone(); - (move || { - let contract_key = sr25519::Pair::restore_from_secret_key(&key); - let ecdh_key = contract_key.derive_ecdh_key().unwrap(); - let result = contract_groups - .instantiate_contract(group_id, owner, wasm_bin, input_data, salt); - match result { - Err(err) => Err(err.to_string()), - Ok(pink) => { - let address = pink.id(); - let pubkey = EcdhPublicKey(ecdh_key.public()); - install_contract(contracts, pink, contract_key, ecdh_key, block); - Ok((address, pubkey)) - } - } - })() - }; - - match &result { + let contract_key = sr25519::Pair::restore_from_secret_key(&key); + let result = self.contract_groups.instantiate_contract( + group_id, + owner.clone(), + wasm_bin, + input_data, + salt, + &contract_key, + block.block_number, + block.now_ms, + ); + match result { Err(err) => { error!( "Instantiate contract error: {}, owner: {:?}, nonce: {}", @@ -748,28 +794,22 @@ impl System { hex::encode(&nonce) ); } - Ok(addr) => { - info!( - "Contract instantiated: owner: {:?}, nonce: {}, address: {}, group: {}", - owner, - hex::encode(&nonce), - hex::encode(addr.0), - hex::encode(&group_id), + Ok(effects) => { + let group = self + .contract_groups + .get_group_mut(&group_id) + .expect("Group must exist after instantiate"); + + apply_pink_side_effects( + effects, + &group_id, + &mut self.contracts, + group, + block, + &self.egress, ); } } - - let message = WorkerPinkReport::InstantiateStatus { - nonce, - owner: phala_types::messaging::AccountId(owner.into()), - result: result.map(|(id, pubkey)| ContractInfo { - id, - group_id, - pubkey, - }), - }; - info!("pink instantiate status: {:?}", message); - self.egress.push_message(&message); } } } @@ -832,6 +872,101 @@ impl System { } } +pub fn handle_contract_command_result( + result: TransactionResult, + group_id: Option, + contracts: &mut ContractMap, + groups: &mut GroupKeeper, + block: &mut BlockInfo, + egress: &SignedMessageChannel, +) { + let effects = match result { + Err(err) => { + error!("Run contract command failed: {:?}", err); + return; + } + Ok(effects) => effects, + }; + if let Some(group_id) = group_id { + let group = match groups.get_group_mut(&group_id) { + None => { + error!( + "BUG: pink group not found, it should always exsists, group_id={:?}", + group_id + ); + return; + } + Some(group) => group, + }; + apply_pink_side_effects(effects, &group_id, contracts, group, block, egress); + } +} + +pub fn apply_pink_side_effects( + effects: ExecSideEffects, + group_id: &phala_mq::ContractGroupId, + contracts: &mut ContractMap, + group: &mut Group, + block: &mut BlockInfo, + egress: &SignedMessageChannel, +) { + let contract_key = group.key().clone(); + let ecdh_key = contract_key + .derive_ecdh_key() + .expect("Derive ecdh_key should not fail"); + + for (deployer, address) in effects.instantiated { + let pink = Pink::from_address(address, group_id.clone()); + let id = pink.id(); + + install_contract( + contracts, + pink, + contract_key.clone(), + ecdh_key.clone(), + block, + ); + + group.add_contract(id.clone()); + + let message = WorkerPinkReport::PinkInstantiated { + id, + group_id: group_id.clone(), + owner: phala_types::messaging::AccountId(deployer.into()), + pubkey: EcdhPublicKey(ecdh_key.public()), + }; + + info!("pink instantiate status: {:?}", message); + egress.push_message(&message); + } + + for (address, message) in effects.messages { + let pink = Pink::from_address(address.clone(), group_id.clone()); + let contract = match contracts.get(&pink.id()) { + Some(contract) => contract, + None => { + panic!( + "BUG: Unknown contract sending message, address={:?}", + address + ); + } + }; + use pink::runtime::EgressMessage; + match message { + EgressMessage::Message(message) => { + contract.push_message(message.payload, message.topic); + } + EgressMessage::OspMessage(message) => { + contract.push_osp_message( + message.message.payload, + message.message.topic, + message.remote_pubkey.as_ref(), + ); + } + } + } +} + pub fn install_contract( contracts: &mut ContractMap, contract: Contract, diff --git a/crates/phala-types/src/lib.rs b/crates/phala-types/src/lib.rs index 3e3a189c14..5eca314380 100644 --- a/crates/phala-types/src/lib.rs +++ b/crates/phala-types/src/lib.rs @@ -519,19 +519,13 @@ pub mod messaging { bind_topic!(WorkerPinkReport, b"phala/pink/worker/report"); #[derive(Encode, Decode, Debug)] pub enum WorkerPinkReport { - InstantiateStatus { - nonce: Vec, + PinkInstantiated { + id: ContractId, + group_id: ContractGroupId, owner: AccountId, - result: Result, + pubkey: EcdhPublicKey, }, } - - #[derive(Encode, Decode, Debug)] - pub struct ContractInfo { - pub id: ContractId, - pub group_id: ContractGroupId, - pub pubkey: EcdhPublicKey, - } } // Types used in storage diff --git a/crates/pink/Cargo.toml b/crates/pink/Cargo.toml index c1309c4fe3..ed9479ad2e 100644 --- a/crates/pink/Cargo.toml +++ b/crates/pink/Cargo.toml @@ -38,6 +38,8 @@ hex = "0.4.3" serde = { version = "1.0.101", features = ["derive"] } serde_json = "1.0.67" +pink-extension = { path = "pink-extension" } + [dev-dependencies] insta = "1.7.2" hex-literal = "0.3.3" \ No newline at end of file diff --git a/crates/pink/examples/mqproxy/.gitignore b/crates/pink/examples/mqproxy/.gitignore new file mode 100755 index 0000000000..8de8f877e4 --- /dev/null +++ b/crates/pink/examples/mqproxy/.gitignore @@ -0,0 +1,9 @@ +# Ignore build artifacts from the local tests sub-crate. +/target/ + +# Ignore backup files creates by cargo fmt. +**/*.rs.bk + +# Remove Cargo.lock when creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/crates/pink/examples/mqproxy/Cargo.toml b/crates/pink/examples/mqproxy/Cargo.toml new file mode 100755 index 0000000000..e9de897e10 --- /dev/null +++ b/crates/pink/examples/mqproxy/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "mqproxy" +authors = ["Kevin Wang "] +version = "0.1.0" +edition = "2018" +resolver = "2" + +[dependencies] +ink_primitives = { version = "3.0.0-rc3", default-features = false } +ink_metadata = { version = "3.0.0-rc3", default-features = false, features = ["derive"], optional = true } +ink_env = { version = "3.0.0-rc3", default-features = false } +ink_storage = { version = "3.0.0-rc3", default-features = false } +ink_lang = { version = "3.0.0-rc3", default-features = false } + +scale = { package = "parity-scale-codec", version = "2.1", default-features = false, features = ["derive"] } +scale-info = { version = "0.6.0", default-features = false, features = ["derive"], optional = true } +pink-extension = { path = "../../pink-extension", default-features = false, features = ["ink-as-dependency"] } + +[lib] +name = "mqproxy" +path = "lib.rs" +crate-type = [ + "cdylib", "lib", +] + +[features] +default = ["std"] +std = [ + "ink_metadata/std", + "ink_env/std", + "ink_storage/std", + "ink_primitives/std", + "scale/std", + "scale-info/std", + "pink-extension/std", +] +ink-as-dependency = [] diff --git a/crates/pink/examples/mqproxy/lib.rs b/crates/pink/examples/mqproxy/lib.rs new file mode 100755 index 0000000000..cac52b41b1 --- /dev/null +++ b/crates/pink/examples/mqproxy/lib.rs @@ -0,0 +1,35 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use ink_lang as ink; + +#[ink::contract(env = PinkEnvironment)] +mod proxy { + extern crate alloc; + use alloc::vec::Vec; + use pink_extension::{push_message, push_osp_message, EcdhPublicKey, PinkEnvironment}; + + #[ink(storage)] + pub struct Proxy {} + + impl Proxy { + #[ink(constructor)] + pub fn default() -> Self { + Proxy {} + } + + #[ink(message)] + pub fn push_message(&self, message: Vec, topic: Vec) { + push_message(message, topic) + } + + #[ink(message)] + pub fn push_osp_message( + &self, + message: Vec, + topic: Vec, + remote_pubkey: Option, + ) { + push_osp_message(message, topic, remote_pubkey) + } + } +} diff --git a/crates/pink/pink-extension/Cargo.toml b/crates/pink/pink-extension/Cargo.toml new file mode 100644 index 0000000000..8cd74f6440 --- /dev/null +++ b/crates/pink/pink-extension/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "pink-extension" +version = "0.1.0" +edition = "2018" + + +[dependencies] +ink_primitives = { version = "3.0.0-rc3", default-features = false } +ink_metadata = { version = "3.0.0-rc3", default-features = false, features = ["derive"], optional = true } +ink_env = { version = "3.0.0-rc3", default-features = false } +ink_storage = { version = "3.0.0-rc3", default-features = false } +ink_lang = { version = "3.0.0-rc3", default-features = false } + +scale = { package = "parity-scale-codec", version = "2.1", default-features = false, features = ["derive"] } +scale-info = { version = "0.6.0", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +insta = "1.7.2" + +[features] +default = ["std"] +std = [ + "ink_metadata/std", + "ink_env/std", + "ink_storage/std", + "ink_primitives/std", + "scale/std", + "scale-info/std", +] +ink-as-dependency = [] diff --git a/crates/pink/pink-extension/src/lib.rs b/crates/pink/pink-extension/src/lib.rs new file mode 100644 index 0000000000..b69cf145e9 --- /dev/null +++ b/crates/pink/pink-extension/src/lib.rs @@ -0,0 +1,133 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +use std::convert::TryInto; + +use alloc::vec::Vec; +use ink_env::{ + emit_event, test::EmittedEvent, topics::state::HasRemainingTopics, Environment, Topics, +}; +use scale::{Decode, Encode}; + +const PHALA_MESSAGE_TOPIC: &[u8] = b"phala.mq.message"; +const PHALA_OSP_MESSAGE_TOPIC: &[u8] = b"phala.mq.osp_message"; + +pub type EcdhPublicKey = [u8; 32]; +pub type Hash = [u8; 32]; + +#[derive(Encode, Decode, Default, Debug)] +pub struct Message { + pub payload: Vec, + pub topic: Vec, +} + +#[derive(Encode, Decode, Default, Debug)] +pub struct OspMessage { + pub message: Message, + pub remote_pubkey: Option, +} + +impl Topics for Message { + type RemainingTopics = [HasRemainingTopics; 1]; + + fn topics( + &self, + builder: ink_env::topics::TopicsBuilder, + ) -> >::Output + where + E: Environment, + B: ink_env::topics::TopicsBuilderBackend, + { + builder + .build::() + .push_topic(&PHALA_MESSAGE_TOPIC) + .finish() + } +} + +impl Message { + pub fn event_topic() -> Hash { + topics_for(Self::default())[0] + } +} + +impl Topics for OspMessage { + type RemainingTopics = [HasRemainingTopics; 1]; + + fn topics( + &self, + builder: ink_env::topics::TopicsBuilder, + ) -> >::Output + where + E: Environment, + B: ink_env::topics::TopicsBuilderBackend, + { + builder + .build::() + .push_topic(&PHALA_OSP_MESSAGE_TOPIC) + .finish() + } +} + +impl OspMessage { + pub fn event_topic() -> Hash { + topics_for(Self::default())[0] + } +} + +/// Push a raw message to a topic accepting only vanilla messages +/// +/// Most phala system topics accept vanilla messages +pub fn push_message(payload: Vec, topic: Vec) { + emit_event::(Message { payload, topic }) +} + +/// Push a message to a topic accepting optinal secret messages +/// +/// Contract commands topic accept osp messages +pub fn push_osp_message(payload: Vec, topic: Vec, remote_pubkey: Option) { + emit_event::(OspMessage { + message: Message { payload, topic }, + remote_pubkey, + }) +} + +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] +pub enum PinkEnvironment {} + +impl Environment for PinkEnvironment { + const MAX_EVENT_TOPICS: usize = ::MAX_EVENT_TOPICS; + + type AccountId = ::AccountId; + type Balance = ::Balance; + type Hash = ::Hash; + type BlockNumber = ::BlockNumber; + type Timestamp = ::Timestamp; + type RentFraction = ::RentFraction; + + type ChainExtension = ::ChainExtension; +} + +fn topics_for(event: impl Topics + Encode) -> Vec { + EmittedEvent::new::(event) + .topics + .into_iter() + .map(|hash| { + hash.encoded_bytes() + .expect("Never fail") + .try_into() + .expect("Never fail") + }) + .collect() +} + +#[cfg(test)] +mod tests { + #[test] + fn test_event_topics() { + insta::assert_debug_snapshot!(super::Message::event_topic()); + insta::assert_debug_snapshot!(super::OspMessage::event_topic()); + } +} diff --git a/crates/pink/pink-extension/src/snapshots/pink_extension__tests__event_topics-2.snap b/crates/pink/pink-extension/src/snapshots/pink_extension__tests__event_topics-2.snap new file mode 100644 index 0000000000..dc20780301 --- /dev/null +++ b/crates/pink/pink-extension/src/snapshots/pink_extension__tests__event_topics-2.snap @@ -0,0 +1,39 @@ +--- +source: crates/pink/pink-extension/src/lib.rs +expression: "super::OspMessage::event_topic()" + +--- +[ + 80, + 112, + 104, + 97, + 108, + 97, + 46, + 109, + 113, + 46, + 111, + 115, + 112, + 95, + 109, + 101, + 115, + 115, + 97, + 103, + 101, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +] diff --git a/crates/pink/pink-extension/src/snapshots/pink_extension__tests__event_topics.snap b/crates/pink/pink-extension/src/snapshots/pink_extension__tests__event_topics.snap new file mode 100644 index 0000000000..e98cec6e3d --- /dev/null +++ b/crates/pink/pink-extension/src/snapshots/pink_extension__tests__event_topics.snap @@ -0,0 +1,39 @@ +--- +source: crates/pink/pink-extension/src/lib.rs +expression: "super::Message::event_topic()" + +--- +[ + 64, + 112, + 104, + 97, + 108, + 97, + 46, + 109, + 113, + 46, + 109, + 101, + 115, + 115, + 97, + 103, + 101, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +] diff --git a/crates/pink/src/contract.rs b/crates/pink/src/contract.rs index 4e49d58f99..cb55671ab4 100644 --- a/crates/pink/src/contract.rs +++ b/crates/pink/src/contract.rs @@ -3,9 +3,9 @@ use sp_core::Hasher as _; use sp_runtime::DispatchError; use crate::{ - runtime::Contracts, + runtime::{Contracts, ExecSideEffects, System, Timestamp}, storage, - types::{AccountId, Hashing, ENOUGH, GAS_LIMIT}, + types::{AccountId, BlockNumber, Hashing, ENOUGH, GAS_LIMIT}, }; pub type Storage = storage::Storage; @@ -25,6 +25,10 @@ impl Contract { Storage::new(Default::default()) } + pub fn from_address(address: AccountId) -> Self { + Contract { address } + } + /// Create a new contract instance. /// /// # Parameters @@ -39,10 +43,15 @@ impl Contract { code: Vec, input_data: Vec, salt: Vec, - ) -> Result { + block_number: BlockNumber, + now: u64, + ) -> Result<(Self, ExecSideEffects), ExecError> { let code_hash = Hashing::hash(&code); - let address = storage.execute_with(false, move || -> Result<_, ExecError> { + let (address, effects) = storage.execute_with(false, move || -> Result<_, ExecError> { + System::set_block_number(block_number); + Timestamp::set_timestamp(now); + let result = Contracts::bare_instantiate( origin.clone(), ENOUGH, @@ -63,9 +72,8 @@ impl Contract { Ok(_) => (), } Ok(Contracts::contract_address(&origin, &code_hash, &salt)) - })?; - - Ok(Self { address }) + }); + Ok((Self { address: address? }, effects)) } pub fn new_with_selector( @@ -75,11 +83,13 @@ impl Contract { selector: [u8; 4], args: impl Encode, salt: Vec, - ) -> Result { + block_number: BlockNumber, + now: u64, + ) -> Result<(Self, ExecSideEffects), ExecError> { let mut input_data = vec![]; selector.encode_to(&mut input_data); args.encode_to(&mut input_data); - Self::new(storage, origin, code, input_data, salt) + Self::new(storage, origin, code, input_data, salt, block_number, now) } /// Call a contract method @@ -94,9 +104,13 @@ impl Contract { origin: AccountId, input_data: Vec, rollback: bool, - ) -> Result, ExecError> { + block_number: BlockNumber, + now: u64, + ) -> Result<(Vec, ExecSideEffects), ExecError> { let addr = self.address.clone(); - let rv = storage.execute_with(rollback, move || -> Result<_, ExecError> { + let (rv, effects) = storage.execute_with(rollback, move || -> Result<_, ExecError> { + System::set_block_number(block_number); + Timestamp::set_timestamp(now); let result = Contracts::bare_call(origin, addr, 0, GAS_LIMIT * 2, input_data, true); match result.result { Err(err) => { @@ -107,8 +121,8 @@ impl Contract { } Ok(rv) => Ok(rv), } - })?; - Ok(rv.data.0) + }); + Ok((rv?.data.0, effects)) } /// Call a contract method given it's selector @@ -119,15 +133,21 @@ impl Contract { selector: [u8; 4], args: impl Encode, rollback: bool, - ) -> Result { + block_number: BlockNumber, + now: u64, + ) -> Result<(RV, ExecSideEffects), ExecError> { let mut input_data = vec![]; selector.encode_to(&mut input_data); args.encode_to(&mut input_data); - let rv = self.bare_call(storage, origin, input_data, rollback)?; - Ok(Decode::decode(&mut &rv[..]).or(Err(ExecError { - source: DispatchError::Other("Decode result failed"), - message: Default::default(), - }))?) + let (rv, messages) = + self.bare_call(storage, origin, input_data, rollback, block_number, now)?; + Ok(( + Decode::decode(&mut &rv[..]).or(Err(ExecError { + source: DispatchError::Other("Decode result failed"), + message: Default::default(), + }))?, + messages, + )) } } diff --git a/crates/pink/src/lib.rs b/crates/pink/src/lib.rs index 2432cc27bc..262c691180 100644 --- a/crates/pink/src/lib.rs +++ b/crates/pink/src/lib.rs @@ -1,6 +1,6 @@ mod storage; mod contract; -pub(crate) mod runtime; +pub mod runtime; pub mod types; diff --git a/crates/pink/src/runtime.rs b/crates/pink/src/runtime.rs index 8c263bea4a..556b980c9c 100644 --- a/crates/pink/src/runtime.rs +++ b/crates/pink/src/runtime.rs @@ -1,21 +1,18 @@ +mod extension; mod mock_types; use crate::types::{AccountId, Balance, BlockNumber, Hash, Hashing, Index}; use frame_support::weights::Weight; use frame_support::{parameter_types, weights::constants::WEIGHT_PER_SECOND}; -use pallet_contracts::{ - chain_extension::{ - ChainExtension, Environment, Ext, InitState, Result as ExtensionResult, RetVal, SysConfig, - UncheckedFrom, - }, - Config, Frame, Schedule, -}; +use pallet_contracts::{Config, Frame, Schedule}; use sp_runtime::{ generic::Header, traits::{Convert, IdentityLookup}, Perbill, }; +pub use extension::{get_side_effects, ExecSideEffects, EgressMessage}; + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -32,18 +29,6 @@ frame_support::construct_runtime! { } } -pub struct NoExtension; - -impl ChainExtension for NoExtension { - fn call(func_id: u32, _env: Environment) -> ExtensionResult - where - E: Ext, - ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, - { - panic!("Unknown func_id: {}", func_id); - } -} - parameter_types! { pub const BlockHashCount: u32 = 250; pub BlockWeights: frame_system::limits::BlockWeights = @@ -130,7 +115,7 @@ impl Config for PinkRuntime { type CallStack = [Frame; 31]; type WeightPrice = Self; type WeightInfo = (); - type ChainExtension = NoExtension; + type ChainExtension = extension::PinkExtension; type DeletionQueueDepth = DeletionQueueDepth; type DeletionWeightLimit = DeletionWeightLimit; type Schedule = DefaultSchedule; diff --git a/crates/pink/src/runtime/extension.rs b/crates/pink/src/runtime/extension.rs new file mode 100644 index 0000000000..ba745cfa61 --- /dev/null +++ b/crates/pink/src/runtime/extension.rs @@ -0,0 +1,74 @@ +use frame_support::log::error; +use pallet_contracts::chain_extension::{ + ChainExtension, Environment, Ext, InitState, RetVal, SysConfig, UncheckedFrom, +}; +use pink_extension::{Message, OspMessage}; +use scale::Decode; +use sp_runtime::DispatchError; + +use crate::types::AccountId; + +#[derive(Debug)] +pub enum EgressMessage { + Message(Message), + OspMessage(OspMessage), +} + +#[derive(Default, Debug)] +pub struct ExecSideEffects { + pub messages: Vec<(AccountId, EgressMessage)>, + pub instantiated: Vec<(AccountId, AccountId)>, +} + +pub fn get_side_effects() -> ExecSideEffects { + let mut result = ExecSideEffects::default(); + for event in super::System::events() { + if let super::Event::Contracts(ink_event) = event.event { + use pallet_contracts::Event as ContractEvent; + match ink_event { + ContractEvent::Instantiated(deployer, address) => { + result.instantiated.push((deployer, address)) + } + ContractEvent::ContractEmitted(address, data) => { + if event.topics.len() != 1 { + continue; + } + if event.topics[0].0 == pink_extension::Message::event_topic() { + match pink_extension::Message::decode(&mut &data[..]) { + Ok(msg) => { + result.messages.push((address, EgressMessage::Message(msg))); + } + Err(_) => { + error!("Contract emitted invalid message"); + } + } + } else if event.topics[0].0 == pink_extension::OspMessage::event_topic() { + match pink_extension::OspMessage::decode(&mut &data[..]) { + Ok(msg) => { + result.messages.push((address, EgressMessage::OspMessage(msg))); + } + Err(_) => { + error!("Contract emitted invalid osp message"); + } + } + } + } + _ => (), + } + } + } + result +} + +/// Contract extension for `pink contracts` +pub struct PinkExtension; + +impl ChainExtension for PinkExtension { + fn call(func_id: u32, _env: Environment) -> Result + where + ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, + { + error!(target: "pink", "Called an unregistered `func_id`: {:}", func_id); + return Err(DispatchError::Other("Unimplemented func_id")); + } +} diff --git a/crates/pink/src/storage.rs b/crates/pink/src/storage.rs index c518cac729..8bec09fa8d 100644 --- a/crates/pink/src/storage.rs +++ b/crates/pink/src/storage.rs @@ -1,4 +1,4 @@ -use crate::types::{BlockNumber, Hash, Hashing}; +use crate::{runtime::ExecSideEffects, types::{BlockNumber, Hash, Hashing}}; use sp_state_machine::{ disabled_changes_trie_state, Backend as StorageBackend, Ext, OverlayedChanges, StorageTransactionCache, @@ -33,7 +33,7 @@ where } } - pub fn execute_with(&mut self, rollback: bool, f: impl FnOnce() -> R) -> R { + pub fn execute_with(&mut self, rollback: bool, f: impl FnOnce() -> R) -> (R, ExecSideEffects) { let backend = self.backend.as_trie_backend().expect("No trie backend?"); self.overlay.start_transaction(); @@ -45,7 +45,11 @@ where disabled_changes_trie_state::<_, BlockNumber>(), None, ); - let r = sp_externalities::set_and_run_with_externalities(&mut ext, f); + let r = sp_externalities::set_and_run_with_externalities(&mut ext, move || { + crate::runtime::System::reset_events(); + let r = f(); + (r, crate::runtime::get_side_effects()) + }); if rollback { self.overlay.rollback_transaction() } else { diff --git a/crates/pink/tests/fixtures/mqproxy/metadata.json b/crates/pink/tests/fixtures/mqproxy/metadata.json new file mode 100644 index 0000000000..7d4e750afb --- /dev/null +++ b/crates/pink/tests/fixtures/mqproxy/metadata.json @@ -0,0 +1,169 @@ +{ + "metadataVersion": "0.1.0", + "source": { + "hash": "0xa7b22230861f511c1778f3fda9f6985e73cfae48bc9be17e402854fd39871865", + "language": "ink! 3.0.0-rc5", + "compiler": "rustc 1.57.0-nightly" + }, + "contract": { + "name": "mqproxy", + "version": "0.1.0", + "authors": [ + "Kevin Wang " + ] + }, + "spec": { + "constructors": [ + { + "args": [], + "docs": [], + "name": [ + "default" + ], + "selector": "0xed4b9d1b" + } + ], + "docs": [], + "events": [], + "messages": [ + { + "args": [ + { + "name": "message", + "type": { + "displayName": [ + "Vec" + ], + "type": 0 + } + }, + { + "name": "topic", + "type": { + "displayName": [ + "Vec" + ], + "type": 0 + } + } + ], + "docs": [], + "mutates": false, + "name": [ + "push_message" + ], + "payable": false, + "returnType": null, + "selector": "0x6495da7f" + }, + { + "args": [ + { + "name": "message", + "type": { + "displayName": [ + "Vec" + ], + "type": 0 + } + }, + { + "name": "topic", + "type": { + "displayName": [ + "Vec" + ], + "type": 0 + } + }, + { + "name": "remote_pubkey", + "type": { + "displayName": [ + "Option" + ], + "type": 2 + } + } + ], + "docs": [], + "mutates": false, + "name": [ + "push_osp_message" + ], + "payable": false, + "returnType": null, + "selector": "0xd09d68e0" + } + ] + }, + "storage": { + "struct": { + "fields": [] + } + }, + "types": [ + { + "id": 0, + "type": { + "def": { + "sequence": { + "type": 1 + } + } + } + }, + { + "id": 1, + "type": { + "def": { + "primitive": "u8" + } + } + }, + { + "id": 2, + "type": { + "def": { + "variant": { + "variants": [ + { + "index": 0, + "name": "None" + }, + { + "fields": [ + { + "type": 3 + } + ], + "index": 1, + "name": "Some" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 3 + } + ], + "path": [ + "Option" + ] + } + }, + { + "id": 3, + "type": { + "def": { + "array": { + "len": 32, + "type": 1 + } + } + } + } + ] +} \ No newline at end of file diff --git a/crates/pink/tests/fixtures/mqproxy/mqproxy.contract b/crates/pink/tests/fixtures/mqproxy/mqproxy.contract new file mode 100644 index 0000000000..a2c6e66a06 --- /dev/null +++ b/crates/pink/tests/fixtures/mqproxy/mqproxy.contract @@ -0,0 +1 @@ +{"metadataVersion":"0.1.0","source":{"hash":"0xa7b22230861f511c1778f3fda9f6985e73cfae48bc9be17e402854fd39871865","language":"ink! 3.0.0-rc5","compiler":"rustc 1.57.0-nightly","wasm":"0x0061736d0100000001640f60027f7f017f60037f7f7f017f60027f7f0060037f7f7f0060047f7f7f7f0060017f0060057f7f7f7f7f0060017f017f60000060017f017e60067f7f7f7f7f7f0060047f7f7f7f017f60057f7f7f7f7f017f60077f7f7f7f7f7f7f017f60027e7f017f02950106057365616c30127365616c5f6465706f7369745f6576656e740004057365616c300a7365616c5f696e7075740002057365616c30147365616c5f686173685f626c616b65325f3235360003057365616c30127365616c5f64656275675f6d6573736167650000057365616c30167365616c5f76616c75655f7472616e73666572726564000203656e76066d656d6f7279020102100373720505050009020807080204060202020504020302020202000200040a00000203020302030202040505050004020101000000000103030203080302020700030403040002000000090a03030303000700000000000601060606070c00000101000002030b0b04020404000300060d0e00000104050170012c2c0608017f01418080040b071102066465706c6f79000b0463616c6c000d0931010041010b2b2e2c08062f061c061e063455062206210638363706740675474756575870424a6e064c065a6061066364650a91b1017210002000280204044020002802001a0b0b0300010b2600024020002802004101460440200041086a280200450d0120002802041a000b0f0b103d000baf0301017f230041206b22022400027f0240024002400240024002400240024020002d000041016b0e0701020304050607000b2002411c6a41003602002002419882043602182002420137020c200241ec84043602082001200241086a10490c070b2002411c6a41003602002002419882043602182002420137020c200241d484043602082001200241086a10490c060b2002411c6a41003602002002419882043602182002420137020c200241b084043602082001200241086a10490c050b2002411c6a41003602002002419882043602182002420137020c2002419084043602082001200241086a10490c040b2002411c6a41003602002002419882043602182002420137020c200241e083043602082001200241086a10490c030b2002411c6a41003602002002419882043602182002420137020c200241a083043602082001200241086a10490c020b2002411c6a41003602002002419882043602182002420137020c200241e482043602082001200241086a10490c010b2002411c6a41003602002002419882043602182002420137020c200241bc82043602082001200241086a10490b200241206a24000bb00202087f017e230041106b220124002001420037030841042102027f02400340200245044020012903082209a741044f0d0241f48404411b419085041043000b20012000101d20012d000041017145044020012d00012105230041106b22032400200341086a21060240200141086a2204280200220841044f0440200521040c010b2004200428020022076a41046a20053a000002402007200741016a22054d0440200420053602000c010b41908104411c41f086041043000b0b200620043a00012006200841034b3a000020032d00084101710440200320032d00093a000f41dc8104412b2003410f6a41888204418087041059000b200341106a2400200241016b21020c010b0b4101210241000c010b410021022009422088a70b2100200141106a24002002ad2000ad420886840bf109010c7f230041106b220b2400200b41086a2109230041306b22022400200241206a20012205103141012106024020022d00204101710d0002400240024020022d0021220441037122074103470440200741016b0e020203010b200441044f0d03200241086a2107230041106b220824002008410036020c0240200522042008410c6a41041032450440200828020c21040c010b410121030b2007200436020420072003360200200841106a240020022802080d03200228020c22054180808080044921060c030b200441fc01714102762105410021060c020b200220043a002d200241013a002c20022005360228200241106a2107230041106b22042400200441003b010e0240200241286a22032004410e6a4102103345044020042f010e21030c010b410121080b200720033b0102200720083b0100200441106a240020022f01100d0120022f0112220441ff014d0d01200441fcff03714102762105410021060c010b200220043a002d200241013a002c20022005360228200241186a2107230041106b220424002004410036020c0240200241286a22032004410c6a41041033450440200428020c21030c010b410121080b2007200336020420072008360200200441106a240020022802180d00200228021c220541808004492106200541027621050b2009200536020420092006360200200241306a24000240200b280208450440200b28020c2105230041106b22042400230041d0006b22022400200241286a2203410136020020032001280204360204024002400240024002400240200228022822034102470440200228022c200549410220031b2206410247410020064101711b0d012003410146200541802049720d032002420037024420024198820428020036024003402005450d052002280248220820054180202005418020491b22076a220d2008490d03200241406b220321092003280208210a230041106b22062400024020072009280204200a6b4d0440200641003602000c010b230041206b220324000240200a2007200a6a220c4d044002402009280204220a0440200341186a41013602002003200a360214200320092802003602100c010b200341003602100b4101210a2003200c200341106a103e20032802004101470440200920032902043702004100210a0c020b200620032902043702040c010b2006200c360204200641086a41003602004101210a0b2006200a360200200341206a24000b20061007200641106a24002002200d360248200241206a200241406b1040200228022021062008200228022422034b04402008200341ac8104104f000b200241186a2209200320086b3602042009200620086a36020020012002280218200228021c10324504404100200520076b2203200320054b1b21050c010b0b20044100360200200241406b10050c060b200441003602000c050b200441003602000c040b41908104411c418081041043000b200241106a20054101103c2002200536024820022002290310370340200241086a200241406b104020012002280208200228020c10320d010b200241386a200241c8006a2802003602002002200229034037033020042002290330370200200441086a200241386a2802003602000c010b20044100360200200241406b10050b200241d0006a2400200428020022010440200020042902043702040b20002001360200200441106a24000c010b200041003602000b200b41106a24000b6501027f4100100c41ff017122014108470440230041306b22002400200020013a000f200041246a410136020020004201370214200041d488043602102000410336022c2000200041286a36022020002000410f6a360228200041106a418c89041048000b0b831d02117f017e23004180026b220d2400027f200045044041084106230041206b22002400200041106a102d2000200041106a102920002000290300370308200041086a102c20002000290308370310027f200041106a10092212a7410171450440410020124280feffffff1f834280daafeab903510d011a0b41010b2101200041206a24004100410c20011b41ff0171410c461b0c010b200d41c0016a2110230041e0006b22092400200941186a102d200941086a200941186a102920092009290308370310200941106a102c20092009290310370358200941186a2106230041e0006b2204240002400240024002400240200941d8006a220110092212a72207410171450440201242ffffffffff1f832212422088a721002012421888a721022012421088a7210502400240200741087641ff0171220741e400470440200741d001460d010c070b200541ff017141950147200241ff017141da014772200041ff0047720d06200441086a2001100a20042802082200450d052004200429020c37022c20042000360228200441086a2001100a20042802082200450d01200441c3006a200441306a2802003600002004200429032837003b200429020c2112200641003a000020062004290038370001200641086a2004413f6a290000370000200641146a2012370200200641106a20003602000c070b200541ff0171419d0147200241ff017141e8004772200041e00147720d05200441386a2001100a20042802382200450d022004200429023c37021c20042000360218200441386a2001100a20042802382200450d032004200429023c37022c20042000360228200441386a210b230041306b220a2400200a2001103102400240200a2d00004101710d000240200a2d000122000e020200010b200a41086a2108230041d0006b22032400200341003602104120210002400240034020004504402003200341296a220f28000036024820032003412c6a28000036004b200341226a21022003411b6a210c200341106a410472210e200341256a28000021052003411e6a280100210120032800172100027f2003280210220741204f0440200341306a28020021112003413e6a200241026a2d00003a00002003413a6a200f41026a2d00003a00002003200e2f01003b01442003200c2f00003b0140200320022f00003b013c2003200f2f00003b01382003200e41026a2d00003a00462003200c41026a2d00003a00422001210220052101200328004b0c010b2003413e6a200c41026a2d00003a00002003413a6a200241026a2d00003a00002003200e2f01003b01402003200c2f00003b013c200320022f00003b01382003200e41026a2d00003a004220032802482111200021022007210020050b2105200741204f0d0241889304411b41a493041043000b200341086a2001101d20032d000841017145044020032d00092107230041106b22022400200341106a2205280200411f4b220e450440024020052005280200220c6a41046a20073a0000200c200c41016a220f4d04402005200f3602000c010b41d09104411c41e094041043000b0b200241086a220520073a00012005200e3a000020022d00084101710440200220022d00093a000f41cc9204412b2002410f6a41f8920441f094041059000b200241106a2400200041016b21000c010b0b200841013a00000c010b200820032f01443b0001200841036a20032d00463a0000200841086a20032f01403b00002008410a6a20032d00423a00002008410f6a20032f013c3b0000200841166a20032f01383b00002008411d6a2011360000200841196a2005360000200841126a20013600002008410b6a2002360000200841046a2000360000200841116a2003413e6a2d00003a0000200841186a2003413a6a2d00003a0000200841003a00000b200341d0006a240041012100200a2d00084101470440200b200a290009370001200b41196a200a41216a290000370000200b41116a200a41196a290000370000200b41096a200a41116a2900003700000c020b0b410221000b200b20003a0000200a41306a240020042d003822004102470440200641026a20042900393700002006411a6a200441d1006a290000370000200641126a200441c9006a2900003700002006410a6a200441c1006a290000370000200441126a200441206a280200360100200641306a2004290328370200200641386a200441306a2802003602002004200429031837010a200620003a0001200641013a0000200641226a2004290108370100200641286a2004410e6a2901003701000c070b200641023a0000200441286a1005200441186a10050c060b200641023a0000200441286a10050c050b200641023a00000c040b200641023a00000c030b200641023a0000200441186a10050c020b200641023a00000c010b200641023a00000b200441e0006a24002010027f20092d00184102470440201041046a200941186a413c10761a41000c010b201041003a000141010b3a0000200941e0006a2400200d2d00c0014101470440200d41086a200d41c6006a200d4184016a200d41c0016a410472413c1076413c1076413c10761a230041d0026b220024000240200d41086a22012d00004101470440200041106a22072001410c6a22022802003602002000411c6a200141186a2802003602002000200141046a220529020022123703082000200141106a290200370214200041d8006a200041186a290300370300200041d0006a2007290300370300200020123703482000419c016a200041dc006a28020036020020004190016a22012002280200360200200020002902543702940120002005290200221237038801200041d8016a20004198016a290300370300200041d0016a2001290300370300200020123703c801200041a0026a20022802003602002000200529020037039802200041b0026a200041dc016a280200360200200020002902d4013703a802230041206b22052400200541086a20004198026a220141086a28020036020020052001290200370300200541186a200041a8026a220141086a28020036020020052001290200370310230041206b22072400200741106a200541086a2802003602002007411c6a200541106a220141086a2802003602002007200529020037030820072001290200370214230041206b22042400200441186a200741086a220141106a290200370300200441106a200141086a29020037030020042001290200370308230041206b22032400200341186a200441086a220141106a290200370300200341106a200141086a29020037030020032001290200370308230041306b22022400200241206a102d230041206b22012400200141186a2206200241206a220841086a280200360200200120082902003703102001200141106a101a200141fc8f0410112006200141086a28020036020020012001290300370310200241086a200141106a101b200141206a2400200241286a200241106a28020036020020022002290308370320200241186a28020021082002280214230041406a22012400200141186a200241206a220641046a1013200141206a2001280218200128021c1024200341086a220a200141206a1016200141206a280208210b200141386a200141286a28020036020020012001290320370330200141106a200141306a102520062001290310370204200141086a2006200b102820022001290308370300200141406b2400200820022802002002280204102b200a1014200241306a2400200341206a2400200441206a2400200741206a2400200541206a24000c010b200041106a2001412c6a22022802003602002000411c6a200141386a2802003602002000200141246a22052902003703082000200141306a290200370214200041206a200141016a412110761a200041c8006a200041086a413c10761a2000419c016a200041dc006a28020036020020004190016a200228020036020020002000290254370294012000200529020037038801200041a0016a200041e0006a412110761a200041c8016a20004188016a413c10761a20004190026a20022802003602002000200529020037038802200041a0026a200041dc016a280200360200200020002902d40137039802200041a8026a200041e0016a412110761a230041d0006b22072400200741106a20004188026a220141086a28020036020020072001290200370308200741206a20004198026a220141086a28020036020020072001290200370318200741286a200041a8026a412110761a230041e0006b22052400200541d0006a2201200741086a220241086a280200360200200541dc006a200741186a220441086a2802003602002005200229020037034820052004290200370254200541206a200741286a412110761a200541186a200541d8006a290300370300200541106a200129030037030020052005290348370308230041406a220124002001200541086a413c107622082101230041406a2202240020022001413c107622092104230041306b22022400200241206a102d230041206b22012400200141186a2203200241206a220641086a280200360200200120062902003703102001200141106a101a20014198900410112003200141086a28020036020020012001290300370310200241086a200141106a101b200141206a2400200241286a200241106a28020036020020022002290308370320200241186a280200210a2002280214230041406a22012400200141186a200241206a220641046a1013200141206a2001280218200128021c10242004200141206a220310160240200441186a220c2d000041014704402003410010270c010b200341011027200c41016a200310190b200141206a2802082103200141386a200141286a28020036020020012001290320370330200141106a200141306a102520062001290310370204200141086a20062003102820022001290308370300200141406b2400200a20022802002002280204102b20041014200241306a2400200941406b2400200841406b2400200541e0006a2400200741d0006a24000b200041d0026a240041080c010b41060b200d4180026a24000bbe0302057f037e230041206b22002400230041406a22012400200141306a102d200141206a200141306a102920012001290320370328200141286a102e20012001290328370330200141086a2103230041106b22022400200241086a22044200370300200242003703000240200141306a20024110103245044020042903002105200229030021060c010b420121070b2003200637030820032007370300200341106a2005370300200241106a24002000027f2001290308a7450440200141186a2903002105200041086a2001290310370300200041106a200537030041000c010b200041003a000141010b3a0000200141406b24000240024020002d00004101470440200041086a290300200041106a2903008450450d014101100c41ff017122014108470d02200041206a24000f0b200020002d00013a001f4190870441342000411f6a41bc810441a488041059000b200041073a0000419c890441c300200041cc8104418c89041059000b230041306b22002400200020013a000f200041246a410136020020004201370214200041fc89043602102000410336022c2000200041286a36022020002000410f6a360228200041106a418c89041048000b4601017f230041106b220224002002200136020c230041106b220124002001200028020036020c2002410c6a2802002001410c6a41041026200141106a2400200241106a24000b3001017f2002200220016b22044f0440200020043602042000200120036a3602000f0b41e08b04412141848c041043000b4701017f230041106b22052400200120034d0440200541086a410020012002100f200020052802083602002000200528020c360204200541106a24000f0b2001200320041050000bb50502057f017e23004180016b22032400230041106b2202240020002802002204200041086a28020022054b04402004200541bc9904104f000b200241086a200420052000280204101f20022903082107200341306a2204410036020020042007370204200241106a2400230041406a22022400200241186a200341306a220441046a1013200241206a2002280218200228021c102420012802002001280204200241206a1017200241206a2802082101200241386a200241286a28020036020020022002290320370330200241106a200241306a102520042002290310370204200241086a200420011028200341286a2002290308370300200241406b240020032802282104200328022c2101200341406b22024200370000200241186a4200370000200241106a4200370000200241086a4200370000200341206a200341406b10230240200328022422022001490440200341f8006a4200370300200341f0006a4200370300200341e8006a42003703002003420037036020042001200341e0006a1002200341086a200341406b102320032002412020024120491b22012003280208200328020c41908d04101020032802002003280204200341e0006a200110460c010b200341186a200341406b1023200341106a20012003280218200328021c41808d041010200328021020032802142004200110460b230041206b2201240020002802002102200141086a200041046a1013200120012802082204200128020c220520021015200141106a200128020020012802041024230041106b220224002002200341406b36020c2002410c6a280200200141106a1019200241106a2400024020002802002202200141106a2802086a220620024f04402000200436020420002006360200200041086a2005360200200141206a24000c010b41d08f04411c41b48f041043000b20034180016a24000bdc0101037f230041106b220324002003200036020c230041106b2200240002402003410c6a28020022042802002202413f4d04402001200241027410270c010b200241ffff004d0440200020024102744101723b010a230041106b220224002002200136020c230041106b2201240020012000410a6a2f01003b010e2002410c6a2802002001410e6a41021026200141106a2400200241106a24000c010b200241ffffffff034d04402000200241027441027236020c2000410c6a2001100e0c010b20014103102720042001100e0b200041106a2400200341106a24000b5102027f017e230041106b22022400200241086a220341003602042003418c980436020020012902002104200228020821032001200228020c3602042001200336020020002004370300200241106a24000b0d00200010052000410c6a10050b4801017f230041106b22042400200220034904402003200241a48f04104f000b200441086a200320022001100f200020042802083602002000200428020c360204200441106a24000b11002000200110182000410c6a200110180b5701027f230041106b22042400230041106b220324002003200136020c2003410c6a20021012200341106a24004100044041908e044116200441086a41808e0441a88e041059000b2002200020011026200441106a24000b2b01017f230041106b22022400200241086a200010402002280208200228020c20011017200241106a24000b0a0020012000412010260bcb0101067f230041106b220324002003410136020c230041206b2202240020012802002104200241086a200141046a1013200220022802082205200228020c220620041015200241106a2002280200200228020410242003410c6a200241106a1012024020012802002204200241106a2802086a220720044f04402001200536020420012007360200200141086a2006360200200241206a24000c010b41d08f04411c41b48f041043000b200341106a2400200041086a200141086a280200360200200020012902003702000baa0102037f017e230041106b22022400200241086a200141086a28020036020020022001290200370300230041106b22032400230041106b220124002002280200210420024100360200200141086a200220041028200341086a220420012802083602002004200128020c360204200141106a240020032903082105200020022902003702002000200537020c200041086a200241086a280200360200200341106a2400200241106a24000bb30101017f230041106b2202240002400240024002400240024002400240024020002d000041016b0e0701020304050607000b2002200141b49104410f106d0c070b20022001419a9104411a106d0c060b20022001418791044113106d0c050b2002200141f690044111106d0c040b2002200141da9004411c106d0c030b2002200141c590044115106d0c020b2002200141b490044111106d0c010b2002200141a090044114106d0b2002105e200241106a24000b3801017f230041106b22022400200241086a2001103120022d00092101200020022d00084101713a0000200020013a0001200241106a24000b6f01017e230041406a22002400200041106a41c49304106620002903102102200041086a41e4930410662000412c6a4102360200200020023703302000420237021c200041f09304360218200020002903083703382000200041306a3602282001200041186a1049200041406b24000b3001017f2002200220016b22044f0440200020043602042000200120036a3602000f0b419096044121418096041043000b5901017f230041106b220624000240200120024d0440200220044d0d012002200420051050000b200120022005106f000b200641086a200120022003101f200020062802083602002000200628020c360204200641106a24000b0b002000280200200110340bfe0201027f20002802002102230041306b22002400410121030240200128021841c0aa04410c2001411c6a28020028020c1101000d0002402002280208220304402000200336020c41012103200041246a410136020020004202370214200041d0aa043602102000411b36022c2000200041286a36022020002000410c6a3602282001200041106a1049450d010c020b20022802002203200228020428020c11090042f4f99ee6eea3aaf9fe00520d002000200336020c41012103200041246a410136020020004202370214200041d0aa043602102000411c36022c2000200041286a36022020002000410c6a3602282001200041106a10490d010b200228020c2103230041306b220224002002412c6a411a360200200241246a411a360200200241146a41033602002002420337020420024198aa043602002002410c36021c2002200336021820022003410c6a3602282002200341086a3602202002200241186a360210200120021049200241306a240021030b200041306a240020030b100020004120360204200020013602000b17002000410036020820002002360204200020013602000b0c00200020012902003703000b6301037f230041106b220324002000280208220420026a2205200449044041c09604411c418c99041043000b200341086a2004200520002802002000280204419c990410202003280208200328020c20012002104620002005360208200341106a24000b3901027f20002802082202200028020422034904402000200241016a360208200028020020026a20013a00000f0b2002200341ac99041045000b5e01027f200141086a2203280200210420034100360200200128020421032001418c9804360204200220044b044041dc9604412341fc97041043000b2001200420026b3602082001200220036a36020420002002360204200020033602000b0c00200020012902043703000b3701017f230041106b22022400200241086a410020012000280200200028020441b49a04102020002002290308370200200241106a24000b0c00200020012002200310000b3301017f230041106b220124002001200028020436020c20002802002001410c6a10012000200128020c102a200141106a24000b1e00200041ccd60436020420004100360200200041086a418080013602000b3301017f230041106b220124002001200028020436020c20002802002001410c6a10042000200128020c102a200141106a24000be50502047f027e230041206b22022400027f02400240024002400240024002400240024002400240024020002d000041016b0e0b0102030405060708090a0b000b200241106a200141e49b044106106d2002200041016a36020c2002410c6a2105230041406a22002400200241106a2204027f20042d000804402004280204210341010c010b20042802042103200428020022012d0000410471450440410120012802184186ad04419ead0420031b4102410120031b2001411c6a28020028020c1101000d011a2005200141f89b042802001100000c010b024020030d002001280218419cad0441022001411c6a28020028020c110100450d004100210341010c010b200041013a0017200041346a41b8ab04360200200041106a200041176a360200200020012902183703082001290208210620012902102107200020012d00203a00382000200737032820002006370320200020012902003703182000200041086a36023041012005200041186a41f89b042802001100000d001a20002802304184ad044102200028023428020c1101000b3a000802402003200341016a22014d044020042001360204200041406b24000c010b41b0a604411c418cad041043000b200241106a105e0c0b0b200241106a200141d79b04410d106d200241106a105e0c0a0b200241106a200141c99b04410e106d200241106a105e0c090b200241106a200141be9b04410b106d200241106a105e0c080b200241106a200141a59b044119106d200241106a105e0c070b200241106a200141979b04410e106d200241106a105e0c060b200241106a200141839b044114106d200241106a105e0c050b200241106a200141f79a04410c106d200241106a105e0c040b200241106a200141ec9a04410b106d200241106a105e0c030b200241106a200141e59a044107106d200241106a105e0c020b200241106a200141d69a04410f106d200241106a105e0c010b200241106a200141c49a044112106d200241106a105e0b200241206a24000b3001017f2002200220016b22044f0440200020043602042000200120036a3602000f0b41c09d04412141ac9d041043000b3f01027f230041106b22022400200241003a000f200020012002410f6a410110322201047f41000520022d000f0b3a0001200020013a0000200241106a24000b5c01047f230041106b22032400200028020422042002492205450440200341086a41002002200028020022061030200120022003280208200328020c104620032002200420061030200020032903003702000b200341106a240020050b4701017f20002f01042103200041003a00042003410171410020021b45044020002802002001200210320f0b200120034108763a00002000280200200141016a200241016b10320bb60101017f230041106b2200240020002001ad4280808080104200200128021841e19d0441052001411c6a28020028020c1101001b84370308200041086a22012d0004210220012d000504402001027f4101200241ff01710d001a200128020022012d000041047145044020012802184189ad0441022001411c6a28020028020c1101000c010b20012802184188ad0441012001411c6a28020028020c1101000b22023a00040b200241ff0171410047200041106a24000b5501017f230041206b2202240020022000360204200241186a200141106a290200370300200241106a200141086a29020037030020022001290200370308200241046a41e89d04200241086a1062200241206a24000bbf0201027f20002802002102230041106b22002400024002400240024020022000410c6a027f02400240200141ff004d0440200228020822032002280204460d010c040b2000410036020c2001418010490d0120014180800449044020002001413f71418001723a000e20002001410c7641e001723a000c20002001410676413f71418001723a000d41030c030b20002001413f71418001723a000f2000200141127641f001723a000c20002001410676413f71418001723a000e20002001410c76413f71418001723a000d41040c020b20024101103f200228020821030c020b20002001413f71418001723a000d2000200141067641c001723a000c41020b10390c010b200228020020036a20013a0000200341016a22012003490d01200220013602080b200041106a24000c010b41809e04411c41d4a3041043000b41000b4a01017f230041206b220224002000280200200241186a200141106a290200370300200241106a200141086a29020037030020022001290200370308200241086a1035200241206a24000b0f00200028020020012002103941000b8a0101027f230041106b220324002003200120026a36020c200320013602082003200341086a220128020022023602002003200128020420026b36020420032802002104200020032802042201103f2000280208220220002802006a2004200110761a2002200120026a22014b044041809e04411c41e4a3041043000b20002001360208200341106a24000b2d00027f41012001450d001a2002450440200110410c010b200110410b210220002001360204200020023602000b3301017f230041106b22022400200241086a20014100103a200020022802083602002000200228020c360204200241106a24000b6901017f230041106b220324000240200141004e0440027f2002450440200341086a2001103b200328020c210120032802080c010b200320014101103a2003280204210120032802000b22020d01000b103d000b2000200236020020002001360204200341106a24000b0f0041b4a204411141c8a2041043000bb80101047f230041106b220324000240027f4101210520014100480d012002280200220445044020032001103b2003280200210220032802040c010b20022802042202450440200341086a20014100103a20032802082102200328020c0c010b2001104122060440200620042001200220012002491b10761a0b2006210220010b21042002044020002002360204410021050c010b20002001360204410121040b20002005360200200041086a2004360200200341106a24000b820201047f20012000280204200028020822056b4b0440230041106b22042400230041206b22022400024002402005200120056a22034d04402000280204220120016a22052001490d012005200320032005491b22034108200341084b1b2103024020010440200241186a410136020020022001360214200220002802003602100c010b200241003602100b4101210120022003200241106a103e2002280200410147044020002002290204370200410021010c030b200420022902043702040c020b20042003360204200441086a4100360200410121010c010b4180a204412141a4a2041043000b20042001360200200241206a240020041007200441106a24000b0b160020002001280208360204200020012802003602000bcc0101067f230041106b22032400200341086a2104230041106b22062400024041d0d605280200220120006a22022001490d0041d4d6052802002002490440200041ffff036a22012000490d012001411076220240002201417f46200141ffff0371200147720d012001411074220120024110746a22022001490d0141d4d6052002360200200020016a22022001490d010b41d0d6052002360200410121050b2004200136020420042005360200200641106a240020032802082100200328020c200341106a2400410020001b0b0e0020002802001a03400c000b000b4601017f230041206b22032400200341146a4100360200200341a4a704360210200342013702042003200136021c200320003602182003200341186a360200200320021048000b3001017f2002200220016b22044f0440200020043602042000200120036a3602000f0b4180a604412141e4b5041043000b6b01017f230041306b2203240020032001360204200320003602002003411c6a41023602002003412c6a41193602002003420237020c20034194ab04360208200341193602242003200341206a360218200320033602282003200341046a360220200341086a20021048000b7d002001200346044020002002200110761a0f0b230041306b2200240020002003360204200020013602002000411c6a41023602002000412c6a41193602002000420337020c20004180b804360208200041193602242000200041206a360218200020003602282000200041046a360220200041086a41b0b7041048000b0b002000350200200110730b8e0502087f017e230041106b220224002002200136020c20022000360208200241b0aa04360204200241a4a704360200230041406a220024002000200236020c200041346a4101360200200042023702242000419098043602202000410e36023c2000200041386a36023020002000410c6a360238230041206b22012400200041106a22072106027f200041206a2202280200220521042005200228020422084103746a2109027f024003402004200947044020032003200441046a2802006a22034b0d02200441086a21040c010b0b20030c010b41809e04411c41b09f041043000b2203200241146a280200450d001a02402008450d0020052802040d00410020034110490d011a0b4100200320036a2204200320044b1b0b2105230041106b22042400230041106b22032400200341086a20054100103c200441086a220520032802083602002005200328020c360204200341106a24002004290308210a200641003602082006200a370200200441106a2400200141186a200241106a290200370300200141106a200241086a290200370300200120022902003703082007200141086a1035044041c09f044133200141086a419c9e0441eca0041059000b200141206a2400230041106b22012400200141086a200041106a1040200020012802083602002000200128020c360204200141106a24002000280200210220002802042103230041106b220124002001200336020c20012002360208200141086a2202280200210320022802042102024041ccd6052d000045044041cdd6052d00004101710d010b2003200210032202410b4d047f200241027441fc9b046a28020005410c0b410947044041ccd60541013a00000b41cdd60541013a00000b200141106a2400200041106a1005000b5601027f230041206b220224002000411c6a28020021032000280218200241186a200141106a290200370300200241106a200141086a290200370300200220012902003703082003200241086a1062200241206a24000b5e01027f230041206b2202240041012103024020002001104b0d002002411c6a4100360200200241a4a7043602182002420137020c200241a8a7043602082001200241086a10490d00200041046a2001104b21030b200241206a240020030b9d0401067f02402001280200220241107145044020024120710d012000200110470f0b2000280200210323004190016b2202240041ff0021040340200241106a20046a027f230041306b220024004130210502402003410f7122062207410a4f044041d70021052007410f4b0d010b200041306a2400200520066a0c010b200020063a00072000411c6a41023602002000412c6a411e3602002000420237020c200041bcce043602082000411e360224200041ccce043602202000200041206a3602182000200041076a360228200041086a41d0ce041048000b3a0000200441016b21042003410f4b200341047621030d000b200241086a200241106a200441016a104e200141acae0441022002280208200228020c105f20024190016a24000f0b2000280200210323004190016b2202240041ff0021040340200241106a20046a027f230041306b220024004130210502402003410f7122062207410a4f0440413721052007410f4b0d010b200041306a2400200520066a0c010b200020063a00072000411c6a41023602002000412c6a411e3602002000420237020c200041bcce043602082000411e360224200041ccce043602202000200041206a3602182000200041076a360228200041086a41e0ce041048000b3a0000200441016b21042003410f4b200341047621030d000b200241086a200241106a200441016a104e200141acae0441022002280208200228020c105f20024190016a24000b0d004286ab8e9cfaf3e2b4847f0b5901017f230041106b220624000240200120024d0440200220044d0d012002200420051050000b200120022005106f000b200641086a2001200220031044200020062802083602002000200628020c360204200641106a24000b4b01017f230041106b2203240020024181014f04402002418001419cae04104f000b200341086a200241800120011044200020032802083602002000200328020c360204200341106a24000b6b01017f230041306b2203240020032001360204200320003602002003411c6a41023602002003412c6a41193602002003420237020c20034180b404360208200341193602242003200341206a3602182003200341046a36022820032003360220200341086a20021048000b6b01017f230041306b2203240020032001360204200320003602002003411c6a41023602002003412c6a41193602002003420237020c200341a0b404360208200341193602242003200341206a3602182003200341046a36022820032003360220200341086a20021048000bba0201047f230041106b22032400200341086a2105027f0240024020014180014f04402001418010490d012001418080044f0d0220022001413f71418001723a000220022001410c7641e001723a000020022001410676413f71418001723a000141030c030b200220013a000041010c020b20022001413f71418001723a00012002200141067641c001723a000041020c010b20022001413f71418001723a00032002200141127641f001723a000020022001410676413f71418001723a000220022001410c76413f71418001723a000141040b2104230041106b22012400200441044b04402004410441b0a8041050000b200141086a2206200436020420062002360200200520012802083602002005200128020c360204200141106a2400200020032802083602002000200328020c360204200341106a24000b1a002000418080c40046044041eca904412b20011043000b20000bf00101057f2000280200220120002802042203460440418080c4000f0b2000200141016a220236020020012d00002204411874411875417f4c047f027f200220034604402003210241000c010b2000200141026a220236020020012d0001413f710b21012004411f712105200441df014d044020012005410674720f0b2001410674027f200220034604402003210141000c010b2000200241016a220136020020022d0000413f710b722102200441f00149044020022005410c74720f0b2001200346047f4100052000200141016a36020020012d0000413f710b2005411274418080f00071200241067472720520040b0b4601017f027f02400340200020014704402002200220002d000041c00171418001476a22024b0d02200041016a21000c010b0b20020c010b41b0a604411c4190ce041043000b0b9e0301067f2000280200210320002802042104230041306b220024002001280210210202400240024020012802082205410147044020020d012001280218200320042001411c6a28020028020c11010021020c030b2002450d010b200141146a28020020002003360224200041286a200320046a3602002000410036022041016a210202400340200241016b22020440200041186a200041206a106b200028021c418080c400470d010c020b0b200041106a200041206a106b2000280214418080c400460d00200041086a200028021020032004106c200028020c2004200028020822021b21042002200320021b21030b20050d002001280218200320042001411c6a28020028020c11010021020c010b2001410c6a28020022022003200320046a105422054d04402001280218200320042001411c6a28020028020c11010021020c010b20002001200220056b4100106a4101210220002802002205418080c400460d002000280204210620012802182207200320042001411c6a280200220128020c1101000d002005200620072001106821020b200041306a240020020b5d01027f20002802002102230041206b220024002001411c6a28020021032001280218200041186a200241106a290200370300200041106a200241086a290200370300200020022902003703082003200041086a1062200041206a24000b0b002000280200200110550b140020002802002001200028020428020c1100000b7c01017f230041406a220524002005200136020c2005200036020820052003360214200520023602102005412c6a41023602002005413c6a411d3602002005420237021c200541a8ab043602182005410c3602342005200541306a3602282005200541106a3602382005200541086a360230200541186a20041048000bc10a010f7f230041e0006b22032400200341d8006a21102000280204210d2000280200210e2000280208210b024003402002450d010240200b2d00000440200e41d0ab044104200d28020c1101000d010b410021002003410036025c200341386a410a200341dc006a10512003410a3602502003200236024c2003410036024820032002360244200320013602402003200328025c3602582003200328023c360254200222042108200121050340200341306a2005200820002004105b0240024002400240024020032802302207450d0002402003280254220041016b220420004d0440200320046a41d8006a2d0000210a2003280234220541084f0440200341286a210f41002104230041106b22092400024002400240200741036a417c7120076b2206450d00230041106b22002400200041086a41002005200620052006491b22042007200541ecb204104d200941086a220620002802083602002006200028020c360204200041106a240041002100200928020c21082009280208210c034020002008460d012000200c6a2d0000200a460d022000200041016a22064d0440200621000c010b0b41b0a604411c4184d0041043000b02402005200541086b22084f0440200a41818284086c210602400340200420084b0d03200441046a22002004490d01200420076a280200200673220c417f73200c41818284086b71200020076a2802002006732200417f73200041818284086b7172418081828478710d032004200441086a22004d0440200021040c010b0b41b0a604411c419cb3041043000b41b0a604411c418cb3041043000b4180a604412141fcb2041043000b230041106b220024002004220620054b04402006200541acb304104f000b200041086a2006200520071044200920002802083602002009200028020c360204200041106a2400410021082009280204210520092802002107410021000240034020002005460d03200020076a2d0000200a460d012000200041016a22044d0440200421000c010b0b41b0a604411c4184d0041043000b200020066a220020064f0d0041b0a604411c41bcb3041043000b410121080b200f2000360204200f2008360200200941106a2400200328022c2100200328022821080c020b4100210841002100034020002005460440200521000c030b200a200020076a2d0000460440410121080c0305200041016a21000c010b000b000b4180a604412141d8bc041043000b20084101470d002000200041016a22044b0d022004200328024822056a22002005490d0320032000360248200020032802542204490d04200341206a20032802402003280244200020046b22062000105b20032802202200450d042003280224210520032802542107230041106b22042400200441086a41002007201041044188bd04104d200341186a220720042802083602002007200428020c360204200441106a240020032802182104200328021c200546047f027f034041002005450d011a200541016b210520042d0000210720002d00002109200041016a2100200441016a210420072009460d000b200920076b0b450541000b450d04200b41013a0000200641016a220020064f0d0141b0a604411c41d4ac041043000b200b41003a0000200221000b200341106a20002001200241e4ac04105c200e20032802102003280214200d28020c1101000d04200341086a20002001200241f4ac04105d200328020c2102200328020821010c050b41b0a604411c41e8bc041043000b41b0a604411c41f8bc041043000b200328024c21042003280248210020032802442108200328024021050c000b000b0b410121110b200341e0006a240020110b4c01037f230041106b220524002002200449200320044b72450440200541086a2003200420011044200528020c2107200528020821060b2000200736020420002006360200200541106a24000b4e01027f230041106b22052400200541086a200120022003106c20052802082206450440200220034100200120041071000b200528020c21012000200636020020002001360204200541106a24000b6400024002402001450d00200120034f044020012003460d010c020b200120026a2c00004140480d010b2003200320016b22044904404180a604412141b4ba041043000b200020043602042000200120026a3602000f0b200220032001200320041071000b940101027f20002d00082101200028020422020440200141ff017121012000027f410120010d001a024020024101470d0020002d0009450d00200028020022022d00004104710d0041012002280218419fad0441012002411c6a28020028020c1101000d011a0b2000280200220128021841a0ad0441012001411c6a28020028020c1101000b22013a00080b200141ff01714100470ba50401077f230041106b22072400418080c4002109024020002802002205410171450440200421060c010b2004200441016a22064d0440412b21090c010b41b0a604411c419cb1041043000b0240024002400240200541047145044041002101200621050c010b2001200120026a105420066a22052006490d010b4101210620002802084101470440200020092001200210690d032000280218200320042000411c6a28020028020c11010021060c030b024002402000410c6a280200220820054b044020002d00004108710d01200820056b220520084b0d022007200020054101106a20072802002205418080c400460d0520072802042108200020092001200210690d052000280218200320042000411c6a28020028020c1101000d05200520082000280218200028021c106821060c050b200020092001200210690d042000280218200320042000411c6a28020028020c11010021060c040b2000280204210a2000413036020420002d0020210b200041013a0020200020092001200210690d03200820056b220120084b0d02200741086a200020014101106a20072802082201418080c400460d03200728020c21022000280218200320042000411c6a28020028020c1101000d03200120022000280218200028021c10680d032000200b3a00202000200a360204410021060c030b4180a604412141ccb1041043000b41b0a604411c41acb1041043000b4180a604412141bcb1041043000b200741106a240020060b3401017f230041106b220224002002410036020c200220012002410c6a1051200020022802002002280204105a200241106a24000b5501017f230041206b2202240020022000360204200241186a200141106a290200370300200241106a200141086a29020037030020022001290200370308200241046a41f8af04200241086a1062200241206a24000bfc0301057f230041406a22032400200341346a2001360200200341033a00382003428080808080043703182003200036023041002101200341003602282003410036022002400240024020022802082200450440200241146a28020041ffffffff0171220641016a210520022802102104410021000340200541016b2205450d02200228020020006a220141046a28020022070440200328023020012802002007200328023428020c1101000d040b200020046a2101200041086a21002001280200200341186a200141046a280200110000450d000b0c020b2002410c6a28020022064105742105200641ffffff3f71210603402005450d01200228020020016a220441046a28020022070440200328023020042802002007200328023428020c1101000d030b200320002d001c3a003820032000290204422089370318200341106a20022802102204200041146a106720032003290310370320200341086a20042000410c6a106720032003290308370328200141086a2101200541206b210520002802002107200041206a2100200420074103746a2204280200200341186a2004280204110000450d000b0c010b4100210020062002280204492201450d012003280230200228020020064103746a410020011b22012802002001280204200328023428020c110100450d010b410121000b200341406b240020000b0d00200028020020012002105a0b0b002000280200200110600b4a01017f230041206b220224002000280200200241186a200141106a290200370300200241106a200141086a29020037030020022001290200370308200241086a1061200241206a24000b10002000410c360204200020013602000b5501027f0240027f02400240200228020041016b0e020103000b200241046a0c010b200120022802044103746a2201280204411f470d0120012802000b2802002104410121030b20002004360204200020033602000b2c01027f0340200422052001470440200541016a2104200220002003280210110000450d010b0b200120054b0b4b000240027f2001418080c4004704404101200028021820012000411c6a2802002802101100000d011a0b20020d0141000b0f0b2000280218200220032000411c6a28020028020c1101000bb20101027f20022105024002400240200320012d0020220320034103461b41ff017141016b0e03010001020b2002200241016a22034d044020034101762105200241017621040c020b41b0a604411c41dcb1041043000b41002105200221040b200441016a21022001411c6a2802002103200128020421042001280218210102400340200241016b2202450d01200120042003280210110000450d000b418080c40021040b20002005360204200020043602000b880101047f200141086a28020021022001280204210402400240200141046a10532205418080c400470440200220046b2203200128020420012802086b6a220220034b0d012001280200220320026a22022003490d02200120023602000b20002005360204200020033602000f0b4180a60441214194b9041043000b41b0a604411c41a4b9041043000b3f01017f024002402001450d00200120034f044020012003460d010c020b200120026a2c00004140480d010b200221040b20002001360204200020043602000b340020002001280218200220032001411c6a28020028020c1101003a00082000200136020020002003453a0009200041003602040b930a020a7f017e230041206b220524004101210802402001280218220941272001411c6a280200280210220a1100000d0041f400210141022106024002400240024002402000280200220041096b0e050402030301000b20004122460d024127210120004127460d0341dc002101200041dc00460d030c020b41f20021010c020b41ee0021010c010b41012106027e0240027f2000410b742104411f2101411f210202400240024002400240024002400240024002400340200120034d0d02200320024101766a22022003490d030240200420024102744194d0046a280200410b7422074d044020042007460d03200221010c010b200241016a22032002490d050b200120036b220220014d0d000b4180a604412141a0b7041043000b200241016a21030b2003411e4b0d02200341027422024194d0046a280200411576210102402003411e47044020024198d0046a280200411576220420016b220220044d0d014180a604412141accc041043000b41b10520016b220241b2054f0d040b20002003200341016b22044f047f2004411f4f0d0520044102744194d0046a28020041ffffff00710541000b6b220720004b0d05200241016b220320024b0d06200141b105200141b1054b1b2104200120026a41016b210b410021020340024002402003047f20012004460d0b2002200220014190d1046a2d00006a22024b0d01200220074d0d02200105200b0b4101710c0b0b41b0a604411c41eccc041043000b200341016b2103200141016a21010c000b000b41b0a604411c4180b7041043000b41b0a604411c4190b7041043000b2003411f418ccc041045000b4180a6044121419ccc041043000b2004411f41fccc041045000b4180a604412141bccc041043000b4180a604412141cccc041043000b200441b10541dccc041045000b450440027f2000418080044f0440200041decd0a6b41214b200041b5ee0a6b410a4b71200041feffff0071419ef00a4771200041a29d0b6b410d4b71200041e1d70b6b419e184b712000419ef40b6b41e10b4b71200041cba60c6b41b4db2b4b71200041f0833849712000418080084f0d011a200041e5c504412641b1c60441af0141e0c70441a30310720c010b200041bcc0044129418ec10441a20241b0c30441b50210720b450d01200021010c030b200041017267410276410773ad4280808080d000840c010b200041017267410276410773ad4280808080d000840b210c41032106200021010b2005200136020420052006360200200541086a200c370200200541186a200541086a290300370300200520052903003703100340027f418080c40021010240024002400240200541106a220028020041016b0e03000102030b2000410036020020002802040c030b2000410136020041dc000c020b027f024002400240024002400240200041046a22002d000841016b0e050005010203040b200041003a000841fd000c050b200041023a000841fb000c040b200041033a000841f5000c030b200041043a000841dc0021010b20010c010b02402000280204220141ffffffff037120014604402001410274220241204f0d0120002802002002411c7176410f712202413072200241d7006a2002410a491b41dca904105221022001450440200041013a000820020c030b2000200141016b36020420020c020b41d0a604412141bca9041043000b4180a704412441cca9041043000b21010b20010b2200418080c40046044020094127200a11000021080c020b20092000200a110000450d000b0b200541206a240020080b6b01017f230041306b2203240020032001360204200320003602002003411c6a41023602002003412c6a41193602002003420237020c200341d4b404360208200341193602242003200341206a3602182003200341046a36022820032003360220200341086a20021048000b0b002000310000200110730ba70601027f23004180016b220524002005200336021c200520023602182005027f024020014181024f0440418002210603402006450d02200020066a2c000041bf7f4a0d02200641016b21060c000b000b2005200136022420052000360220200541a4a70436022841000c010b200541106a20062000200141c8bb04105c2005200529031037032020054198bd0436022841050b36022c024002402005200120024f047f200120034f0d0120030520020b360238200541d4006a4103360200200541ec006a410c360200200541e4006a410c36020020054203370244200541c0bd043602402005411936025c2005200541d8006a3602502005200541286a3602682005200541206a3602602005200541386a3602580c010b200220034d0440024002402002450d00200120024d044020012002460d010c020b200020026a2c00004140480d010b200321020b2005200236023003400240024002402002450440410021020c010b200120024d044020012002470d02200121020c010b200020026a2c00004140480d010b200541086a2002200020012004105d20052005280208220036025820052000200528020c6a36025c2005200541d8006a1053200410522201360234027f41012001418001490d001a41022001418010490d001a41034104200141808004491b0b20026a220020024f0d0141b0a604411c20041043000b200241016b21020c010b0b2005200036023c20052002360238200541d4006a4105360200200541fc006a410c360200200541f4006a410c360200200541ec006a4120360200200541e4006a412136020020054205370244200541d0be043602402005411936025c2005200541d8006a3602502005200541286a3602782005200541206a3602702005200541386a3602682005200541346a3602602005200541306a3602580c010b200541f4006a410c360200200541ec006a410c360200200541e4006a4119360200200541d4006a410436020020054204370244200541fcbd043602402005411936025c2005200541d8006a3602502005200541286a3602702005200541206a36026820052005411c6a3602602005200541186a3602580b200541406b20041048000bfa0201067f230041106b22072400200120024101746a210c20004180fe0371410876210a410021020240024002400240034002402001200c470440200220012d00016a22082002490d04200141026a210b20012d00002209200a460d01200b2101200821022009200a4d0d020b200520066a2104200041ffff0371210241012103034020042005460d03200541016a210020052d000022014118744118752206410048044020002004460d0620052d0001200641ff0071410874722101200541026a21000b200141004a2002200220016b22024a730d0620024100480d0320034101732103200021050c000b000b200741086a2002200820032004418cc004104d20072802082102200728020c210103402001450440200b2101200821020c020b200141016b210120022d0000200241016a2102200041ff0171470d000b0b410021030b200741106a240020034101710f0b41b0a604411c41fcbf041043000b41eca904412b419cc0041043000b4180a604412141acc0041043000bf80201057f230041306b220424004127210202400240024003402000428fce005804402000a7220341e3004a0d020c030b2002200241046b22024c0d03200441096a20026a200020004290ce008022004290ce007e7da7220341ffff037141e4006e220541017441aeae046a2f00003b00002002200241026a22064c0440200441096a20066a2003200541e4006c6b41ffff037141017441aeae046a2f00003b00000c010b0b41b0a604411c41f0ce041043000b2002200241026b22024c0d01200441096a20026a2000a72203200341ffff037141e4006e220341e4006c6b41ffff037141017441aeae046a2f00003b00000b02402003410a4e04402002200241026b22024c0d02200441096a20026a200341017441aeae046a2f00003b00000c010b2002200241016b22024c0d01200441096a20026a200341306a3a00000b412720026b220341274b04400c010b200141a4a7044100200441096a20026a2003105f200441306a24000f0b4180a604412141f0ce041043000b4900230041106b22002400200020012802184180cf0441052001411c6a28020028020c1101003a000820002001360200200041003a0009200041003602042000105e200041106a24000b4900230041106b220024002000200128021841c1d604410b2001411c6a28020028020c1101003a000820002001360200200041003a0009200041003602042000105e200041106a24000b2b01017f03402002200346450440200020036a200120036a2d00003a0000200341016a21030c010b0b20000b0ba6560900418080040bc10f4e6f7420656e6f756768206461746120746f206465636f646520766563746f722f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f727370726f78792e636e2d386636383237633735353562666166382f7061726974792d7363616c652d636f6465632d322e332e312f7372632f636f6465632e727320000100600000004503000022000000617474656d707420746f206164642077697468206f766572666c6f7720000100600000004e0300001d000000040000000100000001000000050000000600000001000000010000000700000063616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c7565000800000001000000010000000900000001000000000000007061696420616e20756e70617961626c65206d6573736167650000002001010019000000636f756c64206e6f74207265616420696e70757420706172616d657465727300440101001f000000756e61626c6520746f206465636f64656420696e70757420706172616d6574657220627974657320666f72206d657373616765006c01010033000000756e61626c6520746f206465636f64656420696e70757420706172616d6574657220627974657320666f7220636f6e7374727563746f7200a801010037000000756e61626c6520746f206465636f64656420696e70757420706172616d6574657220627974657300e801010027000000756e6b6e6f776e206d6573736167652073656c6563746f721802010018000000756e6b6e6f776e20636f6e7374727563746f722073656c6563746f72380201001c000000756e6b6e6f776e2073656c6563746f725c020100100000005765206465636f646520604e6020656c656d656e74733b20716564002000010060000000cd02000017000000756e65787065637465642066697273742062797465206465636f64696e67204f7074696f6e436f756c64206e6f74206465636f646520604f7074696f6e3a3a536f6d6528542960436f756c64206e6f74206465636f64652076617269616e74206279746520666f7220604f7074696f6e602f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f727370726f78792e636e2d386636383237633735353562666166382f61727261797665632d302e372e312f7372632f61727261797665635f696d706c2e727300110301005e0000003900000016000000110301005e0000002700000020000000656e636f756e7465726564206572726f72207768696c65207175657279696e67207472616e736665727265642062616c616e63652f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f727370726f78792e636e2d386636383237633735353562666166382f696e6b5f6c616e672d332e302e302d7263362f7372632f646973706174636865722e727300c40301005f000000910000000a0000006469737061746368696e6720636f6e7374727563746f72206661696c65643a2034040100200000002f686f6d652f6b76696e2f636f6465732f636861696e2f7068616c612f696e6b2f6d7170726f78792f6c69622e7273005c0401002f000000050000000100000063616c6c6572207472616e736665727265642076616c7565206576656e2074686f75676820616c6c20696e6b21206d6573736167652064656e79207061796d656e74736469737061746368696e67206d657373616765206661696c65643a2000df0401001c000000656e636f756e746572656420756e6b6e6f776e20696e6b21206d6573736167652073656c6563746f72656e636f756e746572656420756e6b6e6f776e20696e6b2120636f6e7374727563746f722073656c6563746f722f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f696e6465782e72730000000000000000617474656d707420746f2073756274726163742077697468206f766572666c6f770000005a0501007e000000e70000004f0000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f727370726f78792e636e2d386636383237633735353562666166382f696e6b5f656e762d332e302e302d7263362f7372632f656e67696e652f6f6e5f636861696e2f696d706c732e727300000014060100690000009d0000000d0000001406010069000000a20000000d0000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f727370726f78792e636e2d386636383237633735353562666166382f7061726974792d7363616c652d636f6465632d322e332e312f7372632f636f6465632e72730a00000000000000010000000b000000436f6d7061637420656e636f646573206c656e6774680000a00601006000000011030000310000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f727370726f78792e636e2d386636383237633735353562666166382f696e6b5f656e762d332e302e302d7263362f7372632f656e67696e652f6f6e5f636861696e2f6275666665722e72730000380701006a000000b500000037000000380701006a000000b8000000090041d08f040bf301617474656d707420746f206164642077697468206f766572666c6f777068616c612e6d712e6d657373616765ec070100100000007068616c612e6d712e6f73705f6d657373616765040801001400000050616964556e70617961626c654d657373616765436f756c644e6f7452656164496e707574496e76616c696443616c6c506172616d6574657273496e76616c6964496e7374616e7469617465506172616d6574657273496e76616c6964506172616d6574657273556e6b6e6f776e43616c6c53656c6563746f72556e6b6e6f776e496e7374616e746961746553656c6563746f72556e6b6e6f776e53656c6563746f720041d091040be104617474656d707420746f206164642077697468206f766572666c6f772f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f727370726f78792e636e2d386636383237633735353562666166382f7061726974792d7363616c652d636f6465632d322e332e312f7372632f636f6465632e727363616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c7565000d0000000100000001000000090000005765206465636f646520604e6020656c656d656e74733b2071656400ec08010060000000cd0200001700000043617061636974794572726f72000000b40901000d000000696e73756666696369656e74206361706163697479000000cc090100150000003a2000008809010000000000ec090100020000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f727370726f78792e636e2d386636383237633735353562666166382f61727261797665632d302e372e312f7372632f61727261797665635f696d706c2e72730000000a01005e0000003900000016000000000a01005e00000027000000200000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f696e6465782e72730000800a01007e000000e70000004f000000617474656d707420746f2073756274726163742077697468206f766572666c6f770041c096040bb70b617474656d707420746f206164642077697468206f766572666c6f77617373657274696f6e206661696c65643a206d6964203c3d2073656c662e6c656e28292f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f6d6f642e7273007f0b01007c000000fe050000090000000a0000000c0c0100000000000c0c0100010000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f727370726f78792e636e2d386636383237633735353562666166382f696e6b5f656e762d332e302e302d7263362f7372632f656e67696e652f6f6e5f636861696e2f6275666665722e72730000200c01006a000000580000001c000000200c01006a0000005800000009000000200c01006a0000006300000009000000200c01006a000000810000001a0000002f686f6d652f6b76696e2f2e636172676f2f72656769737472792f7372632f727370726f78792e636e2d386636383237633735353562666166382f696e6b5f656e762d332e302e302d7263362f7372632f656e67696e652f6f6e5f636861696e2f6578742e727300cc0c010067000000790100001400000045636473615265636f7665724661696c65644c6f6767696e6744697361626c6564556e6b6e6f776e4e6f7443616c6c61626c65436f64654e6f74466f756e644e6577436f6e74726163744e6f7446756e6465645472616e736665724661696c656442656c6f7753756273697374656e63655468726573686f6c644b65794e6f74466f756e6443616c6c6565526576657274656443616c6c6565547261707065644465636f646500000f0000000400000004000000100000000d0000000100000002000000030000000400000005000000060000000700000008000000090000000c0000000b0000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f696e6465782e727300002c0e01007e000000e00000004c00000000000000617474656d707420746f2073756274726163742077697468206f766572666c6f774572726f720000110000000400000004000000120000001300000014000000617474656d707420746f206164642077697468206f766572666c6f77150000000000000001000000160000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f697465722f7472616974732f616363756d2e72732c0f0100840000008d000000010000006120666f726d617474696e6720747261697420696d706c656d656e746174696f6e2072657475726e656420616e206572726f722f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f666d742e72730000f30f010077000000470200001c0000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7261775f7665632e7273004180a2040b8103617474656d707420746f206d756c7469706c792077697468206f766572666c6f770000007c1001007b000000b50100001c0000006361706163697479206f766572666c6f770000007c1001007b0000002f020000050000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7665632f6d6f642e727300581101007b0000008e0600000d000000581101007b000000ca060000090000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f616c6c6f632f6c61796f75742e727300f41101007f0000000e01000018004190a5040b65617474656d707420746f206164642077697468206f766572666c6f77f41101007f000000100100003900000063616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c75650017000000000000000100000018004180a6040b21617474656d707420746f2073756274726163742077697468206f766572666c6f770041b0a6040b41617474656d707420746f206164642077697468206f766572666c6f7700000000617474656d707420746f206d756c7469706c792077697468206f766572666c6f77004180a7040bcc2f617474656d707420746f2073686966742072696768742077697468206f766572666c6f772e2e0000a4130100020000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f636861722f6d6574686f64732e727300b01301007f0000006c0600000a0000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f636861722f6d6f642e727300401401007b000000a200000035000000401401007b000000a200000021000000401401007b000000a30000003300000063616c6c656420604f7074696f6e3a3a756e77726170282960206f6e206120604e6f6e65602076616c75653aa413010000000000171501000100000017150100010000002200000000000000010000002300000070616e69636b65642061742027272c204c150100010000004d15010003000000696e646578206f7574206f6620626f756e64733a20746865206c656e20697320206275742074686520696e64657820697320000060150100200000008015010012000000603a2000a413010000000000a515010002000000240000000c00000004000000250000002600000027000000202020202f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f666d742f6275696c646572732e727300d41501007f0000002800000015000000d41501007f0000002f00000021000000d41501007f00000030000000120000002c0a2c207d207d00d41501007f0000005001000009000000280a282c292f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f666d742f6e756d2e727300a11601007a0000006500000014000000307830303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839390000280000000400000004000000290000002a0000002b0000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f666d742f6d6f642e72730000101801007a000000040500000d000000101801007a000000070500000d000000101801007a0000000b0500000d000000101801007a0000002e05000031000000101801007a0000003705000031000000101801007a0000009b050000380000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f6d656d6368722e727300ec1801007f000000410000001e000000ec1801007f0000004800000015000000ec1801007f0000004d0000001f000000ec1801007f0000005600000009000000ec1801007f0000005a00000005000000ec1801007f0000005a0000003d00000072616e676520737461727420696e64657820206f7574206f662072616e676520666f7220736c696365206f66206c656e67746820cc19010012000000de1901002200000072616e676520656e6420696e64657820101a010010000000de19010022000000736c69636520696e64657820737461727473206174202062757420656e64732061742000301a010016000000461a01000d0000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f696e6465782e72730000641a01007e000000e00000004c000000641a01007e000000e70000004f0000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f6d6f642e7273041b01007c0000009408000017000000041b01007c0000009f08000018000000041b01007c000000a808000014000000041b01007c000000ef0b00000d000000736f7572636520736c696365206c656e67746820282920646f6573206e6f74206d617463682064657374696e6174696f6e20736c696365206c656e6774682028c01b010015000000d51b01002b000000a0160100010000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f697465722e727300181c01007b0000009100000026000000181c01007b00000091000000110000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f7472616974732e7273000000b41c01007d0000005d010000130000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f76616c69646174696f6e732e72730000441d01008200000011010000110000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f7061747465726e2e72730000d81d01007e0000009901000047000000d81d01007e000000ac01000020000000d81d01007e000000ac01000011000000d81d01007e000000b0010000260000005b2e2e2e5d6279746520696e64657820206973206f7574206f6620626f756e6473206f66206000009d1e01000b000000a81e010016000000a415010001000000626567696e203c3d20656e642028203c3d2029207768656e20736c6963696e6720600000d81e01000e000000e61e010004000000ea1e010010000000a415010001000000206973206e6f742061206368617220626f756e646172793b20697420697320696e7369646520202862797465732029206f6620609d1e01000b0000001c1f010026000000421f0100080000004a1f010006000000a4150100010000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f756e69636f64652f7072696e7461626c652e7273781f0100840000000800000018000000781f0100840000000a0000001c000000781f0100840000001a00000036000000781f0100840000001e0000000900000000010305050606030706080809110a1c0b190c140d100e0d0f0410031212130916011705180219031a071c021d011f1620032b032c022d0b2e01300331023201a702a902aa04ab08fa02fb05fd04fe03ff09ad78798b8da23057588b8c901c1ddd0e0f4b4cfbfc2e2f3f5c5d5fb5e2848d8e9192a9b1babbc5c6c9cadee4e5ff00041112293134373a3b3d494a5d848e92a9b1b4babbc6cacecfe4e500040d0e11122931343a3b4546494a5e646584919b9dc9cecf0d112945495764658d91a9b4babbc5c9dfe4e5f00d11454964658084b2bcbebfd5d7f0f183858ba4a6bebfc5c7cecfdadb4898bdcdc6cecf494e4f57595e5f898e8fb1b6b7bfc1c6c7d71116175b5cf6f7feff800d6d71dedf0e0f1f6e6f1c1d5f7d7eaeafbbbcfa16171e1f46474e4f585a5c5e7e7fb5c5d4d5dcf0f1f572738f7475962f5f262e2fa7afb7bfc7cfd7df9a409798308f1fc0c1ceff4e4f5a5b07080f10272feeef6e6f373d3f42459091feff536775c8c9d0d1d8d9e7feff00205f2282df048244081b04061181ac0e80ab35280b80e003190801042f043404070301070607110a500f1207550703041c0a090308030703020303030c0405030b06010e15053a0311070605100757070207150d500443032d03010411060f0c3a041d255f206d046a2580c80582b0031a0682fd035907150b1709140c140c6a060a061a0659072b05460a2c040c040103310b2c041a060b0380ac060a06213f4c042d0374083c030f033c0738082b0582ff1118082f112d032010210f808c048297190b158894052f053b07020e180980b32d740c80d61a0c0580ff0580df0cee0d03848d033709815c1480b80880cb2a38030a06380846080c06740b1e035a0459098083181c0a16094c04808a06aba40c170431a10481da26070c050580a511816d1078282a064c04808d0480be031b030f0d0006010103010402080809020a050b020e041001110212051311140115021702190d1c051d0824016a036b02bc02d102d40cd509d602d702da01e005e102e802ee20f004f802f902fa02fb010c273b3e4e4f8f9e9e9f060709363d3e56f3d0d1041418363756577faaaeafbd35e01287898e9e040d0e11122931343a4546494a4e4f64655cb6b71b1c07080a0b141736393aa8a9d8d909379091a8070a3b3e66698f926f5feeef5a629a9b2728559da0a1a3a4a7a8adbabcc4060b0c151d3a3f4551a6a7cccda007191a22253e3fc5c604202325262833383a484a4c50535556585a5c5e606365666b73787d7f8aa4aaafb0c0d0aeaf79cc6e6f935e227b0503042d036603012f2e80821d03310f1c0424091e052b0544040e2a80aa06240424042808340b018090813709160a088098390363080930160521031b05014038044b052f040a070907402027040c0936033a051a07040c07504937330d33072e080a8126524e28082a561c1417094e041e0f430e19070a0648082709750b3f412a063b050a0651060105100305808b621e48080a80a65e22450b0a060d1339070a362c041080c03c64530c48090a46451b4808531d398107460a1d03474937030e080a0639070a81361980b7010f320d839b66750b80c48abc842f8fd18247a1b98239072a040260260a460a28051382b05b654b0439071140050b020e97f80884d62a09a2f7811f3103110408818c89046b050d03090710936080f60a73086e1746809a140c570919808781470385420f1585502b80d52d031a040281703a0501850080d7294c040a04028311444c3d80c23c06010455051b3402810e2c04640c560a80ae381d0d2c040907020e06809a83d8080d030d03740c59070c140c0438080a062808224e81540c15030305070919070709030d072980cb250a84062f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f756e69636f64652f756e69636f64655f646174612e7273000083250100870000004b0000002800000083250100870000004f0000000900000083250100870000004d00000009000000832501008700000054000000110000008325010087000000560000001100000083250100870000005700000016000000832501008700000058000000090000008325010087000000520000003e0000002f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f697465722f7472616974732f616363756d2e72738c260100840000008d000000010000006e756d626572206e6f7420696e207468652072616e676520302e2e3d202701001c000000a5150100020000000f000000a11601007a0000009300000001000000a11601007a0000009400000001000000a11601007a000000ce010000050000004572726f722f686f6d652f6b76696e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032312d30392d31332d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f697465722e72730000852701007d00000085000000010000000003000083042000910560005d13a0001217a01e0c20e01eef2c202b2a30a02b6fa6602c02a8e02c1efbe02d00fea0359effe035fd016136010aa136240d6137ab0ee1382f182139301c6146f31ea14af06a614e4f6fa14e9dbc214f65d1e14f00da215000e0e15130e16153ece2a154d0e8e15420002e55f001bf5500700007002d0101010201020101480b30151001650702060202010423011e1b5b0b3a09090118040109010301052b03770f0120370101010408040103070a021d013a0101010204080109010a021a010202390104020402020303011e0203010b0239010405010204011402160601013a0101020104080107030a021e013b0101010c0109012801030139030503010407020b021d013a01020102010301050207020b021c02390201010204080109010a021d0148010401020301010801510102070c08620102090b064a021b0101010101370e01050102050b0124090166040106010202021902040310040d01020206010f01000300031d031d021e02400201070801020b09012d03770222017603040209010603db0202013a010107010101010208060a020130113f0430070101050128090c0220040202010338010102030101033a0802029803010d0107040106010302c63a01050001c32100038d016020000669020004010a200250020001030104011902050197021a120d012608190b2e0330010204020227014306020202020c0108012f01330101030202050201012a020801ee010201040100010010101000020001e201950500030102050428030401a50200040002990bb001360f3803310402024503240501083e010c0234090a0402015f03020101020601a0010308150239020101010116010e070305c308020301011701510102060101020101020102eb010204060201021b025508020101026a0101010206010165030204010500090102f5010a0201010401900402020401200a280602040801090602032e0d010200070106010152160207010201027a060301010201070101480203010101000200053b0700013f0451010002000101030405080802071e0494030037043208010e011605010f000701110207010201050007000400076d07006080f0004c61796f75744572726f72"},"contract":{"name":"mqproxy","version":"0.1.0","authors":["Kevin Wang "]},"spec":{"constructors":[{"args":[],"docs":[],"name":["default"],"selector":"0xed4b9d1b"}],"docs":[],"events":[],"messages":[{"args":[{"name":"message","type":{"displayName":["Vec"],"type":0}},{"name":"topic","type":{"displayName":["Vec"],"type":0}}],"docs":[],"mutates":false,"name":["push_message"],"payable":false,"returnType":null,"selector":"0x6495da7f"},{"args":[{"name":"message","type":{"displayName":["Vec"],"type":0}},{"name":"topic","type":{"displayName":["Vec"],"type":0}},{"name":"remote_pubkey","type":{"displayName":["Option"],"type":2}}],"docs":[],"mutates":false,"name":["push_osp_message"],"payable":false,"returnType":null,"selector":"0xd09d68e0"}]},"storage":{"struct":{"fields":[]}},"types":[{"id":0,"type":{"def":{"sequence":{"type":1}}}},{"id":1,"type":{"def":{"primitive":"u8"}}},{"id":2,"type":{"def":{"variant":{"variants":[{"index":0,"name":"None"},{"fields":[{"type":3}],"index":1,"name":"Some"}]}},"params":[{"name":"T","type":3}],"path":["Option"]}},{"id":3,"type":{"def":{"array":{"len":32,"type":1}}}}]} \ No newline at end of file diff --git a/crates/pink/tests/fixtures/mqproxy/mqproxy.wasm b/crates/pink/tests/fixtures/mqproxy/mqproxy.wasm new file mode 100644 index 0000000000..103368ebea Binary files /dev/null and b/crates/pink/tests/fixtures/mqproxy/mqproxy.wasm differ diff --git a/crates/pink/tests/snapshots/test_pink_contract__mq_egress-2.snap b/crates/pink/tests/snapshots/test_pink_contract__mq_egress-2.snap new file mode 100644 index 0000000000..e3110e8acb --- /dev/null +++ b/crates/pink/tests/snapshots/test_pink_contract__mq_egress-2.snap @@ -0,0 +1,25 @@ +--- +source: crates/pink/tests/test_pink_contract.rs +expression: effects + +--- +ExecSideEffects { + messages: [ + ( + d7b800810f95b0fa550332988b032812f6708a632b30735abcb9467e8d262f70 (5GwYp55a...), + Message( + Message { + payload: [ + 66, + 66, + ], + topic: [ + 36, + 36, + ], + }, + ), + ), + ], + instantiated: [], +} diff --git a/crates/pink/tests/snapshots/test_pink_contract__mq_egress-3.snap b/crates/pink/tests/snapshots/test_pink_contract__mq_egress-3.snap new file mode 100644 index 0000000000..3ca3626a19 --- /dev/null +++ b/crates/pink/tests/snapshots/test_pink_contract__mq_egress-3.snap @@ -0,0 +1,63 @@ +--- +source: crates/pink/tests/test_pink_contract.rs +expression: effects + +--- +ExecSideEffects { + messages: [ + ( + d7b800810f95b0fa550332988b032812f6708a632b30735abcb9467e8d262f70 (5GwYp55a...), + OspMessage( + OspMessage { + message: Message { + payload: [ + 66, + 66, + ], + topic: [ + 36, + 36, + ], + }, + remote_pubkey: Some( + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + ), + }, + ), + ), + ], + instantiated: [], +} diff --git a/crates/pink/tests/snapshots/test_pink_contract__mq_egress.snap b/crates/pink/tests/snapshots/test_pink_contract__mq_egress.snap new file mode 100644 index 0000000000..6f8f699701 --- /dev/null +++ b/crates/pink/tests/snapshots/test_pink_contract__mq_egress.snap @@ -0,0 +1,14 @@ +--- +source: crates/pink/tests/test_pink_contract.rs +expression: effects + +--- +ExecSideEffects { + messages: [], + instantiated: [ + ( + 0101010101010101010101010101010101010101010101010101010101010101 (5C62Ck4U...), + d7b800810f95b0fa550332988b032812f6708a632b30735abcb9467e8d262f70 (5GwYp55a...), + ), + ], +} diff --git a/crates/pink/tests/test_pink_contract.rs b/crates/pink/tests/test_pink_contract.rs index d58d55a6d7..36c74223a0 100644 --- a/crates/pink/tests/test_pink_contract.rs +++ b/crates/pink/tests/test_pink_contract.rs @@ -15,8 +15,10 @@ fn test_ink_flip() { hex!("9bae9d5e"), // init_value true, vec![], + 0, + 0, ) - .unwrap(); + .unwrap().0; let result: bool = contract .call_with_selector( @@ -25,8 +27,11 @@ fn test_ink_flip() { hex!("2f865bd9"), // get (), false, + 0, + 0, ) - .unwrap(); + .unwrap() + .0; assert_eq!(result, true); // Should equal to the init value @@ -37,8 +42,11 @@ fn test_ink_flip() { hex!("633aa551"), // flip (), false, + 0, + 0, ) - .unwrap(); + .unwrap() + .0; let result: bool = contract .call_with_selector( @@ -47,8 +55,11 @@ fn test_ink_flip() { hex!("2f865bd9"), // get (), false, + 0, + 0, ) - .unwrap(); + .unwrap() + .0; assert_eq!(result, false); // Should be flipped @@ -59,8 +70,11 @@ fn test_ink_flip() { hex!("f7dff04c"), // echo (42u32, 24u128), false, + 0, + 0, ) - .unwrap(); + .unwrap() + .0; assert_eq!(result, (42, 24)); } @@ -81,6 +95,8 @@ fn test_ink_cross_contract_instanciate() { hex!("9bae9d5e"), // init_value true, vec![], + 0, + 0, ) .unwrap(); @@ -91,8 +107,10 @@ fn test_ink_cross_contract_instanciate() { hex!("9bae9d5e"), (), vec![], + 0, + 0, ) - .unwrap(); + .unwrap().0; let result: bool = contract .call_with_selector( @@ -101,8 +119,55 @@ fn test_ink_cross_contract_instanciate() { hex!("c3220014"), // get (), false, + 0, + 0, ) - .unwrap(); + .unwrap() + .0; insta::assert_debug_snapshot!(result); } + +#[test] +fn test_mq_egress() { + let mut storage = Contract::new_storage(); + let (mut contract, effects) = Contract::new_with_selector( + &mut storage, + ALICE.clone(), + include_bytes!("./fixtures/mqproxy/mqproxy.wasm").to_vec(), + hex!("ed4b9d1b"), // init_value + (), + vec![], + 1, + 0, + ) + .unwrap(); + + insta::assert_debug_snapshot!(effects); + + let (_, effects): ((), _) = contract + .call_with_selector( + &mut storage, + ALICE.clone(), + hex!("6495da7f"), // push_message + (b"\x42\x42".to_vec(), b"\x24\x24".to_vec()), + false, + 1, + 0, + ) + .unwrap(); + insta::assert_debug_snapshot!(effects); + + let (_, effects): ((), _) = contract + .call_with_selector( + &mut storage, + ALICE.clone(), + hex!("d09d68e0"), // push_osp_message + (b"\x42\x42".to_vec(), b"\x24\x24".to_vec(), Some([0u8; 32])), + false, + 1, + 0, + ) + .unwrap(); + insta::assert_debug_snapshot!(effects); +} diff --git a/pallets/phala/src/registry.rs b/pallets/phala/src/registry.rs index c8c0ba5d5f..748f83e92e 100644 --- a/pallets/phala/src/registry.rs +++ b/pallets/phala/src/registry.rs @@ -511,16 +511,21 @@ pub mod pallet { Ok(()) } - pub fn on_pink_message_received(message: DecodedMessage) -> DispatchResult { + pub fn on_pink_message_received( + message: DecodedMessage, + ) -> DispatchResult { match &message.sender { MessageOrigin::Worker(_) => (), _ => return Err(Error::::InvalidSender.into()), } match message.payload { - WorkerPinkReport::InstantiateStatus { nonce: _, owner: _, result } => { - if let Ok(info) = result { - ContractKey::::insert(info.id, info.pubkey); - } + WorkerPinkReport::PinkInstantiated { + id, + group_id: _, + owner: _, + pubkey, + } => { + ContractKey::::insert(id, pubkey); } } Ok(()) diff --git a/scripts/debug-cli/src/main.rs b/scripts/debug-cli/src/main.rs index 8816420a62..cf5a3e8415 100644 --- a/scripts/debug-cli/src/main.rs +++ b/scripts/debug-cli/src/main.rs @@ -85,6 +85,10 @@ enum PinkCommand { id: String, message: String, }, + Command { + id: String, + message: String, + }, Deploy { #[structopt(long)] group: Option, @@ -234,6 +238,11 @@ async fn handle_pink_command(command: PinkCommand) { InkMessage(Vec), } + #[derive(Debug, Encode, Decode)] + pub enum Command { + InkMessage { nonce: Vec, message: Vec }, + } + #[derive(Debug, Encode, Decode)] pub enum Response { InkMessageReturn(Vec), @@ -268,6 +277,22 @@ async fn handle_pink_command(command: PinkCommand) { } } } + PinkCommand::Command { id, message } => { + #[derive(Encode)] + enum Payload { + Plain(T) + } + + let id = decode_hex(&id); + let id = ContractId::decode(&mut &id[..]).expect("Bad contract id"); + let message = decode_hex(&message); + let nonce = vec![]; + let command = Command::InkMessage{ nonce, message }; + let mq_payload = Payload::Plain(command); + println!("topic: (0x{})", hex::encode(phala_types::contract::command_topic(id))); + println!("command: (0x{})", hex::encode(mq_payload.encode())); + + } PinkCommand::Deploy { group, worker, wasm_file, input } => { let group_id = group.map(|x| { H256(decode_hex(&x).try_into().expect("Bad group")) @@ -281,7 +306,7 @@ async fn handle_pink_command(command: PinkCommand) { wasm_bin, input_data, }; - println!("{}", hex::encode(request.encode())); + println!("0x{}", hex::encode(request.encode())); } } } diff --git a/standalone/pruntime/enclave/src/libc_hacks.rs b/standalone/pruntime/enclave/src/libc_hacks.rs index 1d38fde02b..deffe11f4e 100644 --- a/standalone/pruntime/enclave/src/libc_hacks.rs +++ b/standalone/pruntime/enclave/src/libc_hacks.rs @@ -67,6 +67,10 @@ pub extern "C" fn posix_memalign(memptr: *mut *mut c_void, align: size_t, size: if ptr.is_null() && size > 0 { libc::ENOMEM } else { + unsafe { + // Initialize the alloced memory to avoid non-deterministic behaivor as much as possible. + sgx_libc::memset(ptr, 0, size); + } *memptr = ptr; 0 } @@ -364,7 +368,14 @@ pub extern "C" fn mmap( lazy_static::lazy_static! { static ref PAGE_SIZE: size_t = unsafe { ocall::sysconf(libc::_SC_PAGESIZE) } as _; } - return unsafe { sgx_libc::memalign(*PAGE_SIZE, len) }; + let addr = unsafe { sgx_libc::memalign(*PAGE_SIZE, len) }; + if !addr.is_null() { + unsafe { + // Initialize the alloced memory to avoid non-deterministic behaivor as much as possible. + sgx_libc::memset(addr, 0, len); + } + } + return addr; } info!( "mmap(addr={:?}, len={}, prot={}, flags={}, fd={}, offset={})",