Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more ways to read scheduled enclave #2620

Merged
merged 18 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,7 @@ jobs:
- test_name: lit-dr-vc-test
- test_name: lit-parentchain-nonce
- test_name: lit-test-failed-parentchain-extrinsic
- test_name: lit-scheduled-enclave-test
steps:
- uses: actions/checkout@v4

Expand Down Expand Up @@ -770,6 +771,7 @@ jobs:
- test_name: lit-di-vc-multiworker-test
- test_name: lit-dr-vc-multiworker-test
- test_name: lit-resume-worker
- test_name: lit-scheduled-enclave-test
steps:
- uses: actions/checkout@v4

Expand Down
14 changes: 7 additions & 7 deletions bitacross-worker/DESIGN.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# sidechain startup internal view
# sidechain startup internal view

```mermaid
sequenceDiagram
participant integritee_network
Expand All @@ -14,13 +15,13 @@ sequenceDiagram
service ->> provisioningserver: spawn (`--mu-ra-port` | 3443)
activate provisioningserver
service ->> enclave: get_ecc_signing_pubkey
service ->> isinitializedserver: spawn (`--untrusted-http-port | 4545)
service ->> isinitializedserver: spawn (`--untrusted-http-port | 4545)
activate isinitializedserver
service ->> metrics: spawn (`--metrics-port`| 8787)
activate metrics
service ->> enclave_rpc: spawn (`--trusted-worker-port`| 2000)
activate enclave_rpc

service ->> enclave: generate_dcap_ra_extrinsic
service ->> integritee_network: send register_sgx_enclave extrinsic
service ->> integritee_network: get ShardStatus
Expand All @@ -30,7 +31,6 @@ sequenceDiagram
service ->> integritee_network: get_block
service ->> enclave: sync_parentchain(blocks, events, proofs)
end
service ->> enclave: init_enclave_sidechain_components
service ->> slotworker: spawn
loop forever
slotworker ->> enclave: execute_trusted_calls
Expand All @@ -46,7 +46,7 @@ sequenceDiagram
end
service ->> service: poll worker_for_shard
service ->> isinitializedserver: worker_for_shard_registered

deactivate enclave_rpc
deactivate metrics
deactivate isinitializedserver
Expand All @@ -61,11 +61,11 @@ sequenceDiagram
participant validateer_1
participant validateer_2
actor alice

validateer_1 ->> integritee_network: register_sgx_enclave()

validateer_2 ->> integritee_network: register_sgx_enclave()

validateer_2 ->> validateer_1: sidechain_fetchBlocksFromPeer()

validateer_1 ->> validateer_2: sidechain_importBlock()
Expand Down
5 changes: 0 additions & 5 deletions bitacross-worker/core-primitives/enclave-api/ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@ extern "C" {
encoded_base_dir_size: u32,
) -> sgx_status_t;

pub fn init_enclave_sidechain_components(
eid: sgx_enclave_id_t,
retval: *mut sgx_status_t,
) -> sgx_status_t;

pub fn init_direct_invocation_server(
eid: sgx_enclave_id_t,
retval: *mut sgx_status_t,
Expand Down
15 changes: 0 additions & 15 deletions bitacross-worker/core-primitives/enclave-api/src/enclave_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ pub trait EnclaveBase: Send + Sync + 'static {
untrusted_worker_addr: &str,
base_dir: &str,
) -> EnclaveResult<()>;

/// Initialize the enclave sidechain components.
fn init_enclave_sidechain_components(&self) -> EnclaveResult<()>;

/// Initialize the direct invocation RPC server.
fn init_direct_invocation_server(&self, rpc_server_addr: String) -> EnclaveResult<()>;

Expand Down Expand Up @@ -156,17 +152,6 @@ mod impl_ffi {
Ok(())
}

fn init_enclave_sidechain_components(&self) -> EnclaveResult<()> {
let mut retval = sgx_status_t::SGX_SUCCESS;

let result = unsafe { ffi::init_enclave_sidechain_components(self.eid, &mut retval) };

ensure!(result == sgx_status_t::SGX_SUCCESS, Error::Sgx(result));
ensure!(retval == sgx_status_t::SGX_SUCCESS, Error::Sgx(retval));

Ok(())
}

fn init_direct_invocation_server(&self, rpc_server_addr: String) -> EnclaveResult<()> {
let mut retval = sgx_status_t::SGX_SUCCESS;

Expand Down
2 changes: 0 additions & 2 deletions bitacross-worker/enclave-runtime/Enclave.edl
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ enclave {

public sgx_status_t publish_wallets();

public sgx_status_t init_enclave_sidechain_components();

public sgx_status_t init_direct_invocation_server(
[in, size=server_addr_size] uint8_t* server_addr, uint32_t server_addr_size
);
Expand Down
12 changes: 4 additions & 8 deletions bitacross-worker/enclave-runtime/src/initialization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@ fn run_bit_across_handler() -> Result<(), Error> {
let ethereum_key_repository = GLOBAL_ETHEREUM_KEY_REPOSITORY_COMPONENT.get()?;
let bitcoin_key_repository = GLOBAL_BITCOIN_KEY_REPOSITORY_COMPONENT.get()?;

let attestation_handler = GLOBAL_ATTESTATION_HANDLER_COMPONENT.get()?;
let mrenclave = attestation_handler.get_mrenclave()?;
GLOBAL_SCHEDULED_ENCLAVE.init(mrenclave).map_err(|e| Error::Other(e.into()))?;

#[allow(clippy::unwrap_used)]
let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?;
let stf_enclave_signer = Arc::new(EnclaveStfEnclaveSigner::new(
Expand All @@ -311,14 +315,6 @@ fn run_bit_across_handler() -> Result<(), Error> {
Ok(())
}

pub(crate) fn init_enclave_sidechain_components() -> EnclaveResult<()> {
// GLOBAL_SCHEDULED_ENCLAVE must be initialized after attestation_handler and enclave
let attestation_handler = GLOBAL_ATTESTATION_HANDLER_COMPONENT.get()?;
let mrenclave = attestation_handler.get_mrenclave()?;
GLOBAL_SCHEDULED_ENCLAVE.init(mrenclave).map_err(|e| Error::Other(e.into()))?;
Ok(())
}

pub(crate) fn init_direct_invocation_server(server_addr: String) -> EnclaveResult<()> {
let rpc_handler = GLOBAL_RPC_WS_HANDLER_COMPONENT.get()?;
let signer = GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT.get()?.retrieve_key()?;
Expand Down
15 changes: 0 additions & 15 deletions bitacross-worker/enclave-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,21 +398,6 @@ pub unsafe extern "C" fn publish_wallets() -> sgx_status_t {
sgx_status_t::SGX_SUCCESS
}

/// Initialize sidechain enclave components.
///
/// Call this once at startup. Has to be called AFTER the light-client
/// (parentchain components) have been initialized (because we need the parentchain
/// block import dispatcher).
#[no_mangle]
pub unsafe extern "C" fn init_enclave_sidechain_components() -> sgx_status_t {
if let Err(e) = initialization::init_enclave_sidechain_components() {
error!("Failed to initialize sidechain components: {:?}", e);
return sgx_status_t::SGX_ERROR_UNEXPECTED
}

sgx_status_t::SGX_SUCCESS
}

/// Call this once at worker startup to initialize the TOP pool and direct invocation RPC server.
///
/// This function will run the RPC server on the same thread as it is called and will loop there.
Expand Down
19 changes: 17 additions & 2 deletions bitacross-worker/enclave-runtime/src/rpc/worker_api_direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ use itp_top_pool_author::traits::AuthorApi;
use itp_types::{DirectRequestStatus, RsaRequest, ShardIdentifier, H256};
use itp_utils::{FromHexPrefixed, ToHexPrefixed};
use jsonrpc_core::{serde_json::json, IoHandler, Params, Value};
#[cfg(feature = "development")]
use lc_scheduled_enclave::{ScheduledEnclaveUpdater, GLOBAL_SCHEDULED_ENCLAVE};
use lc_scheduled_enclave::GLOBAL_SCHEDULED_ENCLAVE;
use litentry_macros::if_development;
use litentry_primitives::{AesRequest, DecryptableRequest};
use log::debug;
Expand Down Expand Up @@ -177,6 +176,22 @@ where
}))
});

io.add_sync_method("state_getScheduledEnclave", move |_: Params| {
debug!("worker_api_direct rpc was called: state_getScheduledEnclave");
let json_value = match GLOBAL_SCHEDULED_ENCLAVE.registry.read() {
Ok(registry) => {
let mut serialized_registry = vec![];
for (block_number, mrenclave) in registry.iter() {
serialized_registry.push((*block_number, *mrenclave));
}
RpcReturnValue::new(serialized_registry.encode(), false, DirectRequestStatus::Ok)
.to_hex()
},
Err(_err) => compute_hex_encoded_return_error("Poisoned registry storage"),
};
Ok(json!(json_value))
});

let local_top_pool_author = top_pool_author.clone();
io.add_sync_method("author_getShardVault", move |_: Params| {
debug!("worker_api_direct rpc was called: author_getShardVault");
Expand Down
2 changes: 1 addition & 1 deletion bitacross-worker/enclave-runtime/src/test/tests_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use itp_stf_primitives::{
use itp_stf_state_handler::handle_state::HandleState;
use itp_test::mock::handle_state_mock;
use itp_top_pool_author::{test_utils::submit_operation_to_top_pool, traits::AuthorApi};
use itp_types::{parentchain::ParentchainId, AccountId, Balance, Block, Header};
use itp_types::{parentchain::ParentchainId, AccountId, Header};
use litentry_primitives::Identity;
use sgx_tunittest::*;
use sgx_types::size_t;
Expand Down
5 changes: 1 addition & 4 deletions bitacross-worker/enclave-runtime/src/test/top_pool_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@ use itp_top_pool_author::{
top_filter::{AllowAllTopsFilter, DirectCallsOnlyFilter},
traits::AuthorApi,
};
use itp_types::{
parentchain::{Address, ParentchainId},
Block, RsaRequest, ShardIdentifier, H256,
};
use itp_types::{RsaRequest, ShardIdentifier};
use jsonrpc_core::futures::executor;
use litentry_primitives::Identity;
use log::*;
Expand Down
2 changes: 1 addition & 1 deletion bitacross-worker/service/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ fn main() {

#[cfg(not(feature = "link-binary"))]
fn main() {
panic!("tried to run the binary without linking. Make sure to pass `--feature link-binary`")
panic!("tried to run the binary without linking. Make sure to pass `--features link-binary`")
}
4 changes: 0 additions & 4 deletions bitacross-worker/service/src/tests/mocks/enclave_api_mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ impl EnclaveBase for EnclaveMock {
Ok(())
}

fn init_enclave_sidechain_components(&self) -> EnclaveResult<()> {
Ok(())
}

fn init_direct_invocation_server(&self, _rpc_server_addr: String) -> EnclaveResult<()> {
unreachable!()
}
Expand Down
24 changes: 24 additions & 0 deletions tee-worker/docker/lit-scheduled-enclave-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
services:
lit-scheduled-enclave-test:
image: litentry/litentry-cli:latest
container_name: litentry-scheduled-enclave-test
volumes:
- ../ts-tests:/ts-tests
- ../client-api:/client-api
- ../cli:/usr/local/worker-cli
build:
context: ..
dockerfile: build.Dockerfile
target: deployed-client
depends_on:
litentry-node:
condition: service_healthy
litentry-worker-1:
condition: service_healthy
networks:
- litentry-test-network
entrypoint: "bash -c '/usr/local/worker-cli/lit_ts_integration_test.sh scheduled_enclave.test.ts 2>&1' "
restart: "no"
networks:
litentry-test-network:
driver: bridge
18 changes: 17 additions & 1 deletion tee-worker/enclave-runtime/src/rpc/worker_api_direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ where
let key_hash = match hex::decode(key_hash) {
Ok(key_hash) => key_hash,
Err(_) =>
return Ok(json!(compute_hex_encoded_return_error("docode key error"))),
return Ok(json!(compute_hex_encoded_return_error("decode key error"))),
};

let shard: ShardIdentifier = match decode_shard_from_base58(shard_str.as_str())
Expand Down Expand Up @@ -435,6 +435,22 @@ where
});
});

io.add_sync_method("state_getScheduledEnclave", move |_: Params| {
debug!("worker_api_direct rpc was called: state_getScheduledEnclave");
let json_value = match GLOBAL_SCHEDULED_ENCLAVE.registry.read() {
Ok(registry) => {
let mut serialized_registry = vec![];
for (block_number, mrenclave) in registry.iter() {
serialized_registry.push((*block_number, *mrenclave));
}
RpcReturnValue::new(serialized_registry.encode(), false, DirectRequestStatus::Ok)
.to_hex()
},
Err(_err) => compute_hex_encoded_return_error("Poisoned registry storage"),
};
Ok(json!(json_value))
});

// system_health
io.add_sync_method("system_health", |_: Params| {
debug!("worker_api_direct rpc was called: system_health");
Expand Down
2 changes: 1 addition & 1 deletion tee-worker/service/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ fn main() {

#[cfg(not(feature = "link-binary"))]
fn main() {
panic!("tried to run the binary without linking. Make sure to pass `--feature link-binary`")
panic!("tried to run the binary without linking. Make sure to pass `--features link-binary`")
}
2 changes: 1 addition & 1 deletion tee-worker/ts-tests/integration-tests/common/call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export async function sendRequest(
): Promise<WorkerRpcReturnValue> {
const rawRes = await wsClient.sendRequest(request, { requestId: request.id, timeout: 6000 });

const res: WorkerRpcReturnValue = api.createType('WorkerRpcReturnValue', rawRes.result);
const res = api.createType('WorkerRpcReturnValue', rawRes.result);
if (res.status.isError) {
console.log('Rpc response error: ' + decodeRpcBytesAsString(res.value));
}
Expand Down
84 changes: 84 additions & 0 deletions tee-worker/ts-tests/integration-tests/scheduled_enclave.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { KeyObject } from 'crypto';
import { step } from 'mocha-steps';
import { initIntegrationTestContext } from './common/utils';
import { getTeeShieldingKey } from './common/di-utils';
import type { IntegrationTestContext, JsonRpcRequest } from './common/common-types';
import { decodeRpcBytesAsString, sendRequest } from './common/call';
import type { CorePrimitivesIdentity } from 'parachain-api';
import { assert } from 'chai';
import { createJsonRpcRequest, nextRequestId } from './common/helpers';

describe('Scheduled Enclave', function () {
let context: IntegrationTestContext = undefined as any;
Copy link
Contributor

Choose a reason for hiding this comment

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

why do we define the type and then cast it to any?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good question 🤔 this one was copy-paste from another test. I just created chore task to cleanup our tests, as I've also seen some fixme's were copied from one test to another

let teeShieldingKey: KeyObject = undefined as any;
let aliceSubstrateIdentity: CorePrimitivesIdentity = undefined as any;

this.timeout(6000000);

before(async () => {
context = await initIntegrationTestContext(
process.env.WORKER_ENDPOINT!, // @fixme evil assertion; centralize env access
process.env.NODE_ENDPOINT! // @fixme evil assertion; centralize env access
);
teeShieldingKey = await getTeeShieldingKey(context);
aliceSubstrateIdentity = await context.web3Wallets.substrate.Alice.getIdentity(context);
});

step('state of scheduled enclave list', async function () {
const request = createJsonRpcRequest('state_getScheduledEnclave', undefined, nextRequestId(context));
const response = await sendRequest(context.tee, request, context.api);
const scheduledEnclaveList = context.api.createType('Vec<(u64, [u8; 32])>', response.value).toJSON() as [
number,
string
][];

assert.equal(1, scheduledEnclaveList.length);

const [blockNumber, mrEnclave] = scheduledEnclaveList[0];
assert.equal(blockNumber, 0);
assert.equal(mrEnclave, context.mrEnclave);
});

step('setting new scheduled enclave', async function () {
const buildRequest = (method: string, params?: any[]) =>
createJsonRpcRequest(method, params, nextRequestId(context));
const callRPC = async (request: JsonRpcRequest) => sendRequest(context.tee, request, context.api);

let response = await callRPC(buildRequest('state_getScheduledEnclave'));
let scheduledEnclaveList = context.api.createType('Vec<(u64, [u8; 32])>', response.value).toJSON() as [
number,
string
][];

assert.equal(scheduledEnclaveList.length, 1);

// set new mrenclave
let setEnclaveResponse = await callRPC(
buildRequest('state_setScheduledEnclave', [20, 'some invalid mrenclave'])
);
assert.include(decodeRpcBytesAsString(setEnclaveResponse.value), 'Failed to decode mrenclave');

setEnclaveResponse = await callRPC(buildRequest('state_setScheduledEnclave', [20, '48656c6c6f20776f726c6421']));
assert.include(
decodeRpcBytesAsString(setEnclaveResponse.value),
'mrenclave len mismatch, expected 32 bytes long'
);

// valid mutation
const validParams = [20, '97f516a61ff59c5eab74b8a9b1b7273d6986b9c0e6c479a4010e22402ca7cee6'];
await callRPC(buildRequest('state_setScheduledEnclave', validParams));

// checking mutated state
response = await callRPC(buildRequest('state_getScheduledEnclave'));
scheduledEnclaveList = context.api.createType('Vec<(u64, [u8; 32])>', response.value).toJSON() as [
number,
string
][];

assert.equal(scheduledEnclaveList.length, 2);

const [blockNumber, mrEnclave] = scheduledEnclaveList[1];
assert.equal(blockNumber, validParams[0]);
assert.equal(mrEnclave, `0x${validParams[1]}`);
});
});