Skip to content

[2/n][guardian-integration] in-process e2e harness#466

Merged
0xsiddharthks merged 8 commits intomainfrom
siddharth/guardian-e2e-harness
Apr 28, 2026
Merged

[2/n][guardian-integration] in-process e2e harness#466
0xsiddharthks merged 8 commits intomainfrom
siddharth/guardian-e2e-harness

Conversation

@0xsiddharthks
Copy link
Copy Markdown
Contributor

@0xsiddharthks 0xsiddharthks commented Apr 17, 2026

Summary

  • lift Enclave (+ EnclaveConfig / EnclaveState / Scratchpad) from main.rs into a new enclave.rs lib module
    @mskd12 this is just a simple move. no changes made to the code.
    • the only change is that enclave_btc_keypair and hashi_btc_master_pubkey went from private to pub(crate).
    • This is required because init.rs::tests reads these fields directly via enclave.config.<field>.get()
    • moving these to enclave.rs allows the e2e-tests to construct and derive an enclave in-process
  • New test-utils feature on hashi-guardian exposing constructors for partially/fully-initialized enclaves.
  • add new guardian client for hashi

Tests harness changes

  • e2e-tests::GuardianHarness runs an in-process guardian over real gRPC.
  • TestNetworksBuilder::with_guardian() orchestrates start → DKG → finalize.
  • test_bitcoin_withdrawal_with_guardian_e2e_flow does full e2e flow with guardian

@0xsiddharthks 0xsiddharthks requested a review from bmwill as a code owner April 17, 2026 16:41
@0xsiddharthks 0xsiddharthks marked this pull request as draft April 17, 2026 17:21
@0xsiddharthks 0xsiddharthks reopened this Apr 19, 2026
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/guardian-e2e-harness branch from aac0a18 to 2fd7fb1 Compare April 19, 2026 23:42
@0xsiddharthks 0xsiddharthks changed the title [6/n][guardian-integration] in-process e2e harness + guardian-enabled withdrawal test [2/n][guardian-integration] in-process e2e harness + TestNetworksBuilder.with_guardian() Apr 19, 2026
@0xsiddharthks 0xsiddharthks changed the base branch from siddharth/guardian-restart-safety to siddharth/deploy-guardian April 19, 2026 23:42
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/guardian-e2e-harness branch from 2fd7fb1 to f58edae Compare April 19, 2026 23:51
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/deploy-guardian branch from 370b474 to 942504b Compare April 23, 2026 10:08
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/guardian-e2e-harness branch from f58edae to c124d70 Compare April 23, 2026 10:09
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/deploy-guardian branch from 942504b to 91bcf58 Compare April 23, 2026 11:34
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/guardian-e2e-harness branch from c124d70 to 2fcf91f Compare April 23, 2026 11:36
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/deploy-guardian branch from 91bcf58 to e0a17e2 Compare April 23, 2026 11:46
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/guardian-e2e-harness branch from 2fcf91f to 56510fb Compare April 23, 2026 11:54
@0xsiddharthks 0xsiddharthks marked this pull request as ready for review April 23, 2026 15:10
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/deploy-guardian branch from e0a17e2 to 1422d8d Compare April 26, 2026 21:22
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/guardian-e2e-harness branch from 56510fb to 1bb33df Compare April 26, 2026 21:22
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/deploy-guardian branch from 1422d8d to 89064c8 Compare April 26, 2026 22:01
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/guardian-e2e-harness branch 4 times, most recently from 96f3774 to 49100e6 Compare April 27, 2026 03:27
aws-sdk-s3 = "1.12.0"
aws-credential-types = "1"

aws-smithy-mocks = { version = "0.1", optional = true }
Copy link
Copy Markdown
Contributor

@mskd12 mskd12 Apr 28, 2026

Choose a reason for hiding this comment

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

nit: any way to remove the mock library from the main dependency list? IIUC it is just used by the test harness, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, afaik we can remove it, but then we have to pass --features test-utils everytime we want to run a test.

but i think we might be able to manage that via nextest profiles.

let me check.

Comment thread crates/hashi-guardian/src/enclave.rs Outdated
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/guardian-e2e-harness branch from f5289b5 to 67c9469 Compare April 28, 2026 16:35
@0xsiddharthks 0xsiddharthks changed the title [2/n][guardian-integration] in-process e2e harness + TestNetworksBuilder.with_guardian() [2/n][guardian-integration] in-process e2e harness Apr 28, 2026
Copy link
Copy Markdown
Contributor

@bmwill bmwill left a comment

Choose a reason for hiding this comment

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

not major issues, mostly just some nits or asks to add TODOs so we don't forget things.

run_bitcoin_withdrawal_e2e(true).await
}

async fn run_bitcoin_withdrawal_e2e(with_guardian: bool) -> Result<()> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I suppose this makes sense while we are getting the integration hooked up. We may want to evaluate if we want to have all tests run with guardian by default eventually.

Comment on lines +36 to +38
/// Start an operator-init'd guardian. Withdrawal RPCs stay gated until
/// [`Self::finalize`] completes provisioner-init.
pub async fn start(network: Network) -> Result<Self> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

At which stage is the guardian pubkey available? Here or after finalize? we do need to commit to it, and likely a url of some such, onchain and it would probably be beneficial to be able to have the key available at contract init time.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

From a conversation we had today, the committing onchain will be done post this series

.await
.context("bind guardian harness listener")?;
let addr: SocketAddr = listener.local_addr()?;
let endpoint = format!("http://{addr}");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just a note, do we want to use traditional TLS termination or require mTLS from the validators to the guardian?

Comment on lines +307 to +309
nodes[0]
.wait_for_mpc_key(std::time::Duration::from_secs(120))
.await?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We do we need this if we fetch the key from onchain below?

.onchain_state()
.current_committee()
.ok_or_else(|| anyhow::anyhow!("no current committee after DKG"))?;
let master_pubkey = hashi.get_onchain_mpc_pubkey()?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

s/master/mpc

Comment on lines +137 to +140
/// URL of the `hashi-guardian` gRPC endpoint. When not set, the guardian
/// integration is bypassed.
#[serde(skip_serializing_if = "Option::is_none")]
pub guardian_endpoint: Option<String>,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

maybe add a TODO that this is temporary and will be removed once we commit it onchain?

Comment on lines +14 to +17
pub struct GuardianClient {
endpoint: String,
channel: Channel,
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should instrument this with metrics like we do our other gRPC client. Happy to add a TODO and add them as a follow up PR.

Comment on lines +71 to +72
/// TODO: Investigate if it can be moved to std::sync::Mutex
pub shares: tokio::sync::Mutex<Vec<Share>>,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

yeah we should have this be std::sync::Mutex

Comment on lines +11 to +18
pub mod enclave;
pub mod getters;
pub mod heartbeat;
pub mod init;
pub mod rpc;
pub mod s3_logger; // used by the monitor
pub mod setup;
pub mod withdraw;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

were these files just not getting compiled?

Comment on lines -26 to -32
mod getters;
mod heartbeat;
mod init;
mod rpc;
mod s3_logger;
mod setup;
mod withdraw;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ah this is where they were.

Base automatically changed from siddharth/deploy-guardian to main April 28, 2026 21:28
`GuardianHarness::finalize` and `create_fully_initialized_enclave` were
running the same "drive an operator-init'd enclave to fully-initialized
state" sequence (set BTC keys, build init state, state.init, mark
logged) inline.

Lift it into `hashi_guardian::test_utils::finalize_enclave` and call it
from both. The harness's `finalize` shrinks to a single helper call
plus the `is_fully_initialized` post-condition. No visibility or API
changes to the `Enclave` types.
The `network` field was set in `start()` but never read internally; the
getter was marked `#[allow(dead_code)]`. The enclave already owns the
network, and `pub` already opts out of dead-code lint, so the attribute
on a `pub` API was a smell.
Extract `run_bitcoin_withdrawal_e2e(with_guardian: bool)` as the shared
body for the deposit → withdrawal → confirm flow. Both
`test_bitcoin_withdrawal_e2e_flow` and
`test_bitcoin_withdrawal_with_guardian_e2e_flow` now reduce to one-line
wrappers that pass `false` / `true`. Forces the two flows to stay in
lockstep — any future change to the deposit/withdrawal path is
automatically exercised under both configurations.

The guardian variant gains the post-deposit balance assertion and the
withdrawal_request_id / withdrawal_txid log lines that were previously
only in the no-guardian variant; behavior is otherwise unchanged.

`setup_test_networks` is no longer called from the bitcoin-withdrawal
test (its setup is now inlined into the parameterized helper) but
remains in use by the other 3 e2e tests.
Reuse setup_test_networks via a shared `_with(builder)` helper so the
guardian withdrawal flow doesn't re-implement the network-init logging.
Trim doc comments on guardian_harness, finalize_enclave, and
create_fully_initialized_enclave.
Collapse the wrapper + helper pair into one function that always takes
a builder. The 3 existing call sites pass `TestNetworksBuilder::new()
.with_nodes(4)` explicitly, which removes the wrapper-of-a-wrapper and
keeps any future setup customization at the call site.
@0xsiddharthks 0xsiddharthks force-pushed the siddharth/guardian-e2e-harness branch from 67c9469 to dffff49 Compare April 28, 2026 21:44
@0xsiddharthks 0xsiddharthks enabled auto-merge (squash) April 28, 2026 21:45
@0xsiddharthks 0xsiddharthks merged commit c735437 into main Apr 28, 2026
11 checks passed
@0xsiddharthks 0xsiddharthks deleted the siddharth/guardian-e2e-harness branch April 28, 2026 21:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants