diff --git a/Cargo.lock b/Cargo.lock index 5d1f9f748..f7829264a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -569,6 +569,7 @@ dependencies = [ "sgxs-loaders", "sha3", "structopt", + "tdbe-common", "test-common", "thiserror", "tokio 0.2.22", diff --git a/chain-abci/Cargo.toml b/chain-abci/Cargo.toml index e299cb46e..b9c0b54f7 100644 --- a/chain-abci/Cargo.toml +++ b/chain-abci/Cargo.toml @@ -17,7 +17,7 @@ chain-core = { path = "../chain-core" } chain-storage = { path = "../chain-storage" } chain-tx-filter = { path = "../chain-tx-filter" } chain-tx-validation = { path = "../chain-tx-validation" } -enclave-protocol = { path = "../enclave-protocol" } +enclave-protocol = { path = "../enclave-protocol", features = ["edp"] } mock-utils = { path = "../chain-tx-enclave/mock-utils" } mls = { path = "../chain-tx-enclave-next/mls" } ra-client = { path = "../chain-tx-enclave-next/enclave-ra/ra-client" } @@ -39,6 +39,7 @@ structopt = "0.3" secp256k1 = { git = "https://github.com/crypto-com/rust-secp256k1-zkp.git", rev = "1aae6edc5f1de0bbdcdb26f1f1d8b00ca28e012a", features = ["recovery", "endomorphism", "global-context"] } parity-scale-codec = { features = ["derive"], version = "1.3" } thiserror = "1.0" +kvdb = "0.7" [target.'cfg(target_os = "linux")'.dependencies] aesm-client = {version = "0.5", features = ["sgxs"], optional = true } @@ -46,6 +47,7 @@ enclave-runner = {version = "0.4", optional = true} sgxs-loaders = {version = "0.2", optional = true} tokio = { version = "0.2", features = ["uds"], optional = true } rand = "0.7" +tdbe-common = { path = "../chain-tx-enclave-next/tdbe/tdbe-common" } [build-dependencies] cc = "1.0" diff --git a/chain-abci/src/enclave_bridge/edp/mod.rs b/chain-abci/src/enclave_bridge/edp/mod.rs index 3319b80f0..3dc6e751a 100644 --- a/chain-abci/src/enclave_bridge/edp/mod.rs +++ b/chain-abci/src/enclave_bridge/edp/mod.rs @@ -1,4 +1,5 @@ mod server; +pub mod tdbe; use crate::enclave_bridge::EnclaveProxy; use aesm_client::AesmClient; @@ -13,7 +14,7 @@ use parity_scale_codec::{Decode, Encode}; use sgxs_loaders::isgx::Device; use std::io::{Read, Write}; use std::sync::{mpsc::channel, Arc, Mutex}; -use std::thread::{self}; +use std::thread; use std::{future::Future, io, pin::Pin}; use ra_sp_server::{config::SpRaConfig, server::SpRaServer}; diff --git a/chain-abci/src/enclave_bridge/edp/tdbe.rs b/chain-abci/src/enclave_bridge/edp/tdbe.rs new file mode 100644 index 000000000..e5dd7f476 --- /dev/null +++ b/chain-abci/src/enclave_bridge/edp/tdbe.rs @@ -0,0 +1,223 @@ +use std::{ + collections::HashMap, + future::Future, + io::{self, Cursor, Seek, SeekFrom}, + os::unix::net::UnixStream, + pin::Pin, + sync::Arc, + thread, +}; + +use aesm_client::AesmClient; +use enclave_runner::{ + usercalls::{AsyncListener, AsyncStream, UsercallExtension}, + EnclaveBuilder, +}; +use kvdb::KeyValueDB; +use sgxs_loaders::isgx::Device; +use tdbe_common::TdbeStartupConfig; +use tokio::net::{TcpListener, TcpStream}; + +use chain_core::tx::data::TxId; +use chain_storage::ReadOnlyStorage; +use enclave_protocol::{ + codec::{StreamRead, StreamWrite}, + tdbe_protocol::PersistenceCommand, + EnclaveRequest, EnclaveResponse, SealedLog, +}; +use ra_sp_server::config::SpRaConfig; + +use crate::enclave_bridge::TdbeConfig; + +#[derive(Debug)] +pub struct TdbeApp { + /// UDS to connect to `chain-abci` + chain_abci_stream: UnixStream, + /// UDS to persist data to `chain-storage` + persistence_stream: UnixStream, + /// `ra-sp-server` address for remote attestation. E.g. `0.0.0.0:8989` + /// TODO: Replace it with a local UDS (using `chain-abci` as launcher). + sp_address: String, + /// Optional address of remote TDBE server for fetching initial data + remote_rpc_address: Option, + /// Local TDBE server address to listen on. E.g. `127.0.0.1:3445` + local_listen_address: String, +} + +impl TdbeApp { + /// Creates a new instance of TDBE app + pub fn new( + tdbe_config: &TdbeConfig, + ra_config: &SpRaConfig, + storage: Arc, + ) -> std::io::Result { + // - `chain_abci_stream` is passed to enclave. Encalve can send requests to chain-abci + // using this + // - `chain_abci_receiver` listens to the requests sent by enclave and responds to them + let (chain_abci_stream, chain_abci_receiver) = UnixStream::pair()?; + + // - `persistence_stream` is passed to enclave. Encalve can send requests to chain-storage + // using this + // - `persistence_receiver` listens to the requests sent by enclave and responds to them + let (persistence_stream, persistence_receiver) = UnixStream::pair()?; + + spawn_chain_abci_thread(chain_abci_receiver, storage.clone()); + spawn_persistence_thread(persistence_receiver, storage); + + Ok(Self { + chain_abci_stream, + persistence_stream, + sp_address: ra_config.address.clone(), + remote_rpc_address: tdbe_config.remote_rpc_address.clone(), + local_listen_address: tdbe_config.local_listen_address.clone(), + }) + } + + pub fn spawn(self) { + thread::spawn(move || { + let mut device = Device::new() + .expect("SGX device was not found") + .einittoken_provider(AesmClient::new()) + .build(); + let mut enclave_builder = EnclaveBuilder::new("tdb-enclave-app.sgxs".as_ref()); + + enclave_builder + .coresident_signature() + .expect("Enclave signature file not found"); + enclave_builder.usercall_extension(self); + + let enclave = enclave_builder + .build(&mut device) + .expect("Failed to build enclave"); + enclave.run().expect("Failed to start enclave") + }); + } +} + +fn spawn_chain_abci_thread(mut receiver: UnixStream, storage: Arc) { + let _ = thread::spawn(move || { + let storage = chain_storage::ReadOnlyStorage::new_db(storage); + + while let Ok(enclave_request) = EnclaveRequest::read_from(&mut receiver) { + match enclave_request { + EnclaveRequest::GetSealedTxData { txids } => { + let response = + EnclaveResponse::GetSealedTxData(get_sealed_tx_data(txids, &storage)); + response + .write_to(&mut receiver) + .expect("Unable to write to TDBE <-> chain-abci unix stream"); + } + _ => unreachable!("TDBE can only send `GetSealedTxData` request"), + } + } + }); +} + +fn get_sealed_tx_data(txids: Vec, storage: &ReadOnlyStorage) -> Option> { + let mut result = Vec::with_capacity(txids.len()); + + for txid in txids { + if let Some(txin) = storage.get_sealed_log(&txid) { + result.push(txin); + } else { + return None; + } + } + + Some(result) +} + +fn spawn_persistence_thread(mut receiver: UnixStream, storage: Arc) { + let _ = thread::spawn(move || { + let mut storage = chain_storage::Storage::new_db(storage); + let mut buffer = HashMap::new(); + let mut kvdb = chain_storage::buffer::BufferStore::new(&storage, &mut buffer); + + while let Ok(persistence_command) = PersistenceCommand::read_from(&mut receiver) { + match persistence_command { + PersistenceCommand::Store { + transaction_id, + sealed_log, + } => chain_storage::store_sealed_log(&mut kvdb, &transaction_id, &sealed_log), + PersistenceCommand::Finish { last_fetched_block } => { + chain_storage::set_last_fetched_block(&mut kvdb, last_fetched_block); + break; + } + } + } + + chain_storage::buffer::flush_storage(&mut storage, std::mem::take(&mut buffer)) + .expect("Unable to flush storage"); + }); +} + +#[allow(clippy::type_complexity)] +impl UsercallExtension for TdbeApp { + fn connect_stream<'future>( + &'future self, + addr: &'future str, + _local_addr: Option<&'future mut String>, + _peer_addr: Option<&'future mut String>, + ) -> Pin>>> + 'future>> { + async fn connect_stream_inner( + this: &TdbeApp, + addr: &str, + ) -> io::Result>> { + match addr { + // Passes initial startup configuration to enclave + "init" => { + let tdbe_startup_config = TdbeStartupConfig { + remote_rpc_address: this.remote_rpc_address.clone(), + }; + + let mut stream = Cursor::new(Vec::new()); + tdbe_startup_config + .write_to(&mut stream) + .expect("Unable to write initial configuration to `Cursor`"); + + stream + .seek(SeekFrom::Start(0)) + .expect("Unable to seek to starting position on a Cursor"); + + Ok(Some(Box::new(stream))) + } + // Connects enclave to chain-abci + "chain-abci" => { + let stream = + tokio::net::UnixStream::from_std(this.chain_abci_stream.try_clone()?)?; + Ok(Some(Box::new(stream))) + } + // Connects enclave to ra-sp-server + "ra-sp-server" => { + let stream = TcpStream::connect(&this.sp_address).await?; + Ok(Some(Box::new(stream))) + } + _ => Ok(None), + } + } + + Box::pin(connect_stream_inner(self, addr)) + } + + fn bind_stream<'future>( + &'future self, + addr: &'future str, + _local_addr: Option<&'future mut String>, + ) -> Pin>>> + 'future>> { + async fn bind_stream_inner( + this: &TdbeApp, + addr: &str, + ) -> io::Result>> { + match addr { + // Binds TCP listener for TDBE server + "tdbe" => { + let listener = TcpListener::bind(&this.local_listen_address).await?; + Ok(Some(Box::new(listener))) + } + _ => Ok(None), + } + } + + Box::pin(bind_stream_inner(self, addr)) + } +} diff --git a/chain-abci/src/enclave_bridge/mod.rs b/chain-abci/src/enclave_bridge/mod.rs index 56c7cdd51..f4b6cb86e 100644 --- a/chain-abci/src/enclave_bridge/mod.rs +++ b/chain-abci/src/enclave_bridge/mod.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + use enclave_protocol::{IntraEnclaveRequest, IntraEnclaveResponse}; /// TODO: feature-guard when workspaces can be built with --features flag: https://github.com/rust-lang/cargo/issues/5015 @@ -6,6 +8,17 @@ pub mod mock; #[cfg(all(not(feature = "mock-enclave"), feature = "edp", target_os = "linux"))] pub mod edp; +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct TdbeConfig { + /// Optional TM RPC address of another TDBE server from where to fetch data + pub remote_rpc_address: Option, + /// Local TDBE server address to listen on. E.g. `127.0.0.1:3445` + pub local_listen_address: String, + /// External TDBE server address, used by remote nodes to send RPC requests. E.g. + /// `:` + pub external_listen_address: String, +} + /// Abstracts over communication with an external part that does enclave calls pub trait EnclaveProxy: Sync + Send + Sized + Clone { // sanity check for checking enclave initialization diff --git a/chain-abci/src/main.rs b/chain-abci/src/main.rs index 368c3bd0c..7d474555c 100644 --- a/chain-abci/src/main.rs +++ b/chain-abci/src/main.rs @@ -5,7 +5,7 @@ use chain_abci::enclave_bridge::edp::{ }; #[cfg(any(feature = "mock-enclave", not(target_os = "linux")))] use chain_abci::enclave_bridge::mock::MockClient; -use chain_abci::enclave_bridge::EnclaveProxy; +use chain_abci::enclave_bridge::{EnclaveProxy, TdbeConfig}; use chain_core::init::network::{get_network, get_network_id, init_chain_id}; use chain_storage::ReadOnlyStorage; use chain_storage::{Storage, StorageConfig, StorageType}; @@ -37,20 +37,6 @@ pub struct Config { data_bootstrap: TdbeConfig, } -/// TODO: more concrete when ready -#[derive(Serialize, Deserialize, Debug, Default)] -pub struct TdbeConfig { - /// Optional TM RPC address of another TDBE server from where to fetch data - /// TODO: it'll get txids + the TDBE connection details from RPC - /// TODO: DNS can be obtained from RPC? - pub remote_rpc_address: Option, - /// Local TDBE server address to listen on. E.g. `127.0.0.1:3445` - pub local_listen_address: String, - /// External TDBE server address, used by remote nodes to send RPC requests. E.g. - /// `:` - pub external_listen_address: String, -} - impl Default for Config { fn default() -> Self { Self { diff --git a/chain-storage/src/api.rs b/chain-storage/src/api.rs index 544cce44d..f654f118f 100644 --- a/chain-storage/src/api.rs +++ b/chain-storage/src/api.rs @@ -14,7 +14,8 @@ use chain_core::tx::data::{ use super::buffer::{GetKV, StoreKV}; use super::{ LookupItem, StoredChainState, CHAIN_ID_KEY, COL_APP_HASHS, COL_APP_STATES, COL_EXTRA, - COL_NODE_INFO, COL_STAKING_VERSIONS, GENESIS_APP_HASH_KEY, LAST_STATE_KEY, + COL_NODE_INFO, COL_STAKING_VERSIONS, GENESIS_APP_HASH_KEY, LAST_FETCHED_BLOCK_KEY, + LAST_STATE_KEY, }; pub fn get_last_app_state(db: &impl GetKV) -> Option> { @@ -34,6 +35,13 @@ pub fn lookup_item( db.get(&(col, txid_or_app_hash.to_vec())) } +pub fn set_last_fetched_block(db: &mut impl StoreKV, last_fetched_block: u32) { + db.set( + (COL_EXTRA, LAST_FETCHED_BLOCK_KEY.to_vec()), + last_fetched_block.encode(), + ) +} + pub fn insert_item( db: &mut impl StoreKV, item_type: LookupItem, diff --git a/chain-storage/src/lib.rs b/chain-storage/src/lib.rs index 99cc4db3c..02e5415c0 100644 --- a/chain-storage/src/lib.rs +++ b/chain-storage/src/lib.rs @@ -45,6 +45,7 @@ pub const NUM_COLUMNS: u32 = 12; pub const CHAIN_ID_KEY: &[u8] = b"chain_id"; pub const GENESIS_APP_HASH_KEY: &[u8] = b"genesis_app_hash"; pub const LAST_STATE_KEY: &[u8] = b"last_state"; +pub const LAST_FETCHED_BLOCK_KEY: &[u8] = b"last_fetched_block"; pub enum StorageType { Node, @@ -114,6 +115,10 @@ impl Get for ReadOnlyStorage { } impl ReadOnlyStorage { + pub fn new_db(db: Arc) -> Self { + Self { db } + } + pub fn get_last_app_state(&self) -> Option> { self.db .get(COL_NODE_INFO, LAST_STATE_KEY) diff --git a/chain-tx-enclave-next/tdbe/enclave-app/src/sgx_module.rs b/chain-tx-enclave-next/tdbe/enclave-app/src/sgx_module.rs index 856a42551..c42a67c95 100644 --- a/chain-tx-enclave-next/tdbe/enclave-app/src/sgx_module.rs +++ b/chain-tx-enclave-next/tdbe/enclave-app/src/sgx_module.rs @@ -9,6 +9,7 @@ use std::{ }; use chrono::Duration; +use parity_scale_codec::Encode; use rustls::{ClientSession, ServerSession, StreamOwned}; use sgx_isa::Report; use thread_pool::ThreadPool; @@ -17,11 +18,12 @@ use webpki::DNSNameRef; use chain_core::tx::data::TxId; use enclave_protocol::{ codec::{StreamRead, StreamWrite}, - tdbe_protocol::{TrustedTdbeRequest, TrustedTdbeResponse}, + tdbe_protocol::{PersistenceCommand, TrustedTdbeRequest, TrustedTdbeResponse}, }; +use enclave_utils::SealedData; use ra_client::{EnclaveCertVerifier, EnclaveCertVerifierConfig, EnclaveInfo}; use ra_enclave::{EnclaveRaConfig, EnclaveRaContext, DEFAULT_EXPIRATION_SECS}; -use tdbe_common::TdbeConfig; +use tdbe_common::TdbeStartupConfig; const THREAD_POOL_SIZE: usize = 4; @@ -40,21 +42,27 @@ pub fn entry() -> std::io::Result<()> { let context = create_ra_context(); // Fetch initial transaction data if TDBE is configured to connect to another TDBE server - if let Some(ref tdbe_dns_name) = tdbe_config.tdbe_dns_name { + if let Some(ref remote_rpc_address) = tdbe_config.remote_rpc_address { + let (tdbe_address, tdbe_dns_name) = + fetch_remote_tdbe_connection_details(remote_rpc_address)?; + let (transaction_ids, last_fetched_block) = fetch_transaction_ids(); + if let Err(err) = fetch_initial_data( &context, verifier.clone(), - tdbe_dns_name, - &tdbe_config.transaction_ids, + &tdbe_address, + &tdbe_dns_name, + &transaction_ids, + last_fetched_block, ) { log::error!("Unable to fetch initial data from another TDBE server"); return Err(err); } } - // Connect to ZeroMQ - log::info!("Connecting to ZeroMQ"); - let zmq_stream = Arc::new(Mutex::new(TcpStream::connect("zmq")?)); + // Connect to chain-abci + log::info!("Connecting to chain-abci"); + let chain_abci = Arc::new(Mutex::new(TcpStream::connect("chain-abci")?)); // Start TDBE server log::info!("Starting TBDE Server"); @@ -66,7 +74,7 @@ pub fn entry() -> std::io::Result<()> { for stream in listener.incoming() { let context = context.clone(); let verifier = verifier.clone(); - let zmq_stream = zmq_stream.clone(); + let chain_abci = chain_abci.clone(); thread_pool_sender .send(move || { @@ -79,7 +87,7 @@ pub fn entry() -> std::io::Result<()> { .expect("Unable to create TLS server stream"); // Handle client conntection - handle_connection(tls_stream, zmq_stream); + handle_connection(tls_stream, chain_abci); }) .expect("Unable to send tasks to thread pool"); } @@ -90,7 +98,7 @@ pub fn entry() -> std::io::Result<()> { Ok(()) } -fn handle_connection(mut stream: T, zmq_stream: Arc>) { +fn handle_connection(mut stream: T, chain_abci: Arc>) { loop { match TrustedTdbeRequest::read_from(&mut stream) { Ok(tdbe_request) => { @@ -98,7 +106,7 @@ fn handle_connection(mut stream: T, zmq_stream: Arc { match handler::get_transactions_with_outputs( transaction_ids.into_owned(), - &mut zmq_stream.lock().unwrap(), + &mut chain_abci.lock().unwrap(), ) { Ok(transactions) => { TrustedTdbeResponse::GetTransactionsWithOutputs { transactions } @@ -136,13 +144,13 @@ fn get_enclave_verifier() -> EnclaveCertVerifier { verifier } -fn get_tdbe_config() -> TdbeConfig { +fn get_tdbe_config() -> TdbeStartupConfig { log::info!("Fetching initial TDBE configuration"); let config_stream = TcpStream::connect("init").expect("Unable to connect to initial configuration stream"); let tdbe_config = - TdbeConfig::read_from(config_stream).expect("Unable to read initial configuration"); + TdbeStartupConfig::read_from(config_stream).expect("Unable to read initial configuration"); log::info!("Finished fetching initial TDBE configuration"); @@ -174,16 +182,31 @@ fn create_ra_context() -> Arc { Arc::new(enclave_ra_context) } +/// Fetches connection details of remote TDBE server using TM RPC +fn fetch_remote_tdbe_connection_details( + _remote_rpc_address: &str, +) -> std::io::Result<(String, String)> { + // TODO: Fetch connection details using TM RPC (use `client-common::TendermintRpcClient`?) + Ok(("".to_string(), "".to_string())) +} + +// TODO: Get transaction IDs as mentioned in https://github.com/crypto-com/chain-docs/blob/master/docs/modules/tdbe.md#light-client +fn fetch_transaction_ids() -> (Vec, u32) { + Default::default() +} + fn fetch_initial_data( context: &EnclaveRaContext, verifier: EnclaveCertVerifier, + tdbe_address: &str, tdbe_dns_name: &str, transaction_ids: &[TxId], + last_fetched_block: u32, ) -> std::io::Result<()> { log::info!("Fetching initial data from another TDBE server"); // Create attested TLS stream - let mut tls_stream = create_tls_client_stream(context, verifier, tdbe_dns_name, "tdbe")?; + let mut tls_stream = create_tls_client_stream(context, verifier, tdbe_dns_name, tdbe_address)?; // Create request to send to TDBE server let request = TrustedTdbeRequest::GetTransactionsWithOutputs { @@ -198,14 +221,33 @@ fn fetch_initial_data( match response { TrustedTdbeResponse::GetTransactionsWithOutputs { transactions } => { - log::info!("{} transactions received", transactions.len()) + // Connect to persistence stream + log::info!("Connecting to persistence stream"); + let mut persistence = TcpStream::connect("persistence")?; + + for transaction in transactions { + let transaction_id = transaction.id(); + let sealed_log: Vec = SealedData::seal(&transaction.encode(), transaction_id) + .map_err(|_| { + std::io::Error::new(std::io::ErrorKind::Other, "Unable to seal transaction") + })?; + + let persistence_command = PersistenceCommand::Store { + transaction_id, + sealed_log, + }; + + persistence_command.write_to(&mut persistence)?; + } + + let persistence_command = PersistenceCommand::Finish { last_fetched_block }; + persistence_command.write_to(&mut persistence)?; } TrustedTdbeResponse::Error { message } => { log::error!("Received error: {}", message); panic!("Cannot fetch initial data from another TDBE server"); } } - // TODO: Persist response log::info!("Finished fetching initial data from another TDBE server"); diff --git a/chain-tx-enclave-next/tdbe/enclave-app/src/sgx_module/handler.rs b/chain-tx-enclave-next/tdbe/enclave-app/src/sgx_module/handler.rs index 4caf1c5bb..a7e95cb0c 100644 --- a/chain-tx-enclave-next/tdbe/enclave-app/src/sgx_module/handler.rs +++ b/chain-tx-enclave-next/tdbe/enclave-app/src/sgx_module/handler.rs @@ -1,20 +1,19 @@ -use std::{ - convert::TryInto, - io::{Read, Write}, - net::TcpStream, -}; +use std::net::TcpStream; use parity_scale_codec::{Decode, Encode}; use zeroize::Zeroize; use chain_core::tx::{data::TxId, TxWithOutputs}; -use enclave_protocol::{EnclaveRequest, EnclaveResponse}; +use enclave_protocol::{ + codec::{StreamRead, StreamWrite}, + EnclaveRequest, EnclaveResponse, +}; use enclave_utils::SealedData; /// Retrieves all the transactions with outputs with given transaction IDs pub fn get_transactions_with_outputs( transaction_ids: Vec, - zmq_stream: &mut TcpStream, + chain_abci: &mut TcpStream, ) -> Result, String> { // Prepare enclave request let enclave_request = EnclaveRequest::GetSealedTxData { @@ -22,29 +21,17 @@ pub fn get_transactions_with_outputs( } .encode(); - // Send request to ZeroMQ - zmq_stream - .write_all(&enclave_request) - .map_err(|err| format!("Error while writing request to ZeroMQ: {}", err))?; - - // Read reponse length from ZeroMQ (little endian u32 bytes) - let mut response_len = [0u8; 4]; - zmq_stream - .read(&mut response_len) - .map_err(|err| format!("Error while reading reponse length from ZeroMQ: {}", err))?; - - let response_len: usize = u32::from_le_bytes(response_len) - .try_into() - .expect("Response length exceeds `usize` bounds"); + // Send request to chain-abci + enclave_request + .write_to(&*chain_abci) + .map_err(|err| format!("Unable to send request to chain-abci: {}", err))?; - // Read result from ZeroMQ - let mut result_buf = vec![0u8; response_len]; - zmq_stream - .read(&mut result_buf) - .map_err(|err| format!("Error while reading response from ZeroMQ: {}", err))?; + // Read response from chain-abci + let enclave_response = EnclaveResponse::read_from(&*chain_abci) + .map_err(|err| format!("Unable to receive response from chain-abci: {}", err))?; - match EnclaveResponse::decode(&mut result_buf.as_ref()) { - Ok(EnclaveResponse::GetSealedTxData(Some(sealed_logs))) => { + match enclave_response { + EnclaveResponse::GetSealedTxData(Some(sealed_logs)) => { let mut transactions_with_outputs = Vec::with_capacity(sealed_logs.len()); for (txid, sealed_log) in transaction_ids.into_iter().zip(sealed_logs.into_iter()) { @@ -71,11 +58,7 @@ pub fn get_transactions_with_outputs( Ok(transactions_with_outputs) } - Ok(EnclaveResponse::GetSealedTxData(None)) => Err("Transactions not found".to_owned()), - Ok(_) => Err("Unexpected response from ZeroMQ".to_owned()), - Err(err) => Err(format!( - "Error while decoding response from ZeroMQ: {}", - err - )), + EnclaveResponse::GetSealedTxData(None) => Err("Transactions not found".to_owned()), + _ => Err("Unexpected response from ZeroMQ".to_owned()), } } diff --git a/chain-tx-enclave-next/tdbe/tdbe-common/src/lib.rs b/chain-tx-enclave-next/tdbe/tdbe-common/src/lib.rs index 39df5422b..6cf1468cc 100644 --- a/chain-tx-enclave-next/tdbe/tdbe-common/src/lib.rs +++ b/chain-tx-enclave-next/tdbe/tdbe-common/src/lib.rs @@ -1,12 +1,8 @@ use parity_scale_codec::{Decode, Encode}; -use chain_core::tx::data::TxId; - /// Configuration options passed to TDBE on startup #[derive(Debug, Encode, Decode)] -pub struct TdbeConfig { - /// DNS name of TDBE server for fetching initial data - pub tdbe_dns_name: Option, - /// Transaction IDs to fetch from another TDBE server - pub transaction_ids: Vec, +pub struct TdbeStartupConfig { + /// Optional TM RPC address of another TDBE server from where to fetch data + pub remote_rpc_address: Option, } diff --git a/enclave-protocol/src/tdbe_protocol.rs b/enclave-protocol/src/tdbe_protocol.rs index 97c2a2193..53b5917a2 100644 --- a/enclave-protocol/src/tdbe_protocol.rs +++ b/enclave-protocol/src/tdbe_protocol.rs @@ -4,6 +4,23 @@ use parity_scale_codec::{Decode, Encode}; use chain_core::tx::{data::TxId, TxWithOutputs}; +/// Command sent by TDBE to persist a sealed transaction in chain-storage +#[derive(Encode, Decode)] +pub enum PersistenceCommand { + /// Command to store transaction in chain-storage + Store { + /// Transaction ID + transaction_id: TxId, + /// Sealed transaction data + sealed_log: Vec, + }, + /// Command to signal completion of catch-up process + Finish { + /// Height of last fetched block in catch-up process + last_fetched_block: u32, + }, +} + /// TDBE request initialized from other TDBE servers (enclave-to-enclave communication) #[derive(Encode, Decode)] pub enum TrustedTdbeRequest<'a> {