Skip to content

Commit

Permalink
Implementation of RPS game to demonstrate STF / runtime use-case
Browse files Browse the repository at this point in the history
Based on the Rock-Paper-Scissors game
  • Loading branch information
Felix Müller committed Aug 9, 2022
1 parent f8007e0 commit 9767e7e
Show file tree
Hide file tree
Showing 16 changed files with 449 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ jobs:
- test: M6
mode: offchain-worker
demo_name: demo-indirect-invocation
- test: RPS
mode: sidechain
demo_name: demo-rps

steps:
- uses: actions/checkout@v3
Expand Down
17 changes: 17 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2364,6 +2364,7 @@ dependencies = [
"itp-utils",
"log 0.4.17",
"pallet-balances",
"pallet-jton_rps",
"parity-scale-codec",
"primitive-types",
"rand 0.8.5",
Expand Down Expand Up @@ -2545,6 +2546,7 @@ dependencies = [
"pallet-balances",
"pallet-evm",
"pallet-grandpa",
"pallet-jton_rps",
"pallet-parentchain",
"pallet-randomness-collective-flip",
"pallet-sudo",
Expand Down Expand Up @@ -2584,6 +2586,7 @@ dependencies = [
"its-state",
"log 0.4.17",
"pallet-balances",
"pallet-jton_rps",
"parity-scale-codec",
"sc-keystore",
"sgx_tstd",
Expand Down Expand Up @@ -4746,6 +4749,20 @@ dependencies = [
"sp-std 4.0.0 (git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.26)",
]

[[package]]
name = "pallet-jton_rps"
version = "0.1.0"
source = "git+https://github.com/integritee-network/pallet-jton-rps.git?branch=integritee-demo#6a8e6dcc579c32d97d4383bc2b5222eaf1f24b88"
dependencies = [
"frame-support",
"frame-system",
"parity-scale-codec",
"scale-info",
"sp-io 6.0.0 (git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.26)",
"sp-runtime",
"sp-std 4.0.0 (git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.26)",
]

[[package]]
name = "pallet-multisig"
version = "4.0.0-dev"
Expand Down
4 changes: 4 additions & 0 deletions app-libs/sgx-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ sp-std = { default-features = false, git = "https://github.com/paritytech/substr
sp-transaction-pool = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26" }
sp-version = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26" }

# use case specific
pallet-rps = { package = "pallet-jton_rps", default-features = false, git = "https://github.com/integritee-network/pallet-jton-rps.git", branch = "integritee-demo" }

# Integritee dependencies
pallet-parentchain = { default-features = false, git = "https://github.com/integritee-network/pallets.git", branch = "master" }
pallet-evm = { default-features = false, optional = true, git = "https://github.com/integritee-network/frontier.git", branch = "polkadot-v0.9.26" }
Expand Down Expand Up @@ -76,6 +79,7 @@ std = [
"pallet-balances/std",
"pallet-grandpa/std",
"pallet-randomness-collective-flip/std",
"pallet-rps/std",
"pallet-sudo/std",
"pallet-timestamp/std",
"pallet-transaction-payment/std",
Expand Down
7 changes: 7 additions & 0 deletions app-libs/sgx-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ pub use frame_support::{
};
pub use pallet_balances::Call as BalancesCall;
pub use pallet_parentchain::Call as ParentchainCall;
pub use pallet_rps::Call as RpsCall;
pub use pallet_timestamp::Call as TimestampCall;

#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
pub use sp_runtime::{Perbill, Permill};
Expand Down Expand Up @@ -290,6 +292,10 @@ impl pallet_parentchain::Config for Runtime {
type WeightInfo = ();
}

impl pallet_rps::Config for Runtime {
type Event = Event;
}

// The plain sgx-runtime without the `evm-pallet`
#[cfg(not(feature = "evm"))]
construct_runtime!(
Expand All @@ -304,6 +310,7 @@ construct_runtime!(
TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event<T>},
Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>},
Parentchain: pallet_parentchain::{Pallet, Call, Storage},
Rps: pallet_rps::{Pallet, Call, Storage, Event<T>},
}
);

Expand Down
3 changes: 3 additions & 0 deletions app-libs/stf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ itp-storage = { default-features = false, path = "../../core-primitives/storage"
its-state = { default-features = false, optional = true, path = "../../sidechain/state" }
sp-io = { optional = true, default-features = false, features = ["disable_oom", "disable_panic_handler", "disable_allocator"], path = "../../core-primitives/substrate-sgx/sp-io" }

# use case specific
pallet-rps = { package = "pallet-jton_rps", default-features = false, git = "https://github.com/integritee-network/pallet-jton-rps.git", branch = "integritee-demo" }

# Substrate dependencies
sp-core = { default-features = false, features = ["full_crypto"], git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26" }
balances = { package = "pallet-balances", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26" }
Expand Down
26 changes: 25 additions & 1 deletion app-libs/stf/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
*/
use crate::{
stf_sgx_primitives::types::*, AccountId, Index, StfError, StfResult, ENCLAVE_ACCOUNT_KEY, H256,
stf_sgx_primitives::types::*, AccountId, Game, Hash, Index, StfError, StfResult,
ENCLAVE_ACCOUNT_KEY, H256,
};
use codec::{Decode, Encode};
use itp_storage::{storage_double_map_key, storage_map_key, storage_value_key, StorageHasher};
Expand Down Expand Up @@ -193,3 +194,26 @@ pub fn ensure_root(account: AccountId) -> StfResult<()> {
Err(StfError::MissingPrivileges(account))
}
}

pub fn get_block_number() -> BlockNumber {
get_storage_value("System", "Number").unwrap()
}

pub fn get_game_for(who: AccountId) -> Option<Game> {
if let Some(game_id) =
get_storage_map::<AccountId, Hash>("Rps", "PlayerGame", &who, &StorageHasher::Identity)
{
if let Some(game) =
get_storage_map::<Hash, Game>("Rps", "Games", &game_id, &StorageHasher::Identity)
{
info!("Game state for {:x?} is: {:?}", game.players, game.states);
Some(game)
} else {
debug!("could not read game");
None
}
} else {
debug!("could not read game id");
None
}
}
11 changes: 11 additions & 0 deletions app-libs/stf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub use my_node_runtime::{Balance, Index};

use codec::{Compact, Decode, Encode};
use derive_more::Display;
use pallet_rps::Game as GameT;
use sp_core::{crypto::AccountId32, ed25519, sr25519, Pair, H256};
use sp_runtime::{traits::Verify, MultiSignature};
use std::string::String;
Expand All @@ -47,6 +48,8 @@ pub type ShardIdentifier = H256;

pub type StfResult<T> = Result<T, StfError>;

pub type Game = GameT<Hash, AccountId>;

#[derive(Debug, Display, PartialEq, Eq)]
pub enum StfError {
#[display(fmt = "Insufficient privileges {:?}, are you sure you are root?", _0)]
Expand Down Expand Up @@ -181,6 +184,9 @@ pub enum TrustedCall {
balance_transfer(AccountId, AccountId, Balance),
balance_unshield(AccountId, AccountId, Balance, ShardIdentifier), // (AccountIncognito, BeneficiaryPublicAccount, Amount, Shard)
balance_shield(AccountId, AccountId, Balance), // (Root, AccountIncognito, Amount)
rps_new_game(AccountId, AccountId),
rps_choose(AccountId, pallet_rps::WeaponType),
rps_reveal(AccountId, pallet_rps::WeaponType),
}

impl TrustedCall {
Expand All @@ -190,6 +196,9 @@ impl TrustedCall {
TrustedCall::balance_transfer(account, _, _) => account,
TrustedCall::balance_unshield(account, _, _, _) => account,
TrustedCall::balance_shield(account, _, _) => account,
TrustedCall::rps_new_game(account, _) => account,
TrustedCall::rps_choose(account, _) => account,
TrustedCall::rps_reveal(account, _) => account,
}
}

Expand All @@ -215,6 +224,7 @@ pub enum TrustedGetter {
free_balance(AccountId),
reserved_balance(AccountId),
nonce(AccountId),
game(AccountId),
}

impl TrustedGetter {
Expand All @@ -223,6 +233,7 @@ impl TrustedGetter {
TrustedGetter::free_balance(account) => account,
TrustedGetter::reserved_balance(account) => account,
TrustedGetter::nonce(account) => account,
TrustedGetter::game(account) => account,
}
}

Expand Down
42 changes: 41 additions & 1 deletion app-libs/stf/src/stf_sgx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::test_genesis::test_genesis_setup;
use crate::{
helpers::{
account_data, account_nonce, enclave_signer_account, ensure_enclave_signer_account,
ensure_root, get_account_info, increment_nonce, root, validate_nonce,
ensure_root, get_account_info, get_game_for, increment_nonce, root, validate_nonce,
},
AccountData, AccountId, Getter, Index, ParentchainHeader, PublicGetter, ShardIdentifier, State,
StateTypeDiff, Stf, StfError, StfResult, TrustedCall, TrustedCallSigned, TrustedGetter,
Expand Down Expand Up @@ -115,6 +115,12 @@ impl Stf {
} else {
None
},
TrustedGetter::game(who) =>
if let Some(game) = get_game_for(who) {
Some(game.encode())
} else {
None
},
},
Getter::public(g) => match g {
PublicGetter::some_value => Some(42u32.encode()),
Expand Down Expand Up @@ -200,6 +206,37 @@ impl Stf {
Self::shield_funds(who, value)?;
Ok(())
},
TrustedCall::rps_new_game(sender, opponent) => {
let origin = ita_sgx_runtime::Origin::signed(sender.clone());
info!("rps new_game");
ita_sgx_runtime::RpsCall::<Runtime>::new_game { opponent }
.dispatch_bypass_filter(origin)
.map_err(|_| StfError::Dispatch("rps_new_game".to_string()))?;
Ok(())
},
TrustedCall::rps_choose(sender, weapon) => {
let origin = ita_sgx_runtime::Origin::signed(sender.clone());
info!("rps choose: {:?}", weapon);
ita_sgx_runtime::RpsCall::<Runtime>::choose {
choice: weapon.clone(),
salt: [0u8; 32],
}
.dispatch_bypass_filter(origin.clone())
.map_err(|e| {
error!("dispatch error {:?}", e);
StfError::Dispatch("rps_choose".to_string())
})?;
Ok(())
},
TrustedCall::rps_reveal(sender, weapon) => {
let origin = ita_sgx_runtime::Origin::signed(sender.clone());
info!("rps reveal");
ita_sgx_runtime::RpsCall::<Runtime>::reveal { choice: weapon, salt: [0u8; 32] }
.dispatch_bypass_filter(origin)
.map_err(|_| StfError::Dispatch("rps_reveal".to_string()))?;
get_game_for(sender);
Ok(())
},
}?;
increment_nonce(&sender);
Ok(())
Expand Down Expand Up @@ -304,6 +341,9 @@ impl Stf {
TrustedCall::balance_transfer(_, _, _) => debug!("No storage updates needed..."),
TrustedCall::balance_unshield(_, _, _, _) => debug!("No storage updates needed..."),
TrustedCall::balance_shield(_, _, _) => debug!("No storage updates needed..."),
TrustedCall::rps_new_game(_, _) => debug!("No storage updates needed..."),
TrustedCall::rps_choose(_, _) => debug!("No storage updates needed..."),
TrustedCall::rps_reveal(_, _) => debug!("No storage updates needed..."),
};
key_hashes
}
Expand Down
3 changes: 3 additions & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ substrate-api-client = { features = ["ws-client"], git = "https://github.com/scs
substrate-client-keystore = { git = "https://github.com/scs/substrate-api-client", branch = "polkadot-v0.9.26" }
teerex-primitives = { git = "https://github.com/integritee-network/pallets.git", branch = "master" }

# use case specific
pallet-rps = { package = "pallet-jton_rps", default-features = false, git = "https://github.com/integritee-network/pallet-jton-rps.git", branch = "integritee-demo" }

# substrate dependencies
sp-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26" }
sc-keystore = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26" }
Expand Down
105 changes: 105 additions & 0 deletions cli/demo_rps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/bin/bash
set -euo pipefail

# setup:
# run all on localhost:
# integritee-node purge-chain --dev
# integritee-node --tmp --dev -lruntime=debug
# rm light_client_db.bin
# integritee-service init_shard
# integritee-service shielding-key
# integritee-service signing-key
# export RUST_LOG=integritee_service=info,ita_stf=debug
# integritee-service run
#
# then run this script

# usage:
# demo_rps.sh -p <NODEPORT> -P <WORKERPORT> -m file

while getopts ":m:p:P:u:V:C:" opt; do
case $opt in
m)
READMRENCLAVE=$OPTARG
;;
p)
NPORT=$OPTARG
;;
P)
WORKER1PORT=$OPTARG
;;
u)
NODEURL=$OPTARG
;;
V)
WORKER1URL=$OPTARG
;;
C)
CLIENT_BIN=$OPTARG
;;
esac
done

# Using default port if none given as arguments.
NPORT=${NPORT:-9944}
NODEURL=${NODEURL:-"ws://127.0.0.1"}

WORKER1PORT=${WORKER1PORT:-2000}
WORKER1URL=${WORKER1URL:-"wss://127.0.0.1"}

CLIENT_BIN=${CLIENT_BIN:-"./../bin/integritee-cli"}

READMRENCLAVE=${READMRENCLAVE:-"onchain-registry"}

echo "Using client binary ${CLIENT_BIN}"
echo "Using node uri ${NODEURL}:${NPORT}"
echo "Using trusted-worker uri ${WORKER1URL}:${WORKER1PORT}"
echo "Reading MRENCLAVE from ${READMRENCLAVE}"

CLIENT="${CLIENT_BIN} -p ${NPORT} -P ${WORKER1PORT} -u ${NODEURL} -U ${WORKER1URL}"

if [ "$READMRENCLAVE" = "file" ]
then
read MRENCLAVE <<< $(cat ~/mrenclave.b58)
echo "Reading MRENCLAVE from file: ${MRENCLAVE}"
else
# this will always take the first MRENCLAVE found in the registry !!
read MRENCLAVE <<< $($CLIENT list-workers | awk '/ MRENCLAVE: / { print $2; exit }')
echo "Reading MRENCLAVE from worker list: ${MRENCLAVE}"
fi
[[ -z $MRENCLAVE ]] && { echo "MRENCLAVE is empty. cannot continue" ; exit 1; }

PLAYER1=$($CLIENT trusted --mrenclave "$MRENCLAVE" new-account)
PLAYER2=$($CLIENT trusted --mrenclave "$MRENCLAVE" new-account)

echo "Alice (sudo) sets initial balances"
${CLIENT} trusted --mrenclave "${MRENCLAVE}" --direct set-balance "${PLAYER1}" 1000
${CLIENT} trusted --mrenclave "${MRENCLAVE}" --direct set-balance "${PLAYER2}" 1000
echo ""

echo "Alice starts new game against Bob"
# shellcheck disable=SC2086
${CLIENT} trusted --mrenclave "${MRENCLAVE}" --direct new-game "${PLAYER1}" "${PLAYER2}"
echo ""

echo "Alice chooses her weapon"
${CLIENT} trusted --mrenclave "${MRENCLAVE}" --direct choose "${PLAYER1}" Rock
echo ""

echo "Bob chooses his weapon"
${CLIENT} trusted --mrenclave "${MRENCLAVE}" --direct choose "${PLAYER2}" Paper
echo ""

echo "Alice reveals"
${CLIENT} trusted --mrenclave "${MRENCLAVE}" --direct reveal "${PLAYER1}" Rock
echo ""

echo "Bob reveals"
${CLIENT} trusted --mrenclave "${MRENCLAVE}" --direct reveal "${PLAYER2}" Paper
echo ""

echo "Query result"
${CLIENT} trusted --mrenclave "${MRENCLAVE}" --direct get-game "${PLAYER1}"
echo ""

exit 0
1 change: 1 addition & 0 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ extern crate log;

mod command_utils;
mod commands;
mod rps_commands;
mod trusted_command_utils;
mod trusted_commands;
mod trusted_operation;
Expand Down
Loading

0 comments on commit 9767e7e

Please sign in to comment.