Skip to content

Commit 8b98390

Browse files
authored
Merge branch 'dev' into supermarket-changes
2 parents ea5f087 + 53b1ba9 commit 8b98390

File tree

17 files changed

+2064
-306
lines changed

17 files changed

+2064
-306
lines changed

Cargo.lock

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

adapter/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,12 @@ mod test {
225225
.expect("The timestamp should be able to be converted to u64");
226226
BigEndian::write_uint(&mut timestamp_buf[26..], n, 6);
227227

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

230230
let channel_id = "061d5e2a67d0a9a10f1c732bca12a676d83f79663a396f7d87b3e30b9b411088";
231231

232232
let state_root = get_signable_state_root(
233-
&hex::decode(&channel_id).expect("fialed"),
233+
&hex::decode(&channel_id).expect("failed"),
234234
&merkle_tree.root(),
235235
)
236236
.expect("Should get state_root");

primitives/Cargo.toml

Lines changed: 1 addition & 0 deletions
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/balances_map.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ impl BalancesMap {
4444
self.0.insert(key, value)
4545
}
4646

47+
pub fn len(&self) -> usize {
48+
self.0.len()
49+
}
50+
4751
pub fn is_empty(&self) -> bool {
4852
self.0.is_empty()
4953
}

primitives/src/merkle_tree.rs

Lines changed: 42 additions & 21 deletions
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

primitives/src/targeting.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use chrono::Utc;
66
use std::collections::HashMap;
77

88
pub use eval::*;
9+
use serde_json::Number;
910

1011
mod eval;
1112

@@ -24,6 +25,7 @@ impl Input {
2425
let spec = &self.global.channel.spec;
2526

2627
match key {
28+
// AdView scope, accessible only on the AdView
2729
"adView.secondsSinceCampaignImpression" => self
2830
.ad_view
2931
.as_ref()
@@ -34,9 +36,22 @@ impl Input {
3436
.as_ref()
3537
.map(|ad_view| Value::Bool(ad_view.has_custom_preferences))
3638
.ok_or(Error::UnknownVariable),
39+
"adView.navigatorLanguage" => self
40+
.ad_view
41+
.as_ref()
42+
.map(|ad_view| Value::String(ad_view.navigator_language.clone()))
43+
.ok_or(Error::UnknownVariable),
44+
// Global scope, accessible everywhere
3745
"adSlotId" => Ok(Value::String(self.global.ad_slot_id.clone())),
3846
"adSlotType" => Ok(Value::String(self.global.ad_slot_type.clone())),
3947
"publisherId" => Ok(Value::String(self.global.publisher_id.to_checksum())),
48+
"country" => self
49+
.global
50+
.country
51+
.clone()
52+
.ok_or(Error::UnknownVariable)
53+
.map(Value::String),
54+
"eventType" => Ok(Value::String(self.global.event_type.clone())),
4055
"secondsSinceEpoch" => Ok(Value::Number(self.global.seconds_since_epoch.into())),
4156
"userAgentOS" => self
4257
.global
@@ -50,7 +65,7 @@ impl Input {
5065
.clone()
5166
.map(Value::String)
5267
.ok_or(Error::UnknownVariable),
53-
68+
// Global scope, accessible everywhere, campaign-dependant
5469
"adUnitId" => {
5570
let ipfs = self
5671
.global
@@ -112,6 +127,7 @@ impl Input {
112127

113128
Ok(Value::BigNum(earned))
114129
}
130+
// adSlot scope, accessible on Supermarket and AdView
115131
"adSlot.categories" => self
116132
.ad_slot
117133
.as_ref()
@@ -213,6 +229,26 @@ pub struct Output {
213229
pub price: HashMap<String, BigNum>,
214230
}
215231

232+
impl Output {
233+
fn try_get(&self, key: &str) -> Result<Value, Error> {
234+
match key {
235+
"show" => Ok(Value::Bool(self.show)),
236+
"boost" => {
237+
let boost = Number::from_f64(self.boost).ok_or(Error::TypeError)?;
238+
Ok(Value::Number(boost))
239+
}
240+
price_key if price_key.starts_with("price.") => {
241+
let price = self
242+
.price
243+
.get(price_key.trim_start_matches("price."))
244+
.ok_or(Error::UnknownVariable)?;
245+
Ok(Value::BigNum(price.clone()))
246+
}
247+
_ => Err(Error::UnknownVariable),
248+
}
249+
}
250+
}
251+
216252
impl From<&Channel> for Output {
217253
fn from(channel: &Channel) -> Self {
218254
let price = match &channel.spec.pricing_bounds {
@@ -325,6 +361,26 @@ mod test {
325361
assert!(input.try_get("adSlot.alexaRank").is_ok());
326362
}
327363

364+
#[test]
365+
fn test_try_get_of_output() {
366+
let output = Output {
367+
show: false,
368+
boost: 5.5,
369+
price: vec![("one".to_string(), 100.into())].into_iter().collect(),
370+
};
371+
372+
assert_eq!(Ok(Value::Bool(false)), output.try_get("show"));
373+
assert_eq!(
374+
Ok(Value::Number(
375+
Number::from_f64(5.5).expect("Should make a number")
376+
)),
377+
output.try_get("boost")
378+
);
379+
assert_eq!(Ok(Value::BigNum(100.into())), output.try_get("price.one"));
380+
assert_eq!(Err(Error::UnknownVariable), output.try_get("price.unknown"));
381+
assert_eq!(Err(Error::UnknownVariable), output.try_get("unknown"));
382+
}
383+
328384
#[test]
329385
fn test_output_from_channel() {
330386
use crate::channel::{Pricing, PricingBounds};

0 commit comments

Comments
 (0)