Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
9d49c1c
initial shielded txs handling
kuzminxyz Jun 15, 2026
517ea1f
simple Voting extension for malachite
kuzminxyz Jun 15, 2026
6c5f9dd
intermediate changes
kuzminxyz Jun 15, 2026
cf55e18
ai generated tdec store for gsigner
kuzminxyz Jun 15, 2026
73a7745
rename TdecKeystore to TdecKeyEntry
kuzminxyz Jun 15, 2026
68cb579
Merge branch 'master' into kd/feat/handling-shielded-txs
kuzminxyz Jun 16, 2026
b660812
chore: implement TransactionRef type
kuzminxyz Jun 16, 2026
3d8be57
chore: rename RpcEvent::InjectedTransaction -> RpcEvent::Transaction
kuzminxyz Jun 16, 2026
607b26f
test compatibility with JS library @noble/curves
kuzminxyz Jun 16, 2026
e776613
chore: implement HashOf<ShieldedTransaction>
kuzminxyz Jun 16, 2026
ebba7a8
chore: handling Shielded transactions in mempool
kuzminxyz Jun 17, 2026
1cc817e
chore: adopt ValidityChecker for ShieldedTransaction
kuzminxyz Jun 17, 2026
8535008
chore(db): put/get ShieldedTransaction to database
kuzminxyz Jun 17, 2026
e59c9b9
chore: add TdecKeyStore to EthexeExternalities
kuzminxyz Jun 18, 2026
fa64279
Merge branch 'master' into kd/feat/handling-shielded-txs
kuzminxyz Jun 18, 2026
5468b9a
chore: remove voting extension, emit event with decryption shares whi…
kuzminxyz Jun 19, 2026
80b9d2b
chore: backbone for gossip distributed decryption shares
kuzminxyz Jun 22, 2026
e753df9
chore: ai generated backbone for decryption shares store
kuzminxyz Jun 22, 2026
a6dfb68
chore: store in malachite context HashMap: validator_address -> its P…
kuzminxyz Jun 22, 2026
5bc795b
chore: add DecryptionKeys variant to Operation enum
kuzminxyz Jun 22, 2026
6c1859b
chore: initial handling shielded transactions in compute service
kuzminxyz Jun 22, 2026
88c0e3b
Merge branch 'master' into kd/feat/handling-shielded-txs
kuzminxyz Jun 22, 2026
1341472
test(service): shielded_tx_fungible_token
kuzminxyz Jun 23, 2026
204cd8e
Merge branch 'master' into kd/feat/handling-shielded-txs
kuzminxyz Jun 23, 2026
3989e54
chore: unshielded output from finalizing block
kuzminxyz Jun 23, 2026
14c404a
chore: adapt RPC to work with TransactionHash
kuzminxyz Jun 23, 2026
03ec325
chore(service-test-env): add tdec setup for testing nodes
kuzminxyz Jun 23, 2026
e124124
chore: parse tdec config from CLI
kuzminxyz Jun 23, 2026
484f5a1
fix: test restart_resilience
kuzminxyz Jun 23, 2026
f6cf8a9
chore: implement Tdec storage for shielding key
kuzminxyz Jun 23, 2026
62bd9c7
fix: test shielded_transaction_fungible_token & validate/block block …
kuzminxyz Jun 23, 2026
b3a7132
chore: fix test for shielded txs
kuzminxyz Jun 24, 2026
1a5c567
chore: allow decryptions keys be a sufficient block content
kuzminxyz Jun 24, 2026
0bd2f80
fix clippy warnings | remove unused deps
kuzminxyz Jun 24, 2026
9f9d4ff
fix: speculative execution when shielded exists
kuzminxyz Jun 24, 2026
341a1bd
fix clippy for get-builtins
kuzminxyz Jun 24, 2026
7b6f3c3
chore: add complex test for shielded transactions
kuzminxyz Jun 24, 2026
827301a
chore: rename InjectedTransactionAcceptance -> TransactionAcceptance
kuzminxyz Jun 24, 2026
6daf9ae
chore: move transactions unshielding to
kuzminxyz Jun 24, 2026
1f8755d
chore: remove remnants of votings extensions from malachite
kuzminxyz Jun 24, 2026
cb37441
feat: add decryption share verification
kuzminxyz Jun 26, 2026
406c198
Merge branch 'master' into kd/feat/handling-shielded-txs
kuzminxyz Jun 29, 2026
8887b6f
Merge branch 'master' into kd/feat/handling-shielded-txs
kuzminxyz Jun 29, 2026
fc23d4f
chote: switch again to voting extension
kuzminxyz Jun 29, 2026
fbcfc02
Merge branch 'kd/feat/handling-shielded-txs' of https://github.com/ge…
kuzminxyz Jun 29, 2026
8403479
chore: update ferveo-* deps to release 0.7.0
kuzminxyz Jun 30, 2026
cc35201
chore: remove feature from ethexe-common | bump gear-tdec to v0.8.0
kuzminxyz Jul 1, 2026
4297322
Merge branch 'master' into kd/feat/handling-shielded-txs
kuzminxyz Jul 1, 2026
c136f10
fix: update license headers
kuzminxyz Jul 1, 2026
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
207 changes: 84 additions & 123 deletions Cargo.lock

Large diffs are not rendered by default.

15 changes: 7 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -248,12 +248,12 @@ which = "4.4.2"
winapi = "0.3.9"
paste = "1.0"
tempfile = "3.19"
ark-std = { version = "0.4.0", default-features = false }
ark-bls12-381 = { version = "0.4.0", default-features = false }
ark-serialize = { version = "0.4", default-features = false }
ark-ec = { version = "0.4.2", default-features = false }
ark-ff = { version = "0.4.2", default-features = false }
ark-scale = { version = "0.0.12", default-features = false }
ark-std = { version = "0.5", default-features = false }
ark-bls12-381 = { version = "0.5", default-features = false }
ark-serialize = { version = "0.5", default-features = false }
ark-ec = { version = "0.5", default-features = false }
ark-ff = { version = "0.5", default-features = false }
ark-scale = { version = "0.0.13", default-features = false }
sha2 = { version = "0.10.8", default-features = false }
sha3 = { version = "0.10.8", default-features = false }
arrayvec = { version = "0.7.4", default-features = false }
Expand All @@ -277,8 +277,7 @@ metrics = "0.24.0"
metrics-derive = "0.1"
metrics-exporter-prometheus = { version = "0.16.0", default-features = false }

gear-tdec = { package = "ferveo-gear-tdec", version = "0.5.0"}

gear-tdec = { package = "ferveo-gear-tdec", version = "0.8.0", default-features = false}
# Published deps
#
# https://github.com/gear-tech/gear-dlmalloc/tree/0.2.1
Expand Down
1 change: 1 addition & 0 deletions ethexe/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ ethexe-processor.workspace = true
ethexe-runtime-common.workspace = true
ethexe-db.workspace = true
gprimitives = { workspace = true, features = ["std"] }
gear-tdec.workspace = true

anyhow.workspace = true
alloy-chains.workspace = true
Expand Down
9 changes: 9 additions & 0 deletions ethexe/cli/src/params/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ mod network;
mod node;
mod prometheus;
mod rpc;
mod tdec;

pub use ethereum::EthereumParams;
pub use malachite::MalachiteParams;
pub use network::NetworkParams;
pub use node::NodeParams;
pub use prometheus::PrometheusParams;
pub use rpc::RpcParams;
pub use tdec::TdecParams;

/// CLI/TOML-config parameters for the ethexe service.
#[derive(Clone, Debug, Default, Deserialize, Parser)]
Expand Down Expand Up @@ -57,6 +59,9 @@ pub struct Params {
/// Prometheus (metrics) service parameters.
#[clap(flatten)]
pub prometheus: Option<PrometheusParams>,

#[clap(flatten)]
pub tdec: Option<TdecParams>,
}

impl Params {
Expand All @@ -81,6 +86,7 @@ impl Params {
malachite,
rpc,
prometheus,
tdec,
} = self;

let node = node.context("missing node params")?;
Expand All @@ -97,13 +103,15 @@ impl Params {
let malachite = malachite.unwrap_or_default().into_config()?;
let rpc = rpc.and_then(|p| p.into_config(&node));
let prometheus = prometheus.and_then(|p| p.into_config());
let tdec = tdec.map(|p| p.into_config());
Ok(Config {
node,
ethereum,
network,
malachite,
rpc,
prometheus,
tdec,
})
}
}
Expand All @@ -117,6 +125,7 @@ impl MergeParams for Params {
malachite: MergeParams::optional_merge(self.malachite, with.malachite),
rpc: MergeParams::optional_merge(self.rpc, with.rpc),
prometheus: MergeParams::optional_merge(self.prometheus, with.prometheus),
tdec: MergeParams::optional_merge(self.tdec, with.tdec),
}
}
}
Expand Down
179 changes: 179 additions & 0 deletions ethexe/cli/src/params/tdec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Copyright (C) Gear Technologies Inc.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

use crate::params::MergeParams;
use ethexe_service::config::ThresholdDecryptionCliConfig;
use gear_tdec::bls12_381::{
DkgPublicKey, PublicDecryptionContextSimple as PublicDecryptionContext,
};
use gsigner::Address;

/// Threshold-decryption parameters.
#[derive(Clone, Debug, serde::Deserialize, clap::Parser)]
pub struct TdecParams {
/// Minimal number of validator decryption shares required to decrypt a
/// shielded transaction.
#[arg(long)]
pub threshold: std::num::NonZeroUsize,

/// DKG public key used by clients to encrypt shielded transaction fields.
#[arg(long = "dkg-public-key", alias = "pubic-key")]
#[serde(rename = "dkg-public-key")]
pub dkg_public_key: DkgPublicKey,

/// Public decryption contexts for validators participating in threshold
/// decryption.
///
/// Pass one option per validator as `ADDRESS=CONTEXT`, where `ADDRESS` is
/// a secp256k1 validator address and `CONTEXT` is the hex string produced
/// by `PublicDecryptionContextSimple`.
#[arg(long = "validators-contexts", value_name = "ADDRESS=CONTEXT")]
#[serde(rename = "validators-contexts")]
pub validators_contexts: Option<Vec<ValidatorContext>>,
}

impl TdecParams {
pub fn into_config(self) -> ThresholdDecryptionCliConfig {
ThresholdDecryptionCliConfig {
threshold: self.threshold,
dkg_public_key: self.dkg_public_key,
validators_contexts: self
.validators_contexts
.map(|ctxs| ctxs.into_iter().map(ValidatorContext::into_parts).collect()),
}
}
}

impl MergeParams for TdecParams {
fn merge(self, with: Self) -> Self {
let validators_contexts = match with.validators_contexts {
Some(mut contexts) => {
if let Some(my_contexts) = self.validators_contexts {
contexts.extend(my_contexts);
}
Some(contexts)
}
None => self.validators_contexts,
};
Self {
threshold: self.threshold,
dkg_public_key: self.dkg_public_key,
validators_contexts,
}
}
}

#[derive(Clone, Debug)]
pub struct ValidatorContext {
pub address: Address,
pub context: PublicDecryptionContext,
}

impl ValidatorContext {
fn into_parts(self) -> (Address, PublicDecryptionContext) {
(self.address, self.context)
}
}

impl From<(Address, PublicDecryptionContext)> for ValidatorContext {
fn from((address, context): (Address, PublicDecryptionContext)) -> Self {
Self { address, context }
}
}

impl std::str::FromStr for ValidatorContext {
type Err = anyhow::Error;

fn from_str(value: &str) -> Result<Self, Self::Err> {
let (address, context) = value.split_once('=').ok_or_else(|| {
anyhow::anyhow!("expected validator context in ADDRESS=CONTEXT format")
})?;

Ok(Self {
address: address.parse()?,
context: context.parse()?,
})
}
}

impl<'de> serde::Deserialize<'de> for ValidatorContext {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(serde::Deserialize)]
#[serde(untagged)]
enum ValidatorContextRepr {
Named {
address: Address,
context: PublicDecryptionContext,
},
Tuple((Address, PublicDecryptionContext)),
}

match ValidatorContextRepr::deserialize(deserializer)? {
ValidatorContextRepr::Named { address, context } => Ok(Self { address, context }),
ValidatorContextRepr::Tuple(tuple) => Ok(tuple.into()),
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use clap::Parser;

fn public_decryption_context(
dealer: &gear_tdec::DealerOutput<gear_tdec::bls12_381::E>,
) -> PublicDecryptionContext {
dealer.private_contexts[0].public_decryption_contexts[0].clone()
}

#[test]
fn validator_context_parses_from_cli_value() {
let dealer = gear_tdec::deal::<gear_tdec::bls12_381::E>(
1,
1,
&mut gear_tdec::rand_utils::test_rng(),
);
let address = Address::from([1; 20]);
let context = public_decryption_context(&dealer);

let parsed = format!("{address}={context}")
.parse::<ValidatorContext>()
.expect("validator context must parse");

assert_eq!(parsed.address, address);
assert_eq!(parsed.context.to_string(), context.to_string());
}

#[test]
fn tdec_params_accepts_validator_contexts_from_clap() {
let dealer = gear_tdec::deal::<gear_tdec::bls12_381::E>(
1,
1,
&mut gear_tdec::rand_utils::test_rng(),
);
let address = Address::from([1; 20]);
let context = public_decryption_context(&dealer);
let context_arg = format!("{address}={context}");

let params = TdecParams::try_parse_from([
"ethexe",
"--threshold",
"1",
"--dkg-public-key",
&dealer.public_key.to_string(),
"--validators-contexts",
&context_arg,
])
.expect("tdec params must parse");

let contexts = params
.validators_contexts
.expect("validator contexts must be present");
assert_eq!(contexts.len(), 1);
assert_eq!(contexts[0].address, address);
assert_eq!(contexts[0].context.to_string(), context.to_string());
}
}
12 changes: 8 additions & 4 deletions ethexe/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,30 @@
[dependencies]
alloy-primitives = { workspace = true, features = ["serde"] }
gear-core.workspace = true
sp-core.workspace = true

Check warning on line 18 in ethexe/common/Cargo.toml

View workflow job for this annotation

GitHub Actions / check / unused-deps

shear/unused_feature_dependency

dependency `sp-core` only used in features
gprimitives.workspace = true
parity-scale-codec.workspace = true
scale-info = { workspace = true, features = ["derive"] }
hex.workspace = true
serde = { workspace = true, optional = true }
derive_more.workspace = true
anyhow.workspace = true
auto_impl.workspace = true
gsigner = { workspace = true, default-features = false, features = [
"secp256k1",
"codec",
"serde",
"tdec",
] }
sha3.workspace = true
k256 = { version = "0.13.4", features = ["ecdsa"], default-features = false }
nonempty.workspace = true
gear-tdec = { workspace = true, optional = true }

ark-ec.workspace = true

# optional dependencies
serde = { workspace = true, optional = true }
gear-tdec = { workspace = true, features = ["serde-hex", "parity-codec", "bls12_381"]}
ark-serialize = { workspace = true }

# mock deps
itertools = { workspace = true, optional = true }
Expand All @@ -59,7 +65,5 @@
"alloy-primitives/std",
"gsigner/std",
"gsigner/keyring",
"shielded"
]
shielded = ["dep:gear-tdec"]
mock = ["std", "itertools/use_std", "tap", "proptest"]
Loading
Loading