Skip to content

Commit 7fdf618

Browse files
authored
Merge pull request #318 from AdExNetwork/hotfix-316-merkle-tree-missing-0-leaves-check
Hotfix #316 MerkleTree missing 0 leaves check
2 parents 7eb40cf + 116539b commit 7fdf618

File tree

10 files changed

+72
-31
lines changed

10 files changed

+72
-31
lines changed

Cargo.lock

+21
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

adapter/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -230,12 +230,12 @@ mod test {
230230
.expect("The timestamp should be able to be converted to u64");
231231
BigEndian::write_uint(&mut timestamp_buf[26..], n, 6);
232232

233-
let merkle_tree = MerkleTree::new(&[timestamp_buf]);
233+
let merkle_tree = MerkleTree::new(&[timestamp_buf]).expect("Should instantiate");
234234

235235
let channel_id = "061d5e2a67d0a9a10f1c732bca12a676d83f79663a396f7d87b3e30b9b411088";
236236

237237
let state_root = get_signable_state_root(
238-
&hex::decode(&channel_id).expect("fialed"),
238+
&hex::decode(&channel_id).expect("failed"),
239239
&merkle_tree.root(),
240240
)
241241
.expect("Should get state_root");

primitives/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ slog = { version = "^2.5.2" , features = ["max_level_trace"] }
2020
slog-term = "^2.4.2"
2121
slog-async = "^2.3.0"
2222
# Domain
23+
thiserror = "^1.0"
2324
chrono = { version = "0.4", features = ["serde"] }
2425
time = "0.1.42"
2526
hex = "0.3.2"

primitives/src/merkle_tree.rs

+42-21
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
use merkletree::hash::Algorithm;
2-
use merkletree::merkle;
3-
use merkletree::merkle::VecStore;
4-
use merkletree::proof::Proof;
1+
use merkletree::{hash::Algorithm, merkle, merkle::VecStore, proof::Proof};
2+
use std::fmt;
53
use std::hash::Hasher;
64
use std::iter::FromIterator;
5+
use thiserror::Error;
76
use tiny_keccak::Keccak;
87

98
#[derive(Clone)]
109
struct KeccakAlgorithm(Keccak);
1110

11+
impl fmt::Debug for KeccakAlgorithm {
12+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13+
write!(f, "Keccak256 Algorithm")
14+
}
15+
}
16+
1217
impl KeccakAlgorithm {
1318
pub fn new() -> KeccakAlgorithm {
1419
KeccakAlgorithm(Keccak::new_keccak256())
@@ -72,39 +77,49 @@ impl Algorithm<MerkleItem> for KeccakAlgorithm {
7277
type ExternalMerkleTree =
7378
merkletree::merkle::MerkleTree<MerkleItem, KeccakAlgorithm, VecStore<MerkleItem>>;
7479

75-
#[derive(Clone)]
80+
#[derive(Debug, Clone)]
7681
enum Tree {
7782
SingleItem(MerkleItem),
7883
MerkleTree(ExternalMerkleTree),
7984
}
8085

86+
#[derive(Debug, Error, Eq, PartialEq)]
87+
pub enum Error {
88+
#[error("No leaves were provided")]
89+
ZeroLeaves,
90+
}
91+
92+
#[derive(Debug)]
8193
pub struct MerkleTree {
8294
tree: Tree,
8395
root: MerkleItem,
8496
}
8597

8698
impl MerkleTree {
87-
pub fn new(data: &[MerkleItem]) -> MerkleTree {
99+
pub fn new(data: &[MerkleItem]) -> Result<MerkleTree, Error> {
88100
let mut leaves: Vec<MerkleItem> = data.to_owned();
89-
90-
let tree: Tree = if leaves.len() == 1 {
91-
Tree::SingleItem(leaves[0].to_owned())
92-
} else {
93-
// sort the merkle tree leaves
94-
leaves.sort();
95-
// remove duplicates
96-
leaves.dedup_by(|a, b| a == b);
97-
98-
let merkletree = merkle::MerkleTree::from_iter(leaves);
99-
Tree::MerkleTree(merkletree)
101+
// sort the MerkleTree leaves
102+
leaves.sort();
103+
// remove duplicates **before** we check the leaves length
104+
leaves.dedup_by(|a, b| a == b);
105+
106+
let tree = match leaves.len() {
107+
0 => return Err(Error::ZeroLeaves),
108+
// should never `panic!`, we have a single leaf after all
109+
1 => Tree::SingleItem(leaves.remove(0)),
110+
_ => {
111+
let merkletree = merkle::MerkleTree::from_iter(leaves);
112+
113+
Tree::MerkleTree(merkletree)
114+
}
100115
};
101116

102117
let root: MerkleItem = match &tree {
103118
Tree::SingleItem(root) => root.to_owned(),
104119
Tree::MerkleTree(merkletree) => merkletree.root(),
105120
};
106121

107-
MerkleTree { tree, root }
122+
Ok(MerkleTree { tree, root })
108123
}
109124

110125
pub fn root(&self) -> MerkleItem {
@@ -134,6 +149,12 @@ mod test {
134149
use super::*;
135150
use hex::FromHex;
136151

152+
#[test]
153+
fn it_returns_error_on_zero_leaves() {
154+
let error = MerkleTree::new(&[]).expect_err("ZeroLeaves error expected");
155+
assert_eq!(Error::ZeroLeaves, error);
156+
}
157+
137158
#[test]
138159
fn it_generates_correct_merkle_tree_that_correlates_with_js_impl() {
139160
let h1 = <[u8; 32]>::from_hex(
@@ -145,7 +166,7 @@ mod test {
145166
)
146167
.unwrap();
147168

148-
let top = MerkleTree::new(&[h1, h2]);
169+
let top = MerkleTree::new(&[h1, h2]).expect("Should create MerkleTree");
149170

150171
let root = hex::encode(&top.root());
151172

@@ -172,7 +193,7 @@ mod test {
172193
.unwrap();
173194

174195
// duplicate leaves
175-
let top = MerkleTree::new(&[h1, h2, h2]);
196+
let top = MerkleTree::new(&[h1, h2, h2]).expect("Should create MerkleTree");
176197

177198
let root = hex::encode(&top.root());
178199

@@ -204,7 +225,7 @@ mod test {
204225
.unwrap();
205226

206227
// odd leaves
207-
let top = MerkleTree::new(&[h1, h2, h3]);
228+
let top = MerkleTree::new(&[h1, h2, h3]).expect("Should create MerkleTree");
208229

209230
let root = hex::encode(&top.root());
210231

sentry/src/db.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub async fn postgres_connection() -> Result<DbPool, bb8_postgres::tokio_postgre
4646
.user(POSTGRES_USER.as_str())
4747
.password(POSTGRES_PASSWORD.as_str())
4848
.host(POSTGRES_HOST.as_str())
49-
.port(POSTGRES_PORT.clone());
49+
.port(*POSTGRES_PORT);
5050
if let Some(db) = POSTGRES_DB.clone() {
5151
config.dbname(&db);
5252
}
@@ -62,7 +62,7 @@ pub async fn setup_migrations(environment: &str) {
6262
.database_user(POSTGRES_USER.as_str())
6363
.database_password(POSTGRES_PASSWORD.as_str())
6464
.database_host(POSTGRES_HOST.as_str())
65-
.database_port(POSTGRES_PORT.clone())
65+
.database_port(*POSTGRES_PORT)
6666
.database_name(&POSTGRES_DB.as_ref().unwrap_or(&POSTGRES_USER))
6767
.build()
6868
.expect("Should build migration settings");

sentry/src/event_aggregator.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ async fn store(db: &DbPool, channel_id: &ChannelId, logger: &Logger, recorder: R
5858
aggregate: new_aggr(&channel_id),
5959
};
6060
channel_recorder.insert(channel_id.to_owned(), record);
61-
};
61+
}
6262
}
6363
}
6464

sentry/src/event_reducer.rs

-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ use crate::analytics_recorder::get_payout;
22
use primitives::sentry::{AggregateEvents, Event, EventAggregate};
33
use primitives::{BigNum, Channel, ValidatorId};
44

5-
// @TODO: Remove attribute once we use this function!
6-
#[allow(dead_code)]
75
pub(crate) fn reduce(channel: &Channel, initial_aggr: &mut EventAggregate, ev: &Event) {
86
match ev {
97
Event::Impression { publisher, .. } => {

sentry/src/middleware/auth.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ fn get_request_ip(req: &Request<Body>) -> Option<String> {
7777
.get("true-client-ip")
7878
.or_else(|| req.headers().get("x-forwarded-for"))
7979
.and_then(|hv| hv.to_str().map(ToString::to_string).ok())
80-
.map(|token| token.split(',').nth(0).map(ToString::to_string))
80+
.map(|token| token.split(',').next().map(ToString::to_string))
8181
.flatten()
8282
}
8383

validator_worker/src/heartbeat.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ async fn send_heartbeat<A: Adapter + 'static>(iface: &SentryApi<A>) -> Result<()
1818
.expect("The timestamp should be able to be converted to u64");
1919
BigEndian::write_uint(&mut timestamp_buf[26..], milliseconds, 6);
2020

21-
let merkle_tree = MerkleTree::new(&[timestamp_buf]);
21+
let merkle_tree = MerkleTree::new(&[timestamp_buf])?;
2222

2323
let state_root_raw = get_signable_state_root(&iface.channel.id, &merkle_tree.root())?;
2424
let state_root = hex::encode(state_root_raw);

validator_worker/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub(crate) fn get_state_root_hash<A: Adapter + 'static>(
3333
.map(|(acc, amount)| get_balance_leaf(acc, amount))
3434
.collect::<Result<_, _>>()?;
3535

36-
let tree = MerkleTree::new(&elems);
36+
let tree = MerkleTree::new(&elems)?;
3737
// keccak256(channelId, balanceRoot
3838
get_signable_state_root(&iface.channel.id, &tree.root())
3939
}

0 commit comments

Comments
 (0)