Skip to content

Commit 13baa25

Browse files
committed
feat(consensus)!: implements state merkle root
1 parent 9a9bd6e commit 13baa25

Some content is hidden

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

66 files changed

+4066
-707
lines changed

.license.ignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
./dan_layer/storage_sqlite/src/global/schema.rs
77
./dan_layer/state_store_sqlite/src/schema.rs
88
./dan_layer/wallet/storage_sqlite/src/schema.rs
9-
./scripts/env_sample
9+
./scripts/env_sample

Cargo.lock

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

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ members = [
2626
"dan_layer/p2p",
2727
"dan_layer/rpc_state_sync",
2828
"dan_layer/state_store_sqlite",
29+
"dan_layer/state_tree",
2930
"dan_layer/storage_lmdb",
3031
"dan_layer/storage_sqlite",
3132
"dan_layer/storage",
@@ -87,6 +88,7 @@ tari_networking = { path = "networking/core" }
8788
tari_rpc_framework = { path = "networking/rpc_framework" }
8889
tari_rpc_macros = { path = "networking/rpc_macros" }
8990
tari_state_store_sqlite = { path = "dan_layer/state_store_sqlite" }
91+
tari_state_tree = { path = "dan_layer/state_tree" }
9092
tari_swarm = { path = "networking/swarm" }
9193
tari_template_abi = { version = "0.3.0", path = "dan_layer/template_abi" }
9294
tari_template_builtin = { path = "dan_layer/template_builtin" }

bindings/src/types/Account.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/*
2+
* // Copyright 2024 The Tari Project
3+
* // SPDX-License-Identifier: BSD-3-Clause
4+
*/
5+
16
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
27
import type { SubstateId } from "./SubstateId";
38

bindings/src/types/Claims.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/*
2+
* // Copyright 2024 The Tari Project
3+
* // SPDX-License-Identifier: BSD-3-Clause
4+
*/
5+
16
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
27
import type { JrpcPermissions } from "./JrpcPermissions";
38

bindings/src/types/JrpcPermission.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/*
2+
* // Copyright 2024 The Tari Project
3+
* // SPDX-License-Identifier: BSD-3-Clause
4+
*/
5+
16
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
27
import type { ComponentAddress } from "./ComponentAddress";
38
import type { ResourceAddress } from "./ResourceAddress";

bindings/src/types/JrpcPermissions.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/*
2+
* // Copyright 2024 The Tari Project
3+
* // SPDX-License-Identifier: BSD-3-Clause
4+
*/
5+
16
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
27
import type { JrpcPermission } from "./JrpcPermission";
38

bindings/src/types/TransactionStatus.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/*
2+
* // Copyright 2024 The Tari Project
3+
* // SPDX-License-Identifier: BSD-3-Clause
4+
*/
5+
16
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
27

38
export type TransactionStatus =

dan_layer/common_types/src/hasher.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,11 @@ impl TariHasher {
4545
}
4646

4747
pub fn result(self) -> FixedHash {
48-
let hash: [u8; 32] = self.hasher.finalize().into();
49-
hash.into()
48+
self.finalize_into_array().into()
49+
}
50+
51+
pub fn finalize_into_array(self) -> [u8; 32] {
52+
self.hasher.finalize().into()
5053
}
5154

5255
fn hash_writer(&mut self) -> impl Write + '_ {

dan_layer/consensus/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ license.workspace = true
1010
[dependencies]
1111
tari_dan_common_types = { workspace = true }
1212
tari_dan_storage = { workspace = true }
13+
tari_engine_types = { workspace = true }
1314
tari_transaction = { workspace = true }
1415
tari_epoch_manager = { workspace = true }
16+
tari_state_tree = { workspace = true }
1517

1618
# Used for PublicKey and Signature and Network enum
1719
tari_common = { workspace = true }

dan_layer/consensus/src/hotstuff/common.rs

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,22 @@
33

44
use log::*;
55
use tari_common::configuration::Network;
6+
use tari_common_types::types::FixedHash;
67
use tari_dan_common_types::{committee::Committee, Epoch, NodeAddressable, NodeHeight};
7-
use tari_dan_storage::consensus_models::{Block, QuorumCertificate};
8+
use tari_dan_storage::consensus_models::{Block, LeafBlock, PendingStateTreeDiff, QuorumCertificate};
9+
use tari_engine_types::{
10+
hashing::substate_value_hasher32,
11+
substate::{Substate, SubstateDiff},
12+
};
13+
use tari_state_tree::{
14+
Hash,
15+
StagedTreeStore,
16+
StateHashTreeDiff,
17+
StateTreeError,
18+
SubstateChange,
19+
TreeStoreReader,
20+
Version,
21+
};
822

923
use crate::traits::LeaderStrategy;
1024

@@ -15,14 +29,17 @@ const LOG_TARGET: &str = "tari::dan::consensus::hotstuff::common";
1529
/// TODO: exhaust > 0
1630
pub const EXHAUST_DIVISOR: u64 = 0;
1731

18-
pub fn calculate_dummy_blocks<TAddr: NodeAddressable, TLeaderStrategy: LeaderStrategy<TAddr>>(
32+
/// Calculates the dummy block required to reach the new height and returns the last dummy block (parent for next
33+
/// proposal).
34+
pub fn calculate_last_dummy_block<TAddr: NodeAddressable, TLeaderStrategy: LeaderStrategy<TAddr>>(
1935
network: Network,
2036
epoch: Epoch,
2137
high_qc: &QuorumCertificate,
38+
parent_merkle_root: FixedHash,
2239
new_height: NodeHeight,
2340
leader_strategy: &TLeaderStrategy,
2441
local_committee: &Committee<TAddr>,
25-
) -> Vec<Block> {
42+
) -> Option<LeafBlock> {
2643
let mut parent_block = high_qc.as_leaf_block();
2744
let mut current_height = high_qc.block_height() + NodeHeight(1);
2845
if current_height > new_height {
@@ -32,7 +49,7 @@ pub fn calculate_dummy_blocks<TAddr: NodeAddressable, TLeaderStrategy: LeaderStr
3249
current_height,
3350
new_height,
3451
);
35-
return Vec::new();
52+
return None;
3653
}
3754

3855
debug!(
@@ -41,8 +58,6 @@ pub fn calculate_dummy_blocks<TAddr: NodeAddressable, TLeaderStrategy: LeaderStr
4158
current_height,
4259
new_height,
4360
);
44-
let num_blocks = new_height.saturating_sub(current_height).as_u64() as usize;
45-
let mut blocks = Vec::with_capacity(num_blocks);
4661
loop {
4762
let leader = leader_strategy.get_leader_public_key(local_committee, current_height);
4863
let dummy_block = Block::dummy_block(
@@ -52,20 +67,56 @@ pub fn calculate_dummy_blocks<TAddr: NodeAddressable, TLeaderStrategy: LeaderStr
5267
current_height,
5368
high_qc.clone(),
5469
epoch,
70+
parent_merkle_root,
5571
);
5672
debug!(
5773
target: LOG_TARGET,
5874
"🍼 new dummy block: {}",
5975
dummy_block,
6076
);
6177
parent_block = dummy_block.as_leaf_block();
62-
blocks.push(dummy_block);
6378

6479
if current_height == new_height {
6580
break;
6681
}
6782
current_height += NodeHeight(1);
6883
}
6984

70-
blocks
85+
Some(parent_block)
86+
}
87+
88+
pub fn diff_to_substate_changes(diff: &SubstateDiff) -> impl Iterator<Item = SubstateChange> + '_ {
89+
diff.down_iter()
90+
.map(|(substate_id, _version)| SubstateChange::Down {
91+
id: substate_id.clone(),
92+
})
93+
.chain(diff.up_iter().map(move |(substate_id, value)| SubstateChange::Up {
94+
id: substate_id.clone(),
95+
value_hash: hash_substate(value),
96+
}))
97+
}
98+
99+
pub fn hash_substate(substate: &Substate) -> FixedHash {
100+
substate_value_hasher32().chain(substate).result().into_array().into()
101+
}
102+
103+
pub fn calculate_state_merkle_diff<TTx: TreeStoreReader<Version>, I: IntoIterator<Item = SubstateChange>>(
104+
tx: &TTx,
105+
current_version: Version,
106+
next_version: Version,
107+
pending_tree_updates: Vec<PendingStateTreeDiff>,
108+
substate_changes: I,
109+
) -> Result<(Hash, StateHashTreeDiff), StateTreeError> {
110+
debug!(
111+
target: LOG_TARGET,
112+
"Calculating state merkle diff from version {} to {} with {} update(s)",
113+
current_version,
114+
next_version,
115+
pending_tree_updates.len(),
116+
);
117+
let mut store = StagedTreeStore::new(tx);
118+
store.apply_ordered_diffs(pending_tree_updates.into_iter().map(|diff| diff.diff));
119+
let mut state_tree = tari_state_tree::SpreadPrefixStateTree::new(&mut store);
120+
let state_root = state_tree.put_substate_changes(current_version, next_version, substate_changes)?;
121+
Ok((state_root, store.into_diff()))
71122
}

dan_layer/consensus/src/hotstuff/error.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
// Copyright 2023 The Tari Project
22
// SPDX-License-Identifier: BSD-3-Clause
33

4+
use tari_common_types::types::FixedHash;
45
use tari_dan_common_types::{Epoch, NodeHeight};
56
use tari_dan_storage::{
67
consensus_models::{BlockId, LeafBlock, LockedBlock, QuorumCertificate, TransactionPoolError},
78
StorageError,
89
};
910
use tari_epoch_manager::EpochManagerError;
1011
use tari_mmr::BalancedBinaryMerkleProofError;
12+
use tari_state_tree::StateTreeError;
1113
use tari_transaction::TransactionId;
1214

1315
use crate::traits::{InboundMessagingError, OutboundMessagingError};
@@ -16,6 +18,8 @@ use crate::traits::{InboundMessagingError, OutboundMessagingError};
1618
pub enum HotStuffError {
1719
#[error("Storage error: {0}")]
1820
StorageError(#[from] StorageError),
21+
#[error("State tree error: {0}")]
22+
StateTreeError(#[from] StateTreeError),
1923
#[error("Internal channel send error when {context}")]
2024
InternalChannelClosed { context: &'static str },
2125
#[error("Inbound messaging error: {0}")]
@@ -176,4 +180,10 @@ pub enum ProposalValidationError {
176180
block_network: String,
177181
block_id: BlockId,
178182
},
183+
#[error("Invalid state merkle root for block {block_id}: calculated {calculated} but block has {from_block}")]
184+
InvalidStateMerkleRoot {
185+
block_id: BlockId,
186+
calculated: FixedHash,
187+
from_block: FixedHash,
188+
},
179189
}

0 commit comments

Comments
 (0)