Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 89 additions & 53 deletions enclave/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ pub unsafe extern "C" fn sync_chain_relay(
Err(e) => return e,
};

for signed_block in blocks.iter() {
let mut calls = Vec::new();
for signed_block in blocks.into_iter() {
validator
.check_xt_inclusion(validator.num_relays, &signed_block.block)
.unwrap(); // panic can only happen if relay_id is does not exist
Expand All @@ -321,12 +322,16 @@ pub unsafe extern "C" fn sync_chain_relay(
error!("Block verification failed. Error : {:?}", e);
return sgx_status_t::SGX_ERROR_UNEXPECTED;
}
}

let calls = match scan_blocks_for_relevant_xt(blocks, node_url) {
Ok(c) => c,
Err(e) => return e,
};
match scan_block_for_relevant_xt(&signed_block.block, node_url) {
Ok(c) => calls.extend(c.into_iter()),
Err(_) => error!("Error executing relevant extrinsics"),
};

if update_states(signed_block.block.header, node_url).is_err() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brenzi As the runtime does perform state updates at the end of block execution I suppose it does make sense that we also update the state after we executed the relevant extrinsics?

error!("Error performing state updates upon block import")
}
}

if let Err(_e) = stf_post_actions(validator, calls, xt_slice, *nonce) {
return sgx_status_t::SGX_ERROR_UNEXPECTED;
Expand All @@ -335,35 +340,50 @@ pub unsafe extern "C" fn sync_chain_relay(
sgx_status_t::SGX_SUCCESS
}

pub fn update_states(header: Header, node_url: &[u8]) -> SgxResult<()> {
debug!("Update STF storage upon block import!");
let requests = Stf::storage_hashes_to_update_on_block()
.into_iter()
.map(|key| WorkerRequest::ChainStorage(key, Some(header.hash())))
.collect();

let responses: Vec<WorkerResponse<Vec<u8>>> = worker_request(requests, node_url)?;
let update_map = verify_worker_responses(responses, header)?;

let shards = state::list_shards()?;
debug!("found shards: {:?}", shards);
for s in shards {
let mut state = state::load(&s)?;
Stf::update_storage(&mut state, &update_map);
state::write(state, &s)?;
}
Ok(())
}

/// Scans blocks for extrinsics that ask the enclave to execute some actions.
pub fn scan_blocks_for_relevant_xt(
blocks: Vec<SignedBlock<Block>>,
node_url: &[u8],
) -> SgxResult<Vec<OpaqueCall>> {
pub fn scan_block_for_relevant_xt(block: &Block, node_url: &[u8]) -> SgxResult<Vec<OpaqueCall>> {
debug!("Scanning blocks for relevant xt");
let mut calls = Vec::<OpaqueCall>::new();
for block in blocks.iter() {
for xt_opaque in block.block.extrinsics.iter() {
if let Ok(xt) =
UncheckedExtrinsicV4::<ShieldFundsFn>::decode(&mut xt_opaque.0.encode().as_slice())
{
// confirm call decodes successfully as well
if xt.function.0 == [SUBSRATEE_REGISTRY_MODULE, SHIELD_FUNDS] {
if let Err(e) = handle_shield_funds_xt(&mut calls, xt) {
error!("Error performing shieldfunds. Error: {:?}", e);
}
for xt_opaque in block.extrinsics.iter() {
if let Ok(xt) =
UncheckedExtrinsicV4::<ShieldFundsFn>::decode(&mut xt_opaque.0.encode().as_slice())
{
// confirm call decodes successfully as well
if xt.function.0 == [SUBSRATEE_REGISTRY_MODULE, SHIELD_FUNDS] {
if let Err(e) = handle_shield_funds_xt(&mut calls, xt) {
error!("Error performing shieldfunds. Error: {:?}", e);
}
};

if let Ok(xt) =
UncheckedExtrinsicV4::<CallWorkerFn>::decode(&mut xt_opaque.0.encode().as_slice())
{
if xt.function.0 == [SUBSRATEE_REGISTRY_MODULE, CALL_WORKER] {
if let Err(e) =
handle_call_worker_xt(&mut calls, xt, block.block.header.clone(), node_url)
{
error!("Error performing worker call: Error: {:?}", e);
}
}
};

if let Ok(xt) =
UncheckedExtrinsicV4::<CallWorkerFn>::decode(&mut xt_opaque.0.encode().as_slice())
{
if xt.function.0 == [SUBSRATEE_REGISTRY_MODULE, CALL_WORKER] {
if let Err(e) =
handle_call_worker_xt(&mut calls, xt, block.header.clone(), node_url)
{
error!("Error performing worker call: Error: {:?}", e);
}
}
}
Expand All @@ -380,7 +400,11 @@ fn handle_shield_funds_xt(
call, account_encrypted, amount, shard
);

let mut state = state::load(&shard)?;
let mut state = if state::exists(&shard) {
state::load(&shard)?
} else {
Stf::init_state()
};

debug!("decrypt the call");
let rsa_keypair = rsa3072::unseal_pair()?;
Expand Down Expand Up @@ -449,7 +473,11 @@ fn handle_call_worker_xt(
return Ok(());
}

let mut state = state::load(&shard)?;
let mut state = if state::exists(&shard) {
state::load(&shard)?
} else {
Stf::init_state()
};

debug!("Update STF storage!");
let requests = Stf::get_storage_hashes_to_update(&stf_call_signed)
Expand All @@ -459,6 +487,33 @@ fn handle_call_worker_xt(

let responses: Vec<WorkerResponse<Vec<u8>>> = worker_request(requests, node_url)?;

let update_map = verify_worker_responses(responses, header)?;

Stf::update_storage(&mut state, &update_map);

debug!("execute STF");
if let Err(e) = Stf::execute(&mut state, stf_call_signed, calls) {
error!("Error performing Stf::execute. Error: {:?}", e);
return Ok(());
}

let state_hash = state::write(state, &shard)?;

let xt_call = [SUBSRATEE_REGISTRY_MODULE, CALL_CONFIRMED];
let call_hash = blake2_256(&request_vec);
debug!("Call hash 0x{}", hex::encode_hex(&call_hash));

calls.push(OpaqueCall(
(xt_call, shard, call_hash, state_hash.encode()).encode(),
));

Ok(())
}

fn verify_worker_responses(
responses: Vec<WorkerResponse<Vec<u8>>>,
header: Header,
) -> SgxResult<HashMap<Vec<u8>, Vec<u8>>> {
let mut update_map = HashMap::new();
for response in responses.iter() {
match response {
Expand Down Expand Up @@ -486,26 +541,7 @@ fn handle_call_worker_xt(
}
}
}

Stf::update_storage(&mut state, update_map);

debug!("execute STF");
if let Err(e) = Stf::execute(&mut state, stf_call_signed, calls) {
error!("Error performing Stf::execute. Error: {:?}", e);
return Ok(());
}

let state_hash = state::write(state, &shard)?;

let xt_call = [SUBSRATEE_REGISTRY_MODULE, CALL_CONFIRMED];
let call_hash = blake2_256(&request_vec);
debug!("Call hash 0x{}", hex::encode_hex(&call_hash));

calls.push(OpaqueCall(
(xt_call, shard, call_hash, state_hash.encode()).encode(),
));

Ok(())
Ok(update_map)
}

extern "C" {
Expand Down
33 changes: 31 additions & 2 deletions enclave/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

*/

use std::fs;
use std::vec::Vec;

use log::*;
Expand All @@ -25,10 +26,12 @@ use crate::aes;
use crate::constants::{ENCRYPTED_STATE_FILE, SHARDS_PATH};
use crate::hex;
use crate::io;
use base58::ToBase58;
use codec::Encode;
use crate::utils::UnwrapOrSgxErrorUnexpected;
use base58::{FromBase58, ToBase58};
use codec::{Decode, Encode};
use sgx_externalities::SgxExternalitiesTrait;
use sp_core::H256;
use std::path::Path;
use substratee_stf::{ShardIdentifier, State as StfState, Stf};

pub fn load(shard: &ShardIdentifier) -> SgxResult<StfState> {
Expand Down Expand Up @@ -79,6 +82,16 @@ pub fn write(state: StfState, shard: &ShardIdentifier) -> SgxResult<H256> {
Ok(state_hash.into())
}

pub fn exists(shard: &ShardIdentifier) -> bool {
Path::new(&format!(
"{}/{}/{}",
SHARDS_PATH,
shard.encode().to_base58(),
ENCRYPTED_STATE_FILE
))
.exists()
}

fn read(path: &str) -> SgxResult<Vec<u8>> {
let mut bytes = match io::read(path) {
Ok(vec) => match vec.len() {
Expand Down Expand Up @@ -108,6 +121,22 @@ fn encrypt(mut state: Vec<u8>) -> SgxResult<Vec<u8>> {
Ok(state)
}

pub fn list_shards() -> SgxResult<Vec<ShardIdentifier>> {
let files = fs::read_dir(SHARDS_PATH).sgx_error()?;
let mut shards = Vec::new();
for file in files {
let s = file
.sgx_error()?
.file_name()
.into_string()
.sgx_error()?
.from_base58()
.sgx_error()?;
shards.push(ShardIdentifier::decode(&mut s.as_slice()).sgx_error()?);
}
Ok(shards)
}

pub fn test_encrypted_state_io_works() {
let path = "test_state_file.bin";
let plaintext = b"The quick brown fox jumps over the lazy dog.";
Expand Down
9 changes: 8 additions & 1 deletion stf/src/sgx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl Stf {
ext
}

pub fn update_storage(ext: &mut State, map_update: HashMap<Vec<u8>, Vec<u8>>) {
pub fn update_storage(ext: &mut State, map_update: &HashMap<Vec<u8>, Vec<u8>>) {
ext.execute_with(|| {
map_update
.iter()
Expand Down Expand Up @@ -203,6 +203,13 @@ impl Stf {
};
key_hashes
}

pub fn storage_hashes_to_update_on_block() -> Vec<Vec<u8>> {
// let key_hashes = Vec::new();
// key_hashes.push(storage_value_key("dummy", "dummy"));
// key_hashes
Vec::new()
}
}

// get the AccountInfo key where the nonce is stored
Expand Down
16 changes: 0 additions & 16 deletions worker/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,6 @@ fn worker(node_url: &str, w_ip: &str, w_port: &str, mu_ra_port: &str, shard: &Sh
// ------------------------------------------------------------------------
// check for required files
check_files();
ensure_shard_initialized(shard);
// ------------------------------------------------------------------------
// initialize the enclave
#[cfg(feature = "production")]
Expand Down Expand Up @@ -583,21 +582,6 @@ fn get_balance(api: &Api<sr25519::Pair>, who: &AccountId32) -> u128 {
}
}

fn ensure_shard_initialized(shard: &ShardIdentifier) {
let shardenc = shard.encode().to_base58();
if !Path::new(&format!(
"{}/{}/{}",
constants::SHARDS_PATH,
&shardenc,
constants::ENCRYPTED_STATE_FILE
))
.exists()
{
panic!("shard {} hasn't been initialized", shardenc);
}
debug!("state file is present for shard {}", shardenc);
}

pub fn check_files() {
debug!("*** Check files");
let files = vec![
Expand Down