Skip to content

Commit

Permalink
evm: make confidentiality a config option
Browse files Browse the repository at this point in the history
  • Loading branch information
nhynes committed May 16, 2022
1 parent 8596d78 commit c94b02f
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 136 deletions.
3 changes: 0 additions & 3 deletions runtime-sdk/modules/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,3 @@ fixed-hash = "0.7.0"
primitive-types = { version = "0.10.1", default-features = false, features = ["rlp", "num-traits"] }
rlp = "0.5.1"
uint = "0.9.1"

[features]
confidential = [] # Use confidential storage by default.
26 changes: 21 additions & 5 deletions runtime-sdk/modules/evm/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ pub struct Vicinity {
pub origin: H160,
}

/// This macro is like `fn with_storage(ctx, addr, f: FnOnce(impl Storage) -> T) ->T`
/// that chooses public/confidential storage, if that such a function were possible to
/// write without the compiler complaining about unspecified generic type errors.
macro_rules! with_storage {
($ctx:expr, $addr:expr, |$store:ident| $handler:expr) => {
if Cfg::CONFIDENTIAL {
#[allow(unused_mut)]
let mut $store = state::confidential_storage($ctx, $addr);
$handler
} else {
#[allow(unused_mut)]
let mut $store = state::public_storage($ctx, $addr);
$handler
}
};
}

/// Backend for the evm crate that enables the use of our storage.
pub struct Backend<'ctx, C: Context, Cfg: Config> {
vicinity: Vicinity,
Expand Down Expand Up @@ -125,8 +142,7 @@ impl<'ctx, C: Context, Cfg: Config> EVMBackend for Backend<'ctx, C, Cfg> {
let idx: H256 = index.into();

let mut ctx = self.ctx.borrow_mut();
let store = state::storage(*ctx, &address);
let res: H256 = store.get(&idx).unwrap_or_default();
let res: H256 = with_storage!(*ctx, &address, |store| store.get(&idx).unwrap_or_default());
res.into()
}

Expand Down Expand Up @@ -241,11 +257,11 @@ impl<'c, C: Context, Cfg: Config> ApplyBackendResult for Backend<'c, C, Cfg> {
let idx: H256 = index.into();
let val: H256 = value.into();

let mut store = state::storage(*self.ctx.get_mut(), &addr);
let ctx = self.ctx.get_mut();
if value == primitive_types::H256::default() {
store.remove(&idx);
with_storage!(*ctx, &addr, |store| store.remove(&idx));
} else {
store.insert(&idx, val);
with_storage!(*ctx, &addr, |store| store.insert(&idx, val));
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions runtime-sdk/modules/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ pub trait Config: 'static {
/// Token denomination used as the native EVM token.
const TOKEN_DENOMINATION: token::Denomination;

/// Whether to use confidential storage by default, and transaction data encryption.
const CONFIDENTIAL: bool = false;

/// Maps an Ethereum address into an SDK account address.
fn map_address(address: primitive_types::H160) -> Address {
Address::new(
Expand Down
2 changes: 2 additions & 0 deletions runtime-sdk/modules/evm/src/raw_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ mod test {

use super::decode;

#[allow(clippy::too_many_arguments)]
fn decode_expect_call(
raw: &str,
expected_chain_id: Option<u64>,
Expand Down Expand Up @@ -241,6 +242,7 @@ mod test {
assert_eq!(tx.auth_info.fee.gas, expected_gas_limit);
}

#[allow(clippy::too_many_arguments)]
fn decode_expect_create(
raw: &str,
expected_chain_id: Option<u64>,
Expand Down
36 changes: 6 additions & 30 deletions runtime-sdk/modules/evm/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,16 @@ pub const STORAGES: &[u8] = &[0x02];
/// Prefix for Ethereum block hashes (only for last BLOCK_HASH_WINDOW_SIZE blocks
/// excluding current) storage in our storage (maps Round -> H256).
pub const BLOCK_HASHES: &[u8] = &[0x03];
#[cfg(feature = "confidential")]
/// Prefix for Ethereum account storage in our confidential storage (maps H160||H256 -> H256).
pub const CONFIDENTIAL_STORAGES: &[u8] = &[0x04];

#[cfg(feature = "confidential")]
/// Confidential store key pair ID domain separation context base.
pub const CONFIDENTIAL_STORE_KEY_PAIR_ID_CONTEXT_BASE: &[u8] = b"oasis-runtime-sdk/evm: state";
#[cfg(feature = "confidential")]
const CONTEXT_KEY_CONFIDENTIAL_STORE_INSTANCE_COUNT: &str = "evm.ConfidentialStoreCounter";

/// The number of hash blocks that can be obtained from the current blockchain.
pub const BLOCK_HASH_WINDOW_SIZE: u64 = 256;

/// Get a typed store for the given address' storage.
pub fn storage<'a, C: Context>(
ctx: &'a mut C,
address: &'a H160,
) -> storage::TypedStore<impl storage::Store + 'a> {
#[cfg(feature = "confidential")]
{
confidential_storage(ctx, address)
}
#[cfg(not(feature = "confidential"))]
{
public_storage(ctx, address)
}
}

pub fn public_storage<'a, C: Context>(
ctx: &'a mut C,
address: &'a H160,
Expand All @@ -46,26 +28,20 @@ pub fn public_storage<'a, C: Context>(
))
}

#[cfg(feature = "confidential")]
pub fn confidential_storage<'a, C: Context>(
ctx: &'a mut C,
address: &'a H160,
) -> storage::TypedStore<Box<dyn storage::Store + 'a>> {
fn empty_store() -> storage::TypedStore<Box<dyn storage::Store>> {
storage::TypedStore::new(Box::new(storage::EmptyStore::new()))
}
let kmgr_client = match ctx.key_manager() {
Some(kmgr_client) => kmgr_client,
None => return empty_store(),
};
let kmgr_client = ctx
.key_manager()
.expect("key manager must be available to use confidential storage");
let key_id = oasis_runtime_sdk::keymanager::get_key_pair_id(&[
CONFIDENTIAL_STORE_KEY_PAIR_ID_CONTEXT_BASE,
address.as_ref(),
]);
let keypair = match kmgr_client.get_or_create_keys(key_id) {
Ok(keypair) => keypair,
Err(_) => return empty_store(),
};
let keypair = kmgr_client
.get_or_create_keys(key_id)
.expect("unable to retrieve confidential storage keys");
let confidential_key = keypair.state_key;

// These values are used to derive the confidential store nonce:
Expand Down
94 changes: 61 additions & 33 deletions runtime-sdk/modules/evm/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,17 @@ impl Config for EVMConfig {
const TOKEN_DENOMINATION: Denomination = Denomination::NATIVE;
}

type EVM = EVMModule<EVMConfig>;
struct ConfidentialEVMConfig;

impl Config for ConfidentialEVMConfig {
type Accounts = Accounts;

const CHAIN_ID: u64 = 0x5afe;

const TOKEN_DENOMINATION: Denomination = Denomination::NATIVE;

const CONFIDENTIAL: bool = true;
}

fn load_erc20() -> Vec<u8> {
Vec::from_hex(
Expand Down Expand Up @@ -83,8 +93,7 @@ fn test_evm_caller_addr_derivation() {
assert_eq!(derived, expected);
}

#[test]
fn test_evm_calls() {
fn do_test_evm_calls<C: Config>() {
let mut mock = mock::Mock::default();
let mut ctx = mock.create_ctx();

Expand Down Expand Up @@ -120,7 +129,7 @@ fn test_evm_calls() {
},
);

EVM::init(
EVMModule::<C>::init(
&mut ctx,
Genesis {
parameters: Default::default(),
Expand All @@ -137,7 +146,7 @@ fn test_evm_calls() {
method: "evm.Create".to_owned(),
body: cbor::to_value(types::Create {
value: 0.into(),
init_code: erc20.clone(),
init_code: erc20,
}),
},
auth_info: transaction::AuthInfo {
Expand All @@ -157,11 +166,11 @@ fn test_evm_calls() {

let erc20_addr = ctx.with_tx(0, create_tx, |mut tx_ctx, call| {
let addr = H160::from_slice(
&EVM::tx_create(&mut tx_ctx, cbor::from_value(call.body).unwrap())
&EVMModule::<C>::tx_create(&mut tx_ctx, cbor::from_value(call.body).unwrap())
.expect("create should succeed"),
);

EVM::check_invariants(&mut tx_ctx).expect("invariants should hold");
EVMModule::<C>::check_invariants(&mut tx_ctx).expect("invariants should hold");

tx_ctx.commit();

Expand Down Expand Up @@ -197,10 +206,10 @@ fn test_evm_calls() {
Accounts::authenticate_tx(&mut ctx, &call_name_tx).unwrap();

let erc20_name = ctx.with_tx(0, call_name_tx, |mut tx_ctx, call| {
let name = EVM::tx_call(&mut tx_ctx, cbor::from_value(call.body).unwrap())
let name = EVMModule::<C>::tx_call(&mut tx_ctx, cbor::from_value(call.body).unwrap())
.expect("call name should succeed");

EVM::check_invariants(&mut tx_ctx).expect("invariants should hold");
EVMModule::<C>::check_invariants(&mut tx_ctx).expect("invariants should hold");

tx_ctx.commit();

Expand All @@ -211,19 +220,29 @@ fn test_evm_calls() {
assert_eq!(erc20_name[64..68], vec![0x54, 0x65, 0x73, 0x74]); // "Test".
}

#[test]
fn test_evm_calls() {
do_test_evm_calls::<EVMConfig>();
}

#[test]
fn test_c10l_evm_calls() {
do_test_evm_calls::<ConfidentialEVMConfig>();
}

struct CoreConfig;

impl core::Config for CoreConfig {}

/// EVM test runtime.
struct EVMRuntime;
struct EVMRuntime<C>(C);

impl Runtime for EVMRuntime {
impl<C: Config> Runtime for EVMRuntime<C> {
const VERSION: Version = Version::new(0, 0, 0);

type Core = Core<CoreConfig>;

type Modules = (Core<CoreConfig>, Accounts, EVM);
type Modules = (Core<CoreConfig>, Accounts, EVMModule<C>);

fn genesis_state() -> <Self::Modules as module::MigrationHandler>::Genesis {
(
Expand Down Expand Up @@ -258,12 +277,11 @@ impl Runtime for EVMRuntime {
}
}

#[test]
fn test_evm_runtime() {
fn do_test_evm_runtime<C: Config>() {
let mut mock = mock::Mock::default();
let mut ctx = mock.create_ctx_for_runtime::<EVMRuntime>(context::Mode::ExecuteTx);
let mut ctx = mock.create_ctx_for_runtime::<EVMRuntime<C>>(context::Mode::ExecuteTx);

EVMRuntime::migrate(&mut ctx);
EVMRuntime::<C>::migrate(&mut ctx);

let erc20 = load_erc20();

Expand Down Expand Up @@ -291,15 +309,15 @@ fn test_evm_runtime() {
},
};
// Run authentication handler to simulate nonce increments.
<EVMRuntime as Runtime>::Modules::authenticate_tx(&mut ctx, &create_tx).unwrap();
<EVMRuntime<C> as Runtime>::Modules::authenticate_tx(&mut ctx, &create_tx).unwrap();

let erc20_addr = ctx.with_tx(0, create_tx, |mut tx_ctx, call| {
let addr = H160::from_slice(
&EVM::tx_create(&mut tx_ctx, cbor::from_value(call.body).unwrap())
&EVMModule::<C>::tx_create(&mut tx_ctx, cbor::from_value(call.body).unwrap())
.expect("create should succeed"),
);

EVM::check_invariants(&mut tx_ctx).expect("invariants should hold");
EVMModule::<C>::check_invariants(&mut tx_ctx).expect("invariants should hold");

tx_ctx.commit();

Expand Down Expand Up @@ -330,17 +348,17 @@ fn test_evm_runtime() {
},
};
// Run authentication handler to simulate nonce increments.
<EVMRuntime as Runtime>::Modules::authenticate_tx(&mut ctx, &out_of_gas_create).unwrap();
<EVMRuntime<C> as Runtime>::Modules::authenticate_tx(&mut ctx, &out_of_gas_create).unwrap();

ctx.with_tx(0, out_of_gas_create.clone(), |mut tx_ctx, call| {
EVM::tx_create(&mut tx_ctx, cbor::from_value(call.body).unwrap())
EVMModule::<C>::tx_create(&mut tx_ctx, cbor::from_value(call.body).unwrap())
.expect_err("call transfer should fail");
});

// CheckTx should not fail.
ctx.with_child(context::Mode::CheckTx, |mut check_ctx| {
check_ctx.with_tx(0, out_of_gas_create, |mut tx_ctx, call| {
let rsp = EVM::tx_create(&mut tx_ctx, cbor::from_value(call.body).unwrap())
let rsp = EVMModule::<C>::tx_create(&mut tx_ctx, cbor::from_value(call.body).unwrap())
.expect("call should succeed with empty result");

assert_eq!(
Expand Down Expand Up @@ -377,15 +395,15 @@ fn test_evm_runtime() {
},
};
// Run authentication handler to simulate nonce increments.
<EVMRuntime as Runtime>::Modules::authenticate_tx(&mut ctx, &call_name_tx).unwrap();
<EVMRuntime<C> as Runtime>::Modules::authenticate_tx(&mut ctx, &call_name_tx).unwrap();

// Test transaction call in simulate mode.
ctx.with_child(context::Mode::SimulateTx, |mut sim_ctx| {
let erc20_name = sim_ctx.with_tx(0, call_name_tx.clone(), |mut tx_ctx, call| {
let name = EVM::tx_call(&mut tx_ctx, cbor::from_value(call.body).unwrap())
let name = EVMModule::<C>::tx_call(&mut tx_ctx, cbor::from_value(call.body).unwrap())
.expect("call name should succeed");

EVM::check_invariants(&mut tx_ctx).expect("invariants should hold");
EVMModule::<C>::check_invariants(&mut tx_ctx).expect("invariants should hold");

tx_ctx.commit();

Expand All @@ -397,10 +415,10 @@ fn test_evm_runtime() {
});

let erc20_name = ctx.with_tx(0, call_name_tx.clone(), |mut tx_ctx, call| {
let name = EVM::tx_call(&mut tx_ctx, cbor::from_value(call.body).unwrap())
let name = EVMModule::<C>::tx_call(&mut tx_ctx, cbor::from_value(call.body).unwrap())
.expect("call name should succeed");

EVM::check_invariants(&mut tx_ctx).expect("invariants should hold");
EVMModule::<C>::check_invariants(&mut tx_ctx).expect("invariants should hold");

tx_ctx.commit();

Expand Down Expand Up @@ -444,13 +462,13 @@ fn test_evm_runtime() {
},
};
// Run authentication handler to simulate nonce increments.
<EVMRuntime as Runtime>::Modules::authenticate_tx(&mut ctx, &call_transfer_tx).unwrap();
<EVMRuntime<C> as Runtime>::Modules::authenticate_tx(&mut ctx, &call_transfer_tx).unwrap();

let transfer_ret = ctx.with_tx(0, call_transfer_tx.clone(), |mut tx_ctx, call| {
let ret = EVM::tx_call(&mut tx_ctx, cbor::from_value(call.body).unwrap())
let ret = EVMModule::<C>::tx_call(&mut tx_ctx, cbor::from_value(call.body).unwrap())
.expect("call transfer should succeed");

EVM::check_invariants(&mut tx_ctx).expect("invariants should hold");
EVMModule::<C>::check_invariants(&mut tx_ctx).expect("invariants should hold");

tx_ctx.commit();

Expand Down Expand Up @@ -485,17 +503,17 @@ fn test_evm_runtime() {
},
},
};
<EVMRuntime as Runtime>::Modules::authenticate_tx(&mut ctx, &out_of_gas_tx).unwrap();
<EVMRuntime<C> as Runtime>::Modules::authenticate_tx(&mut ctx, &out_of_gas_tx).unwrap();

ctx.with_tx(0, out_of_gas_tx.clone(), |mut tx_ctx, call| {
EVM::tx_call(&mut tx_ctx, cbor::from_value(call.body).unwrap())
EVMModule::<C>::tx_call(&mut tx_ctx, cbor::from_value(call.body).unwrap())
.expect_err("call transfer should fail");
});

// CheckTx should not fail.
ctx.with_child(context::Mode::CheckTx, |mut check_ctx| {
check_ctx.with_tx(0, out_of_gas_tx, |mut tx_ctx, call| {
let rsp = EVM::tx_call(&mut tx_ctx, cbor::from_value(call.body).unwrap())
let rsp = EVMModule::<C>::tx_call(&mut tx_ctx, cbor::from_value(call.body).unwrap())
.expect("call should succeed with empty result");

assert_eq!(
Expand All @@ -507,6 +525,16 @@ fn test_evm_runtime() {
});
}

#[test]
fn test_evm_runtime() {
do_test_evm_runtime::<EVMConfig>();
}

#[test]
fn test_c10l_evm_runtime() {
do_test_evm_runtime::<ConfidentialEVMConfig>();
}

#[test]
fn test_revert_reason_decoding() {
let long_reason = vec![0x61; 1050];
Expand Down
Loading

0 comments on commit c94b02f

Please sign in to comment.