Skip to content

Commit

Permalink
Port kitties to mq
Browse files Browse the repository at this point in the history
  • Loading branch information
kvinwang committed Jun 25, 2021
1 parent 673c37a commit 7e73b10
Show file tree
Hide file tree
Showing 15 changed files with 144 additions and 381 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

16 changes: 16 additions & 0 deletions common/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,22 @@ pub mod messaging {
},
}

// Messages for Kitties

bind_topic!(KittyEvent<AccountId, Hash>, b"phala/kitties/event");
#[derive(Encode, Decode, Debug)]
pub enum KittyEvent<AccountId, Hash> {
Created(AccountId, Hash),
}


bind_topic!(KittyTransfer<AccountId>, b"^phala/kitties/trasfer");
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub struct KittyTransfer<AccountId> {
pub dest: AccountId,
pub kitty_id: Vec<u8>,
}

}

// Messages: System
Expand Down
2 changes: 2 additions & 0 deletions pallets/kitties/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ libsecp256k1 = { version = "0.3.2", default-features = false }
blake2-rfc = { version = "0.2.18", default-features = false }

pallet-balances = { version = "3.0.0", default-features = false, path = "../../substrate/frame/balances" }
phala-pallets = { path = "../phala", default-features = false }
phala-types = { path = "../../common/types", default-features = false }

[features]
default = ["std"]
Expand Down
162 changes: 59 additions & 103 deletions pallets/kitties/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ use frame_support::{
};
use frame_system::{self as system, ensure_signed};
use pallet_balances as balances;
use secp256k1;
use sp_runtime::traits::{AccountIdConversion, Hash, Zero};
use sp_runtime::{DispatchResult, traits::{AccountIdConversion, Hash, Zero}};
use sp_std::prelude::*;
use phala_pallets::{pallet_mq::{self, MessageOriginInfo}, phala_legacy::OnMessageReceived};
use phala_types::messaging::{BindTopic, KittyEvent, KittyTransfer, Message, MessageOrigin};

mod hashing;

Expand All @@ -22,34 +23,13 @@ pub struct Kitty<Hash, Balance> {
gen: u64,
}

#[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub struct KittyTransfer<AccountId> {
dest: AccountId,
kitty_id: Vec<u8>,
sequence: u64,
}
#[derive(Debug, Clone, Encode, Decode)]
pub struct KittyTransferData<AccountId> {
data: KittyTransfer<AccountId>,
signature: Vec<u8>,
}

pub trait SignedDataType<T> {
fn raw_data(&self) -> Vec<u8>;
fn signature(&self) -> T;
}

impl<AccountId: Encode> SignedDataType<Vec<u8>> for KittyTransferData<AccountId> {
fn raw_data(&self) -> Vec<u8> {
Encode::encode(&self.data)
}

fn signature(&self) -> Vec<u8> {
self.signature.clone()
}
}

pub trait Config: balances::Config {
pub trait Config: balances::Config + pallet_mq::Config {
type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;

/// Something that provides randomness in the runtime.
Expand All @@ -62,9 +42,7 @@ decl_event!(
<T as system::Config>::AccountId,
<T as system::Config>::Hash
{
Created(AccountId, Hash),
Transferred(AccountId, AccountId, Hash),
TransferToChain(AccountId, Hash, u64),
NewLottery(u32, u32),
Open(u32, Hash, Hash),
}
Expand Down Expand Up @@ -157,42 +135,11 @@ decl_module! {

<Nonce>::mutate(|n| *n += 1);

Self::deposit_event(RawEvent::Created(sender, random_hash));
Self::push_message(KittyEvent::Created(sender, random_hash));

Ok(())
}
#[weight = 0]
fn transfer(_origin, to: T::AccountId, kitty_id: T::Hash) -> Result {
let sender = Self::account_id();

let _owner = Self::owner_of(kitty_id).ok_or("No owner for this kitty")?;
let owned_kitty_count_from = Self::owned_kitties_count(&sender);
let owned_kitty_count_to = Self::owned_kitties_count(&to);
let new_owned_kitty_count_to = owned_kitty_count_to.checked_add(1)
.ok_or("Transfer causes overflow of 'to' kitty balance")?;

let new_owned_kitty_count_from = owned_kitty_count_from.checked_sub(1)
.ok_or("Transfer causes underflow of 'from' kitty balance")?;

let kitty_index = <OwnedKittiesIndex<T>>::get(kitty_id);
if kitty_index != new_owned_kitty_count_from {
let last_kitty_id = <OwnedKittiesArray<T>>::get((sender.clone(), new_owned_kitty_count_from));
<OwnedKittiesArray<T>>::insert((sender.clone(), kitty_index), last_kitty_id);
<OwnedKittiesIndex<T>>::insert(last_kitty_id, kitty_index);
}
<KittyOwner<T>>::insert(&kitty_id, &to);
<OwnedKittiesIndex<T>>::insert(kitty_id, owned_kitty_count_to);

<OwnedKittiesArray<T>>::remove((sender.clone(), new_owned_kitty_count_from));
<OwnedKittiesArray<T>>::insert((to.clone(), owned_kitty_count_to), kitty_id);

<OwnedKittiesCount<T>>::insert(&sender, new_owned_kitty_count_from);
<OwnedKittiesCount<T>>::insert(&to, new_owned_kitty_count_to);

Self::deposit_event(RawEvent::Transferred(sender, to, kitty_id));

Ok(())
}
#[weight = 0]
pub fn create_kitties(origin) -> Result {
ensure_signed(origin.clone())?;
Expand All @@ -202,61 +149,70 @@ decl_module! {
}
Ok(())
}

#[weight = 0]
pub fn transfer_to_chain(origin, data: Vec<u8>) -> Result {
const CONTRACT_ID: u32 = 6;
let transfer_data: KittyTransferData<<T as system::Config>::AccountId> = Decode::decode(&mut &data[..]).map_err(|_| Error::<T>::InvalidInput)?;
// Check sequence
let sequence = IngressSequence::get(CONTRACT_ID);
ensure!(transfer_data.data.sequence == sequence + 1, Error::<T>::BadMessageSequence);
// Contract key
ensure!(ContractKey::contains_key(CONTRACT_ID), Error::<T>::InvalidContract);
let pubkey = ContractKey::get(CONTRACT_ID);

let new_owner = &transfer_data.data.dest;
let new_owner_kitty_id = &transfer_data.data.kitty_id;
// Validate TEE signature
Self::verify_signature(&pubkey, &transfer_data)?;
// Announce the successful execution
let kitty_id: T::Hash = Decode::decode(&mut &new_owner_kitty_id[..]).map_err(|_| Error::<T>::InvalidKitty)?;
Self::transfer(origin, new_owner.clone(), kitty_id.clone())?;
IngressSequence::insert(CONTRACT_ID, sequence + 1);

Self::deposit_event(RawEvent::TransferToChain(transfer_data.data.dest, kitty_id, sequence + 1));
Ok(())
}
}
}
impl<T: Config> Module<T> {
pub fn account_id() -> T::AccountId {
PALLET_ID.into_account()
}

pub fn verify_signature(
serialized_pk: &Vec<u8>,
data: &impl SignedDataType<Vec<u8>>,
) -> Result {
let pub_key = Self::try_parse_ecdsa_key(serialized_pk)?;
let signature = secp256k1::Signature::parse_slice(&data.signature())
.map_err(|_| Error::<T>::InvalidSignature)?;
let msg_hash = hashing::blake2_256(&data.raw_data());
let mut buffer = [0u8; 32];
buffer.copy_from_slice(&msg_hash);
let message = secp256k1::Message::parse(&buffer);
let verified = secp256k1::verify(&message, &signature, &pub_key);
ensure!(verified, Error::<T>::FailedToVerify);
fn transfer(to: T::AccountId, kitty_id: T::Hash) -> Result {
let sender = Self::account_id();

let _owner = Self::owner_of(kitty_id).ok_or("No owner for this kitty")?;
let owned_kitty_count_from = Self::owned_kitties_count(&sender);
let owned_kitty_count_to = Self::owned_kitties_count(&to);
let new_owned_kitty_count_to = owned_kitty_count_to.checked_add(1)
.ok_or("Transfer causes overflow of 'to' kitty balance")?;

let new_owned_kitty_count_from = owned_kitty_count_from.checked_sub(1)
.ok_or("Transfer causes underflow of 'from' kitty balance")?;

let kitty_index = <OwnedKittiesIndex<T>>::get(kitty_id);
if kitty_index != new_owned_kitty_count_from {
let last_kitty_id = <OwnedKittiesArray<T>>::get((sender.clone(), new_owned_kitty_count_from));
<OwnedKittiesArray<T>>::insert((sender.clone(), kitty_index), last_kitty_id);
<OwnedKittiesIndex<T>>::insert(last_kitty_id, kitty_index);
}
<KittyOwner<T>>::insert(&kitty_id, &to);
<OwnedKittiesIndex<T>>::insert(kitty_id, owned_kitty_count_to);

<OwnedKittiesArray<T>>::remove((sender.clone(), new_owned_kitty_count_from));
<OwnedKittiesArray<T>>::insert((to.clone(), owned_kitty_count_to), kitty_id);

<OwnedKittiesCount<T>>::insert(&sender, new_owned_kitty_count_from);
<OwnedKittiesCount<T>>::insert(&to, new_owned_kitty_count_to);

Self::deposit_event(RawEvent::Transferred(sender, to, kitty_id));

Ok(())
}

fn try_parse_ecdsa_key(
serialized_pk: &Vec<u8>,
) -> frame_support::dispatch::result::Result<secp256k1::PublicKey, Error<T>> {
let mut pk = [0u8; 33];
if serialized_pk.len() != 33 {
return Err(Error::<T>::InvalidPubKey);
fn push_message(message: impl Encode + BindTopic) {
pallet_mq::Pallet::<T>::push_bound_message(Self::message_origin(), message)
}
}

impl<T: Config> OnMessageReceived for Module<T> {
fn on_message_received(message: &Message) -> DispatchResult {
const CONTRACT_ID: u32 = 6;

if message.sender != MessageOrigin::native_contract(CONTRACT_ID) {
return Err(Error::<T>::InvalidContract)?;
}
pk.copy_from_slice(&serialized_pk);
secp256k1::PublicKey::parse_compressed(&pk).map_err(|_| Error::<T>::InvalidPubKey)

let data: KittyTransfer<T::AccountId> =
message.decode_payload().ok_or(Error::<T>::InvalidInput)?;

let new_owner = &data.dest;
let new_owner_kitty_id = &data.kitty_id;
// Announce the successful execution
let kitty_id: T::Hash = Decode::decode(&mut &new_owner_kitty_id[..]).map_err(|_| Error::<T>::InvalidKitty)?;
Self::transfer(new_owner.clone(), kitty_id.clone())?;
Ok(())
}
}

impl<T: Config> MessageOriginInfo for Module<T> {
type Config = T;
}
45 changes: 1 addition & 44 deletions standalone/phost/src/msg_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::chain_client::fetch_mq_ingress_seq;
use super::{
update_signer_nonce,
error::Error,
types::{ReqData, QueryRespData, KittyTransferData, GetEgressMessagesReq},
types::{ReqData, QueryRespData, GetEgressMessagesReq},
runtimes,
XtClient, PrClient, SrSigner
};
Expand Down Expand Up @@ -81,49 +81,6 @@ impl<'a> MsgSync<'a> {
Ok(())
}

pub async fn _maybe_sync_kitty_egress(&mut self, sequence: &mut u64) -> Result<()> {
let query_resp = self.pr.query(6, ReqData::PendingKittyTransfer {sequence: *sequence}).await?;
let transfer_data = match query_resp {
QueryRespData::PendingKittyTransfer { transfer_queue_b64 } =>
base64::decode(&transfer_queue_b64)
.map_err(|_| Error::FailedToDecode)?,
_ => return Err(anyhow!(Error::FailedToDecode))
};

let transfer_queue: Vec<KittyTransferData> = Decode::decode(&mut &transfer_data[..])
.map_err(|_|Error::FailedToDecode)?;
// No pending message. We are done.
if transfer_queue.is_empty() {
return Ok(());
}

self.maybe_update_signer_nonce().await?;

let mut next_seq = *sequence;
for transfer_data in &transfer_queue {
let msg_seq = transfer_data.data.sequence;
if msg_seq <= *sequence {
println!("Kitty {} has been submitted. Skipping...", msg_seq);
continue;
}
next_seq = cmp::max(next_seq, msg_seq);
let ret = self.client.submit(runtimes::kitties::TransferToChainCall {
_runtime: PhantomData,
data: transfer_data.encode()
}, self.signer).await;

if let Err(err) = ret {
println!("Failed to submit tx: {:?}", err);
// TODO: Should we fail early?
}
self.signer.increment_nonce();
}

*sequence = next_seq;

Ok(())
}

pub async fn maybe_sync_mq_egress(&mut self) -> Result<()> {
// Send the query
let resp = self
Expand Down
16 changes: 0 additions & 16 deletions standalone/phost/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,12 @@ pub struct Query {

#[derive(Serialize, Deserialize, Debug)]
pub enum ReqData {
PendingKittyTransfer { sequence: u64 }, // Kitties
PendingLotteryEgress { sequence: u64 }, // Btc lottery
GetWorkerEgress { start_sequence: u64 }, // System
}

#[derive(Serialize, Deserialize, Debug)]
pub enum QueryRespData {
PendingKittyTransfer {
transfer_queue_b64: String,
},
PendingLotteryEgress {
lottery_queue_b64: String,
},
Expand All @@ -128,18 +124,6 @@ impl Resp for QueryReq {
type Resp = Payload;
}

#[derive(Serialize, Deserialize, Debug, Encode, Decode)]
pub struct KittyTransfer {
pub dest: [u8; 32],
pub kitty_id: Vec<u8>,
pub sequence: u64,
}
#[derive(Serialize, Deserialize, Debug, Encode, Decode)]
pub struct KittyTransferData {
pub data: KittyTransfer,
pub signature: Vec<u8>,
}

// API: init_runtime

#[derive(Serialize, Deserialize, Debug)]
Expand Down
2 changes: 1 addition & 1 deletion standalone/pruntime/app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ fn rocket() -> rocket::Rocket {
test, init_runtime, get_info,
dump_states, load_states,
sync_header, dispatch_block, query,
set, get, get_runtime_info, get_egress_messages, test_ink]);
get_runtime_info, get_egress_messages, test_ink]);

if *ENABLE_KICK_API {
info!("ENABLE `kick` API");
Expand Down
3 changes: 3 additions & 0 deletions standalone/pruntime/enclave/Cargo.lock

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

1 change: 1 addition & 0 deletions standalone/pruntime/enclave/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ parity-scale-codec = { package = "parity-scale-codec", version = "2.0.0", defa
# Phala specific
runtime = { path = "../../runtime", default-features = false, package = "phala-node-runtime", features = ["native-nostd"] }
phala-pallets = { path = "../../../pallets/phala", default-features = false }
pallet-kitties = { path = "../../../pallets/kitties", default-features = false }
bridge-transfer = { package = "pallet-bridge-transfer", path = "../../../pallets/bridge_transfer", default-features = false }
phala-types = { path = "../../../common/types", default-features = false, features = ["enable_serde", "pruntime", "sgx"] }
enclave-api = { path = "../enclave-api" }
Expand Down
2 changes: 1 addition & 1 deletion standalone/pruntime/enclave/src/contracts/balances.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ impl contracts::NativeContract for Balances {
origin: MessageOrigin,
event: Self::Event,
) {
if origin != phala::Module::<chain::Runtime>::message_origin() {
if origin != chain::Phala::message_origin() {
error!("Received event from unexpected origin: {:?}", origin);
return;
}
Expand Down

0 comments on commit 7e73b10

Please sign in to comment.