diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 867e5112..cb12eb46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,11 +33,9 @@ jobs: matrix: os: [ ubuntu-latest ] check: [ cargo build --release, - cargo build --release --features skip-ias-check, cargo build --release --features dot, cargo build --release --features ksm, cargo test --all --features runtime-benchmarks, - cargo test --all --features skip-ias-check, cargo test --all --features dot, cargo test --all --features ksm, cargo fmt --all -- --check, diff --git a/Cargo.lock b/Cargo.lock index 805916b1..f67a5378 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -969,7 +969,7 @@ dependencies = [ [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "frame-support", "frame-support-procedural", @@ -1006,7 +1006,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "bitflags", "environmental", @@ -1039,7 +1039,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "Inflector", "cfg-expr", @@ -1055,7 +1055,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -1067,7 +1067,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "proc-macro2", "quote", @@ -1077,7 +1077,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "frame-support", "log", @@ -2090,7 +2090,7 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "frame-benchmarking", "frame-support", @@ -2194,6 +2194,7 @@ dependencies = [ "sp-std 5.0.0", "substrate-fixed", "teeracle-primitives", + "teerex-primitives", "test-utils", ] @@ -2226,7 +2227,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "frame-benchmarking", "frame-support", @@ -2244,7 +2245,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "frame-benchmarking", "frame-support", @@ -3333,7 +3334,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "hash-db", "log", @@ -3353,7 +3354,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "Inflector", "blake2", @@ -3367,7 +3368,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "parity-scale-codec", "scale-info", @@ -3380,7 +3381,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "integer-sqrt", "num-traits", @@ -3394,7 +3395,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "parity-scale-codec", "scale-info", @@ -3407,7 +3408,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "parity-scale-codec", "scale-info", @@ -3419,7 +3420,7 @@ dependencies = [ [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "array-bytes", "bitflags", @@ -3463,7 +3464,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "blake2b_simd", "byteorder", @@ -3492,7 +3493,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "proc-macro2", "quote", @@ -3503,7 +3504,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "proc-macro2", "quote", @@ -3513,7 +3514,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "environmental", "parity-scale-codec", @@ -3524,7 +3525,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -3539,7 +3540,7 @@ dependencies = [ [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "bytes", "ed25519", @@ -3565,7 +3566,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "lazy_static", "sp-core", @@ -3576,7 +3577,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "futures", "parity-scale-codec", @@ -3590,7 +3591,7 @@ dependencies = [ [[package]] name = "sp-metadata-ir" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "frame-metadata", "parity-scale-codec", @@ -3601,7 +3602,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "backtrace", "lazy_static", @@ -3611,7 +3612,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "either", "hash256-std-hasher", @@ -3633,7 +3634,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -3651,7 +3652,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "Inflector", "proc-macro-crate", @@ -3663,7 +3664,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "parity-scale-codec", "scale-info", @@ -3676,7 +3677,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "hash-db", "log", @@ -3696,7 +3697,7 @@ dependencies = [ [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" [[package]] name = "sp-std" @@ -3707,7 +3708,7 @@ checksum = "1de8eef39962b5b97478719c493bed2926cf70cb621005bbf68ebe58252ff986" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "impl-serde", "parity-scale-codec", @@ -3720,7 +3721,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "async-trait", "futures-timer", @@ -3735,7 +3736,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "parity-scale-codec", "sp-std 5.0.0", @@ -3747,7 +3748,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "ahash 0.8.3", "hash-db", @@ -3770,7 +3771,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "impl-serde", "parity-scale-codec", @@ -3787,7 +3788,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -3798,7 +3799,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -3812,7 +3813,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" dependencies = [ "parity-scale-codec", "scale-info", @@ -4055,12 +4056,14 @@ name = "teerex-primitives" version = "0.1.0" dependencies = [ "common-primitives", + "derive_more", "hex-literal 0.3.4", "parity-scale-codec", "scale-info", "serde", "sp-core", "sp-io", + "sp-runtime", "sp-std 5.0.0", ] diff --git a/primitives/teerex/Cargo.toml b/primitives/teerex/Cargo.toml index 6ee2b313..94b941f9 100644 --- a/primitives/teerex/Cargo.toml +++ b/primitives/teerex/Cargo.toml @@ -10,12 +10,14 @@ edition = "2021" [dependencies] codec = { version = "3.0.0", default-features = false, features = ["derive"], package = "parity-scale-codec" } common-primitives = { path = "../common", default-features = false } +derive_more = "0.99.16" scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = { version = "1.0.13", default-features = false } # substrate dependencies sp-core = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } sp-io = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } sp-std = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } [dev-dependencies] @@ -31,5 +33,6 @@ std = [ # substrate "sp-core/std", "sp-io/std", + "sp-runtime/std", "sp-std/std", ] diff --git a/primitives/teerex/src/lib.rs b/primitives/teerex/src/lib.rs index 31e2a830..f9ae32a0 100644 --- a/primitives/teerex/src/lib.rs +++ b/primitives/teerex/src/lib.rs @@ -17,9 +17,12 @@ //!Primitives for teerex #![cfg_attr(not(feature = "std"), no_std)] +extern crate derive_more; use codec::{Decode, Encode}; +use derive_more::From; use scale_info::TypeInfo; -use sp_core::H256; +use sp_core::{bounded_vec::BoundedVec, ConstU32, H256}; +use sp_runtime::MultiSigner; use sp_std::prelude::*; #[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, sp_core::RuntimeDebug, TypeInfo)] @@ -75,7 +78,7 @@ impl AsRef<[u8; 64]> for SgxReportData { } impl SgxReportData { - fn lower32(&self) -> [u8; 32] { + pub fn lower32(&self) -> [u8; 32] { let mut lower = [0u8; 32]; lower.copy_from_slice(&self.d[..32]); lower @@ -92,6 +95,70 @@ pub enum SgxStatus { ConfigurationNeeded, } +pub type OpaqueSigner = BoundedVec>; +pub type EnclaveFingerprint = H256; + +#[derive(Encode, Decode, Clone, PartialEq, Eq, From, sp_core::RuntimeDebug, TypeInfo)] +pub enum AnySigner { + Opaque(OpaqueSigner), + Known(MultiSigner), +} + +#[derive(Encode, Decode, Copy, Clone, PartialEq, From, Eq, sp_core::RuntimeDebug, TypeInfo)] +pub enum MultiEnclave { + Sgx(SgxEnclave), +} + +impl MultiEnclave { + pub fn author(self) -> AnySigner { + match self { + MultiEnclave::Sgx(enclave) => AnySigner::Opaque( + OpaqueSigner::try_from(enclave.mr_signer.to_vec()).unwrap_or_default(), + ), + } + } + + pub fn fingerprint(&self) -> EnclaveFingerprint { + match self { + MultiEnclave::Sgx(enclave) => EnclaveFingerprint::from(enclave.mr_enclave), + } + } + + pub fn instance_signer(self) -> AnySigner { + match self { + MultiEnclave::Sgx(enclave) => match enclave.maybe_pubkey() { + Some(pubkey) => + AnySigner::from(MultiSigner::from(sp_core::ed25519::Public::from_raw(pubkey))), + None => AnySigner::Opaque( + OpaqueSigner::try_from(enclave.report_data.d.to_vec()).unwrap_or_default(), + ), + }, + } + } + + pub fn instance_url(self) -> Option { + match self { + MultiEnclave::Sgx(enclave) => enclave.url, + } + } + + pub fn attestation_timestamp(self) -> u64 { + match self { + MultiEnclave::Sgx(enclave) => enclave.timestamp, + } + } + + pub fn attestaion_proxied(self) -> bool { + match self { + MultiEnclave::Sgx(enclave) => matches!( + enclave.attestation_method, + SgxAttestationMethod::Skip { proxied: true } | + SgxAttestationMethod::Dcap { proxied: true } + ), + } + } +} + #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, sp_core::RuntimeDebug, TypeInfo)] pub struct SgxEnclave { pub report_data: SgxReportData, @@ -285,6 +352,13 @@ pub struct Request { pub cyphertext: Vec, } +#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, sp_core::RuntimeDebug, TypeInfo)] +pub struct ShardSignerStatus { + pub signer: AccountId, + pub fingerprint: EnclaveFingerprint, + pub last_activity: BlockNumber, +} + #[cfg(test)] mod tests { use super::*; diff --git a/sidechain/src/benchmarking.rs b/sidechain/src/benchmarking.rs index 491447bf..2677f722 100644 --- a/sidechain/src/benchmarking.rs +++ b/sidechain/src/benchmarking.rs @@ -21,13 +21,12 @@ use super::*; -use crate::Pallet as Sidechain; use frame_benchmarking::{account, benchmarks}; use frame_system::RawOrigin; use test_utils::test_data::ias::*; fn assert_latest_worker_update(sender: &T::AccountId, shard: &ShardIdentifier) { - assert_eq!(Sidechain::::worker_for_shard(shard), Teerex::::enclave_index(sender)); + assert_eq!(Teerex::::most_recent_shard_update(shard).unwrap().signer, *sender); } fn generate_accounts(amount: u32) -> Vec { @@ -38,9 +37,11 @@ fn add_enclaves_to_registry(accounts: &[T::AccountId]) { for a in accounts.iter() { Teerex::::add_enclave( a, - &SgxEnclave::test_enclave() - .with_pubkey(&a.encode()) - .with_mr_enclave(TEST4_SETUP.mrenclave), + &MultiEnclave::from( + SgxEnclave::test_enclave() + .with_pubkey(&a.encode()) + .with_mr_enclave(TEST4_SETUP.mrenclave), + ), ) .unwrap(); } @@ -68,7 +69,7 @@ use crate::{Config, Pallet as PalletModule}; #[cfg(test)] use frame_benchmarking::impl_benchmark_test_suite; -use teerex_primitives::SgxEnclave; +use teerex_primitives::{MultiEnclave, SgxEnclave}; use test_utils::TestEnclave; #[cfg(test)] diff --git a/sidechain/src/lib.rs b/sidechain/src/lib.rs index 108cc9c7..de3de263 100644 --- a/sidechain/src/lib.rs +++ b/sidechain/src/lib.rs @@ -60,12 +60,6 @@ pub mod pallet { FinalizedSidechainBlock(T::AccountId, H256), } - // Enclave index of the worker that recently committed an update. - #[pallet::storage] - #[pallet::getter(fn worker_for_shard)] - pub type WorkerForShard = - StorageMap<_, Blake2_128Concat, ShardIdentifier, u64, ValueQuery>; - #[pallet::storage] #[pallet::getter(fn latest_sidechain_block_confirmation)] pub type LatestSidechainBlockConfirmation = @@ -92,19 +86,19 @@ pub mod pallet { let sender = ensure_signed(origin)?; Teerex::::ensure_registered_enclave(&sender)?; - let sender_index = Teerex::::enclave_index(&sender); - let sender_enclave = Teerex::::enclave(sender_index) - .ok_or(pallet_teerex::Error::::EmptyEnclaveRegistry)?; + let enclave = Teerex::::sovereign_enclaves(&sender) + .ok_or(pallet_teerex::Error::::EnclaveIsNotRegistered)?; ensure!( - sender_enclave.mr_enclave.encode() == shard_id.encode(), - pallet_teerex::Error::::WrongMrenclaveForShard + enclave.fingerprint().encode() == shard_id.encode(), + pallet_teerex::Error::::WrongFingerprintForShard ); + let shard_status = Teerex::::touch_shard(enclave.fingerprint(), &sender)?; - // Simple logic for now: only accept blocks from first registered enclave. - if sender_index != 1 { + // TODO: Simple logic for now: only accept blocks from first registered enclave. + if sender != shard_status[0].signer { log::debug!( - "Ignore block confirmation from registered enclave with index {:?}", - sender_index + "Ignore block confirmation from registered enclave with index > 1: {:}", + sender ); return Ok(().into()) } @@ -127,7 +121,7 @@ pub mod pallet { next_finalization_candidate_block_number, ); - Self::finalize_block(shard_id, confirmation, &sender, sender_index); + Self::finalize_block(shard_id, confirmation, &sender); Ok(().into()) } } @@ -146,10 +140,8 @@ impl Pallet { shard_id: ShardIdentifier, confirmation: SidechainBlockConfirmation, sender: &T::AccountId, - sender_index: u64, ) { >::insert(shard_id, confirmation); - >::insert(shard_id, sender_index); let block_header_hash = confirmation.block_header_hash; log::debug!( "Imported sidechain block confirmed with shard {:?}, block header hash {:?}", diff --git a/sidechain/src/mock.rs b/sidechain/src/mock.rs index 92551930..e6976093 100644 --- a/sidechain/src/mock.rs +++ b/sidechain/src/mock.rs @@ -120,7 +120,7 @@ pub type Moment = u64; impl pallet_timestamp::Config for Test { type Moment = Moment; - type OnTimestampSet = Teerex; + type OnTimestampSet = (); type MinimumPeriod = MinimumPeriod; type WeightInfo = (); } diff --git a/sidechain/src/tests.rs b/sidechain/src/tests.rs index bf16a71c..879d615c 100644 --- a/sidechain/src/tests.rs +++ b/sidechain/src/tests.rs @@ -18,7 +18,7 @@ limitations under the License. use crate::{mock::*, Error, Event as SidechainEvent, Teerex}; use frame_support::{assert_err, assert_ok, dispatch::DispatchResultWithPostInfo}; use sp_core::H256; -use teerex_primitives::MrSigner; +use teerex_primitives::{MrSigner, SgxAttestationMethod}; use test_utils::test_data::consts::*; // give get_signer a concrete type @@ -98,7 +98,7 @@ fn confirm_imported_sidechain_block_from_shard_neq_mrenclave_errs() { block_number, hash ), - pallet_teerex::Error::::WrongMrenclaveForShard + pallet_teerex::Error::::WrongFingerprintForShard ); }) } @@ -187,8 +187,8 @@ fn dont_process_confirmation_of_second_registered_enclave() { Timestamp::set_timestamp(TEST7_TIMESTAMP); let shard7 = H256::from_slice(&TEST7_MRENCLAVE); - register_ias_enclave(TEST7_SIGNER_PUB, TEST7_CERT, 1); - register_ias_enclave(TEST6_SIGNER_PUB, TEST6_CERT, 2); + register_ias_enclave(TEST7_SIGNER_PUB, TEST7_CERT); + register_ias_enclave(TEST6_SIGNER_PUB, TEST6_CERT); assert_ok!(confirm_block(shard7, TEST6_SIGNER_PUB, 1, 2, H256::default(), false)); assert_eq!(Sidechain::latest_sidechain_block_confirmation(shard7).block_number, 0); @@ -196,19 +196,20 @@ fn dont_process_confirmation_of_second_registered_enclave() { } fn register_ias_enclave7() { - register_ias_enclave(TEST7_SIGNER_PUB, TEST7_CERT, 1); + register_ias_enclave(TEST7_SIGNER_PUB, TEST7_CERT); } -fn register_ias_enclave(signer_pub_key: &MrSigner, cert: &[u8], expected_enclave_count: u64) { - let signer7 = get_signer(signer_pub_key); +fn register_ias_enclave(signer_pub_key: &MrSigner, cert: &[u8]) { + let signer = get_signer(signer_pub_key); //Ensure that enclave is registered - assert_ok!(Teerex::::register_ias_enclave( - RuntimeOrigin::signed(signer7), + assert_ok!(Teerex::::register_sgx_enclave( + RuntimeOrigin::signed(signer.clone()), cert.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias, )); - assert_eq!(Teerex::::enclave_count(), expected_enclave_count); + assert!(Teerex::::sovereign_enclaves(signer).is_some()); } fn confirm_block7( diff --git a/teeracle/Cargo.toml b/teeracle/Cargo.toml index 31073765..18347adb 100644 --- a/teeracle/Cargo.toml +++ b/teeracle/Cargo.toml @@ -16,6 +16,7 @@ scale-info = { version = "2.0.1", default-features = false, features = ["derive" # local pallet-teerex = { path = "../teerex", default-features = false } teeracle-primitives = { path = "../primitives/teeracle", default-features = false } +teerex-primitives = { path = "../primitives/teerex", default-features = false } # encointer substrate-fixed = { tag = "v0.5.9", default-features = false, git = "https://github.com/encointer/substrate-fixed.git" } diff --git a/teeracle/src/benchmarking.rs b/teeracle/src/benchmarking.rs index fba3dff1..a34ff640 100644 --- a/teeracle/src/benchmarking.rs +++ b/teeracle/src/benchmarking.rs @@ -28,6 +28,7 @@ use pallet_teerex::Pallet as Teerex; use sp_runtime::traits::CheckedConversion; use sp_std::prelude::*; use teeracle_primitives::{DataSource, OracleDataName, TradingPairString}; +use teerex_primitives::SgxAttestationMethod; use test_utils::{ get_signer, @@ -51,13 +52,14 @@ benchmarks! { let data_source: DataSource = "https://api.coingecko.com".into(); // simply register the enclave before to make sure it already // exists when running the benchmark - Teerex::::register_ias_enclave( + Teerex::::register_sgx_enclave( RawOrigin::Signed(signer.clone()).into(), TEST4_SETUP.cert.to_vec(), - URL.to_vec() + Some(URL.to_vec()), + SgxAttestationMethod::Ias, ).unwrap(); - let mrenclave = Teerex::::enclave(1).unwrap().mr_enclave; - Teeracle::::add_to_whitelist(RawOrigin::Root.into(), data_source.clone(), mrenclave).unwrap(); + let fingerprint = Teerex::::sovereign_enclaves(&signer).unwrap().fingerprint(); + Teeracle::::add_to_whitelist(RawOrigin::Root.into(), data_source.clone(), fingerprint).unwrap(); }: _(RawOrigin::Signed(signer), data_source.clone(), trading_pair.clone(), Some(rate)) verify { @@ -74,34 +76,35 @@ benchmarks! { vec![1].try_into().expect("Can Convert to OracleDataBlob; QED"); // simply register the enclave before to make sure it already // exists when running the benchmark - Teerex::::register_ias_enclave( + Teerex::::register_sgx_enclave( RawOrigin::Signed(signer.clone()).into(), TEST4_SETUP.cert.to_vec(), - URL.to_vec() + Some(URL.to_vec()), + SgxAttestationMethod::Ias, ).unwrap(); - let mrenclave = Teerex::::enclave(1).unwrap().mr_enclave; - Teeracle::::add_to_whitelist(RawOrigin::Root.into(), data_source.clone(), mrenclave).unwrap(); + let fingerprint = Teerex::::sovereign_enclaves(&signer).unwrap().fingerprint(); + Teeracle::::add_to_whitelist(RawOrigin::Root.into(), data_source.clone(), fingerprint).unwrap(); }: _(RawOrigin::Signed(signer), oracle_name.clone(), data_source.clone(), oracle_blob.clone()) verify { assert_eq!(Teeracle::::oracle_data(oracle_name, data_source), oracle_blob); } add_to_whitelist { - let mrenclave = TEST4_MRENCLAVE; + let fingerprint = EnclaveFingerprint::from(TEST4_MRENCLAVE); let data_source: DataSource = "https://api.coingecko.com".into(); - }: _(RawOrigin::Root, data_source.clone(), mrenclave) + }: _(RawOrigin::Root, data_source.clone(), fingerprint) verify { assert_eq!(Teeracle::::whitelist(data_source).len(), 1, "mrenclave not added to whitelist") } remove_from_whitelist { - let mrenclave = TEST4_MRENCLAVE; + let fingerprint = EnclaveFingerprint::from(TEST4_MRENCLAVE); let data_source: DataSource = "https://api.coingecko.com".into(); - Teeracle::::add_to_whitelist(RawOrigin::Root.into(), data_source.clone(), mrenclave).unwrap(); + Teeracle::::add_to_whitelist(RawOrigin::Root.into(), data_source.clone(), fingerprint).unwrap(); - }: _(RawOrigin::Root, data_source.clone(), mrenclave) + }: _(RawOrigin::Root, data_source.clone(), fingerprint) verify { assert_eq!(Teeracle::::whitelist(data_source).len(), 0, "mrenclave not removed from whitelist") } diff --git a/teeracle/src/lib.rs b/teeracle/src/lib.rs index dcb9c960..f1f3f9a9 100644 --- a/teeracle/src/lib.rs +++ b/teeracle/src/lib.rs @@ -32,8 +32,10 @@ #![cfg_attr(not(feature = "std"), no_std)] pub use crate::weights::WeightInfo; pub use pallet::*; +use pallet_teerex::Pallet as Teerex; pub use substrate_fixed::types::U32F32; use teeracle_primitives::{DataSource, MAX_ORACLE_DATA_NAME_LEN}; +use teerex_primitives::EnclaveFingerprint; const MAX_TRADING_PAIR_LEN: usize = 11; const MAX_SOURCE_LEN: usize = 40; @@ -97,7 +99,7 @@ pub mod pallet { _, Blake2_128Concat, DataSource, - WeakBoundedVec<[u8; 32], T::MaxWhitelistedReleases>, + WeakBoundedVec, ValueQuery, >; @@ -111,8 +113,8 @@ pub mod pallet { ExchangeRateUpdated(DataSource, TradingPairString, Option), ExchangeRateDeleted(DataSource, TradingPairString), OracleUpdated(OracleDataName, DataSource), - AddedToWhitelist(DataSource, [u8; 32]), - RemovedFromWhitelist(DataSource, [u8; 32]), + AddedToWhitelist(DataSource, EnclaveFingerprint), + RemovedFromWhitelist(DataSource, EnclaveFingerprint), } #[pallet::error] @@ -138,19 +140,19 @@ pub mod pallet { pub fn add_to_whitelist( origin: OriginFor, data_source: DataSource, - mrenclave: [u8; 32], + fingerprint: EnclaveFingerprint, ) -> DispatchResult { ensure_root(origin)?; ensure!(data_source.len() <= MAX_SOURCE_LEN, Error::::DataSourceStringTooLong); ensure!( - !Self::is_whitelisted(&data_source, mrenclave), + !Self::is_whitelisted(&data_source, fingerprint), >::ReleaseAlreadyWhitelisted ); - >::try_mutate(data_source.clone(), |mrenclave_vec| { - mrenclave_vec.try_push(mrenclave) + >::try_mutate(data_source.clone(), |fingerprints| { + fingerprints.try_push(fingerprint) }) .map_err(|_| Error::::ReleaseWhitelistOverflow)?; - Self::deposit_event(Event::AddedToWhitelist(data_source, mrenclave)); + Self::deposit_event(Event::AddedToWhitelist(data_source, fingerprint)); Ok(()) } #[pallet::call_index(1)] @@ -158,17 +160,17 @@ pub mod pallet { pub fn remove_from_whitelist( origin: OriginFor, data_source: DataSource, - mrenclave: [u8; 32], + fingerprint: EnclaveFingerprint, ) -> DispatchResult { ensure_root(origin)?; ensure!( - Self::is_whitelisted(&data_source, mrenclave), + Self::is_whitelisted(&data_source, fingerprint), >::ReleaseNotWhitelisted ); - >::mutate(&data_source, |mrenclave_vec| { - mrenclave_vec.retain(|m| *m != mrenclave) + >::mutate(&data_source, |fingerprints| { + fingerprints.retain(|m| *m != fingerprint) }); - Self::deposit_event(Event::RemovedFromWhitelist(data_source, mrenclave)); + Self::deposit_event(Event::RemovedFromWhitelist(data_source, fingerprint)); Ok(()) } @@ -180,14 +182,12 @@ pub mod pallet { data_source: DataSource, new_blob: OracleDataBlob, ) -> DispatchResultWithPostInfo { - let signer = ensure_signed(origin)?; - >::ensure_registered_enclave(&signer)?; - let signer_index = >::enclave_index(signer); - let signer_enclave = >::enclave(signer_index) - .ok_or(pallet_teerex::Error::::EmptyEnclaveRegistry)?; + let sender = ensure_signed(origin)?; + let enclave = Teerex::::sovereign_enclaves(&sender) + .ok_or(pallet_teerex::Error::::EnclaveIsNotRegistered)?; ensure!( - Self::is_whitelisted(&data_source, signer_enclave.mr_enclave), + Self::is_whitelisted(&data_source, enclave.fingerprint()), >::ReleaseNotWhitelisted ); ensure!( @@ -214,17 +214,16 @@ pub mod pallet { new_value: Option, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - >::ensure_registered_enclave(&sender)?; - let sender_index = >::enclave_index(sender); - let sender_enclave = >::enclave(sender_index) - .ok_or(pallet_teerex::Error::::EmptyEnclaveRegistry)?; + let enclave = Teerex::::sovereign_enclaves(&sender) + .ok_or(pallet_teerex::Error::::EnclaveIsNotRegistered)?; + // Todo: Never checks data source len ensure!( trading_pair.len() <= MAX_TRADING_PAIR_LEN, Error::::TradingPairStringTooLong ); ensure!( - Self::is_whitelisted(&data_source, sender_enclave.mr_enclave), + Self::is_whitelisted(&data_source, enclave.fingerprint()), >::ReleaseNotWhitelisted ); if new_value.is_none() || new_value == Some(U32F32::from_num(0)) { @@ -247,8 +246,8 @@ pub mod pallet { } } impl Pallet { - fn is_whitelisted(data_source: &DataSource, mrenclave: [u8; 32]) -> bool { - Self::whitelist(data_source).contains(&mrenclave) + fn is_whitelisted(data_source: &DataSource, fingerprint: EnclaveFingerprint) -> bool { + Self::whitelist(data_source).contains(&fingerprint) } } diff --git a/teeracle/src/mock.rs b/teeracle/src/mock.rs index ae837e3c..54d9d389 100644 --- a/teeracle/src/mock.rs +++ b/teeracle/src/mock.rs @@ -118,7 +118,7 @@ pub type Moment = u64; impl timestamp::Config for Test { type Moment = Moment; - type OnTimestampSet = Teerex; + type OnTimestampSet = (); type MinimumPeriod = MinimumPeriod; type WeightInfo = (); } diff --git a/teeracle/src/tests.rs b/teeracle/src/tests.rs index 8a7755d1..c09adca0 100644 --- a/teeracle/src/tests.rs +++ b/teeracle/src/tests.rs @@ -21,6 +21,7 @@ use pallet_teerex::Error; use sp_runtime::DispatchError::BadOrigin; use substrate_fixed::types::U32F32; use teeracle_primitives::*; +use teerex_primitives::{EnclaveFingerprint, SgxAttestationMethod}; use test_utils::test_data::consts::{ TEST4_CERT, TEST4_MRENCLAVE, TEST4_SIGNER_PUB, TEST4_TIMESTAMP, TEST5_MRENCLAVE, TEST5_SIGNER_PUB, TEST8_MRENCLAVE, URL, @@ -39,13 +40,14 @@ fn get_signer(pubkey: &[u8; 32]) -> AccountId { fn register_ias_enclave_and_add_oracle_to_whitelist_ok(src: &str) { Timestamp::set_timestamp(TEST4_TIMESTAMP); let signer = get_signer(TEST4_SIGNER_PUB); - assert_ok!(Teerex::register_ias_enclave( - RuntimeOrigin::signed(signer), + assert_ok!(Teerex::register_sgx_enclave( + RuntimeOrigin::signed(signer.clone()), TEST4_CERT.to_vec(), - URL.to_vec() + Some(URL.to_vec()), + SgxAttestationMethod::Ias, )); - let mrenclave = Teerex::enclave(1).unwrap().mr_enclave; - assert_ok!(Teeracle::add_to_whitelist(RuntimeOrigin::root(), src.to_owned(), mrenclave)); + let fingerprint = Teerex::sovereign_enclaves(&signer).unwrap().fingerprint(); + assert_ok!(Teeracle::add_to_whitelist(RuntimeOrigin::root(), src.to_owned(), fingerprint)); } fn update_exchange_rate_dot_dollars_ok(src: &str, rate: Option) { @@ -222,10 +224,11 @@ fn update_exchange_rate_from_not_whitelisted_oracle_fails() { new_test_ext().execute_with(|| { Timestamp::set_timestamp(TEST4_TIMESTAMP); let signer = get_signer(TEST4_SIGNER_PUB); - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer.clone()), TEST4_CERT.to_vec(), - URL.to_vec() + Some(URL.to_vec()), + SgxAttestationMethod::Ias, )); let rate = U32F32::from_num(43.65); @@ -246,10 +249,11 @@ fn update_oracle_from_not_whitelisted_oracle_fails() { new_test_ext().execute_with(|| { Timestamp::set_timestamp(TEST4_TIMESTAMP); let signer = get_signer(TEST4_SIGNER_PUB); - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer.clone()), TEST4_CERT.to_vec(), - URL.to_vec() + Some(URL.to_vec()), + SgxAttestationMethod::Ias, )); assert_noop!( @@ -287,14 +291,15 @@ fn update_exchange_rate_with_too_long_trading_pair_fails() { #[test] fn add_to_whitelist_works() { new_test_ext().execute_with(|| { + let fingerprint = EnclaveFingerprint::from(TEST4_MRENCLAVE); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE + fingerprint )); let expected_event = RuntimeEvent::Teeracle(crate::Event::AddedToWhitelist( COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE, + fingerprint, )); assert!(System::events().iter().any(|a| a.event == expected_event)); assert_eq!(Teeracle::whitelist(COINGECKO_SRC.to_owned()).len(), 1); @@ -304,19 +309,20 @@ fn add_to_whitelist_works() { #[test] fn add_mulitple_src_to_whitelists_works() { new_test_ext().execute_with(|| { + let fingerprint = EnclaveFingerprint::from(TEST4_MRENCLAVE); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE + fingerprint )); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINMARKETCAP_SRC.to_owned(), - TEST4_MRENCLAVE + fingerprint )); let expected_event = RuntimeEvent::Teeracle(crate::Event::AddedToWhitelist( COINMARKETCAP_SRC.to_owned(), - TEST4_MRENCLAVE, + fingerprint, )); assert!(System::events().iter().any(|a| a.event == expected_event)); @@ -328,16 +334,17 @@ fn add_mulitple_src_to_whitelists_works() { #[test] fn add_two_times_to_whitelist_fails() { new_test_ext().execute_with(|| { + let fingerprint = EnclaveFingerprint::from(TEST4_MRENCLAVE); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE + fingerprint )); assert_err!( Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE + fingerprint ), crate::Error::::ReleaseAlreadyWhitelisted ); @@ -351,58 +358,74 @@ fn add_too_many_oracles_to_whitelist_fails() { assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE + EnclaveFingerprint::from(TEST4_MRENCLAVE) )); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST5_MRENCLAVE + EnclaveFingerprint::from(TEST5_MRENCLAVE) )); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - hex!("f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d2") + EnclaveFingerprint::from(hex!( + "f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d2" + )) )); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - hex!("f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d3") + EnclaveFingerprint::from(hex!( + "f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d3" + )) )); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - hex!("f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d4") + EnclaveFingerprint::from(hex!( + "f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d4" + )) )); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - hex!("f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d5") + EnclaveFingerprint::from(hex!( + "f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d5" + )) )); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - hex!("f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d6") + EnclaveFingerprint::from(hex!( + "f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d6" + )) )); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - hex!("f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d7") + EnclaveFingerprint::from(hex!( + "f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d7" + )) )); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - hex!("f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d8") + EnclaveFingerprint::from(hex!( + "f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d8" + )) )); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - hex!("f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d9") + EnclaveFingerprint::from(hex!( + "f4dedfc9e5fcc48443332bc9b23161c34a3c3f5a692eaffdb228db27b704d9d9" + )) )); assert_err!( Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST8_MRENCLAVE + EnclaveFingerprint::from(TEST8_MRENCLAVE) ), crate::Error::::ReleaseWhitelistOverflow ); @@ -414,7 +437,11 @@ fn add_to_whitelist_too_long_source_fails() { new_test_ext().execute_with(|| { let too_long_source = "123456789_223456789_323456789_423456789_1".to_owned(); assert_err!( - Teeracle::add_to_whitelist(RuntimeOrigin::root(), too_long_source, TEST4_MRENCLAVE), + Teeracle::add_to_whitelist( + RuntimeOrigin::root(), + too_long_source, + EnclaveFingerprint::from(TEST4_MRENCLAVE) + ), crate::Error::::DataSourceStringTooLong ); }) @@ -424,11 +451,12 @@ fn add_to_whitelist_too_long_source_fails() { fn non_root_add_to_whitelist_fails() { new_test_ext().execute_with(|| { let signer = get_signer(TEST5_SIGNER_PUB); + let fingerprint = EnclaveFingerprint::from(TEST4_MRENCLAVE); assert_err!( Teeracle::add_to_whitelist( RuntimeOrigin::signed(signer), COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE + fingerprint ), BadOrigin ); @@ -439,19 +467,20 @@ fn non_root_add_to_whitelist_fails() { #[test] fn remove_from_whitelist_works() { new_test_ext().execute_with(|| { + let fingerprint = EnclaveFingerprint::from(TEST4_MRENCLAVE); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE + fingerprint )); assert_ok!(Teeracle::remove_from_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE + fingerprint )); let expected_event = RuntimeEvent::Teeracle(crate::Event::RemovedFromWhitelist( COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE, + fingerprint, )); assert!(System::events().iter().any(|a| a.event == expected_event)); assert_eq!(Teeracle::whitelist(COINGECKO_SRC.to_owned()).len(), 0); @@ -464,13 +493,13 @@ fn remove_from_whitelist_not_whitelisted_fails() { assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE + EnclaveFingerprint::from(TEST4_MRENCLAVE) )); assert_err!( Teeracle::remove_from_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST5_MRENCLAVE + EnclaveFingerprint::from(TEST5_MRENCLAVE) ), crate::Error::::ReleaseNotWhitelisted ); @@ -486,7 +515,7 @@ fn remove_from_empty_whitelist_doesnt_crash() { Teeracle::remove_from_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST5_MRENCLAVE + EnclaveFingerprint::from(TEST5_MRENCLAVE) ), crate::Error::::ReleaseNotWhitelisted ); @@ -498,16 +527,17 @@ fn remove_from_empty_whitelist_doesnt_crash() { fn non_root_remove_from_whitelist_fails() { new_test_ext().execute_with(|| { let signer = get_signer(TEST5_SIGNER_PUB); + let fingerprint = EnclaveFingerprint::from(TEST4_MRENCLAVE); assert_ok!(Teeracle::add_to_whitelist( RuntimeOrigin::root(), COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE + fingerprint )); assert_err!( Teeracle::remove_from_whitelist( RuntimeOrigin::signed(signer), COINGECKO_SRC.to_owned(), - TEST4_MRENCLAVE + fingerprint ), BadOrigin ); diff --git a/teerex/Cargo.toml b/teerex/Cargo.toml index 50f53749..559c0e97 100644 --- a/teerex/Cargo.toml +++ b/teerex/Cargo.toml @@ -68,7 +68,5 @@ runtime-benchmarks = [ "test-utils", "timestamp/runtime-benchmarks", ] -# allow workers to register without remote attestation for dev purposes -skip-ias-check = [] try-runtime = ["frame-support/try-runtime"] diff --git a/teerex/src/benchmarking.rs b/teerex/src/benchmarking.rs index bdeca0c1..13983d24 100644 --- a/teerex/src/benchmarking.rs +++ b/teerex/src/benchmarking.rs @@ -22,7 +22,7 @@ use super::*; use crate::{ - test_helpers::{get_test_tcb_info, register_test_quoting_enclave, register_test_tcb_info}, + test_helpers::{get_test_tcb_info, register_test_quoting_enclave}, Pallet as Teerex, }; use frame_benchmarking::{account, benchmarks}; @@ -34,6 +34,8 @@ use test_utils::{ test_data::{consts::*, dcap::*, ias::*}, }; +const MAX_SILENCE_TIME: u64 = 172_800_000; // 48h + fn ensure_not_skipping_ra_check() { #[cfg(not(test))] if cfg!(feature = "skip-ias-check") { @@ -56,22 +58,23 @@ benchmarks! { // Benchmark `register_ias_enclave` with the worst possible conditions: // * remote attestation is valid // * enclave already exists - register_ias_enclave { + register_sgx_enclave { ensure_not_skipping_ra_check(); timestamp::Pallet::::set_timestamp(TEST4_SETUP.timestamp.checked_into().unwrap()); let signer: T::AccountId = get_signer(TEST4_SETUP.signer_pub); // simply register the enclave before to make sure it already // exists when running the benchmark - Teerex::::register_ias_enclave( + Teerex::::register_sgx_enclave( RawOrigin::Signed(signer.clone()).into(), TEST4_SETUP.cert.to_vec(), - URL.to_vec() + Some(URL.to_vec()), + SgxAttestationMethod::Ias ).unwrap(); - }: _(RawOrigin::Signed(signer), TEST4_SETUP.cert.to_vec(), URL.to_vec()) + }: _(RawOrigin::Signed(signer.clone()), TEST4_SETUP.cert.to_vec(), Some(URL.to_vec()), SgxAttestationMethod::Ias) verify { - assert_eq!(Teerex::::enclave_count(), 1); + assert!(crate::SovereignEnclaves::::contains_key(&signer)); } // Benchmark `register_quoting_enclave` with the worst possible conditions: @@ -100,10 +103,10 @@ benchmarks! { // This is the date that the is registered in register_tcb_info and represents the date 2023-04-16T12:45:32Z assert_eq!(get_test_tcb_info::().next_update, 1681649132000); } - +/* // Benchmark `register_dcap_enclave` with the worst possible conditions: // * dcap registration succeeds - register_dcap_enclave { + register_sgx_enclave { ensure_not_skipping_ra_check(); timestamp::Pallet::::set_timestamp(TEST_VALID_COLLATERAL_TIMESTAMP.checked_into().unwrap()); let signer: T::AccountId = get_signer(&TEST1_DCAP_QUOTE_SIGNER); @@ -111,23 +114,23 @@ benchmarks! { register_test_quoting_enclave::(signer.clone()); register_test_tcb_info::(signer.clone()); - }: _(RawOrigin::Signed(signer), TEST1_DCAP_QUOTE.to_vec(), URL.to_vec()) + }: _(RawOrigin::Signed(signer), TEST1_DCAP_QUOTE.to_vec(), Some(URL.to_vec()), SgxAttestationMethod::Dcap { proxied: false }) verify { assert_eq!(Teerex::::enclave_count(), 1); } - +*/ // Benchmark `unregister_enclave` enclave with the worst possible conditions: // * enclave exists // * enclave is not the most recently registered enclave - unregister_enclave { + unregister_sovereign_enclave { let enclave_count = 3; let accounts: Vec = generate_accounts::(enclave_count); add_enclaves_to_registry::(&accounts); + timestamp::Pallet::::set_timestamp((TEST4_TIMESTAMP + MAX_SILENCE_TIME + 1).checked_into().unwrap()); - }: _(RawOrigin::Signed(accounts[0].clone())) + }: _(RawOrigin::Signed(accounts[0].clone()), accounts[0].clone()) verify { - assert!(!crate::EnclaveIndex::::contains_key(&accounts[0])); - assert_eq!(Teerex::::enclave_count(), enclave_count as u64 - 1); + assert!(!crate::SovereignEnclaves::::contains_key(&accounts[0])); } // Benchmark `call_worker`. There are no worst conditions. The benchmark showed that @@ -179,7 +182,7 @@ fn add_enclaves_to_registry(accounts: &[T::AccountId]) { for a in accounts.iter() { Teerex::::add_enclave( a, - &SgxEnclave::test_enclave().with_mr_enclave(TEST4_SETUP.mrenclave), + &MultiEnclave::from(SgxEnclave::test_enclave().with_mr_enclave(TEST4_SETUP.mrenclave)), ) .unwrap(); } diff --git a/teerex/src/lib.rs b/teerex/src/lib.rs index bba125bb..cc9ab4f3 100644 --- a/teerex/src/lib.rs +++ b/teerex/src/lib.rs @@ -21,7 +21,7 @@ use codec::Encode; use frame_support::{ dispatch::{DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo}, ensure, - traits::{Currency, ExistenceRequirement, Get, OnTimestampSet}, + traits::{Currency, ExistenceRequirement, Get}, }; use frame_system::{self, ensure_signed}; use sgx_verify::{ @@ -38,11 +38,17 @@ use teerex_primitives::{SgxBuildMode, SgxStatus}; // Disambiguate associated types pub type AccountId = ::AccountId; pub type BalanceOf = <::Currency as Currency>>::Balance; +pub type ShardSignerStatusVec = Vec< + ShardSignerStatus< + ::AccountId, + ::BlockNumber, + >, +>; pub use pallet::*; -const MAX_RA_REPORT_LEN: usize = 4096; -const MAX_DCAP_QUOTE_LEN: usize = 5000; +const SGX_RA_PROOF_MAX_LEN: usize = 5000; + const MAX_URL_LEN: usize = 256; /// Maximum number of topics for the `publish_hash` call. const TOPICS_LIMIT: usize = 5; @@ -72,7 +78,7 @@ pub mod pallet { type WeightInfo: WeightInfo; - /// If a worker does not re-register within `MaxSilenceTime`, it will be unregistered. + /// If a worker does not re-register within `MaxSilenceTime`, it can be unregistered by anyone. #[pallet::constant] type MaxSilenceTime: Get; } @@ -82,7 +88,7 @@ pub mod pallet { pub enum Event { AddedEnclave { registered_by: T::AccountId, - worker_url: Vec, + worker_url: Option>, tcb_status: Option, attestation_method: SgxAttestationMethod, }, @@ -93,15 +99,15 @@ pub mod pallet { ProcessedParentchainBlock(T::AccountId, H256, H256, T::BlockNumber), /// An enclave with [mr_enclave] has published some [hash] with some metadata [data]. PublishedHash { - mr_enclave: MrEnclave, + fingerprint: EnclaveFingerprint, hash: H256, data: Vec, }, - TcbInfoRegistered { + SgxTcbInfoRegistered { fmspc: Fmspc, on_chain_info: SgxTcbInfoOnChain, }, - QuotingEnclaveRegistered { + SgxQuotingEnclaveRegistered { quoting_enclave: SgxQuotingEnclave, }, } @@ -109,13 +115,19 @@ pub mod pallet { // Watch out: we start indexing with 1 instead of zero in order to // avoid ambiguity between Null and 0. #[pallet::storage] - #[pallet::getter(fn enclave)] - pub type EnclaveRegistry = - StorageMap<_, Blake2_128Concat, u64, SgxEnclave>, OptionQuery>; + #[pallet::getter(fn sovereign_enclaves)] + pub type SovereignEnclaves = + StorageMap<_, Blake2_128Concat, T::AccountId, MultiEnclave>, OptionQuery>; #[pallet::storage] - #[pallet::getter(fn enclave_count)] - pub type EnclaveCount = StorageValue<_, u64, ValueQuery>; + #[pallet::getter(fn shard_status)] + pub type ShardStatus = StorageMap< + _, + Blake2_128Concat, + ShardIdentifier, + Vec>, + OptionQuery, + >; #[pallet::storage] #[pallet::getter(fn quoting_enclave)] @@ -126,11 +138,6 @@ pub mod pallet { pub type SgxTcbInfo = StorageMap<_, Blake2_128Concat, Fmspc, SgxTcbInfoOnChain, ValueQuery>; - #[pallet::storage] - #[pallet::getter(fn enclave_index)] - pub type EnclaveIndex = - StorageMap<_, Blake2_128Concat, T::AccountId, u64, ValueQuery>; - #[pallet::storage] #[pallet::getter(fn confirmed_calls)] pub type ExecutedCalls = StorageMap<_, Blake2_128Concat, H256, u64, ValueQuery>; @@ -162,70 +169,146 @@ pub mod pallet { // the integritee-service wants to register his enclave #[pallet::call_index(0)] #[pallet::weight((::WeightInfo::register_ias_enclave(), DispatchClass::Normal, Pays::Yes))] - pub fn register_ias_enclave( + pub fn register_sgx_enclave( origin: OriginFor, - ra_report: Vec, - worker_url: Vec, + proof: Vec, + worker_url: Option>, + attestation_method: SgxAttestationMethod, ) -> DispatchResultWithPostInfo { - log::info!("teerex: called into runtime call register_ias_enclave()"); + log::info!("teerex: called into runtime call register_sgx_enclave()"); let sender = ensure_signed(origin)?; - ensure!(ra_report.len() <= MAX_RA_REPORT_LEN, >::RaReportTooLong); - ensure!(worker_url.len() <= MAX_URL_LEN, >::EnclaveUrlTooLong); + ensure!(proof.len() <= SGX_RA_PROOF_MAX_LEN, >::RaProofTooLong); + if let Some(ref url) = worker_url { + ensure!(url.len() <= MAX_URL_LEN, >::EnclaveUrlTooLong); + } log::info!("teerex: parameter length ok"); - #[cfg(not(feature = "skip-ias-check"))] - let enclave = Self::verify_report(&sender, ra_report)?.with_url(worker_url.clone()); + let enclave = match attestation_method { + SgxAttestationMethod::Ias => { + let report = sgx_verify::verify_ias_report(&proof) + .map_err(|_| >::RemoteAttestationVerificationFailed)?; + log::info!("teerex: IAS report successfully verified"); + + Self::ensure_timestamp_within_24_hours(report.timestamp)?; + + let enclave = SgxEnclave::new( + report.report_data, + report.mr_enclave, + report.mr_signer, + report.timestamp, + report.build_mode, + report.status, + ) + .with_attestation_method(SgxAttestationMethod::Ias); + + ensure!( + Ok(sender.clone()) == + T::AccountId::decode(&mut report.report_data.lower32().as_ref()), + >::SenderIsNotAttestedEnclave + ); + + // TODO: activate state checks as soon as we've fixed our setup #83 + // ensure!((report.status == SgxStatus::Ok) | (report.status == SgxStatus::ConfigurationNeeded), + // "RA status is insufficient"); + // log::info!("teerex: status is acceptable"); + + enclave + }, + SgxAttestationMethod::Dcap { proxied } => { + let verification_time = >::get(); + + let qe = >::get(); + let (fmspc, tcb_info, report) = sgx_verify::verify_dcap_quote( + &proof, + verification_time.saturated_into(), + &qe, + ) + .map_err(|e| { + log::warn!("verify_dcap_quote failed: {:?}", e); + >::RemoteAttestationVerificationFailed + })?; + + if !proxied { + ensure!( + Ok(sender.clone()) == + T::AccountId::decode(&mut report.report_data.lower32().as_ref()), + >::SenderIsNotAttestedEnclave + ); + } + + log::info!("teerex: DCAP quote verified. FMSPC from quote: {:?}", fmspc); + let tcb_info_on_chain = >::get(fmspc); + ensure!(tcb_info_on_chain.verify_examinee(&tcb_info), "tcb_info is outdated"); + + // TODO: activate state checks as soon as we've fixed our setup #83 + // ensure!((report.status == SgxStatus::Ok) | (report.status == SgxStatus::ConfigurationNeeded), + // "RA status is insufficient"); + // log::info!("teerex: status is acceptable"); + + SgxEnclave::new( + report.report_data, + report.mr_enclave, + report.mr_signer, + report.timestamp, + report.build_mode, + report.status, + ) + .with_attestation_method(SgxAttestationMethod::Dcap { proxied }) + }, + SgxAttestationMethod::Skip { proxied } => SgxEnclave::new( + SgxReportData::default(), + // insert mrenclave if the ra_report represents one, otherwise insert default + ::decode(&mut proof.as_slice()).unwrap_or_default(), + MrSigner::default(), + >::get().saturated_into(), + SgxBuildMode::default(), + SgxStatus::Invalid, + ) + .with_pubkey(sender.encode().as_ref()) + .with_attestation_method(SgxAttestationMethod::Skip { proxied }), + }; - #[cfg(not(feature = "skip-ias-check"))] if !>::get() && enclave.build_mode == SgxBuildMode::Debug { log::warn!("teerex: debug mode is not allowed to attest!"); return Err(>::SgxModeNotAllowed.into()) } - #[cfg(feature = "skip-ias-check")] - log::warn!("[teerex]: Skipping remote attestation check. Only dev-chains are allowed to do this!"); - - #[cfg(feature = "skip-ias-check")] - let enclave = SgxEnclave::>::new( - SgxReportData::default(), - // insert mrenclave if the ra_report represents one, otherwise insert default - ::decode(&mut ra_report.as_slice()).unwrap_or_default(), - MrSigner::default(), - >::get().saturated_into(), - SgxBuildMode::default(), - SgxStatus::Invalid, - ) - .with_pubkey(&sender.encode()) - .with_url(worker_url.clone()); - - Self::add_enclave(&sender, &enclave)?; - - #[cfg(not(feature = "skip-ias-check"))] + let enclave = match worker_url { + Some(ref url) => enclave.with_url(url.clone()), + None => enclave, + }; + + Self::add_enclave(&sender, &MultiEnclave::from(enclave.clone()))?; + Self::touch_shard(enclave.mr_enclave.into(), &sender)?; + Self::deposit_event(Event::AddedEnclave { registered_by: sender, worker_url, tcb_status: Some(enclave.status), attestation_method: enclave.attestation_method, }); - - #[cfg(feature = "skip-ias-check")] - Self::deposit_event(Event::AddedEnclave { - registered_by: sender, - worker_url, - tcb_status: None, - attestation_method: SgxAttestationMethod::Skip { proxied: false }, - }); Ok(().into()) } #[pallet::call_index(1)] #[pallet::weight((::WeightInfo::unregister_enclave(), DispatchClass::Normal, Pays::Yes))] - pub fn unregister_enclave(origin: OriginFor) -> DispatchResultWithPostInfo { - log::info!("teerex: called into runtime call unregister_enclave()"); - let sender = ensure_signed(origin)?; - - Self::remove_enclave(&sender)?; - Self::deposit_event(Event::RemovedEnclave(sender)); + pub fn unregister_sovereign_enclave( + origin: OriginFor, + enclave_signer: T::AccountId, + ) -> DispatchResultWithPostInfo { + log::info!("teerex: called into runtime call unregister_sovereign_enclave()"); + ensure_signed(origin)?; + let enclave = Self::sovereign_enclaves(&enclave_signer) + .ok_or(>::EnclaveIsNotRegistered)?; + let now = >::get(); + let oldest_acceptable_attestation_time = + now.saturating_sub(T::MaxSilenceTime::get()).saturated_into::(); + if enclave.attestation_timestamp() < oldest_acceptable_attestation_time { + >::remove(&enclave_signer); + } else { + return Err(>::UnregisterActiveEnclaveNotAllowed.into()) + } + Self::deposit_event(Event::RemovedEnclave(enclave_signer)); Ok(().into()) } @@ -248,7 +331,10 @@ pub mod pallet { trusted_calls_merkle_root: H256, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - Self::ensure_registered_enclave(&sender)?; + let enclave = + >::get(&sender).ok_or(>::EnclaveIsNotRegistered)?; + Self::touch_shard(enclave.fingerprint(), &sender)?; + log::debug!( "Processed parentchain block confirmed for mrenclave {:?}, block hash {:?}", sender, @@ -296,11 +382,12 @@ pub mod pallet { call_hash: H256, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - Self::ensure_registered_enclave(&sender)?; - let sender_enclave = Self::get_enclave(&sender)?; + let sender_enclave = + >::get(&sender).ok_or(>::EnclaveIsNotRegistered)?; + Self::touch_shard(sender_enclave.fingerprint(), &sender)?; ensure!( - sender_enclave.mr_enclave.encode() == bonding_account.encode(), + sender_enclave.fingerprint().encode() == bonding_account.encode(), >::WrongMrenclaveForBondingAccount ); @@ -322,65 +409,6 @@ pub mod pallet { Ok(().into()) } - #[pallet::call_index(6)] - #[pallet::weight((::WeightInfo::register_dcap_enclave(), DispatchClass::Normal, Pays::Yes))] - pub fn register_dcap_enclave( - origin: OriginFor, - dcap_quote: Vec, - worker_url: Vec, - ) -> DispatchResultWithPostInfo { - log::info!("teerex: called into runtime call register_dcap_enclave()"); - let sender = ensure_signed(origin)?; - ensure!(dcap_quote.len() <= MAX_DCAP_QUOTE_LEN, >::RaReportTooLong); - ensure!(worker_url.len() <= MAX_URL_LEN, >::EnclaveUrlTooLong); - log::info!("teerex: parameter length ok"); - - #[cfg(not(feature = "skip-ias-check"))] - let enclave = Self::verify_dcap_quote(&sender, dcap_quote)?.with_url(worker_url.clone()); - - #[cfg(not(feature = "skip-ias-check"))] - if !>::get() && enclave.build_mode == SgxBuildMode::Debug { - log::warn!("teerex: debug mode is not allowed to attest!"); - return Err(>::SgxModeNotAllowed.into()) - } - - #[cfg(feature = "skip-ias-check")] - log::warn!("[teerex]: Skipping remote attestation check. Only dev-chains are allowed to do this!"); - - #[cfg(feature = "skip-ias-check")] - let enclave = SgxEnclave::new( - SgxReportData::default(), - // insert mrenclave if the ra_report represents one, otherwise insert default - ::decode(&mut dcap_quote.as_slice()).unwrap_or_default(), - MrSigner::default(), - >::get().saturated_into(), - SgxBuildMode::default(), - SgxStatus::Invalid, - ) - .with_pubkey(&sender.encode()) - .with_url(worker_url.clone()) - .with_attestation_method(SgxAttestationMethod::Skip { proxied: false }); - - Self::add_enclave(&sender, &enclave)?; - - #[cfg(not(feature = "skip-ias-check"))] - Self::deposit_event(Event::AddedEnclave { - registered_by: sender, - worker_url, - tcb_status: Some(enclave.status), - attestation_method: enclave.attestation_method, - }); - - #[cfg(feature = "skip-ias-check")] - Self::deposit_event(Event::AddedEnclave { - registered_by: sender, - worker_url, - tcb_status: None, - attestation_method: SgxAttestationMethod::Skip { proxied: false }, - }); - Ok(().into()) - } - #[pallet::call_index(7)] #[pallet::weight((::WeightInfo::register_quoting_enclave(), DispatchClass::Normal, Pays::Yes))] pub fn register_quoting_enclave( @@ -398,7 +426,7 @@ pub mod pallet { certificate_chain, )?; >::put("ing_enclave); - Self::deposit_event(Event::QuotingEnclaveRegistered { quoting_enclave }); + Self::deposit_event(Event::SgxQuotingEnclaveRegistered { quoting_enclave }); Ok(().into()) } @@ -416,7 +444,7 @@ pub mod pallet { let (fmspc, on_chain_info) = Self::verify_tcb_info(tcb_info, signature, certificate_chain)?; >::insert(fmspc, &on_chain_info); - Self::deposit_event(Event::TcbInfoRegistered { fmspc, on_chain_info }); + Self::deposit_event(Event::SgxTcbInfoRegistered { fmspc, on_chain_info }); Ok(().into()) } @@ -436,18 +464,19 @@ pub mod pallet { data: Vec, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - Self::ensure_registered_enclave(&sender)?; - let enclave = Self::get_enclave(&sender)?; + let enclave = + >::get(&sender).ok_or(>::EnclaveIsNotRegistered)?; + Self::touch_shard(enclave.fingerprint(), &sender)?; ensure!(extra_topics.len() <= TOPICS_LIMIT, >::TooManyTopics); ensure!(data.len() <= DATA_LENGTH_LIMIT, >::DataTooLong); let mut topics = extra_topics; - topics.push(enclave.mr_enclave.into()); + topics.push(T::Hash::from(enclave.fingerprint().into())); Self::deposit_event_indexed( &topics, - Event::PublishedHash { mr_enclave: enclave.mr_enclave, hash, data }, + Event::PublishedHash { fingerprint: enclave.fingerprint(), hash, data }, ); Ok(().into()) @@ -470,11 +499,11 @@ pub mod pallet { /// The bonding account doesn't match the enclave. WrongMrenclaveForBondingAccount, /// The shard doesn't match the enclave. - WrongMrenclaveForShard, + WrongFingerprintForShard, /// The worker url is too long. EnclaveUrlTooLong, - /// The Remote Attestation report is too long. - RaReportTooLong, + /// The Remote Attestation proof is too long. + RaProofTooLong, /// No enclave is registered. EmptyEnclaveRegistry, /// The provided collateral data is invalid @@ -483,103 +512,30 @@ pub mod pallet { TooManyTopics, /// The length of the `data` passed to `publish_hash` exceeds the limit. DataTooLong, + /// It is not allowed to unregister enclaves with recent activity + UnregisterActiveEnclaveNotAllowed, } } impl Pallet { pub fn add_enclave( sender: &T::AccountId, - enclave: &SgxEnclave>, + multi_enclave: &MultiEnclave>, ) -> DispatchResultWithPostInfo { - let enclave_idx = if >::contains_key(sender) { - log::info!("Updating already registered enclave"); - >::get(sender) - } else { - let enclaves_count = Self::enclave_count() - .checked_add(1) - .ok_or("[Teerex]: Overflow adding new enclave to registry")?; - >::insert(sender, enclaves_count); - >::put(enclaves_count); - enclaves_count - }; - - >::insert(enclave_idx, enclave); - Ok(().into()) - } - - fn remove_enclave(sender: &T::AccountId) -> DispatchResultWithPostInfo { - ensure!(>::contains_key(sender), >::EnclaveIsNotRegistered); - let index_to_remove = >::take(sender); - - let enclaves_count = Self::enclave_count(); - let new_enclaves_count = enclaves_count - .checked_sub(1) - .ok_or("[Teerex]: Underflow removing an enclave from the registry")?; - - Self::swap_and_pop(index_to_remove, new_enclaves_count + 1)?; - >::put(new_enclaves_count); - - Ok(().into()) - } - - pub(crate) fn get_enclave(sender: &T::AccountId) -> Result>, Error> { - let sender_index = >::get(sender); - >::get(sender_index).ok_or(Error::::EmptyEnclaveRegistry) - } - - /// Our list implementation would introduce holes in out list if if we try to remove elements from the middle. - /// As the order of the enclave entries is not important, we use the swap and pop method to remove elements from - /// the registry. - fn swap_and_pop(index_to_remove: u64, new_enclaves_count: u64) -> DispatchResultWithPostInfo { - if index_to_remove != new_enclaves_count { - let last_enclave = >::get(new_enclaves_count) - .ok_or(Error::::EmptyEnclaveRegistry)?; - >::insert(index_to_remove, &last_enclave); - >::insert( - last_enclave - .maybe_pubkey::() - .ok_or(Error::::EnclaveSignerDecodeError)?, - index_to_remove, - ); + if multi_enclave.clone().attestaion_proxied() { + log::warn!("proxied enclaves not supported yet"); + return Err(Error::::SenderIsNotAttestedEnclave.into()) } - >::remove(new_enclaves_count); + >::insert(sender, multi_enclave); Ok(().into()) } - fn unregister_silent_workers(now: T::Moment) { - let minimum = now.saturating_sub(T::MaxSilenceTime::get()).saturated_into::(); - if minimum == 0 { - log::error!("Invalid time in unregister_silent_workers. Is the timestamp pallet properly configured?"); - return - } - let silent_workers = >::iter() - .filter(|e| e.1.timestamp < minimum) - .map(|e| e.1.maybe_pubkey()); - for maybe_index in silent_workers { - match maybe_index { - Some(index) => { - let result = Self::remove_enclave(&index); - match result { - Ok(_) => { - log::info!("Unregister enclave because silent worker : {:?}", index); - Self::deposit_event(Event::RemovedEnclave(index)); - }, - Err(e) => { - log::error!("Cannot unregister enclave : {:?}", e); - }, - }; - }, - None => log::error!("Cannot unregister enclave"), - } - } - } - /// Check if the sender is a registered enclave pub fn ensure_registered_enclave( account: &T::AccountId, ) -> Result<(), DispatchErrorWithPostInfo> { - ensure!(>::contains_key(account), >::EnclaveIsNotRegistered); + ensure!(>::contains_key(account), >::EnclaveIsNotRegistered); Ok(()) } @@ -593,76 +549,6 @@ impl Pallet { ) } - #[cfg(not(feature = "skip-ias-check"))] - fn verify_report( - sender: &T::AccountId, - ra_report: Vec, - ) -> Result>, DispatchErrorWithPostInfo> { - let report = sgx_verify::verify_ias_report(&ra_report) - .map_err(|_| >::RemoteAttestationVerificationFailed)?; - log::info!("teerex: IAS report successfully verified"); - let enclave = SgxEnclave::new( - report.report_data, - report.mr_enclave, - report.mr_signer, - report.timestamp, - report.build_mode, - report.status, - ) - .with_attestation_method(SgxAttestationMethod::Ias); - let enclave_signer = enclave.maybe_pubkey().ok_or(>::EnclaveSignerDecodeError)?; - - ensure!(sender == &enclave_signer, >::SenderIsNotAttestedEnclave); - - // TODO: activate state checks as soon as we've fixed our setup #83 - // ensure!((report.status == SgxStatus::Ok) | (report.status == SgxStatus::ConfigurationNeeded), - // "RA status is insufficient"); - // log::info!("teerex: status is acceptable"); - - Self::ensure_timestamp_within_24_hours(report.timestamp)?; - Ok(enclave) - } - - #[cfg(not(feature = "skip-ias-check"))] - fn verify_dcap_quote( - sender: &T::AccountId, - dcap_quote: Vec, - ) -> Result>, DispatchErrorWithPostInfo> { - let verification_time = >::get(); - - let qe = >::get(); - let (fmspc, tcb_info, report) = - sgx_verify::verify_dcap_quote(&dcap_quote, verification_time.saturated_into(), &qe) - .map_err(|e| { - log::warn!("verify_dcap_quote failed: {:?}", e); - >::RemoteAttestationVerificationFailed - })?; - - log::info!("teerex: DCAP quote verified. FMSPC from quote: {:?}", fmspc); - let tcb_info_on_chain = >::get(fmspc); - ensure!(tcb_info_on_chain.verify_examinee(&tcb_info), "tcb_info is outdated"); - - let enclave = SgxEnclave::new( - report.report_data, - report.mr_enclave, - report.mr_signer, - report.timestamp, - report.build_mode, - report.status, - ) - .with_attestation_method(SgxAttestationMethod::Dcap { proxied: false }); - - let enclave_signer = enclave.maybe_pubkey().ok_or(>::EnclaveSignerDecodeError)?; - ensure!(sender == &enclave_signer, >::SenderIsNotAttestedEnclave); - - // TODO: activate state checks as soon as we've fixed our setup #83 - // ensure!((report.status == SgxStatus::Ok) | (report.status == SgxStatus::ConfigurationNeeded), - // "RA status is insufficient"); - // log::info!("teerex: status is acceptable"); - - Ok(enclave) - } - fn verify_quoting_enclave( enclave_identity: Vec, signature: Vec, @@ -703,7 +589,6 @@ impl Pallet { } } - #[cfg(not(feature = "skip-ias-check"))] fn ensure_timestamp_within_24_hours(report_timestamp: u64) -> DispatchResultWithPostInfo { use sp_runtime::traits::CheckedSub; @@ -717,11 +602,46 @@ impl Pallet { Err(>::RemoteAttestationTooOld.into()) } } -} -impl OnTimestampSet for Pallet { - fn on_timestamp_set(moment: T::Moment) { - Self::unregister_silent_workers(moment) + pub fn touch_shard( + shard: ShardIdentifier, + enclave_signer: &T::AccountId, + ) -> Result, DispatchErrorWithPostInfo> { + let enclave = Self::sovereign_enclaves(enclave_signer.clone()) + .ok_or(>::EnclaveIsNotRegistered)?; + + let current_block_number = >::block_number(); + + let new_status = ShardSignerStatus { + signer: enclave_signer.clone(), + fingerprint: enclave.fingerprint(), + last_activity: current_block_number, + }; + + let signer_statuses = >::get(shard) + .map(|mut status_vec| { + if let Some(index) = status_vec.iter().position(|i| &i.signer == enclave_signer) { + status_vec[index] = new_status.clone(); + } else { + status_vec.push(new_status.clone()); + } + status_vec + }) + .unwrap_or_else(|| vec![new_status]); + + >::insert(shard, signer_statuses.clone()); + Ok(signer_statuses) + } + + pub fn most_recent_shard_update( + shard: &ShardIdentifier, + ) -> Option> { + >::get(shard) + .map(|mut statuses| { + statuses.sort_by_key(|a| a.last_activity); + statuses.last().cloned() + }) + .unwrap_or_default() } } diff --git a/teerex/src/mock.rs b/teerex/src/mock.rs index d9d64a24..50517b09 100644 --- a/teerex/src/mock.rs +++ b/teerex/src/mock.rs @@ -119,7 +119,7 @@ pub type Moment = u64; impl timestamp::Config for Test { type Moment = Moment; - type OnTimestampSet = Teerex; + type OnTimestampSet = (); type MinimumPeriod = MinimumPeriod; type WeightInfo = (); } diff --git a/teerex/src/tests/test_cases.rs b/teerex/src/tests/test_cases.rs index 24a7f0b1..39eb0d68 100644 --- a/teerex/src/tests/test_cases.rs +++ b/teerex/src/tests/test_cases.rs @@ -18,22 +18,24 @@ use crate::{ mock::*, test_helpers::{register_test_quoting_enclave, register_test_tcb_info}, - EnclaveRegistry, Error, Event as TeerexEvent, ExecutedCalls, Request, SgxEnclave, - ShardIdentifier, DATA_LENGTH_LIMIT, + Error, Event as TeerexEvent, ExecutedCalls, Request, SgxEnclave, ShardIdentifier, + SovereignEnclaves, DATA_LENGTH_LIMIT, }; use frame_support::{assert_err, assert_ok}; use hex_literal::hex; use sgx_verify::test_data::dcap::TEST1_DCAP_QUOTE_SIGNER; use sp_core::H256; use sp_keyring::AccountKeyring; -use teerex_primitives::{SgxAttestationMethod, SgxBuildMode, SgxReportData, SgxStatus}; +use teerex_primitives::{ + MultiEnclave, SgxAttestationMethod, SgxBuildMode, SgxReportData, SgxStatus, +}; use test_utils::test_data::{ consts::*, dcap::{TEST1_DCAP_QUOTE, TEST_VALID_COLLATERAL_TIMESTAMP}, }; -fn list_enclaves() -> Vec<(u64, SgxEnclave>)> { - >::iter().collect::>)>>() +fn list_enclaves() -> Vec<(AccountId, MultiEnclave>)> { + >::iter().collect::>)>>() } // give get_signer a concrete type @@ -48,22 +50,60 @@ fn add_and_remove_dcap_enclave_works() { let alice = AccountKeyring::Alice.to_account_id(); register_test_quoting_enclave::(alice.clone()); - register_test_tcb_info::(alice); + register_test_tcb_info::(alice.clone()); let signer = get_signer(&TEST1_DCAP_QUOTE_SIGNER); - assert_ok!(Teerex::register_dcap_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer.clone()), TEST1_DCAP_QUOTE.to_vec(), - URL.to_vec() + Some(URL.to_vec()), + SgxAttestationMethod::Dcap { proxied: false } + )); + assert!(>::contains_key(&signer)); + assert_eq!( + Teerex::sovereign_enclaves(&signer).unwrap().attestation_timestamp(), + TEST_VALID_COLLATERAL_TIMESTAMP + ); + Timestamp::set_timestamp(TEST_VALID_COLLATERAL_TIMESTAMP + ::get() + 1); + assert_ok!(Teerex::unregister_sovereign_enclave( + RuntimeOrigin::signed(alice.clone()), + signer.clone() )); - assert_eq!(Teerex::enclave_count(), 1); - assert_eq!(Teerex::enclave(1).unwrap().timestamp, TEST_VALID_COLLATERAL_TIMESTAMP); - assert_ok!(Teerex::unregister_enclave(RuntimeOrigin::signed(signer))); - assert_eq!(Teerex::enclave_count(), 0); + assert!(!>::contains_key(&signer)); assert_eq!(list_enclaves(), vec![]) }) } +#[test] +fn unregister_active_enclave_fails() { + new_test_ext().execute_with(|| { + Timestamp::set_timestamp(TEST_VALID_COLLATERAL_TIMESTAMP); + let alice = AccountKeyring::Alice.to_account_id(); + register_test_quoting_enclave::(alice.clone()); + register_test_tcb_info::(alice.clone()); + + let signer = get_signer(&TEST1_DCAP_QUOTE_SIGNER); + assert_ok!(Teerex::register_sgx_enclave( + RuntimeOrigin::signed(signer.clone()), + TEST1_DCAP_QUOTE.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Dcap { proxied: false } + )); + assert!(>::contains_key(&signer)); + + Timestamp::set_timestamp(TEST_VALID_COLLATERAL_TIMESTAMP + ::get() / 2 + 1); + + assert_err!( + Teerex::unregister_sovereign_enclave( + RuntimeOrigin::signed(alice.clone()), + signer.clone() + ), + Error::::UnregisterActiveEnclaveNotAllowed + ); + assert!(>::contains_key(&signer)); + }) +} + #[test] fn register_quoting_enclave_works() { new_test_ext().execute_with(|| { @@ -77,7 +117,7 @@ fn register_quoting_enclave_works() { assert_eq!(qe.isvprodid, 1); let expected_event = - RuntimeEvent::Teerex(TeerexEvent::QuotingEnclaveRegistered { quoting_enclave: qe }); + RuntimeEvent::Teerex(TeerexEvent::SgxQuotingEnclaveRegistered { quoting_enclave: qe }); assert!(System::events().iter().any(|a| a.event == expected_event)) }) } @@ -93,8 +133,10 @@ fn register_tcb_info_works() { // This is the date that the is registered in register_tcb_info and represents the date 2023-04-16T12:45:32Z assert_eq!(tcb_info.next_update, 1681649132000); - let expected_event = - RuntimeEvent::Teerex(TeerexEvent::TcbInfoRegistered { fmspc, on_chain_info: tcb_info }); + let expected_event = RuntimeEvent::Teerex(TeerexEvent::SgxTcbInfoRegistered { + fmspc, + on_chain_info: tcb_info, + }); assert!(System::events().iter().any(|a| a.event == expected_event)) }) } @@ -105,12 +147,13 @@ fn add_enclave_works() { // set the now in the runtime such that the remote attestation reports are within accepted range (24h) Timestamp::set_timestamp(TEST4_TIMESTAMP); let signer = get_signer(TEST4_SIGNER_PUB); - assert_ok!(Teerex::register_ias_enclave( - RuntimeOrigin::signed(signer), + assert_ok!(Teerex::register_sgx_enclave( + RuntimeOrigin::signed(signer.clone()), TEST4_CERT.to_vec(), - URL.to_vec() + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); - assert_eq!(Teerex::enclave_count(), 1); + assert!(>::contains_key(&signer)); }) } @@ -118,15 +161,21 @@ fn add_enclave_works() { fn add_and_remove_enclave_works() { new_test_ext().execute_with(|| { Timestamp::set_timestamp(TEST4_TIMESTAMP); + let alice = AccountKeyring::Alice.to_account_id(); let signer = get_signer(TEST4_SIGNER_PUB); - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer.clone()), TEST4_CERT.to_vec(), - URL.to_vec() + Some(URL.to_vec()), + SgxAttestationMethod::Ias + )); + assert!(>::contains_key(&signer)); + Timestamp::set_timestamp(TEST4_TIMESTAMP + ::get() + 1); + assert_ok!(Teerex::unregister_sovereign_enclave( + RuntimeOrigin::signed(alice.clone()), + signer.clone() )); - assert_eq!(Teerex::enclave_count(), 1); - assert_ok!(Teerex::unregister_enclave(RuntimeOrigin::signed(signer))); - assert_eq!(Teerex::enclave_count(), 0); + assert!(!>::contains_key(&signer)); assert_eq!(list_enclaves(), vec![]) }) } @@ -136,13 +185,14 @@ fn add_enclave_without_timestamp_fails() { new_test_ext().execute_with(|| { Timestamp::set_timestamp(0); let signer = get_signer(TEST4_SIGNER_PUB); - assert!(Teerex::register_ias_enclave( + assert!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias ) .is_err()); - assert_eq!(Teerex::enclave_count(), 0); + assert!(!>::contains_key(&signer)); }) } @@ -161,100 +211,15 @@ fn list_enclaves_works() { attestation_method: SgxAttestationMethod::Ias, status: SgxStatus::ConfigurationNeeded, }; - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), - )); - assert_eq!(Teerex::enclave_count(), 1); - let enclaves = list_enclaves(); - assert_eq!(enclaves[0].1.maybe_pubkey(), Some(signer)); - assert_eq!(enclaves[0].1, e_1); - assert!(enclaves.contains(&(1, e_1))); - }) -} - -#[test] -fn remove_middle_enclave_works() { - new_test_ext().execute_with(|| { - // use the newest timestamp, is as now such that all reports are valid - Timestamp::set_timestamp(TEST7_TIMESTAMP); - - let signer5 = get_signer(TEST5_SIGNER_PUB); - let signer6 = get_signer(TEST6_SIGNER_PUB); - let signer7 = get_signer(TEST7_SIGNER_PUB); - - // add enclave 1 - let e_1: SgxEnclave> = SgxEnclave { - report_data: SgxReportData::from(TEST5_SIGNER_PUB), - mr_enclave: TEST5_MRENCLAVE, - timestamp: TEST5_TIMESTAMP, - url: Some(URL.to_vec()), - build_mode: SgxBuildMode::Debug, - mr_signer: TEST4_MRSIGNER, - attestation_method: SgxAttestationMethod::Ias, - status: SgxStatus::ConfigurationNeeded, - }; - - let e_2: SgxEnclave> = SgxEnclave { - report_data: SgxReportData::from(TEST6_SIGNER_PUB), - mr_enclave: TEST6_MRENCLAVE, - timestamp: TEST6_TIMESTAMP, - url: Some(URL.to_vec()), - build_mode: SgxBuildMode::Debug, - mr_signer: TEST4_MRSIGNER, - attestation_method: SgxAttestationMethod::Ias, - status: SgxStatus::ConfigurationNeeded, - }; - - let e_3: SgxEnclave> = SgxEnclave { - report_data: SgxReportData::from(TEST7_SIGNER_PUB), - mr_enclave: TEST7_MRENCLAVE, - timestamp: TEST7_TIMESTAMP, - url: Some(URL.to_vec()), - build_mode: SgxBuildMode::Debug, - mr_signer: TEST4_MRSIGNER, - attestation_method: SgxAttestationMethod::Ias, - status: SgxStatus::ConfigurationNeeded, - }; - - assert_ok!(Teerex::register_ias_enclave( - RuntimeOrigin::signed(signer5), - TEST5_CERT.to_vec(), - URL.to_vec(), - )); - assert_eq!(Teerex::enclave_count(), 1); - assert_eq!(list_enclaves(), vec![(1, e_1.clone())]); - - // add enclave 2 - assert_ok!(Teerex::register_ias_enclave( - RuntimeOrigin::signed(signer6.clone()), - TEST6_CERT.to_vec(), - URL.to_vec(), - )); - assert_eq!(Teerex::enclave_count(), 2); - let enclaves = list_enclaves(); - assert!(enclaves.contains(&(1, e_1.clone()))); - assert!(enclaves.contains(&(2, e_2.clone()))); - - // add enclave 3 - assert_ok!(Teerex::register_ias_enclave( - RuntimeOrigin::signed(signer7), - TEST7_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias, )); - assert_eq!(Teerex::enclave_count(), 3); + assert!(>::contains_key(&signer)); let enclaves = list_enclaves(); - assert!(enclaves.contains(&(1, e_1.clone()))); - assert!(enclaves.contains(&(2, e_2))); - assert!(enclaves.contains(&(3, e_3.clone()))); - - // remove enclave 2 - assert_ok!(Teerex::unregister_enclave(RuntimeOrigin::signed(signer6))); - assert_eq!(Teerex::enclave_count(), 2); - let enclaves = list_enclaves(); - assert!(enclaves.contains(&(1, e_1))); - assert!(enclaves.contains(&(2, e_3))); + assert_eq!(enclaves[0].1, MultiEnclave::from(e_1)); }) } @@ -262,11 +227,13 @@ fn remove_middle_enclave_works() { fn register_ias_enclave_with_different_signer_fails() { new_test_ext().execute_with(|| { let signer = get_signer(TEST7_SIGNER_PUB); + Timestamp::set_timestamp(TEST7_TIMESTAMP); assert_err!( - Teerex::register_ias_enclave( + Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer), TEST5_CERT.to_vec(), - URL.to_vec() + Some(URL.to_vec()), + SgxAttestationMethod::Ias ), Error::::SenderIsNotAttestedEnclave ); @@ -279,10 +246,11 @@ fn register_ias_enclave_with_to_old_attestation_report_fails() { Timestamp::set_timestamp(TEST7_TIMESTAMP + TWENTY_FOUR_HOURS + 1); let signer = get_signer(TEST7_SIGNER_PUB); assert_err!( - Teerex::register_ias_enclave( + Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer), TEST7_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias ), Error::::RemoteAttestationTooOld ); @@ -294,10 +262,11 @@ fn register_ias_enclave_with_almost_too_old_report_works() { new_test_ext().execute_with(|| { Timestamp::set_timestamp(TEST7_TIMESTAMP + TWENTY_FOUR_HOURS - 1); let signer = get_signer(TEST7_SIGNER_PUB); - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer), TEST7_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); }) } @@ -313,28 +282,31 @@ fn update_enclave_url_works() { report_data: SgxReportData::from(TEST4_SIGNER_PUB), mr_enclave: TEST4_MRENCLAVE, timestamp: TEST4_TIMESTAMP, - url: Some(url2.to_vec()), + url: None, build_mode: SgxBuildMode::Debug, mr_signer: TEST4_MRSIGNER, attestation_method: SgxAttestationMethod::Ias, status: SgxStatus::ConfigurationNeeded, }; - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); - assert_eq!(Teerex::enclave(1).unwrap().url, Some(URL.to_vec())); + assert_eq!(Teerex::sovereign_enclaves(&signer).unwrap().instance_url(), Some(URL.to_vec())); - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer.clone()), TEST4_CERT.to_vec(), - url2.to_vec(), + Some(url2.to_vec()), + SgxAttestationMethod::Ias )); - assert_eq!(Teerex::enclave(1).unwrap().url, Some(url2.to_vec())); - let enclaves = list_enclaves(); - assert_eq!(enclaves[0].1.maybe_pubkey(), Some(signer)) + assert_eq!( + Teerex::sovereign_enclaves(&signer).unwrap().instance_url(), + Some(url2.to_vec()) + ); }) } @@ -347,12 +319,13 @@ fn update_ipfs_hash_works() { let block_number = 3; let signer = get_signer(TEST4_SIGNER_PUB); - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); - assert_eq!(Teerex::enclave_count(), 1); + assert!(>::contains_key(&signer)); assert_ok!(Teerex::confirm_processed_parentchain_block( RuntimeOrigin::signed(signer.clone()), block_hash, @@ -407,10 +380,11 @@ fn unshield_is_only_executed_once_for_the_same_call_hash() { let call_hash: H256 = H256::from([1u8; 32]); let bonding_account = get_signer(&TEST4_MRENCLAVE); - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); assert_ok!(Balances::transfer( @@ -440,87 +414,6 @@ fn unshield_is_only_executed_once_for_the_same_call_hash() { assert_eq!(>::get(call_hash), 2) }) } -#[test] -fn timestamp_callback_works() { - new_test_ext().execute_with(|| { - set_timestamp(TEST7_TIMESTAMP); - - let signer5 = get_signer(TEST5_SIGNER_PUB); - let signer6 = get_signer(TEST6_SIGNER_PUB); - let signer7 = get_signer(TEST7_SIGNER_PUB); - - // add enclave 1 - let e_2: SgxEnclave> = SgxEnclave { - report_data: SgxReportData::from(TEST6_SIGNER_PUB), - mr_enclave: TEST6_MRENCLAVE, - timestamp: TEST6_TIMESTAMP, - url: Some(URL.to_vec()), - build_mode: SgxBuildMode::Debug, - mr_signer: TEST4_MRSIGNER, - attestation_method: SgxAttestationMethod::Ias, - status: SgxStatus::ConfigurationNeeded, - }; - - let e_3: SgxEnclave> = SgxEnclave { - report_data: SgxReportData::from(TEST7_SIGNER_PUB), - mr_enclave: TEST7_MRENCLAVE, - timestamp: TEST7_TIMESTAMP, - url: Some(URL.to_vec()), - build_mode: SgxBuildMode::Debug, - mr_signer: TEST4_MRSIGNER, - attestation_method: SgxAttestationMethod::Ias, - status: SgxStatus::ConfigurationNeeded, - }; - - //Register 3 enclaves: 5, 6 ,7 - assert_ok!(Teerex::register_ias_enclave( - RuntimeOrigin::signed(signer5.clone()), - TEST5_CERT.to_vec(), - URL.to_vec(), - )); - assert_ok!(Teerex::register_ias_enclave( - RuntimeOrigin::signed(signer6.clone()), - TEST6_CERT.to_vec(), - URL.to_vec(), - )); - assert_ok!(Teerex::register_ias_enclave( - RuntimeOrigin::signed(signer7.clone()), - TEST7_CERT.to_vec(), - URL.to_vec(), - )); - assert_eq!(Teerex::enclave_count(), 3); - - //enclave 5 silent since 49h -> unregistered - run_to_block(2); - set_timestamp(TEST5_TIMESTAMP + 2 * TWENTY_FOUR_HOURS + 1); - - let expected_event = RuntimeEvent::Teerex(TeerexEvent::RemovedEnclave(signer5)); - assert!(System::events().iter().any(|a| a.event == expected_event)); - assert_eq!(Teerex::enclave_count(), 2); - //2 and 3 are still there. 3 and 1 were swapped -> 3 and 2 - let enclaves = list_enclaves(); - assert!(enclaves.contains(&(1, e_3))); - assert!(enclaves.contains(&(2, e_2))); - - run_to_block(3); - //enclave 6 and 7 still registered: not long enough silent - set_timestamp(TEST6_TIMESTAMP + 2 * TWENTY_FOUR_HOURS); - assert_eq!(Teerex::enclave_count(), 2); - - //unregister 6 to generate an error next call of callbakc - assert_ok!(Teerex::unregister_enclave(RuntimeOrigin::signed(signer6.clone()))); - let expected_event = RuntimeEvent::Teerex(TeerexEvent::RemovedEnclave(signer6)); - assert!(System::events().iter().any(|a| a.event == expected_event)); - assert_eq!(Teerex::enclave_count(), 1); - - //enclave 6 and 7 silent since TWENTY_FOUR_HOURS + 1 -> unregistered - run_to_block(4); - set_timestamp(TEST7_TIMESTAMP + 2 * TWENTY_FOUR_HOURS + 1); - let expected_event = RuntimeEvent::Teerex(TeerexEvent::RemovedEnclave(signer7)); - assert!(System::events().iter().any(|a| a.event == expected_event)); - assert_eq!(Teerex::enclave_count(), 0); - }) -} #[test] fn debug_mode_enclave_attest_works_when_sgx_debug_mode_is_allowed() { @@ -539,14 +432,15 @@ fn debug_mode_enclave_attest_works_when_sgx_debug_mode_is_allowed() { }; //Register an enclave compiled in debug mode - assert_ok!(Teerex::register_ias_enclave( - RuntimeOrigin::signed(signer4), + assert_ok!(Teerex::register_sgx_enclave( + RuntimeOrigin::signed(signer4.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); - assert_eq!(Teerex::enclave_count(), 1); + assert!(>::contains_key(&signer4)); let enclaves = list_enclaves(); - assert!(enclaves.contains(&(1, e_0))); + assert!(enclaves.contains(&(signer4, MultiEnclave::from(e_0)))); }) } @@ -568,15 +462,15 @@ fn production_mode_enclave_attest_works_when_sgx_debug_mode_is_allowed() { }; //Register an enclave compiled in production mode - assert_ok!(Teerex::register_ias_enclave( - RuntimeOrigin::signed(signer8), + assert_ok!(Teerex::register_sgx_enclave( + RuntimeOrigin::signed(signer8.clone()), TEST8_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); - assert_eq!(Teerex::enclave_count(), 1); + assert!(>::contains_key(&signer8)); let enclaves = list_enclaves(); - assert_eq!(enclaves[0].1, e_0); - assert!(enclaves.contains(&(1, e_0))); + assert!(enclaves.contains(&(signer8, MultiEnclave::from(e_0)))); }) }) } @@ -588,14 +482,15 @@ fn debug_mode_enclave_attest_fails_when_sgx_debug_mode_not_allowed() { let signer4 = get_signer(TEST4_SIGNER_PUB); //Try to register an enclave compiled in debug mode assert_err!( - Teerex::register_ias_enclave( - RuntimeOrigin::signed(signer4), + Teerex::register_sgx_enclave( + RuntimeOrigin::signed(signer4.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias ), Error::::SgxModeNotAllowed ); - assert_eq!(Teerex::enclave_count(), 0); + assert!(!>::contains_key(&signer4)); }) } #[test] @@ -615,15 +510,15 @@ fn production_mode_enclave_attest_works_when_sgx_debug_mode_not_allowed() { }; //Register an enclave compiled in production mode - assert_ok!(Teerex::register_ias_enclave( - RuntimeOrigin::signed(signer8), + assert_ok!(Teerex::register_sgx_enclave( + RuntimeOrigin::signed(signer8.clone()), TEST8_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); - assert_eq!(Teerex::enclave_count(), 1); + assert!(>::contains_key(&signer8)); let enclaves = list_enclaves(); - assert_eq!(enclaves[0].1, e_0); - assert!(enclaves.contains(&(1, e_0))); + assert!(enclaves.contains(&(signer8, MultiEnclave::from(e_0)))); }) } @@ -637,12 +532,13 @@ fn verify_unshield_funds_works() { let incognito_account = INCOGNITO_ACCOUNT.to_vec(); //Register enclave - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer4.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); - assert_eq!(Teerex::enclave_count(), 1); + assert!(>::contains_key(&signer4)); assert!(Teerex::shield_funds( RuntimeOrigin::signed(AccountKeyring::Alice.to_account_id()), @@ -681,7 +577,7 @@ fn unshield_funds_from_not_registered_enclave_errs() { let signer4 = get_signer(TEST4_SIGNER_PUB); let call_hash: H256 = H256::from([1u8; 32]); - assert_eq!(Teerex::enclave_count(), 0); + assert_eq!(list_enclaves().len(), 0); assert_err!( Teerex::unshield_funds( @@ -707,10 +603,11 @@ fn unshield_funds_from_enclave_neq_bonding_account_errs() { let not_bonding_account = get_signer(&TEST7_MRENCLAVE); //Ensure that enclave is registered - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer4.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); //Ensure that bonding account has funds @@ -756,12 +653,13 @@ fn confirm_processed_parentchain_block_works() { let signer7 = get_signer(TEST7_SIGNER_PUB); //Ensure that enclave is registered - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer7.clone()), TEST7_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); - assert_eq!(Teerex::enclave_count(), 1); + assert!(>::contains_key(&signer7)); assert_ok!(Teerex::confirm_processed_parentchain_block( RuntimeOrigin::signed(signer7.clone()), @@ -788,10 +686,11 @@ fn ensure_registered_enclave_works() { let signer6 = get_signer(TEST6_SIGNER_PUB); //Ensure that enclave is registered - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer4.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); assert_ok!(Teerex::ensure_registered_enclave(&signer4)); assert_err!( @@ -810,10 +709,11 @@ fn publish_hash_works() { let signer4 = get_signer(TEST4_SIGNER_PUB); //Ensure that enclave is registered - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer4.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); // There are no events emitted at the genesis block. @@ -840,7 +740,7 @@ fn publish_hash_works() { vec![] )); - let mr_enclave = Teerex::get_enclave(&signer4).unwrap().mr_enclave; + let mr_enclave = Teerex::sovereign_enclaves(&signer4).unwrap().fingerprint(); let mut topics = extra_topics; topics.push(mr_enclave.into()); @@ -850,12 +750,22 @@ fn publish_hash_works() { vec![ EventRecord { phase: Phase::Initialization, - event: TeerexEvent::PublishedHash { mr_enclave, hash, data }.into(), + event: TeerexEvent::PublishedHash { + fingerprint: mr_enclave.into(), + hash, + data + } + .into(), topics, }, EventRecord { phase: Phase::Initialization, - event: TeerexEvent::PublishedHash { mr_enclave, hash, data: vec![] }.into(), + event: TeerexEvent::PublishedHash { + fingerprint: mr_enclave.into(), + hash, + data: vec![] + } + .into(), topics: vec![mr_enclave.into()], }, ] @@ -882,10 +792,11 @@ fn publish_hash_with_too_many_topics_fails() { let signer4 = get_signer(TEST4_SIGNER_PUB); //Ensure that enclave is registered - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer4.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); let hash = H256::from([1u8; 32]); @@ -912,10 +823,11 @@ fn publish_hash_with_too_much_data_fails() { let signer4 = get_signer(TEST4_SIGNER_PUB); //Ensure that enclave is registered - assert_ok!(Teerex::register_ias_enclave( + assert_ok!(Teerex::register_sgx_enclave( RuntimeOrigin::signed(signer4.clone()), TEST4_CERT.to_vec(), - URL.to_vec(), + Some(URL.to_vec()), + SgxAttestationMethod::Ias )); let hash = H256::from([1u8; 32]);