Skip to content

Commit

Permalink
runtime-sdk: Add confidential store
Browse files Browse the repository at this point in the history
  • Loading branch information
jberci committed Feb 11, 2022
1 parent 7558627 commit 485fdec
Show file tree
Hide file tree
Showing 22 changed files with 1,172 additions and 60 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

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

5 changes: 5 additions & 0 deletions runtime-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ oasis-runtime-sdk-macros = { path = "../runtime-sdk-macros", optional = true }
byteorder = "1.4.3"
curve25519-dalek = "3.2.0"
digest = "0.9.0"
hmac = "0.11.0"
sha2 = "0.9.8"
sha3 = { version = "0.9", default-features = false }
k256 = { version = "0.9.6" }
Expand All @@ -33,6 +34,10 @@ once_cell = "1.8.0"
slog = "2.7.0"
tiny-keccak = { version = "2.0", features = ["tuple_hash"] }
tokio = { version = "1", features = ["rt"] }
zeroize = "1.4"

[dev-dependencies]
blake3 = { version = "1.2.0", features = ["traits-preview"] }

[features]
default = ["oasis-runtime-sdk-macros"]
Expand Down
2 changes: 1 addition & 1 deletion runtime-sdk/modules/contracts/src/abi/oasis/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ impl<Cfg: Config> OasisV1<Cfg> {
fn get_instance_store<'a, C: Context>(
ec: &'a mut ExecutionContext<'_, C>,
store_kind: u32,
) -> Result<impl Store + 'a, wasm3::Trap> {
) -> Result<Box<dyn Store + 'a>, wasm3::Trap> {
// Determine which store we should be using.
let store_kind: StoreKind = store_kind.try_into().map_err(|_| wasm3::Trap::Abort)?;

Expand Down
7 changes: 5 additions & 2 deletions runtime-sdk/modules/contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ use oasis_runtime_sdk::{
modules,
modules::{accounts::API as _, core::API as _},
runtime::Runtime,
sdk_derive,
storage::{self, Store as _},
sdk_derive, storage,
};

mod abi;
Expand Down Expand Up @@ -114,6 +113,10 @@ pub enum Error {
#[sdk_error(code = 19)]
CodeAlreadyUpgraded(u64),

#[error("abort: {0}")]
#[sdk_error(code = 20, abort)]
Abort(#[from] sdk::dispatcher::Error),

#[error("core: {0}")]
#[sdk_error(transparent)]
Core(#[from] modules::core::Error),
Expand Down
4 changes: 4 additions & 0 deletions runtime-sdk/modules/contracts/src/results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ use crate::{
/// not exceeded as that could result in a stack overflow.
const CONTEXT_KEY_DEPTH: &str = "contracts.CallDepth";

pub(crate) fn get_current_subcall_depth<C: Context>(ctx: &mut C) -> u16 {
*ctx.value(CONTEXT_KEY_DEPTH).or_default()
}

/// Process an execution result by performing gas accounting and returning the inner result.
pub(crate) fn process_execution_result<C: TxContext>(
ctx: &mut C,
Expand Down
65 changes: 60 additions & 5 deletions runtime-sdk/modules/contracts/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,61 @@
use oasis_contract_sdk_types::storage::StoreKind;
use oasis_runtime_sdk::{
context::Context,
dispatcher,
keymanager::{self, StateKey},
storage::{self, Store},
};

use crate::{state, types, Error, MODULE_NAME};
use crate::{results, state, types, Error, MODULE_NAME};

/// Confidential store key pair ID domain separation context base.
pub const CONFIDENTIAL_STORE_KEY_PAIR_ID_CONTEXT_BASE: &[u8] =
b"oasis-runtime-sdk/contracts: state";

const CONTEXT_KEY_CONFIDENTIAL_STORE_INSTANCE_COUNT: &str = "contracts.ConfidentialStoreCounter";

/// Create a contract instance store.
///
/// Confidential stores are only available in transaction contexts.
pub fn for_instance<'a, C: Context>(
ctx: &'a mut C,
instance_info: &types::Instance,
store_kind: StoreKind,
) -> Result<impl Store + 'a, Error> {
) -> Result<Box<dyn Store + 'a>, Error> {
// subcall_count, instance_count, round are all used as nonce derivation context
// in the confidential store. Along with confidential_key, they all need ctx,
// which becomes unavailable after the first PrefixStore is created, since that
// keeps a mutable reference to it (via runtime_state()).
let subcall_count = if let StoreKind::Confidential = store_kind {
results::get_current_subcall_depth(ctx)
} else {
0
};
let instance_count: Option<usize> = if let StoreKind::Confidential = store_kind {
let cnt = *ctx
.value(CONTEXT_KEY_CONFIDENTIAL_STORE_INSTANCE_COUNT)
.or_default();
ctx.value(CONTEXT_KEY_CONFIDENTIAL_STORE_INSTANCE_COUNT)
.set(cnt + 1);
Some(cnt)
} else {
None
};
let round = ctx.runtime_header().round;
let confidential_key: Option<StateKey> = if let StoreKind::Confidential = store_kind {
let kmgr_client = ctx.key_manager().ok_or(Error::Unsupported)?;
let kid = keymanager::get_key_pair_id(&[
CONFIDENTIAL_STORE_KEY_PAIR_ID_CONTEXT_BASE,
&instance_info.id.to_storage_key(),
]);
let kp = kmgr_client
.get_or_create_keys(kid)
.map_err(|err| Error::Abort(dispatcher::Error::KeyManagerFailure(err)))?;
Some(kp.state_key)
} else {
None
};

let store = storage::PrefixStore::new(ctx.runtime_state(), &MODULE_NAME);
let instance_prefix = instance_info.id.to_storage_key();
let contract_state = storage::PrefixStore::new(
Expand All @@ -23,10 +67,21 @@ pub fn for_instance<'a, C: Context>(

match store_kind {
// For public storage we use a hashed store using the Blake3 hash function.
StoreKind::Public => Ok(storage::HashedStore::<_, blake3::Hasher>::new(
StoreKind::Public => Ok(Box::new(storage::HashedStore::<_, blake3::Hasher>::new(
contract_state,
)),
))),

StoreKind::Confidential => Err(Error::Unsupported), // Not yet implemented.
StoreKind::Confidential => {
let confidential_store = storage::ConfidentialStore::new_with_key(
contract_state,
confidential_key.unwrap().0,
&[
round.to_le_bytes().as_slice(),
subcall_count.to_le_bytes().as_slice(),
instance_count.unwrap().to_le_bytes().as_slice(),
],
);
Ok(Box::new(confidential_store))
}
}
}
20 changes: 10 additions & 10 deletions runtime-sdk/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use oasis_core_runtime::{

use crate::{
event::{Event, EventTag, EventTags},
keymanager::KeyManagerClientWithContext,
keymanager::KeyManager,
modules::core::Error,
runtime,
storage::{self, NestedStore, Store},
Expand Down Expand Up @@ -123,7 +123,7 @@ pub trait Context {
}

/// The key manager, if the runtime is confidential.
fn key_manager(&self) -> Option<&KeyManagerClientWithContext<'_>>;
fn key_manager(&self) -> Option<&dyn KeyManager>;

/// Last runtime block header.
fn runtime_header(&self) -> &roothash::Header;
Expand Down Expand Up @@ -244,7 +244,7 @@ pub struct RuntimeBatchContext<'a, R: runtime::Runtime, S: NestedStore> {
mode: Mode,

host_info: &'a HostInfo,
key_manager: Option<KeyManagerClientWithContext<'a>>,
key_manager: Option<Box<dyn KeyManager>>,
runtime_header: &'a roothash::Header,
runtime_round_results: &'a roothash::RoundResults,
runtime_storage: S,
Expand Down Expand Up @@ -275,7 +275,7 @@ impl<'a, R: runtime::Runtime, S: NestedStore> RuntimeBatchContext<'a, R, S> {
pub fn new(
mode: Mode,
host_info: &'a HostInfo,
key_manager: Option<KeyManagerClientWithContext<'a>>,
key_manager: Option<Box<dyn KeyManager>>,
runtime_header: &'a roothash::Header,
runtime_round_results: &'a roothash::RoundResults,
runtime_storage: S,
Expand Down Expand Up @@ -308,7 +308,7 @@ impl<'a, R: runtime::Runtime, S: NestedStore> RuntimeBatchContext<'a, R, S> {
pub(crate) fn from_runtime(
ctx: &'a mut RuntimeContext<'_>,
host_info: &'a HostInfo,
key_manager: Option<KeyManagerClientWithContext<'a>>,
key_manager: Option<Box<dyn KeyManager>>,
) -> RuntimeBatchContext<'a, R, storage::MKVSStore<&'a mut dyn mkvs::MKVS>> {
let mode = if ctx.check_only {
Mode::CheckTx
Expand Down Expand Up @@ -352,8 +352,8 @@ impl<'a, R: runtime::Runtime, S: NestedStore> Context for RuntimeBatchContext<'a
self.host_info
}

fn key_manager(&self) -> Option<&KeyManagerClientWithContext<'a>> {
self.key_manager.as_ref()
fn key_manager(&self) -> Option<&dyn KeyManager> {
self.key_manager.as_ref().map(Box::as_ref)
}

fn runtime_header(&self) -> &roothash::Header {
Expand Down Expand Up @@ -517,7 +517,7 @@ pub struct RuntimeTxContext<'round, 'store, R: runtime::Runtime, S: Store> {
mode: Mode,

host_info: &'round HostInfo,
key_manager: Option<KeyManagerClientWithContext<'round>>,
key_manager: Option<Box<dyn KeyManager>>,
runtime_header: &'round roothash::Header,
runtime_round_results: &'round roothash::RoundResults,
consensus_state: &'round consensus::state::ConsensusState,
Expand Down Expand Up @@ -568,8 +568,8 @@ impl<'round, 'store, R: runtime::Runtime, S: Store> Context
self.host_info
}

fn key_manager(&self) -> Option<&KeyManagerClientWithContext<'round>> {
self.key_manager.as_ref()
fn key_manager(&self) -> Option<&dyn KeyManager> {
self.key_manager.as_ref().map(Box::as_ref)
}

fn runtime_header(&self) -> &roothash::Header {
Expand Down
4 changes: 2 additions & 2 deletions runtime-sdk/src/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl From<module::CallResult> for DispatchResult {
/// The runtime dispatcher.
pub struct Dispatcher<R: Runtime> {
host_info: HostInfo,
key_manager: Option<KeyManagerClient>,
key_manager: Option<Arc<KeyManagerClient>>,
schedule_control_host: Arc<dyn ScheduleControlHost>,
_runtime: PhantomData<R>,
}
Expand All @@ -117,7 +117,7 @@ impl<R: Runtime> Dispatcher<R> {
/// instance can be used directly with the dispatcher system provided by Oasis Core.
pub(super) fn new(
host_info: HostInfo,
key_manager: Option<KeyManagerClient>,
key_manager: Option<Arc<KeyManagerClient>>,
schedule_control_host: Arc<dyn ScheduleControlHost>,
) -> Self {
Self {
Expand Down
Loading

0 comments on commit 485fdec

Please sign in to comment.