diff --git a/Cargo.lock b/Cargo.lock index cb73618dc44..05eeec2ecd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -345,7 +345,6 @@ dependencies = [ "rustracing_jaeger 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_cbor 0.9.0 (git+https://github.com/pyfisch/cbor?rev=114ecaeac53799d0bf81ca8d1b980c7c419d76fe)", "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -392,7 +391,6 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lru 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_cbor 0.9.0 (git+https://github.com/pyfisch/cbor?rev=114ecaeac53799d0bf81ca8d1b980c7c419d76fe)", "sgx-isa 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp800-185 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -423,7 +421,7 @@ dependencies = [ "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_cbor 0.9.0 (git+https://github.com/pyfisch/cbor?rev=114ecaeac53799d0bf81ca8d1b980c7c419d76fe)", + "serde_cbor 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "sgx-isa 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1303,8 +1301,8 @@ dependencies = [ [[package]] name = "serde_cbor" -version = "0.9.0" -source = "git+https://github.com/pyfisch/cbor?rev=114ecaeac53799d0bf81ca8d1b980c7c419d76fe#114ecaeac53799d0bf81ca8d1b980c7c419d76fe" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "half 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2108,7 +2106,7 @@ dependencies = [ "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4" "checksum serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "defbb8a83d7f34cc8380751eeb892b825944222888aff18996ea7901f24aec88" -"checksum serde_cbor 0.9.0 (git+https://github.com/pyfisch/cbor?rev=114ecaeac53799d0bf81ca8d1b980c7c419d76fe)" = "" +"checksum serde_cbor 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6ef26f80c739ba7709ec3275c582a1691c5b261f4ce06edd8f539008fa1a36d" "checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79" "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "checksum sgx-isa 0.2.0 (git+https://github.com/fortanix/rust-sgx?rev=ecf51e6b48c854242841f169edbfb14445fd59fb)" = "" diff --git a/client/Cargo.toml b/client/Cargo.toml index d71066b6bdc..298c49cf4d6 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -9,8 +9,6 @@ ekiden-runtime = { path = "../runtime" } serde = "1.0.71" serde_bytes = "~0.10" serde_derive = "1.0" -# TODO: Change to released version when 0.10.0 is released. -serde_cbor = { git = "https://github.com/pyfisch/cbor", rev = "114ecaeac53799d0bf81ca8d1b980c7c419d76fe" } failure = "0.1.5" futures = "0.1.25" tokio-executor = "0.1.6" diff --git a/client/src/lib.rs b/client/src/lib.rs index 0ace95ff37b..619ce55a8c2 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -11,7 +11,6 @@ extern crate rustracing; extern crate rustracing_jaeger; extern crate serde; extern crate serde_bytes; -extern crate serde_cbor; extern crate serde_derive; #[macro_use] extern crate failure; diff --git a/client/src/rpc/client.rs b/client/src/rpc/client.rs index f7b465b7fc6..c3bfededfc8 100644 --- a/client/src/rpc/client.rs +++ b/client/src/rpc/client.rs @@ -14,10 +14,10 @@ use futures::{ use grpcio::Channel; use io_context::Context; use serde::{de::DeserializeOwned, Serialize}; -use serde_cbor; use tokio_executor::spawn; use ekiden_runtime::{ + common::cbor, protocol::Protocol, rpc::{ session::{Builder, Session}, @@ -61,7 +61,7 @@ trait Transport: Send + Sync { payload: data, }; - self.write_message_impl(ctx, serde_cbor::to_vec(&frame).unwrap()) + self.write_message_impl(ctx, cbor::to_vec(&frame)) } fn write_message_impl(&self, ctx: Context, data: Vec) -> BoxFuture>; @@ -197,16 +197,13 @@ impl RpcClient { { let request = types::Request { method: method.to_owned(), - args: match serde_cbor::to_value(args) { - Ok(args) => args, - Err(error) => return Box::new(future::err(error.into())), - }, + args: cbor::to_value(args), }; Box::new( self.execute_call(ctx, request) .and_then(|response| match response.body { - types::Body::Success(value) => Ok(serde_cbor::from_value(value)?), + types::Body::Success(value) => Ok(cbor::from_value(value)?), types::Body::Error(error) => Err(RpcClientError::CallFailed(error).into()), }), ) diff --git a/client/src/transaction/client.rs b/client/src/transaction/client.rs index f7ef5c2fffc..e5b75d6cae2 100644 --- a/client/src/transaction/client.rs +++ b/client/src/transaction/client.rs @@ -7,10 +7,9 @@ use grpcio::{Channel, Error::RpcFailure, RpcStatus, RpcStatusCode}; use rustracing::{sampler::AllSampler, tag}; use rustracing_jaeger::{span::Span, Tracer}; use serde::{de::DeserializeOwned, Serialize}; -use serde_cbor; use ekiden_runtime::{ - common::{crypto::hash::Hash, runtime::RuntimeId}, + common::{cbor, crypto::hash::Hash, runtime::RuntimeId}, transaction::types::{TxnBatch, TxnCall, TxnOutput}, }; @@ -67,10 +66,7 @@ impl TxnClient { { let call = TxnCall { method: method.to_owned(), - args: match serde_cbor::to_value(args) { - Ok(args) => args, - Err(error) => return Box::new(future::err(error.into())), - }, + args: cbor::to_value(args), }; Box::new( @@ -88,10 +84,7 @@ impl TxnClient { let mut request = api::client::SubmitTxRequest::new(); request.set_runtime_id(self.runtime_id.as_ref().to_vec()); - match serde_cbor::to_vec(&call) { - Ok(data) => request.set_data(data), - Err(error) => return Box::new(future::err(error.into())), - } + request.set_data(cbor::to_vec(&call)); match self.client.submit_tx_async_opt(&request, options) { Ok(resp) => Box::new( @@ -165,7 +158,7 @@ impl TxnClient { .and_then(move |rsp| { Ok(BlockSnapshot::new( storage_client.clone(), - serde_cbor::from_slice(&rsp.block)?, + cbor::from_slice(&rsp.block)?, Hash::from(rsp.block_hash), )) }), @@ -204,7 +197,7 @@ impl TxnClient { Err(error) => Err(TxnClientError::CallFailed(format!("{}", error)).into()), Ok(rsp) => Ok(Some(BlockSnapshot::new( storage_client, - serde_cbor::from_slice(&rsp.block)?, + cbor::from_slice(&rsp.block)?, Hash::from(rsp.block_hash), ))), })) @@ -236,7 +229,7 @@ impl TxnClient { })) => Ok(None), Err(error) => Err(TxnClientError::CallFailed(format!("{}", error)).into()), Ok(rsp) => { - let rsp: TxnResult = serde_cbor::from_slice(&rsp.result)?; + let rsp: TxnResult = cbor::from_slice(&rsp.result)?; Ok(Some(TransactionSnapshot::new( storage_client, rsp.block, @@ -281,7 +274,7 @@ impl TxnClient { })) => Ok(None), Err(error) => Err(TxnClientError::CallFailed(format!("{}", error)).into()), Ok(rsp) => { - let rsp: TxnResult = serde_cbor::from_slice(&rsp.result)?; + let rsp: TxnResult = cbor::from_slice(&rsp.result)?; Ok(Some(TransactionSnapshot::new( storage_client, rsp.block, @@ -347,7 +340,7 @@ impl TxnClient { Err(error) => Err(TxnClientError::CallFailed(format!("{}", error)).into()), Ok(rsp) => Ok(Some(BlockSnapshot::new( storage_client, - serde_cbor::from_slice(&rsp.block)?, + cbor::from_slice(&rsp.block)?, Hash::from(rsp.block_hash), ))), })) @@ -383,7 +376,7 @@ impl TxnClient { })) => Ok(None), Err(error) => Err(TxnClientError::CallFailed(format!("{}", error)).into()), Ok(rsp) => { - let rsp: TxnResult = serde_cbor::from_slice(&rsp.result)?; + let rsp: TxnResult = cbor::from_slice(&rsp.result)?; Ok(Some(TransactionSnapshot::new( storage_client, rsp.block, @@ -408,10 +401,7 @@ impl TxnClient { let (span, options) = self.prepare_options("TxnClient::query_txn"); let mut request = api::client::QueryTxnsRequest::new(); request.set_runtime_id(self.runtime_id.as_ref().to_vec()); - match serde_cbor::to_vec(&query) { - Ok(query) => request.set_query(query), - Err(error) => return Box::new(future::err(error.into())), - } + request.set_query(cbor::to_vec(&query)); let result: BoxFuture> = match self .client @@ -422,7 +412,7 @@ impl TxnClient { Box::new( resp.map_err(|error| TxnClientError::CallFailed(format!("{}", error)).into()) .and_then(move |rsp| { - let rsp: Vec = serde_cbor::from_slice(&rsp.results)?; + let rsp: Vec = cbor::from_slice(&rsp.results)?; rsp.into_iter() .map(|tx| { TransactionSnapshot::new( @@ -493,9 +483,9 @@ pub fn parse_call_output(output: Vec) -> Fallible where O: DeserializeOwned, { - let output: TxnOutput = serde_cbor::from_slice(&output)?; + let output: TxnOutput = cbor::from_slice(&output)?; match output { - TxnOutput::Success(data) => Ok(serde_cbor::from_value(data)?), + TxnOutput::Success(data) => Ok(cbor::from_value(data)?), TxnOutput::Error(error) => Err(TxnClientError::TxnFailed(error).into()), } } diff --git a/client/src/transaction/snapshot.rs b/client/src/transaction/snapshot.rs index 1679c204023..3e408d08978 100644 --- a/client/src/transaction/snapshot.rs +++ b/client/src/transaction/snapshot.rs @@ -3,6 +3,7 @@ use std::{any::Any, cell::RefCell, rc::Rc}; use ekiden_runtime::{ common::{ + cbor, crypto::hash::Hash, roothash::{Block, Namespace}, }, @@ -20,7 +21,6 @@ use ekiden_runtime::{ }; use failure::{Fallible, ResultExt}; use io_context::Context; -use serde_cbor; use super::{api, client::TxnClientError}; @@ -49,8 +49,8 @@ impl TransactionSnapshot { Ok(Self { block_snapshot: BlockSnapshot::new(storage_client, block, block_hash), index, - input: serde_cbor::from_slice(&input).context("input is malformed")?, - output: serde_cbor::from_slice(&output).context("output is malformed")?, + input: cbor::from_slice(&input).context("input is malformed")?, + output: cbor::from_slice(&output).context("output is malformed")?, }) } } @@ -157,7 +157,7 @@ impl ReadSync for RemoteReadSync { max_depth: u8, ) -> Fallible { let mut request = api::storage::GetSubtreeRequest::new(); - request.set_root(serde_cbor::to_vec(&root).unwrap()); + request.set_root(cbor::to_vec(&root)); request.set_id({ let mut nid = api::storage::NodeID::new(); nid.set_path(id.path.as_ref().to_vec()); @@ -184,7 +184,7 @@ impl ReadSync for RemoteReadSync { start_depth: u8, ) -> Fallible { let mut request = api::storage::GetPathRequest::new(); - request.set_root(serde_cbor::to_vec(&root).unwrap()); + request.set_root(cbor::to_vec(&root)); request.set_key(key.as_ref().to_vec()); request.set_start_depth(start_depth.into()); @@ -200,7 +200,7 @@ impl ReadSync for RemoteReadSync { fn get_node(&mut self, _ctx: Context, root: Root, id: NodeID) -> Fallible { let mut request = api::storage::GetNodeRequest::new(); - request.set_root(serde_cbor::to_vec(&root).unwrap()); + request.set_root(cbor::to_vec(&root)); request.set_id({ let mut nid = api::storage::NodeID::new(); nid.set_path(id.path.as_ref().to_vec()); diff --git a/go/common/namespace.go b/go/common/namespace.go index 1a67761f22c..f6dcdd1f681 100644 --- a/go/common/namespace.go +++ b/go/common/namespace.go @@ -50,6 +50,6 @@ func (n *Namespace) Equal(cmp *Namespace) bool { } // String returns the string representation of a chain namespace identifier. -func (n *Namespace) String() string { +func (n Namespace) String() string { return hex.EncodeToString(n[:]) } diff --git a/go/common/runtime/runtime_test.go b/go/common/runtime/runtime_test.go new file mode 100644 index 00000000000..ce71d55ace1 --- /dev/null +++ b/go/common/runtime/runtime_test.go @@ -0,0 +1,20 @@ +package runtime + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/oasislabs/ekiden/go/common/crypto/hash" +) + +func TestConsistentHash(t *testing.T) { + // NOTE: These hashes MUST be synced with runtime/src/transaction/types.rs. + batch := Batch{[]byte("foo"), []byte("bar"), []byte("aaa")} + var h hash.Hash + h.From(batch) + + var expectedHash hash.Hash + _ = expectedHash.UnmarshalHex("c451dd4fd065b815e784aac6b300e479b2167408f0eebbb95a8bd36b9e71e34d") + require.EqualValues(t, h, expectedHash) +} diff --git a/go/storage/mkvs/urkel/node/node.go b/go/storage/mkvs/urkel/node/node.go index 1bbca79d1d3..affd78e6415 100644 --- a/go/storage/mkvs/urkel/node/node.go +++ b/go/storage/mkvs/urkel/node/node.go @@ -49,6 +49,11 @@ type Root struct { Hash hash.Hash `codec:"hash"` } +// String returns the string representation of a storage root. +func (r Root) String() string { + return fmt.Sprintf("", r.Namespace, r.Round, r.Hash) +} + // MarshalCBOR serializes the type into a CBOR byte vector. func (r *Root) MarshalCBOR() []byte { return cbor.Marshal(r) diff --git a/go/worker/keymanager/keymanager.go b/go/worker/keymanager/keymanager.go index 11cd9e064c0..9a189c76191 100644 --- a/go/worker/keymanager/keymanager.go +++ b/go/worker/keymanager/keymanager.go @@ -308,23 +308,15 @@ func (w *worker) onProcessStart(proto *protocol.Protocol, tee *node.CapabilityTE } func extractMessageResponsePayload(raw []byte) ([]byte, error) { - // Because of how serde_cbor serializes unit enums, simply de-serializing - // the response into a struct is not possible. Do this the hard way. - // - // This could alternatively be done by changing the rust side, or maybe - // this should be a general protocol helper, but this is probably the - // only place that will need such a thing. - // - // See: runtime/src/rcp/types.rs + // See: runtime/src/rpc/types.rs type MessageResponseBody struct { - Status string `codec:""` - Value interface{} `codec:""` + Success interface{} + Error *string } type MessageResponse struct { - Type string `codec:""` - Inner struct { + Response *struct { Body MessageResponseBody `codec:"body"` - } `codec:""` + } } var msg MessageResponse @@ -332,26 +324,19 @@ func extractMessageResponsePayload(raw []byte) ([]byte, error) { return nil, errors.Wrap(err, "malformed message envelope") } - if mType := msg.Type; mType != "Response" { - return nil, fmt.Errorf("message is not a response: '%s'", mType) + if msg.Response == nil { + return nil, fmt.Errorf("message is not a response: '%s'", hex.EncodeToString(raw)) } - switch msg.Inner.Body.Status { - case "Success": - case "Error": - if msg.Inner.Body.Value == nil { - return nil, fmt.Errorf("unknown rpc response failure (nil)") - } - mErr, ok := msg.Inner.Body.Value.(string) - if !ok { - return nil, fmt.Errorf("unknown rpc response failure (%T)", msg.Inner.Body.Value) - } - return nil, fmt.Errorf("rpc failure: '%s'", mErr) + switch { + case msg.Response.Body.Success != nil: + case msg.Response.Body.Error != nil: + return nil, fmt.Errorf("rpc failure: '%s'", *msg.Response.Body.Error) default: - return nil, fmt.Errorf("unknown rpc response status: '%s'", msg.Inner.Body.Status) + return nil, fmt.Errorf("unknown rpc response status: '%s'", hex.EncodeToString(raw)) } - return cbor.Marshal(msg.Inner.Body.Value), nil + return cbor.Marshal(msg.Response.Body.Success), nil } func (w *worker) onNodeRegistration(n *node.Node) error { diff --git a/keymanager-runtime/Cargo.toml b/keymanager-runtime/Cargo.toml index 9b00c395d8c..fb16a06421b 100644 --- a/keymanager-runtime/Cargo.toml +++ b/keymanager-runtime/Cargo.toml @@ -16,8 +16,6 @@ ekiden-keymanager-client = { path = "../keymanager-client" } failure = "0.1.5" lazy_static = "1.3.0" lru = "0.1.15" -# TODO: Change to released version when 0.10.0 is released. -serde_cbor = { git = "https://github.com/pyfisch/cbor", rev = "114ecaeac53799d0bf81ca8d1b980c7c419d76fe" } io-context = "0.2.0" rand = "0.6.5" sgx-isa = { version = "0.2.0", features = ["sgxstd"] } diff --git a/keymanager-runtime/src/kdf.rs b/keymanager-runtime/src/kdf.rs index 4424e7edddc..cf3a8d88a2d 100644 --- a/keymanager-runtime/src/kdf.rs +++ b/keymanager-runtime/src/kdf.rs @@ -6,7 +6,6 @@ use io_context::Context as IoContext; use lazy_static::lazy_static; use lru::LruCache; use rand::{rngs::OsRng, Rng}; -use serde_cbor; use sgx_isa::Keypolicy; use sp800_185::{CShake, KMac}; use tiny_keccak::sha3_256; @@ -21,6 +20,7 @@ use ekiden_keymanager_api::{ use ekiden_keymanager_client::{KeyManagerClient, RemoteClient}; use ekiden_runtime::{ common::{ + cbor, crypto::{ mrae::deoxysii::{DeoxysII, NONCE_SIZE, TAG_SIZE}, signature, @@ -288,7 +288,7 @@ impl Kdf { policy_checksum, }; - let body = serde_cbor::to_vec(&init_response)?; + let body = cbor::to_vec(&init_response); let signature = inner .signer .as_ref() diff --git a/keymanager-runtime/src/main.rs b/keymanager-runtime/src/main.rs index e7cbe86410c..5cf8af5948f 100644 --- a/keymanager-runtime/src/main.rs +++ b/keymanager-runtime/src/main.rs @@ -6,7 +6,6 @@ extern crate io_context; extern crate lazy_static; extern crate lru; extern crate rand; -extern crate serde_cbor; extern crate sp800_185; extern crate tiny_keccak; extern crate x25519_dalek; diff --git a/keymanager-runtime/src/policy.rs b/keymanager-runtime/src/policy.rs index 7c91e55f818..cfd0f0e1486 100644 --- a/keymanager-runtime/src/policy.rs +++ b/keymanager-runtime/src/policy.rs @@ -7,7 +7,6 @@ use std::{ use failure::Fallible; use lazy_static::lazy_static; use rand::{rngs::OsRng, Rng}; -use serde_cbor; use sgx_isa::Keypolicy; use tiny_keccak::sha3_256; use zeroize::Zeroize; @@ -15,6 +14,7 @@ use zeroize::Zeroize; use ekiden_keymanager_api::*; use ekiden_runtime::{ common::{ + cbor, crypto::{ mrae::deoxysii::{DeoxysII, NONCE_SIZE, TAG_SIZE}, signature::{PrivateKey, PublicKey}, @@ -259,10 +259,10 @@ struct CachedPolicy { impl CachedPolicy { fn parse(raw: &Vec) -> Fallible { // Parse out the signed policy. - let untrusted_policy: SignedPolicySGX = serde_cbor::from_slice(&raw)?; + let untrusted_policy: SignedPolicySGX = cbor::from_slice(&raw)?; // Verify the signatures. - let untrusted_policy_raw = serde_cbor::to_vec(&untrusted_policy.policy)?; + let untrusted_policy_raw = cbor::to_vec(&untrusted_policy.policy); let mut signers: HashSet = HashSet::new(); for sig in untrusted_policy.signatures { let public_key = match sig.public_key { diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 5c603907041..d6bccc331f1 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -12,8 +12,7 @@ slog-scope = "4.1.1" slog-stdlog = "3.0.4-pre" serde = "1.0.71" serde_derive = "1.0" -# TODO: Change to released version when 0.10.0 is released. -serde_cbor = { git = "https://github.com/pyfisch/cbor", rev = "114ecaeac53799d0bf81ca8d1b980c7c419d76fe" } +serde_cbor = "0.10" serde_json = "1.0.39" serde_bytes = "~0.10" lazy_static = "1.3.0" diff --git a/runtime/src/common/cbor.rs b/runtime/src/common/cbor.rs new file mode 100644 index 00000000000..83681a90365 --- /dev/null +++ b/runtime/src/common/cbor.rs @@ -0,0 +1,29 @@ +//! Canonical CBOR serialization/deserialization functions. +use serde::{Deserialize, Serialize}; +pub use serde_cbor::value::{from_value, Value}; +use serde_cbor::{self, Result}; + +/// Convert a value to a `Value`. +pub fn to_value(value: T) -> Value +where + T: Serialize, +{ + serde_cbor::value::to_value(value).unwrap() +} + +/// Serializes a value to a vector. +pub fn to_vec(value: &T) -> Vec +where + T: Serialize, +{ + // Use to_value first to force serialization into canonical format. + serde_cbor::to_vec(&to_value(&value)).unwrap() +} + +/// Deserializes a slice to a value. +pub fn from_slice<'a, T>(slice: &'a [u8]) -> Result +where + T: Deserialize<'a>, +{ + serde_cbor::from_slice(slice) +} diff --git a/runtime/src/common/mod.rs b/runtime/src/common/mod.rs index 4dcf58822c0..97e5f3d1788 100644 --- a/runtime/src/common/mod.rs +++ b/runtime/src/common/mod.rs @@ -2,6 +2,7 @@ #[macro_use] pub mod bytes; +pub mod cbor; pub mod crypto; pub mod logger; pub mod roothash; diff --git a/runtime/src/common/roothash.rs b/runtime/src/common/roothash.rs index af71b3dd6f7..8a6e59f9f3d 100644 --- a/runtime/src/common/roothash.rs +++ b/runtime/src/common/roothash.rs @@ -4,10 +4,12 @@ //! //! This **MUST** be kept in sync with go/roothash/api/block. //! -use serde_cbor; use serde_derive::{Deserialize, Serialize}; -use super::crypto::{hash::Hash, signature::SignatureBundle}; +use super::{ + cbor, + crypto::{hash::Hash, signature::SignatureBundle}, +}; /// The key holding inputs in the I/O tree. pub const IO_KEY_INPUTS: &'static [u8] = b"i"; @@ -51,7 +53,7 @@ pub struct Header { impl Header { /// Returns a hash of an encoded header. pub fn encoded_hash(&self) -> Hash { - Hash::digest_bytes(&serde_cbor::to_vec(&self).unwrap()) + Hash::digest_bytes(&cbor::to_vec(&self)) } } diff --git a/runtime/src/dispatcher.rs b/runtime/src/dispatcher.rs index 2bfaf02409e..8313326fca1 100644 --- a/runtime/src/dispatcher.rs +++ b/runtime/src/dispatcher.rs @@ -11,6 +11,7 @@ use slog::Logger; use crate::{ common::{ + cbor, crypto::{ hash::Hash, signature::{Signature, Signer}, @@ -310,7 +311,7 @@ impl Dispatcher { .insert( Context::create_child(&ctx), IO_KEY_INPUTS, - &serde_cbor::to_vec(&inputs).unwrap(), + &cbor::to_vec(&inputs), ) .expect("input insert must succeed"); let (_, old_io_root) = io_mkvs @@ -331,14 +332,14 @@ impl Dispatcher { .insert( Context::create_child(&ctx), IO_KEY_OUTPUTS, - &serde_cbor::to_vec(&outputs).unwrap(), + &cbor::to_vec(&outputs), ) .expect("output insert must succeed"); io_mkvs .insert( Context::create_child(&ctx), IO_KEY_TAGS, - &serde_cbor::to_vec(&tags).unwrap(), + &cbor::to_vec(&tags), ) .expect("tag insert must succeed"); let (io_write_log, io_root) = io_mkvs @@ -363,10 +364,7 @@ impl Dispatcher { let rak_sig = if self.rak.public_key().is_some() { self.rak - .sign( - &COMPUTE_RESULTS_HEADER_CONTEXT, - &serde_cbor::to_vec(&header).unwrap(), - ) + .sign(&COMPUTE_RESULTS_HEADER_CONTEXT, &cbor::to_vec(&header)) .unwrap() } else { Signature::default() @@ -522,7 +520,7 @@ impl Dispatcher { ) { debug!(self.logger, "Received local RPC call request"; "state_root" => ?state_root); - let req: RpcRequest = serde_cbor::from_slice(&request).unwrap(); + let req: RpcRequest = cbor::from_slice(&request).unwrap(); // Request, dispatch. let ctx = ctx.freeze(); @@ -548,7 +546,7 @@ impl Dispatcher { debug!(self.logger, "Local RPC call dispatch complete"); - let response = serde_cbor::to_vec(&response).unwrap(); + let response = cbor::to_vec(&response); let protocol_response = Body::WorkerLocalRPCCallResponse { response }; protocol.send_response(id, protocol_response).unwrap(); diff --git a/runtime/src/protocol.rs b/runtime/src/protocol.rs index 854a7d357a1..c469657a190 100644 --- a/runtime/src/protocol.rs +++ b/runtime/src/protocol.rs @@ -12,11 +12,10 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use crossbeam::channel; use failure::Fallible; use io_context::Context; -use serde_cbor::{self, SerializerOptions}; use slog::Logger; use crate::{ - common::logger::get_logger, + common::{cbor, logger::get_logger}, dispatcher::Dispatcher, rak::RAK, storage::KeyValue, @@ -146,21 +145,14 @@ impl Protocol { let mut buffer = vec![0; length]; reader.read_exact(&mut buffer)?; - Ok(serde_cbor::from_slice(&buffer)?) + Ok(cbor::from_slice(&buffer)?) } fn encode_message(&self, message: Message) -> Fallible<()> { let _guard = self.outgoing_mutex.lock().unwrap(); let mut writer = BufWriter::new(&self.stream); - let buffer = serde_cbor::to_vec_with_options( - &message, - &SerializerOptions { - packed: false, - enum_as_map: true, - self_describe: false, - }, - )?; + let buffer = cbor::to_vec(&message); if buffer.len() > MAX_MESSAGE_SIZE { return Err(ProtocolError::MessageTooLarge.into()); } diff --git a/runtime/src/rpc/demux.rs b/runtime/src/rpc/demux.rs index ea42e1c9830..e2fad674f02 100644 --- a/runtime/src/rpc/demux.rs +++ b/runtime/src/rpc/demux.rs @@ -2,13 +2,15 @@ use std::{collections::HashMap, io::Write, sync::Arc, time::SystemTime}; use failure::Fallible; -use serde_cbor; use super::{ session::{Builder, Session, SessionInfo}, types::{Frame, Message, SessionID}, }; -use crate::{common::time::insecure_posix_system_time, rak::RAK}; +use crate::{ + common::{cbor, time::insecure_posix_system_time}, + rak::RAK, +}; /// Maximum concurrent EnclaveRPC sessions. const DEFAULT_MAX_CONCURRENT_SESSIONS: usize = 100; @@ -89,7 +91,7 @@ impl Demux { data: Vec, writer: W, ) -> Fallible> { - let frame: Frame = serde_cbor::from_slice(&data)?; + let frame: Frame = cbor::from_slice(&data)?; let id = frame.session.clone(); if let Some(enriched_session) = self.sessions.get_mut(&id) { diff --git a/runtime/src/rpc/dispatcher.rs b/runtime/src/rpc/dispatcher.rs index 6ebe9163825..684e59a1071 100644 --- a/runtime/src/rpc/dispatcher.rs +++ b/runtime/src/rpc/dispatcher.rs @@ -3,12 +3,12 @@ use std::collections::HashMap; use failure::Fallible; use serde::{de::DeserializeOwned, Serialize}; -use serde_cbor; use super::{ context::Context, types::{Body, Request, Response}, }; +use crate::common::cbor; /// Dispatch error. #[derive(Debug, Fail)] @@ -82,11 +82,11 @@ where } fn dispatch(&self, request: Request, ctx: &mut Context) -> Fallible { - let request = serde_cbor::from_value(request.args)?; + let request = cbor::from_value(request.args)?; let response = self.handler.handle(&request, ctx)?; Ok(Response { - body: Body::Success(serde_cbor::to_value(response)?), + body: Body::Success(cbor::to_value(response)), }) } } diff --git a/runtime/src/rpc/session.rs b/runtime/src/rpc/session.rs index 230cd46ca45..68ff6c96163 100644 --- a/runtime/src/rpc/session.rs +++ b/runtime/src/rpc/session.rs @@ -2,13 +2,13 @@ use std::{collections::HashSet, io::Write, sync::Arc}; use failure::Fallible; -use serde_cbor; use serde_derive::{Deserialize, Serialize}; use snow; use super::types::Message; use crate::{ common::{ + cbor, crypto::signature::{PublicKey, Signature, Signer}, sgx::avr, }, @@ -142,7 +142,7 @@ impl Session { State::Transport => { // TODO: Restore session in case of errors. let len = session.read_message(&data, &mut self.buf)?; - let msg = serde_cbor::from_slice(&self.buf[..len])?; + let msg = cbor::from_slice(&self.buf[..len])?; self.session = Some(session); return Ok(Some(msg)); @@ -166,7 +166,7 @@ impl Session { let session = self.session.as_mut().ok_or(SessionError::Closed)?; - let msg = serde_cbor::to_vec(&msg)?; + let msg = cbor::to_vec(&msg); let len = session.write_message(&msg, &mut self.buf)?; writer.write_all(&self.buf[..len])?; @@ -198,7 +198,7 @@ impl Session { .unwrap(), }; - serde_cbor::to_vec(&rak_binding).unwrap() + cbor::to_vec(&rak_binding) } None => vec![], } @@ -218,7 +218,7 @@ impl Session { return Ok(None); } - let rak_binding: RAKBinding = serde_cbor::from_slice(rak_binding)?; + let rak_binding: RAKBinding = cbor::from_slice(rak_binding)?; let authenticated_avr = avr::verify(&rak_binding.avr)?; // Verify MRSIGNER/MRENCLAVE. diff --git a/runtime/src/rpc/types.rs b/runtime/src/rpc/types.rs index 70ff974cf28..9aaf1f284ec 100644 --- a/runtime/src/rpc/types.rs +++ b/runtime/src/rpc/types.rs @@ -1,8 +1,9 @@ //! RPC protocol types. use ring::rand::{SecureRandom, SystemRandom}; -use serde_cbor::Value; use serde_derive::{Deserialize, Serialize}; +use crate::common::cbor::Value; + impl_bytes!( SessionID, 32, diff --git a/runtime/src/storage/mkvs/mod.rs b/runtime/src/storage/mkvs/mod.rs index 2f540490068..af087396a15 100644 --- a/runtime/src/storage/mkvs/mod.rs +++ b/runtime/src/storage/mkvs/mod.rs @@ -94,3 +94,23 @@ pub trait MKVS: Send + Sync { // Re-exports. pub use self::urkel::UrkelTree; + +#[cfg(test)] +mod tests { + use super::*; + + use crate::common::cbor; + + #[test] + fn test_write_log_serialization() { + let write_log = vec![LogEntry { + key: b"foo".to_vec(), + value: b"bar".to_vec(), + }]; + + let raw = cbor::to_vec(&write_log); + let deserialized: WriteLog = cbor::from_slice(&raw).unwrap(); + + assert_eq!(write_log, deserialized); + } +} diff --git a/runtime/src/transaction/dispatcher.rs b/runtime/src/transaction/dispatcher.rs index 2693bdb3d67..27aa99304d9 100644 --- a/runtime/src/transaction/dispatcher.rs +++ b/runtime/src/transaction/dispatcher.rs @@ -3,14 +3,13 @@ use std::collections::HashMap; use failure::{Fallible, ResultExt}; use serde::{de::DeserializeOwned, Serialize}; -use serde_cbor::{self, SerializerOptions, Value}; use super::{ context::Context, types::{TxnBatch, TxnCall, TxnOutput}, }; use crate::{ - common::crypto::hash::Hash, + common::{cbor, crypto::hash::Hash}, types::{Tag, TAG_TXN_INDEX_BLOCK}, }; @@ -104,7 +103,7 @@ pub trait MethodHandlerDispatch { fn get_descriptor(&self) -> &MethodDescriptor; /// Dispatches the given raw call. - fn dispatch(&self, call: TxnCall, ctx: &mut Context) -> Fallible; + fn dispatch(&self, call: TxnCall, ctx: &mut Context) -> Fallible; } struct MethodHandlerDispatchImpl { @@ -123,11 +122,11 @@ where &self.descriptor } - fn dispatch(&self, call: TxnCall, ctx: &mut Context) -> Fallible { - let call = serde_cbor::from_value(call.args).context("unable to parse call arguments")?; + fn dispatch(&self, call: TxnCall, ctx: &mut Context) -> Fallible { + let call = cbor::from_value(call.args).context("unable to parse call arguments")?; let response = self.handler.handle(&call, ctx)?; - Ok(serde_cbor::to_value(response)?) + Ok(cbor::to_value(response)) } } @@ -159,7 +158,7 @@ impl Method { } /// Dispatch method call. - pub fn dispatch(&self, call: TxnCall, ctx: &mut Context) -> Fallible { + pub fn dispatch(&self, call: TxnCall, ctx: &mut Context) -> Fallible { self.dispatcher.dispatch(call, ctx) } } @@ -264,26 +263,18 @@ impl Dispatcher { Ok(response) => TxnOutput::Success(response), Err(error) => { if let Some(check_msg) = error.downcast_ref::() { - TxnOutput::Success(serde_cbor::Value::String(format!("{}", check_msg))) + TxnOutput::Success(cbor::Value::Text(format!("{}", check_msg))) } else { TxnOutput::Error(format!("{}", error)) } } }; - serde_cbor::to_vec_with_options( - &rsp, - &SerializerOptions { - packed: false, - enum_as_map: true, - self_describe: false, - }, - ) - .unwrap() + cbor::to_vec(&rsp) } - fn dispatch_fallible(&self, call: &Vec, ctx: &mut Context) -> Fallible { - let call: TxnCall = serde_cbor::from_slice(call).context("unable to parse call")?; + fn dispatch_fallible(&self, call: &Vec, ctx: &mut Context) -> Fallible { + let call: TxnCall = cbor::from_slice(call).context("unable to parse call")?; match self.methods.get(&call.method) { Some(dispatcher) => dispatcher.dispatch(call, ctx), @@ -305,10 +296,9 @@ impl Dispatcher { #[cfg(test)] mod tests { use io_context::Context as IoContext; - use serde_cbor; use serde_derive::{Deserialize, Serialize}; - use crate::common::roothash::Header; + use crate::common::{cbor, roothash::Header}; use super::*; @@ -346,13 +336,12 @@ mod tests { // Prepare a dummy call. let call = TxnCall { method: "dummy".to_owned(), - args: serde_cbor::to_value(Complex { + args: cbor::to_value(Complex { text: "hello".to_owned(), number: 21, - }) - .unwrap(), + }), }; - let call_encoded = serde_cbor::to_vec(&call).unwrap(); + let call_encoded = cbor::to_vec(&call); let header = Header { timestamp: TEST_TIMESTAMP, @@ -364,10 +353,10 @@ mod tests { let result = dispatcher.dispatch(&call_encoded, &mut ctx); // Decode result. - let result_decoded: TxnOutput = serde_cbor::from_slice(&result).unwrap(); + let result_decoded: TxnOutput = cbor::from_slice(&result).unwrap(); match result_decoded { TxnOutput::Success(value) => { - let value: Complex = serde_cbor::from_value(value).unwrap(); + let value: Complex = cbor::from_value(value).unwrap(); assert_eq!( value, diff --git a/runtime/src/transaction/types.rs b/runtime/src/transaction/types.rs index eff11d796c4..de86cb464c4 100644 --- a/runtime/src/transaction/types.rs +++ b/runtime/src/transaction/types.rs @@ -4,9 +4,10 @@ use std::{ ops::{Deref, DerefMut}, }; -use serde_cbor::Value; use serde_derive::{Deserialize, Serialize}; +use crate::common::cbor::Value; + /// Transaction call. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct TxnCall { @@ -94,3 +95,20 @@ impl Into>> for TxnBatch { self.0.into() } } + +#[cfg(test)] +mod tests { + use super::*; + + use crate::common::{cbor, crypto::hash::Hash}; + + #[test] + fn test_consistent_hash() { + let batch = TxnBatch(vec![b"foo".to_vec(), b"bar".to_vec(), b"aaa".to_vec()]); + let h = Hash::digest_bytes(&cbor::to_vec(&batch)); + assert_eq!( + h, + Hash::from("c451dd4fd065b815e784aac6b300e479b2167408f0eebbb95a8bd36b9e71e34d") + ); + } +}