Skip to content

Commit 1ddcd46

Browse files
authored
Merge pull request #1560 from input-output-hk/jpraynaud/1533-block-range-merkle-tree-cardano-tx
Implement Block range merkelization for Cardano transactions
2 parents ffe19a9 + dfbad9d commit 1ddcd46

File tree

232 files changed

+5638
-2835
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

232 files changed

+5638
-2835
lines changed

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mithril-aggregator/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-aggregator"
3-
version = "0.4.47"
3+
version = "0.4.48"
44
description = "A Mithril Aggregator server"
55
authors = { workspace = true }
66
edition = { workspace = true }

mithril-aggregator/src/dependency_injection/builder.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,9 @@ use mithril_common::{
3131
EraChecker, EraMarker, EraReader, EraReaderAdapter, SupportedEra,
3232
},
3333
signable_builder::{
34-
CardanoImmutableFilesFullSignableBuilder, MithrilStakeDistributionSignableBuilder,
35-
},
36-
signable_builder::{
37-
CardanoTransactionsSignableBuilder, MithrilSignableBuilderService, SignableBuilderService,
38-
TransactionStore,
34+
CardanoImmutableFilesFullSignableBuilder, CardanoTransactionsSignableBuilder,
35+
MithrilSignableBuilderService, MithrilStakeDistributionSignableBuilder,
36+
SignableBuilderService, TransactionStore,
3937
},
4038
BeaconProvider, BeaconProviderImpl,
4139
};

mithril-aggregator/src/services/prover.rs

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
use std::sync::Arc;
1+
use std::{collections::HashMap, sync::Arc};
22

33
use anyhow::Context;
44
use async_trait::async_trait;
55

66
use mithril_common::{
7-
crypto_helper::{MKTree, MKTreeNode, MKTreeStore},
8-
entities::{Beacon, CardanoTransaction, CardanoTransactionsSetProof, TransactionHash},
7+
crypto_helper::{MKMap, MKMapNode, MKTree, MKTreeNode},
8+
entities::{
9+
Beacon, BlockRange, CardanoTransaction, CardanoTransactionsSetProof, TransactionHash,
10+
},
911
StdResult,
1012
};
1113

@@ -44,6 +46,36 @@ impl MithrilProverService {
4446
transaction_retriever,
4547
}
4648
}
49+
50+
fn compute_merkle_map_from_transactions(
51+
&self,
52+
transactions: &[CardanoTransaction],
53+
) -> StdResult<MKMap<BlockRange, MKMapNode<BlockRange>>> {
54+
let mut transactions_by_block_ranges: HashMap<BlockRange, Vec<TransactionHash>> =
55+
HashMap::new();
56+
for transaction in transactions {
57+
let block_range = BlockRange::from_block_number(transaction.block_number);
58+
transactions_by_block_ranges
59+
.entry(block_range)
60+
.or_default()
61+
.push(transaction.transaction_hash.to_owned());
62+
}
63+
let mk_hash_map = MKMap::new(
64+
transactions_by_block_ranges
65+
.into_iter()
66+
.try_fold(
67+
vec![],
68+
|mut acc, (block_range, transactions)| -> StdResult<Vec<(_, MKMapNode<_>)>> {
69+
acc.push((block_range, MKTree::new(&transactions)?.into()));
70+
Ok(acc)
71+
},
72+
)?
73+
.as_slice(),
74+
)
75+
.with_context(|| "ProverService failed to compute the merkelized structure that proves ownership of the transaction")?;
76+
77+
Ok(mk_hash_map)
78+
}
4779
}
4880

4981
#[async_trait]
@@ -54,26 +86,33 @@ impl ProverService for MithrilProverService {
5486
transaction_hashes: &[TransactionHash],
5587
) -> StdResult<Vec<CardanoTransactionsSetProof>> {
5688
let transactions = self.transaction_retriever.get_up_to(up_to).await?;
57-
let mk_leaves_all: Vec<MKTreeNode> =
58-
transactions.iter().map(|t| t.to_owned().into()).collect();
59-
let store = MKTreeStore::default();
60-
let mktree = MKTree::new(&mk_leaves_all, &store)
61-
.with_context(|| "MKTree creation should not fail")?;
62-
89+
let mk_map = self.compute_merkle_map_from_transactions(&transactions)?;
90+
let transactions_to_prove = transactions
91+
.iter()
92+
.filter_map(|transaction| {
93+
let block_range = BlockRange::from_block_number(transaction.block_number);
94+
transaction_hashes
95+
.contains(&transaction.transaction_hash)
96+
.then(|| (block_range, transaction.to_owned()))
97+
})
98+
.collect::<Vec<_>>();
6399
let mut transaction_hashes_certified = vec![];
64-
for transaction_hash in transaction_hashes {
65-
let mk_leaf = transaction_hash.to_string().into();
66-
if mktree.compute_proof(&[mk_leaf]).is_ok() {
67-
transaction_hashes_certified.push(transaction_hash.to_string());
100+
for (_block_range, transaction) in transactions_to_prove {
101+
let mk_tree_node_transaction_hash: MKTreeNode =
102+
transaction.transaction_hash.to_owned().into();
103+
if mk_map
104+
.compute_proof(&[mk_tree_node_transaction_hash])
105+
.is_ok()
106+
{
107+
transaction_hashes_certified.push(transaction.transaction_hash.to_string());
68108
}
69109
}
70-
71110
if !transaction_hashes_certified.is_empty() {
72111
let mk_leaves: Vec<MKTreeNode> = transaction_hashes_certified
73112
.iter()
74113
.map(|h| h.to_owned().into())
75114
.collect();
76-
let mk_proof = mktree.compute_proof(&mk_leaves)?;
115+
let mk_proof = mk_map.compute_proof(&mk_leaves)?;
77116
let transactions_set_proof_batch =
78117
CardanoTransactionsSetProof::new(transaction_hashes_certified, mk_proof);
79118

@@ -171,9 +210,6 @@ mod tests {
171210
transactions_set_proof[0].verify().unwrap();
172211
}
173212

174-
// this one can't be done right now because we don't have a merkle tree of merkle tree yet
175-
// todo: compute_proof_for_multiple_set_with_multiple_transactions
176-
177213
#[tokio::test]
178214
async fn cant_compute_proof_if_retriever_fail() {
179215
let (transaction_hashes, _transactions) = generate_transactions(3);

mithril-client/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-client"
3-
version = "0.6.7"
3+
version = "0.6.8"
44
description = "Mithril client library"
55
authors = { workspace = true }
66
edition = { workspace = true }

mithril-client/tests/extensions/fake.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,9 @@ mod proof {
160160
certificate_hash: certificate_hash.to_string(),
161161
certified_transactions: vec![CardanoTransactionsSetProof {
162162
transactions_hashes: tx_hashes.iter().map(|h| h.to_string()).collect(),
163-
proof: ProtocolMkProof::new(proof.clone()).to_json_hex().unwrap(),
163+
proof: ProtocolMkProof::new(proof.to_owned().into())
164+
.to_json_hex()
165+
.unwrap(),
164166
}],
165167
non_certified_transactions: vec![],
166168
latest_immutable_file_number: 9999,

mithril-common/Cargo.toml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-common"
3-
version = "0.3.19"
3+
version = "0.3.20"
44
description = "Common types, interfaces, and utilities for Mithril nodes."
55
authors = { workspace = true }
66
edition = { workspace = true }
@@ -15,6 +15,15 @@ crate-type = ["lib", "cdylib", "staticlib"]
1515
[[bench]]
1616
name = "digester"
1717
harness = false
18+
required-features = ["fs"]
19+
20+
[[bench]]
21+
name = "merkle_tree"
22+
harness = false
23+
24+
[[bench]]
25+
name = "merkle_map"
26+
harness = false
1827

1928
[dependencies]
2029
anyhow = "1.0.79"
@@ -91,7 +100,7 @@ reqwest = { version = "0.11.23", features = ["json"] }
91100
slog-async = "2.8.0"
92101
slog-scope = "4.4.0"
93102
slog-term = "2.9.0"
94-
tokio = { version = "1.35.1", features = ["macros", "time"] }
103+
tokio = { version = "1.35.1", features = ["macros", "rt-multi-thread", "time"] }
95104

96105
[build-dependencies]
97106
mithril-build-script = { path = "../internal/mithril-build-script", version = "=0.1.3" }

mithril-common/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ check:
2424
doc:
2525
${CARGO} doc --no-deps --open --features full
2626

27+
bench:
28+
${CARGO} bench --features full --verbose
29+
2730
# Compute the powerset of all the given features and save it to a file
2831
.feature-sets:
2932
powerset() { [ $$# -eq 0 ] && echo || (shift; powerset "$$@") | while read r ; do echo "$$1 $$r"; echo "$$r"; done };\
@@ -35,5 +38,7 @@ check-all-features-set: .feature-sets
3538
echo "Clippy common with feature '$$features_set''"; \
3639
${CARGO} clippy -p mithril-common --features "$$features_set"; \
3740
done
41+
echo "Clippy common without features"; \
42+
${CARGO} clippy -p mithril-common
3843

3944
rm .features-sets

0 commit comments

Comments
 (0)