Skip to content

Commit

Permalink
Add nonce validation to trusted calls (#225)
Browse files Browse the repository at this point in the history
* closes #89 
* Trusted getter for nonce (#232)
  • Loading branch information
haerdib authored Apr 6, 2021
1 parent 686d1db commit 1b18c35
Show file tree
Hide file tree
Showing 20 changed files with 532 additions and 241 deletions.
23 changes: 7 additions & 16 deletions client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ use substrate_api_client::{
use substrate_client_keystore::LocalKeystore;
use substratee_stf::{ShardIdentifier, TrustedCallSigned, TrustedOperation};
use substratee_worker_api::direct_client::DirectApi as DirectWorkerApi;
use substratee_worker_primitives::{DirectCallStatus, RpcRequest, RpcResponse, RpcReturnValue};
use substratee_worker_primitives::{DirectRequestStatus, RpcRequest, RpcResponse, RpcReturnValue};

type AccountPublic = <Signature as Verify>::Signer;
const KEYSTORE_PATH: &str = "my_keystore";
Expand Down Expand Up @@ -459,10 +459,7 @@ fn get_state(matches: &ArgMatches<'_>, getter: TrustedOperation) -> Option<Vec<u
return None;
}
};
let shard = match read_shard(matches) {
Ok(shard) => shard,
Err(e) => panic!(e),
};
let shard = read_shard(matches).unwrap();

// compose jsonrpc call
let data = Request {
Expand All @@ -484,7 +481,7 @@ fn get_state(matches: &ArgMatches<'_>, getter: TrustedOperation) -> Option<Vec<u
Ok(response) => {
let response: RpcResponse = serde_json::from_str(&response).unwrap();
if let Ok(return_value) = RpcReturnValue::decode(&mut response.result.as_slice()) {
if return_value.status == DirectCallStatus::Error {
if return_value.status == DirectRequestStatus::Error {
println!(
"[Error] {}",
String::decode(&mut return_value.value.as_slice()).unwrap()
Expand Down Expand Up @@ -532,10 +529,7 @@ fn send_request(matches: &ArgMatches<'_>, call: TrustedCallSigned) -> Option<Vec
}
};

let shard = match read_shard(matches) {
Ok(shard) => shard,
Err(e) => panic!(e),
};
let shard = read_shard(matches).unwrap();

let arg_signer = matches.value_of("xt-signer").unwrap();
let signer = get_pair_from_str(arg_signer);
Expand Down Expand Up @@ -619,10 +613,7 @@ fn send_direct_request(
return None;
}
};
let shard = match read_shard(matches) {
Ok(shard) => shard,
Err(e) => panic!(e),
};
let shard = read_shard(matches).unwrap();

// compose jsonrpc call
let data = Request {
Expand Down Expand Up @@ -650,13 +641,13 @@ fn send_direct_request(
let response: RpcResponse = serde_json::from_str(&response).unwrap();
if let Ok(return_value) = RpcReturnValue::decode(&mut response.result.as_slice()) {
match return_value.status {
DirectCallStatus::Error => {
DirectRequestStatus::Error => {
if let Ok(value) = String::decode(&mut return_value.value.as_slice()) {
println!("[Error] {}", value);
}
return None;
}
DirectCallStatus::TrustedOperationStatus(status) => {
DirectRequestStatus::TrustedOperationStatus(status) => {
if let Ok(value) = Hash::decode(&mut return_value.value.as_slice()) {
println!("Trusted call {:?} is {:?}", value, status);
}
Expand Down
6 changes: 5 additions & 1 deletion enclave/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
limitations under the License.
*/
use substratee_stf::Index;

pub const RSA3072_SEALED_KEY_FILE: &str = "rsa3072_key_sealed.bin";
pub const SEALED_SIGNER_SEED_FILE: &str = "ed25519_key_sealed.bin";
Expand Down Expand Up @@ -49,5 +50,8 @@ pub static RUNTIME_SPEC_VERSION: u32 = 1;
pub static RUNTIME_TRANSACTION_VERSION: u32 = 1;

// timeouts for getter and call execution
pub static CALLTIMEOUT: i64 = 300; // timeout in ms
pub static CALLTIMEOUT: i64 = 300; // timeout in ms
pub static GETTERTIMEOUT: i64 = 300; // timeout in ms

// maximum allowed tops in the future pool per account
pub static MAX_ALLOWED_FUTURE_TOP: Index = 64;
5 changes: 3 additions & 2 deletions enclave/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ use substratee_stf::{

use rpc::author::{hash::TrustedOperationOrHash, Author, AuthorApi};
use rpc::worker_api_direct;
use rpc::{api::FillerChainApi, basic_pool::BasicPool};
use rpc::{api::SideChainApi, basic_pool::BasicPool};

mod aes;
mod attestation;
Expand Down Expand Up @@ -108,7 +108,7 @@ pub enum Timeout {
}

pub type Hash = sp_core::H256;
type BPool = BasicPool<FillerChainApi<Block>, Block>;
type BPool = BasicPool<SideChainApi<Block>, Block>;

#[no_mangle]
pub unsafe extern "C" fn init() -> sgx_status_t {
Expand Down Expand Up @@ -588,6 +588,7 @@ fn execute_top_pool_calls(
Ok((calls, _)) => calls,
Err(_) => return Err(sgx_status_t::SGX_ERROR_UNEXPECTED),
};
debug!("Got following trusted calls from pool: {:?}", trusted_calls);
// call execution
for trusted_call_signed in trusted_calls.into_iter() {
match handle_trusted_worker_call(
Expand Down
44 changes: 29 additions & 15 deletions enclave/src/rpc/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,41 +21,49 @@ extern crate alloc;
use alloc::{boxed::Box, vec::Vec};
use log::*;

use codec::Encode;
use codec::{Encode, Decode};
use jsonrpc_core::futures::future::{ready, Future, Ready};
use std::{marker::PhantomData, pin::Pin};

use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, Hash as HashT, Header as HeaderT},
transaction_validity::{
TransactionValidity, TransactionValidityError, UnknownTransaction, ValidTransaction,
TransactionValidity, TransactionValidityError, UnknownTransaction,
InvalidTransaction, ValidTransaction,
},
};

use crate::top_pool::pool::{ChainApi, ExtrinsicHash, NumberFor};
use crate::top_pool::primitives::TrustedOperationSource;
use crate::state;

use substratee_stf::{Getter, TrustedOperation as StfTrustedOperation};
use substratee_stf::{Getter, TrustedOperation as StfTrustedOperation, AccountId,
Index, ShardIdentifier, Stf};
use substratee_worker_primitives::BlockHash as SidechainBlockHash;

use crate::rpc::error;

use crate::constants::MAX_ALLOWED_FUTURE_TOP;

/// Future that resolves to account nonce.
pub type Result<T> = core::result::Result<T, ()>;

/// The operation pool logic for full client.
pub struct FillerChainApi<Block> {
pub struct SideChainApi<Block> {
_marker: PhantomData<Block>,
}

impl<Block> FillerChainApi<Block> {
impl<Block> SideChainApi<Block> {
/// Create new operation pool logic.
pub fn new() -> Self {
FillerChainApi {
SideChainApi {
_marker: Default::default(),
}
}
}

impl<Block> ChainApi for FillerChainApi<Block>
impl<Block> ChainApi for SideChainApi<Block>
where
Block: BlockT,
{
Expand All @@ -71,17 +79,23 @@ where

fn validate_transaction(
&self,
_at: &BlockId<Self::Block>,
_source: TrustedOperationSource,
uxt: StfTrustedOperation,
_shard: ShardIdentifier,
) -> Self::ValidationFuture {
let operation = match uxt {
StfTrustedOperation::direct_call(call) => ValidTransaction {
priority: 1 << 20,
requires: vec![],
provides: vec![vec![call.nonce as u8], call.signature.encode()],
longevity: 3,
propagate: true,
StfTrustedOperation::direct_call(signed_call) => {
let from = signed_call.call.account();
let requires = vec![];
let provides = vec![from.encode()];

ValidTransaction {
priority: 1 << 20,
requires: requires,
provides: provides,
longevity: 64,
propagate: true,
}
},
StfTrustedOperation::get(getter) => match getter {
Getter::public(_) => {
Expand All @@ -93,7 +107,7 @@ where
priority: 1 << 20,
requires: vec![],
provides: vec![trusted_getter.signature.encode()],
longevity: 3,
longevity: 64,
propagate: true,
},
},
Expand Down
22 changes: 8 additions & 14 deletions enclave/src/rpc/author/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,10 @@ where
shard: ShardIdentifier,
) -> FutureResult<TxHash<P>, RpcError> {
// check if shard already exists
let shards = match state::list_shards() {
Ok(shards) => shards,
Err(_) => return Box::pin(ready(Err(ClientError::InvalidShard.into()))),
};
if !shards.contains(&shard) {
return Box::pin(ready(Err(ClientError::InvalidShard.into())));
}
if !state::exists(&shard) {
//FIXME: Should this be an error? -> Issue error handling
return Box::pin(ready(Err(ClientError::InvalidShard.into())))
}
// decrypt call
let rsa_keypair = rsa3072::unseal_pair().unwrap();
let request_vec: Vec<u8> = match rsa3072::decrypt(&ext.as_slice(), &rsa_keypair) {
Expand Down Expand Up @@ -237,13 +234,10 @@ where

fn watch_top(&self, ext: Vec<u8>, shard: ShardIdentifier) -> FutureResult<TxHash<P>, RpcError> {
// check if shard already exists
let shards = match state::list_shards() {
Ok(shards) => shards,
Err(_) => return Box::pin(ready(Err(ClientError::InvalidShard.into()))),
};
if !shards.contains(&shard) {
return Box::pin(ready(Err(ClientError::InvalidShard.into())));
}
if !state::exists(&shard) {
//FIXME: Should this be an error? -> Issue error handling
return Box::pin(ready(Err(ClientError::InvalidShard.into())))
}
// decrypt call
let rsa_keypair = rsa3072::unseal_pair().unwrap();
let request_vec: Vec<u8> = match rsa3072::decrypt(&ext.as_slice(), &rsa_keypair) {
Expand Down
33 changes: 16 additions & 17 deletions enclave/src/rpc/worker_api_direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use codec::{Decode, Encode};
use log::*;

use crate::rpc::{
api::FillerChainApi,
api::SideChainApi,
author::{Author, AuthorApi},
basic_pool::BasicPool,
};
Expand All @@ -57,7 +57,7 @@ use chain_relay::Block;

use substratee_node_primitives::Request;
use substratee_worker_primitives::RpcReturnValue;
use substratee_worker_primitives::{TrustedOperationStatus, DirectCallStatus};
use substratee_worker_primitives::{TrustedOperationStatus, DirectRequestStatus};

use crate::utils::write_slice_and_whitespace_pad;
use crate::rsa3072;
Expand All @@ -84,9 +84,9 @@ extern "C" {
#[no_mangle]
// initialise tx pool and store within static atomic pointer
pub unsafe extern "C" fn initialize_pool() -> sgx_status_t {
let api = Arc::new(FillerChainApi::new());
let api = Arc::new(SideChainApi::new());
let tx_pool = BasicPool::create(PoolOptions::default(), api);
let pool_ptr = Arc::new(SgxMutex::<BasicPool<FillerChainApi<Block>, Block>>::new(
let pool_ptr = Arc::new(SgxMutex::<BasicPool<SideChainApi<Block>, Block>>::new(
tx_pool,
));
let ptr = Arc::into_raw(pool_ptr);
Expand All @@ -95,9 +95,9 @@ pub unsafe extern "C" fn initialize_pool() -> sgx_status_t {
sgx_status_t::SGX_SUCCESS
}

pub fn load_top_pool() -> Option<&'static SgxMutex<BasicPool<FillerChainApi<Block>, Block>>> {
pub fn load_top_pool() -> Option<&'static SgxMutex<BasicPool<SideChainApi<Block>, Block>>> {
let ptr = GLOBAL_TX_POOL.load(Ordering::SeqCst)
as *mut SgxMutex<BasicPool<FillerChainApi<Block>, Block>>;
as *mut SgxMutex<BasicPool<SideChainApi<Block>, Block>>;
if ptr.is_null() {
None
} else {
Expand Down Expand Up @@ -134,7 +134,7 @@ fn compute_encoded_return_error(error_msg: String) -> Vec<u8> {
let return_value = RpcReturnValue {
value: error_msg.encode(),
do_watch: false,
status: DirectCallStatus::Error,
status: DirectRequestStatus::Error,
};
return_value.encode()
}
Expand Down Expand Up @@ -173,7 +173,7 @@ fn init_io_handler() -> IoHandler {
RpcReturnValue {
do_watch: true,
value: hash_value.encode(),
status: DirectCallStatus::TrustedOperationStatus(TrustedOperationStatus::Submitted),
status: DirectRequestStatus::TrustedOperationStatus(TrustedOperationStatus::Submitted),
}.encode()
},
Err(rpc_error) => compute_encoded_return_error(rpc_error.message)
Expand Down Expand Up @@ -220,7 +220,7 @@ fn init_io_handler() -> IoHandler {
RpcReturnValue {
do_watch: false,
value: hash_value.encode(),
status: DirectCallStatus::TrustedOperationStatus(TrustedOperationStatus::Submitted),
status: DirectRequestStatus::TrustedOperationStatus(TrustedOperationStatus::Submitted),
}.encode()
},
Err(rpc_error) => compute_encoded_return_error(rpc_error.message)
Expand Down Expand Up @@ -259,34 +259,34 @@ fn init_io_handler() -> IoHandler {
};
if let Ok(vec_of_operations) = author.pending_tops(shard) {
retrieved_operations.push(vec_of_operations);
}
}
}
let json_value = RpcReturnValue {
do_watch: false,
value: retrieved_operations.encode(),
status: DirectCallStatus::Ok,
status: DirectRequestStatus::Ok,
};
Ok(json!(json_value.encode()))
}
Err(e) => {
let error_msg: String = format!("Could not retrieve pending calls due to: {}", e);
Ok(json!(compute_encoded_return_error(error_msg)))
}
}
}
});

// author_getShieldingKey
let rsa_pubkey_name: &str = "author_getShieldingKey";
rpc_methods_vec.push(rsa_pubkey_name);
io.add_sync_method(rsa_pubkey_name, move |_: Params| {
io.add_sync_method(rsa_pubkey_name, move |_: Params| {
let rsa_pubkey = match rsa3072::unseal_pubkey() {
Ok(key) => key,
Err(status) => {
let error_msg: String = format!("Could not get rsa pubkey due to: {}", status);
return Ok(json!(compute_encoded_return_error(error_msg)))
},
};

let rsa_pubkey_json = match serde_json::to_string(&rsa_pubkey) {
Ok(k) => k,
Err(x) => {
Expand All @@ -296,11 +296,10 @@ fn init_io_handler() -> IoHandler {
return Ok(json!(compute_encoded_return_error(error_msg)))
},
};
let json_value = RpcReturnValue::new(rsa_pubkey_json.encode(), false, DirectCallStatus::Ok);
Ok(json!(json_value.encode()))
let json_value = RpcReturnValue::new(rsa_pubkey_json.encode(), false, DirectRequestStatus::Ok);
Ok(json!(json_value.encode()))
});


// chain_subscribeAllHeads
let chain_subscribe_all_heads_name: &str = "chain_subscribeAllHeads";
rpc_methods_vec.push(chain_subscribe_all_heads_name);
Expand Down
Loading

0 comments on commit 1b18c35

Please sign in to comment.