Skip to content

Add private recovery API for validated inputs - #2407

Open
huitseeker wants to merge 6 commits into
nextfrom
admin-private-record-share-rpc
Open

Add private recovery API for validated inputs#2407
huitseeker wants to merge 6 commits into
nextfrom
admin-private-record-share-rpc

Conversation

@huitseeker

@huitseeker huitseeker commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

After #2393, validators store transaction inputs under a Golden threshold key. The demo also needs a private way to find these records and ask each validator for a decryption share.

Operators can now start an optional HTTP admin service on a separate listener. GET /admin/transactions returns all stored records as hex-encoded JSON in insertion order. Each entry includes the transaction ID, encrypted inputs, nonce, encrypted content key, and decryption context.

POST /admin/decryption-share accepts an encrypted content key and its decryption context. It returns this validator's hex-encoded Golden share.

The public validator service does not receive the Golden secret share. The admin service has no caller authentication, so operators must control access to its port. A later TEE flow will add caller checks and a share release policy.

Tests recover one validator's stored TransactionInputs with shares from two other validators in the same Golden setup. Recovery tools receive the public Golden setup through deployment configuration.

Changelog

[[entry]]
scope = "validator"
impact = "added"
description = "Operators can list stored private inputs and issue Golden decryption shares through a private admin API."

@igamigo igamigo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not the most in-depth review for now, but leaving some comments

Comment thread bin/validator/src/db/migrations/002_validated_transaction_insertion_order.sql Outdated
Comment thread bin/validator/src/db/sql/insert_transaction.sql Outdated
Comment thread proto/proto/internal/validator_admin.proto Outdated
@huitseeker
huitseeker marked this pull request as draft July 30, 2026 00:17
@huitseeker huitseeker changed the title Add private recovery RPCs for validated inputs Add private recovery API for validated inputs Jul 30, 2026
@huitseeker
huitseeker marked this pull request as ready for review July 30, 2026 00:31

@kkovaacs kkovaacs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I assume this is a temporary feature just for the demo, right?

In that context this looks good to me.

Comment thread bin/validator/src/storage_key.rs Outdated
) -> Result<Vec<u8>, PrivateRecordError>
where
R: RngCore + CryptoRng,
P: PrivateRecordSharePolicy + ?Sized,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why do we need this policy thing? Surely we have exactly one.

return Err(PrivateRecordError::ShareDenied);
}

self.issue_decryption_share(rng, record.encrypted_record_key(), request.context())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why do we have two pub methods?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This could just be called load_all_transactions imo. Currently it implies there exist public or unvalidated transactions.

CHECK (length(encrypted_record) >= 16),
CHECK (length(encrypted_record_key) > 0)
) WITHOUT ROWID;
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why are we adding back ROWID?

Comment thread bin/validator/src/db/mod.rs Outdated
Comment on lines +193 to +194
/// Loads all validated private transactions in insertion order.
pub(crate) fn load_validated_private_transactions(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Similar nit:

Suggested change
/// Loads all validated private transactions in insertion order.
pub(crate) fn load_validated_private_transactions(
/// Loads all validated private transactions in insertion order.
pub(crate) fn load_all_transactions(

Comment thread bin/validator/src/commands/mod.rs Outdated
listen: std::net::SocketAddr,

/// Socket address at which to serve the private administration API.
#[arg(long = "admin-listen", env = ENV_ADMIN_LISTEN, value_name = "LISTEN")]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
#[arg(long = "admin-listen", env = ENV_ADMIN_LISTEN, value_name = "LISTEN")]
#[arg(long = "admin.listen", env = ENV_ADMIN_LISTEN, value_name = "LISTEN")]

Comment on lines +90 to +96
target: LOG_TARGET,
{
service.name = "miden-validator-admin",
validator.admin_listen = %endpoint,
},
"Validator admin server ready",
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@kkovaacs is there some sort of standard for this?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@kkovaacs is there some sort of standard for this?

Not really. We do have a standard log line that is logged when starting up a service, but this is just an additional API that is exposed by the validator service.

Comment thread bin/validator/src/server/mod.rs Outdated
pub async fn serve(self, shutdown: CancellationToken) -> anyhow::Result<()> {
let listener = TcpListener::bind(self.address)
.await
.context("failed to bind validator admin address")?;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: we don't really need to prefix things with validator, this is already in the validator context.

Suggested change
.context("failed to bind validator admin address")?;
.context("failed to bind admin address")?;

@huitseeker
huitseeker force-pushed the admin-private-record-share-rpc branch from df32357 to 396e12f Compare July 30, 2026 12:17
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.

4 participants