Skip to content

Commit

Permalink
CFE RPC Client optional genesis hash check for tests (#4041)
Browse files Browse the repository at this point in the history
* refactor: optional genesis hash for tests

* chore: renamed new_ext -> new_inner
  • Loading branch information
j4m1ef0rd authored and dandanlen committed Sep 26, 2023
1 parent 88277d6 commit f08610c
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 10 deletions.
27 changes: 23 additions & 4 deletions engine/src/dot/http_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use subxt::{
};

use anyhow::Result;
use tracing::{error, warn};
use utilities::{make_periodic_tick, redact_endpoint_secret::SecretUrl};

use crate::constants::DOT_AVERAGE_BLOCK_TIME;
Expand Down Expand Up @@ -80,7 +81,10 @@ pub struct DotHttpRpcClient {
}

impl DotHttpRpcClient {
pub fn new(url: SecretUrl) -> Result<impl Future<Output = Self>> {
pub fn new(
url: SecretUrl,
expected_genesis_hash: Option<PolkadotHash>,
) -> Result<impl Future<Output = Self>> {
let polkadot_http_client = Arc::new(PolkadotHttpClient::new(&url)?);

Ok(async move {
Expand All @@ -94,9 +98,23 @@ impl DotHttpRpcClient {
match OnlineClient::<PolkadotConfig>::from_rpc_client(polkadot_http_client.clone())
.await
{
Ok(online_client) => break online_client,
Ok(online_client) => {
if let Some(expected_genesis_hash) = expected_genesis_hash {
let genesis_hash = online_client.genesis_hash();
if genesis_hash == expected_genesis_hash {
break online_client
} else {
error!(
"Connected to Polkadot node at {url} but the genesis hash {genesis_hash} does not match the expected genesis hash {expected_genesis_hash}. Please check your CFE configuration file."
)
}
} else {
warn!("Skipping Polkadot genesis hash check");
break online_client
}
},
Err(e) => {
tracing::error!(
error!(
"Failed to connect to Polkadot node at {url} with error: {e}. Please check your CFE
configuration file. Retrying in {:?}...",
poll_interval.period()
Expand Down Expand Up @@ -201,7 +219,8 @@ mod tests {
#[ignore = "requires local node"]
#[tokio::test]
async fn test_http_rpc() {
let dot_http_rpc = DotHttpRpcClient::new("http://localhost:9945".into()).unwrap().await;
let dot_http_rpc =
DotHttpRpcClient::new("http://localhost:9945".into(), None).unwrap().await;
let block_hash = dot_http_rpc.block_hash(1).await.unwrap();
println!("block_hash: {:?}", block_hash);
}
Expand Down
15 changes: 13 additions & 2 deletions engine/src/dot/retry_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ impl DotRetryRpcClient {
pub fn new(
scope: &Scope<'_, anyhow::Error>,
nodes: NodeContainer<WsHttpEndpoints>,
expected_genesis_hash: PolkadotHash,
) -> Result<Self> {
Self::new_inner(scope, nodes, Some(expected_genesis_hash))
}

fn new_inner(
scope: &Scope<'_, anyhow::Error>,
nodes: NodeContainer<WsHttpEndpoints>,
// The genesis hash is optional to facilitate testing
expected_genesis_hash: Option<PolkadotHash>,
) -> Result<Self> {
let f_create_clients = |endpoints: WsHttpEndpoints| {
Result::<_, anyhow::Error>::Ok((
Expand All @@ -57,7 +67,7 @@ impl DotRetryRpcClient {
let (backup_rpc_client, backup_sub_client) =
option_inner(nodes.backup.map(f_create_clients).transpose()?);

Ok(Self {
Ok(DotRetryRpcClient {
rpc_retry_client: RetrierClient::new(
scope,
"dot_rpc",
Expand Down Expand Up @@ -306,7 +316,7 @@ mod tests {
async fn my_test() {
task_scope(|scope| {
async move {
let dot_retry_rpc_client = DotRetryRpcClient::new(
let dot_retry_rpc_client = DotRetryRpcClient::new_inner(
scope,
NodeContainer {
primary: WsHttpEndpoints {
Expand All @@ -315,6 +325,7 @@ mod tests {
},
backup: None,
},
None,
)
.unwrap();

Expand Down
32 changes: 28 additions & 4 deletions engine/src/dot/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use subxt::{
Config, OnlineClient, PolkadotConfig,
};
use tokio::sync::RwLock;
use tracing::warn;
use utilities::redact_endpoint_secret::SecretUrl;

use anyhow::{anyhow, Result};
Expand Down Expand Up @@ -136,11 +137,12 @@ impl DotRpcApi for DotRpcClient {
#[derive(Clone)]
pub struct DotSubClient {
pub ws_endpoint: SecretUrl,
expected_genesis_hash: Option<PolkadotHash>,
}

impl DotSubClient {
pub fn new(ws_endpoint: SecretUrl) -> Self {
Self { ws_endpoint }
pub fn new(ws_endpoint: SecretUrl, expected_genesis_hash: Option<PolkadotHash>) -> Self {
Self { ws_endpoint, expected_genesis_hash }
}
}

Expand All @@ -149,7 +151,8 @@ impl DotSubscribeApi for DotSubClient {
async fn subscribe_best_heads(
&self,
) -> Result<Pin<Box<dyn Stream<Item = Result<PolkadotHeader>> + Send>>> {
let client = OnlineClient::<PolkadotConfig>::from_url(&self.ws_endpoint).await?;
let client = create_online_client(&self.ws_endpoint, self.expected_genesis_hash).await?;

Ok(Box::pin(
client
.blocks()
Expand All @@ -163,7 +166,8 @@ impl DotSubscribeApi for DotSubClient {
async fn subscribe_finalized_heads(
&self,
) -> Result<Pin<Box<dyn Stream<Item = Result<PolkadotHeader>> + Send>>> {
let client = OnlineClient::<PolkadotConfig>::from_url(&self.ws_endpoint).await?;
let client = create_online_client(&self.ws_endpoint, self.expected_genesis_hash).await?;

Ok(Box::pin(
client
.blocks()
Expand All @@ -175,6 +179,26 @@ impl DotSubscribeApi for DotSubClient {
}
}

/// Creates an OnlineClient from the given websocket endpoint and checks the genesis hash if
/// provided.
async fn create_online_client(
ws_endpoint: &SecretUrl,
expected_genesis_hash: Option<PolkadotHash>,
) -> Result<OnlineClient<PolkadotConfig>> {
let client = OnlineClient::<PolkadotConfig>::from_url(ws_endpoint).await?;

if let Some(expected_genesis_hash) = expected_genesis_hash {
let genesis_hash = client.genesis_hash();
if genesis_hash != expected_genesis_hash {
bail!("Expected Polkadot genesis hash {expected_genesis_hash} but got {genesis_hash}");
}
} else {
warn!("Skipping Polkadot genesis hash check");
}

Ok(client)
}

#[async_trait]
impl DotSubscribeApi for DotRpcClient {
async fn subscribe_best_heads(
Expand Down

0 comments on commit f08610c

Please sign in to comment.