Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0370f5d
[integritee-service/teeracle] minor code simplifications by introduci…
clangenb Jun 6, 2023
7c2f804
[integritee-service/teeracle] make `execute_market_update` generic ov…
clangenb Jun 6, 2023
341ebc5
[integritee-service/teeracle] disable the wheather oracle again
clangenb Jun 6, 2023
c5e89ac
[integritee-service/teeracle] slightly simplify code
clangenb Jun 6, 2023
4fe5a33
[integritee-service] add `reregister_teeracle-interval` CLI
clangenb Jun 6, 2023
08a4580
[integritee-service] extract method to re-register the teeracle
clangenb Jun 6, 2023
90261e1
[integritee-service] fix test compilation
clangenb Jun 6, 2023
5930f43
[integritee-service] group teeracle imports
clangenb Jun 6, 2023
2c928a4
[integritee-service] fix blocking sleep: spawn a re-registration thread
clangenb Jun 6, 2023
49f75b1
[integritee-service/config] fix pass correct flag to re-registration …
clangenb Jun 6, 2023
ad77c06
[integritee-service] fix compilation
clangenb Jun 6, 2023
96ff5ac
[integritee-service] format cli.yml
clangenb Jun 6, 2023
6a6c9e3
add documentation
clangenb Jun 6, 2023
5aa8c1e
[teeracle] print success of the reregistration
clangenb Jun 6, 2023
56bb800
[integritee-service/teeracle] make `schedule_on_repeating_intervals` …
clangenb Jun 7, 2023
62a5ac9
[integritee-service/teeracle] fix thread name
clangenb Jun 7, 2023
d7b98e4
[integritee-service/teeracle] consistent naming
clangenb Jun 7, 2023
68e37f7
[integritee-service/teeracle] better loggin
clangenb Jun 7, 2023
b8e23ea
[integritee-service/teeracle] renamed interval to periodic/period to …
clangenb Jun 7, 2023
953ad3c
[integritee-service/teeracle] add comment about automatic reregistrat…
clangenb Jun 7, 2023
027fc5c
[integritee-service/teeracle] better naming for periodic reregistration
clangenb Jun 7, 2023
bea8607
[integritee-service/teeracle] better logging
clangenb Jun 7, 2023
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
6 changes: 5 additions & 1 deletion core-primitives/settings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,9 @@ pub mod enclave {}
pub mod teeracle {
use core::time::Duration;
// Send extrinsic to update market exchange rate on the parentchain once per day
pub static DEFAULT_MARKET_DATA_UPDATE_INTERVAL: Duration = Duration::from_secs(86400);
pub static DEFAULT_MARKET_DATA_UPDATE_INTERVAL: Duration = ONE_DAY;

pub static ONE_DAY: Duration = Duration::from_secs(86400);

pub static THIRTY_MINUTES: Duration = Duration::from_secs(1800);
}
5 changes: 5 additions & 0 deletions service/src/cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ subcommands:
short: i
help: Set the teeracle exchange rate update interval. Example of accepted syntax <5 seconds 15 minutes 2 hours 1 days> or short <5s15m2h1d>
takes_value: true
- reregister-teeracle-interval:
required: false
long: reregister
help: Set the teeracle reregistration interval. Example of accepted syntax <5 seconds 15 minutes 2 hours 1 days> or short <5s15m2h1d>
takes_value: true
- request-state:
about: join a shard by requesting key provisioning from another worker
args:
Expand Down
27 changes: 25 additions & 2 deletions service/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

use clap::ArgMatches;
use itc_rest_client::rest_client::Url;
use itp_settings::teeracle::DEFAULT_MARKET_DATA_UPDATE_INTERVAL;
use itp_settings::teeracle::{DEFAULT_MARKET_DATA_UPDATE_INTERVAL, ONE_DAY, THIRTY_MINUTES};
use parse_duration::parse;
use serde::{Deserialize, Serialize};
use std::{
Expand Down Expand Up @@ -225,6 +225,8 @@ pub struct RunConfig {
shard: Option<String>,
/// Optional teeracle update interval
teeracle_update_interval: Option<Duration>,
/// Optional teeracle reregistration interval
reregister_teeracle_interval: Option<Duration>,
/// Marblerun's Prometheus endpoint base URL
marblerun_base_url: Option<String>,
}
Expand All @@ -250,6 +252,15 @@ impl RunConfig {
self.teeracle_update_interval.unwrap_or(DEFAULT_MARKET_DATA_UPDATE_INTERVAL)
}

/// The periodic registration period of the teeracle.
///
/// Defaults to 23h30m, as this is slightly below the currently configured automatic
/// deregistration period on the Integritee chains.
pub fn reregister_teeracle_interval(&self) -> Duration {
// Todo: Derive this from chain https://github.com/integritee-network/worker/issues/1351
self.reregister_teeracle_interval.unwrap_or(ONE_DAY - THIRTY_MINUTES)
}

pub fn marblerun_base_url(&self) -> &str {
// This conflicts with the default port of a substrate node, but it is indeed the
// default port of marblerun too:
Expand All @@ -267,13 +278,25 @@ impl From<&ArgMatches<'_>> for RunConfig {
let teeracle_update_interval = m.value_of("teeracle-interval").map(|i| {
parse(i).unwrap_or_else(|e| panic!("teeracle-interval parsing error {:?}", e))
});
let reregister_teeracle_interval = m.value_of("reregister-teeracle-interval").map(|i| {
parse(i).unwrap_or_else(|e| panic!("teeracle-interval parsing error {:?}", e))
});

let marblerun_base_url = m.value_of("marblerun-url").map(|i| {
Url::parse(i)
.unwrap_or_else(|e| panic!("marblerun-url parsing error: {:?}", e))
.to_string()
});

Self { skip_ra, dev, request_state, shard, teeracle_update_interval, marblerun_base_url }
Self {
skip_ra,
dev,
request_state,
shard,
teeracle_update_interval,
reregister_teeracle_interval,
marblerun_base_url,
}
}
}

Expand Down
25 changes: 19 additions & 6 deletions service/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#![cfg_attr(test, feature(assert_matches))]

#[cfg(feature = "teeracle")]
use crate::teeracle::start_interval_market_update;
use crate::teeracle::{schedule_periodic_reregistration_thread, start_periodic_market_update};

#[cfg(not(feature = "dcap"))]
use crate::utils::check_files;
Expand Down Expand Up @@ -445,12 +445,20 @@ fn start_worker<E, T, D, InitializationHandler, WorkerModeProvider>(
} else {
println!("[!] creating remote attestation report and create enclave register extrinsic.");
};

// clones because of the move
let enclave2 = enclave.clone();
let node_api2 = node_api.clone();
#[cfg(not(feature = "dcap"))]
let xt = enclave.generate_ias_ra_extrinsic(&trusted_url, skip_ra).unwrap();
let register_xt = move || enclave2.generate_ias_ra_extrinsic(&trusted_url, skip_ra).unwrap();
#[cfg(feature = "dcap")]
let xt = enclave.generate_dcap_ra_extrinsic(&trusted_url, skip_ra).unwrap();
let register_enclave_block_hash =
send_extrinsic(xt, &node_api, &tee_accountid, is_development_mode);
let register_xt = move || enclave2.generate_dcap_ra_extrinsic(&trusted_url, skip_ra).unwrap();

let send_register_xt = move || {
send_extrinsic(register_xt(), &node_api2, &tee_accountid.clone(), is_development_mode)
};

let register_enclave_block_hash = send_register_xt();

let register_enclave_xt_header =
node_api.get_header(register_enclave_block_hash).unwrap().unwrap();
Expand All @@ -470,7 +478,12 @@ fn start_worker<E, T, D, InitializationHandler, WorkerModeProvider>(
// initialize teeracle interval
#[cfg(feature = "teeracle")]
if WorkerModeProvider::worker_mode() == WorkerMode::Teeracle {
start_interval_market_update(
schedule_periodic_reregistration_thread(
send_register_xt,
run_config.reregister_teeracle_interval(),
);

start_periodic_market_update(
&node_api,
run_config.teeracle_update_interval(),
enclave.as_ref(),
Expand Down
150 changes: 71 additions & 79 deletions service/src/teeracle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@

*/

use crate::teeracle::interval_scheduling::schedule_on_repeating_intervals;
use crate::{error::ServiceResult, teeracle::schedule_periodic::schedule_periodic};
use codec::{Decode, Encode};
use itp_enclave_api::teeracle_api::TeeracleApi;
use itp_node_api::api_client::ParentchainApi;
use itp_types::parentchain::Hash;
use itp_utils::hex::hex_encode;
use log::*;
use sp_runtime::OpaqueExtrinsic;
Expand All @@ -27,99 +28,88 @@ use substrate_api_client::{SubmitAndWatch, XtStatus};
use teeracle_metrics::{increment_number_of_request_failures, set_extrinsics_inclusion_success};
use tokio::runtime::Handle;

pub(crate) mod interval_scheduling;
pub(crate) mod schedule_periodic;
pub(crate) mod teeracle_metrics;

/// Send extrinsic to chain according to the market data update interval in the settings
/// with the current market data (for now only exchange rate).
pub(crate) fn start_interval_market_update<E: TeeracleApi>(
/// Schedule periodic reregistration of the enclave.
///
/// The `send_register_xt` needs to create a fresh registration extrinsic every time it is called
/// (updated nonce, fresh IAS-RA or DCAP-Quote).
///
/// Currently, this is only used for the teeracle, but could also be used for other flavors in the
/// future.
pub(crate) fn schedule_periodic_reregistration_thread(
send_register_xt: impl Fn() -> Option<Hash> + std::marker::Send + 'static,
period: Duration,
) {
println!("Schedule periodic enclave reregistration every: {:?}", period);

std::thread::Builder::new()
.name("enclave_reregistration_thread".to_owned())
.spawn(move || {
schedule_periodic(
|| {
trace!("Reregistering the enclave.");
if let Some(block_hash) = send_register_xt() {
println!(
"✅ Successfully reregistered the enclave. Block hash: {}.",
block_hash
)
} else {
error!("❌ Could not reregister the enclave.")
}
},
period,
);
})
.unwrap();
}

/// Executes a periodic teeracle data update and sends the new data to the parentchain.
///
/// Note: Puts the current thread to sleep for `period`.
pub(crate) fn start_periodic_market_update<E: TeeracleApi>(
api: &ParentchainApi,
interval: Duration,
period: Duration,
enclave_api: &E,
tokio_handle: &Handle,
) {
let updates_to_run = || {
execute_market_update(api, enclave_api, tokio_handle);
if let Err(e) = execute_oracle_update(api, tokio_handle, || {
// Get market data for usd (hardcoded)
enclave_api.update_market_data_xt("TEER", "USD")
}) {
error!("Error running market update {:?}", e)
}

// TODO: Refactor and add this back according to ISSUE: https://github.com/integritee-network/worker/issues/1300
// execute_weather_update(api, enclave_api, tokio_handle);
// if let Err(e) = execute_oracle_update(api, tokio_handle, || {
// enclave_api.update_weather_data_xt("54.32", "15.37")
// }) {
// error!("Error running weather update {:?}", e)
// }
};
info!("Teeracle will update now");
updates_to_run();

info!("Starting teeracle interval for oracle update, interval of {:?}", interval);
schedule_on_repeating_intervals(updates_to_run, interval);
info!("Schedule teeracle updates every {:?}", period);
schedule_periodic(updates_to_run, period);
}

#[allow(dead_code)]
fn execute_weather_update<E: TeeracleApi>(
fn execute_oracle_update<F>(
node_api: &ParentchainApi,
enclave: &E,
tokio_handle: &Handle,
) {
let updated_extrinsic = match enclave.update_weather_data_xt("54.32", "15.37") {
Err(e) => {
error!("{:?}", e);
increment_number_of_request_failures();
return
},
Ok(r) => r,
};

let extrinsics = match <Vec<OpaqueExtrinsic>>::decode(&mut updated_extrinsic.as_slice()) {
Ok(calls) => calls,
Err(e) => {
error!("Failed to decode opaque extrinsics(s): {:?}: ", e);
return
},
};

extrinsics.into_iter().for_each(|call| {
let node_api_clone = node_api.clone();
tokio_handle.spawn(async move {
let encoded_extrinsic = call.encode();
debug!("Hex encoded extrinsic to be sent: {}", hex_encode(&encoded_extrinsic));
println!("[>] Update oracle (send the extrinsic)");
let extrinsic_hash = match node_api_clone.submit_and_watch_opaque_extrinsic_until(
encoded_extrinsic.into(),
XtStatus::InBlock,
) {
Err(e) => {
error!("Failed to send extrinsic: {:?}", e);
set_extrinsics_inclusion_success(false);
return
},
Ok(report) => {
set_extrinsics_inclusion_success(true);
report.extrinsic_hash
},
};
println!("[<] Extrinsic got included into a block. Hash: {:?}\n", extrinsic_hash);
});
});
}

fn execute_market_update<E: TeeracleApi>(
node_api: &ParentchainApi,
enclave: &E,
tokio_handle: &Handle,
) {
// Get market data for usd (hardcoded)
let updated_extrinsic = match enclave.update_market_data_xt("TEER", "USD") {
Err(e) => {
error!("{:?}", e);
increment_number_of_request_failures();
return
},
Ok(r) => r,
};

let extrinsics: Vec<OpaqueExtrinsic> = match Decode::decode(&mut updated_extrinsic.as_slice()) {
Ok(calls) => calls,
Err(e) => {
error!("Failed to decode opaque extrinsic(s): {:?}: ", e);
return
},
};
get_oracle_xt: F,
) -> ServiceResult<()>
where
F: Fn() -> Result<Vec<u8>, itp_enclave_api::error::Error>,
{
let oracle_xt = get_oracle_xt().map_err(|e| {
increment_number_of_request_failures();
e
})?;

let extrinsics = <Vec<OpaqueExtrinsic>>::decode(&mut oracle_xt.as_slice())?;

// Send the extrinsics to the parentchain and wait for InBlock confirmation.
for call in extrinsics.into_iter() {
Expand All @@ -128,7 +118,7 @@ fn execute_market_update<E: TeeracleApi>(
let encoded_extrinsic = call.encode();
debug!("Hex encoded extrinsic to be sent: {}", hex_encode(&encoded_extrinsic));

println!("[>] Update the exchange rate (send the extrinsic)");
println!("[>] Update oracle data (send the extrinsic)");
let extrinsic_hash = match node_api_clone.submit_and_watch_opaque_extrinsic_until(
encoded_extrinsic.into(),
XtStatus::InBlock,
Expand All @@ -147,4 +137,6 @@ fn execute_market_update<E: TeeracleApi>(
println!("[<] Extrinsic got included into a block. Hash: {:?}\n", extrinsic_hash);
});
}

Ok(())
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,26 @@ use std::{
time::{Duration, Instant},
};

/// Schedules a task on perpetually looping intervals.
/// Schedules a periodic task in the current thread.
///
/// In case the task takes longer than is scheduled by the interval duration,
/// the interval timing will drift. The task is responsible for
/// ensuring it does not use up more time than is scheduled.
pub(super) fn schedule_on_repeating_intervals<T>(task: T, interval_duration: Duration)
pub(super) fn schedule_periodic<T>(task: T, period: Duration)
where
T: Fn(),
{
let mut interval_start = Instant::now();
loop {
let elapsed = interval_start.elapsed();

if elapsed >= interval_duration {
if elapsed >= period {
// update interval time
interval_start = Instant::now();
task();
} else {
// sleep for the rest of the interval
let sleep_time = interval_duration - elapsed;
let sleep_time = period - elapsed;
thread::sleep(sleep_time);
}
}
Expand Down