From 822898f183ea8757a88c37376fc196ef190808f6 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Mon, 29 Jun 2020 14:40:37 +0300 Subject: [PATCH 01/27] Remove fields made obslote by AIP#31 --- primitives/src/ad_slot.rs | 11 ++--------- primitives/src/ad_unit.rs | 8 +------- primitives/src/channel.rs | 29 ++--------------------------- 3 files changed, 5 insertions(+), 43 deletions(-) diff --git a/primitives/src/ad_slot.rs b/primitives/src/ad_slot.rs index 65ffb45bc..fa56b44e3 100644 --- a/primitives/src/ad_slot.rs +++ b/primitives/src/ad_slot.rs @@ -1,4 +1,4 @@ -use crate::{BigNum, TargetingTag, ValidatorId}; +use crate::{BigNum, ValidatorId, targeting::Rule}; use chrono::serde::{ts_milliseconds, ts_milliseconds_option}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -32,18 +32,11 @@ pub struct AdSlot { pub media_mime: String, /// Advertised URL pub target_url: String, - /// Array of TargetingTag - #[serde(default)] - pub targeting: Vec, // HashMap for the minimum payment accepted per impression #[serde(default)] pub min_per_impression: Option>, - /// Array of TargetingTag - /// meant for discovery between publishers/advertisers - #[serde(default)] - pub tags: Vec, #[serde(default)] - pub auto_tags: Vec, + pub rules: Vec, /// Valid ipfs hash for Ad Unit object. It will be used as fallback data (optional) #[serde(default)] pub fallback_unit: Option, diff --git a/primitives/src/ad_unit.rs b/primitives/src/ad_unit.rs index 56cd612f2..636321e62 100644 --- a/primitives/src/ad_unit.rs +++ b/primitives/src/ad_unit.rs @@ -2,7 +2,7 @@ use chrono::serde::{ts_milliseconds, ts_milliseconds_option}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::{TargetingTag, ValidatorId}; +use crate::ValidatorId; #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] @@ -25,14 +25,8 @@ pub struct AdUnit { pub media_mime: String, /// Advertised URL pub target_url: String, - /// Array of TargetingTag - pub targeting: Vec, /// Number; minimum targeting score (optional) pub min_targeting_score: Option, - /// Array of TargetingTag (optional) - /// meant for discovery between publishers/advertisers - #[serde(default)] - pub tags: Vec, /// user address from the session pub owner: ValidatorId, /// number, UTC timestamp in milliseconds, used as nonce for escaping duplicated spec ipfs hashes diff --git a/primitives/src/channel.rs b/primitives/src/channel.rs index 51171c743..90142c03e 100644 --- a/primitives/src/channel.rs +++ b/primitives/src/channel.rs @@ -136,18 +136,14 @@ pub struct ChannelSpec { pub title: Option, pub validators: SpecValidators, /// Maximum payment per impression + /// **OBSOLETE**, only used if `pricingBounds` is missing an `IMPRESSION` entry pub max_per_impression: BigNum, /// Minimum payment offered per impression + /// **OBSOLETE**, only used if `pricingBounds` is missing an `IMPRESSION` entry pub min_per_impression: BigNum, /// Event pricing bounds #[serde(default, skip_serializing_if = "Option::is_none")] pub pricing_bounds: Option, - /// An array of TargetingTag (optional) - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub targeting: Vec, - /// Minimum targeting score (optional) - #[serde(default, skip_serializing_if = "Option::is_none")] - pub min_targeting_score: Option, /// EventSubmission object, applies to event submission (POST /channel/:id/events) #[serde(default, skip_serializing_if = "Option::is_none")] pub event_submission: Option, @@ -176,27 +172,6 @@ pub struct ChannelSpec { pub ad_units: Vec, #[serde(default)] pub targeting_rules: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub price_multiplication_rules: Vec, - #[serde(default)] - pub price_dynamic_adjustment: bool, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct PriceMultiplicationRules { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub multiplier: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub amount: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub ev_type: Option>, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub publisher: Option>, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub os_type: Option>, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub country: Option>, } #[derive(Serialize, Deserialize, Debug, Clone)] From edf2962c078dce7b40a7a2918095d6808261d366 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Mon, 29 Jun 2020 14:52:06 +0300 Subject: [PATCH 02/27] WIP remove obsolete fields --- adapter/src/ethereum.rs | 4 ---- primitives/src/ad_slot.rs | 2 +- primitives/src/targeting.rs | 2 -- primitives/src/targeting/eval.rs | 2 -- primitives/src/util/tests/prep_db.rs | 4 ---- 5 files changed, 1 insertion(+), 13 deletions(-) diff --git a/adapter/src/ethereum.rs b/adapter/src/ethereum.rs index 34bdc8c9c..df74da456 100644 --- a/adapter/src/ethereum.rs +++ b/adapter/src/ethereum.rs @@ -675,9 +675,7 @@ mod test { validators: SpecValidators::new(leader_validator_desc, follower_validator_desc), max_per_impression: 10.into(), min_per_impression: 10.into(), - targeting: vec![], targeting_rules: vec![], - min_targeting_score: None, event_submission: Some(EventSubmission { allow: vec![] }), created: Utc::now(), active_from: None, @@ -685,8 +683,6 @@ mod test { withdraw_period_start: Utc::now() + Duration::days(1), ad_units: vec![], pricing_bounds: None, - price_multiplication_rules: Default::default(), - price_dynamic_adjustment: false, }, }; diff --git a/primitives/src/ad_slot.rs b/primitives/src/ad_slot.rs index fa56b44e3..0d8f8c13d 100644 --- a/primitives/src/ad_slot.rs +++ b/primitives/src/ad_slot.rs @@ -1,4 +1,4 @@ -use crate::{BigNum, ValidatorId, targeting::Rule}; +use crate::{targeting::Rule, BigNum, ValidatorId}; use chrono::serde::{ts_milliseconds, ts_milliseconds_option}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; diff --git a/primitives/src/targeting.rs b/primitives/src/targeting.rs index 2d5d92076..d94e8e1d1 100644 --- a/primitives/src/targeting.rs +++ b/primitives/src/targeting.rs @@ -249,9 +249,7 @@ mod test { media_url: "media_url".to_string(), media_mime: "media_mime".to_string(), target_url: "target_url".to_string(), - targeting: vec![], min_targeting_score: None, - tags: vec![], owner: IDS["creator"], created: Utc::now(), title: None, diff --git a/primitives/src/targeting/eval.rs b/primitives/src/targeting/eval.rs index 37e7d352f..36f4dad68 100644 --- a/primitives/src/targeting/eval.rs +++ b/primitives/src/targeting/eval.rs @@ -625,9 +625,7 @@ mod test { media_url: "media_url".to_string(), media_mime: "media_mime".to_string(), target_url: "target_url".to_string(), - targeting: vec![], min_targeting_score: None, - tags: vec![], owner: IDS["creator"], created: Utc::now(), title: None, diff --git a/primitives/src/util/tests/prep_db.rs b/primitives/src/util/tests/prep_db.rs index cd3773464..6fcb30fcf 100644 --- a/primitives/src/util/tests/prep_db.rs +++ b/primitives/src/util/tests/prep_db.rs @@ -73,8 +73,6 @@ lazy_static! { max_per_impression: 10.into(), min_per_impression: 1.into(), targeting_rules: vec![], - targeting: vec![], - min_targeting_score: None, event_submission: Some(EventSubmission { allow: vec![] }), // July 29, 2019 7:00:00 AM created: Utc.timestamp(1_564_383_600, 0), @@ -83,8 +81,6 @@ lazy_static! { withdraw_period_start: Utc.timestamp_millis(4_073_414_400_000), ad_units: vec![], pricing_bounds: Some(PricingBounds {impression: None, click: Some(Pricing { max: 0.into(), min: 0.into()})}), - price_multiplication_rules: Default::default(), - price_dynamic_adjustment: false, }, } }; From 40e587bcb016ad1d0e7c1544a5863dfe419ed393 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Tue, 21 Jul 2020 12:43:18 +0300 Subject: [PATCH 03/27] Clean usage of TargetingTag --- primitives/src/channel.rs | 2 +- primitives/src/targeting/eval_test.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/primitives/src/channel.rs b/primitives/src/channel.rs index 90142c03e..6399071bc 100644 --- a/primitives/src/channel.rs +++ b/primitives/src/channel.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Deserializer, Serialize}; use serde_hex::{SerHex, StrictPfx}; use crate::{ - targeting::Rule, AdUnit, BigNum, EventSubmission, TargetingTag, ValidatorDesc, ValidatorId, + targeting::Rule, AdUnit, BigNum, EventSubmission, ValidatorDesc, ValidatorId, }; use hex::{FromHex, FromHexError}; diff --git a/primitives/src/targeting/eval_test.rs b/primitives/src/targeting/eval_test.rs index b776a3d2e..558b51fa2 100644 --- a/primitives/src/targeting/eval_test.rs +++ b/primitives/src/targeting/eval_test.rs @@ -14,9 +14,7 @@ fn get_default_input() -> Input { media_url: "media_url".to_string(), media_mime: "media_mime".to_string(), target_url: "target_url".to_string(), - targeting: vec![], min_targeting_score: None, - tags: vec![], owner: IDS["creator"], created: Utc::now(), title: None, From 5c054f94bb5d776f31de5efed413c814ec544902 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 24 Jul 2020 13:29:27 +0300 Subject: [PATCH 04/27] adview-manager - Cargo - add lazy_static --- Cargo.lock | 1 + adview-manager/Cargo.toml | 1 + primitives/src/supermarket.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 1dd6b5109..15dd3cc40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,6 +31,7 @@ name = "adview-manager" version = "0.1.0" dependencies = [ "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "primitives 0.1.0", "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/adview-manager/Cargo.toml b/adview-manager/Cargo.toml index 1d74345ce..9961670bd 100644 --- a/adview-manager/Cargo.toml +++ b/adview-manager/Cargo.toml @@ -10,3 +10,4 @@ chrono = "0.4" num-bigint = {version = "0.3", features = ["serde"]} serde = {version = "^1.0", features = ['derive']} serde_json = "^1.0" +lazy_static = "1.4" diff --git a/primitives/src/supermarket.rs b/primitives/src/supermarket.rs index ae38c4db1..466e4164c 100644 --- a/primitives/src/supermarket.rs +++ b/primitives/src/supermarket.rs @@ -39,6 +39,7 @@ pub enum Finalized { Exhausted, Withdraw, } + pub mod units_for_slot { pub mod response { use crate::{targeting::Rule, BigNum, ChannelId, ChannelSpec, SpecValidators, ValidatorId}; From f908234295baec38642c07559cd68057f7d8c839 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 24 Jul 2020 13:30:47 +0300 Subject: [PATCH 05/27] WIP payouts, analytics recorder, event aggregator, event reducer --- primitives/src/channel.rs | 4 +- sentry/src/analytics_recorder.rs | 4 + sentry/src/event_aggregator.rs | 5 +- sentry/src/event_reducer.rs | 42 ++- sentry/src/payout.rs | 534 +++++++------------------------ 5 files changed, 147 insertions(+), 442 deletions(-) diff --git a/primitives/src/channel.rs b/primitives/src/channel.rs index 6399071bc..2d78de670 100644 --- a/primitives/src/channel.rs +++ b/primitives/src/channel.rs @@ -7,9 +7,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Deserializer, Serialize}; use serde_hex::{SerHex, StrictPfx}; -use crate::{ - targeting::Rule, AdUnit, BigNum, EventSubmission, ValidatorDesc, ValidatorId, -}; +use crate::{targeting::Rule, AdUnit, BigNum, EventSubmission, ValidatorDesc, ValidatorId}; use hex::{FromHex, FromHexError}; #[derive(Serialize, Deserialize, PartialEq, Eq, Copy, Clone, Hash)] diff --git a/sentry/src/analytics_recorder.rs b/sentry/src/analytics_recorder.rs index fa57552a5..ce0e43a24 100644 --- a/sentry/src/analytics_recorder.rs +++ b/sentry/src/analytics_recorder.rs @@ -34,7 +34,11 @@ pub async fn record( referrer, } => { let divisor = BigNum::from(10u64.pow(18)); + // @Todo: Check this! let pay_amount = get_payout(&channel, event, &session) + .expect("should have payout") + .map(|(_, payout)| payout) + .unwrap_or_default() .div_floor(&divisor) .to_f64() .expect("should always have a payout"); diff --git a/sentry/src/event_aggregator.rs b/sentry/src/event_aggregator.rs index 3a218f202..d4a9be855 100644 --- a/sentry/src/event_aggregator.rs +++ b/sentry/src/event_aggregator.rs @@ -144,7 +144,10 @@ impl EventAggregator { })?; events.iter().for_each(|ev| { - event_reducer::reduce(&record.channel, &mut record.aggregate, ev, &session) + match event_reducer::reduce(&record.channel, &mut record.aggregate, ev, &session) { + Ok(_) => {} + Err(err) => error!(&app.logger, "Event Reducer failed"; "error" => ?err ), + } }); // only time we don't have session is during diff --git a/sentry/src/event_reducer.rs b/sentry/src/event_reducer.rs index ccefb1dd1..b35ae3f36 100644 --- a/sentry/src/event_reducer.rs +++ b/sentry/src/event_reducer.rs @@ -8,21 +8,28 @@ pub(crate) fn reduce( initial_aggr: &mut EventAggregate, ev: &Event, session: &Session, -) { +) -> Result<(), Box> { + let event_type = ev.to_string(); match ev { Event::Impression { publisher, .. } => { - let impression = initial_aggr.events.get("IMPRESSION"); - let payout = get_payout(&channel, &ev, session); - let merge = merge_impression_ev(impression, &publisher, &payout); - - initial_aggr.events.insert("IMPRESSION".to_owned(), merge); + let impression = initial_aggr.events.get(&event_type); + let payout = get_payout(&channel, &ev, session)?; + let merge = merge_impression_ev( + impression, + payout.unwrap_or_else(|| (*publisher, Default::default())), + ); + + initial_aggr.events.insert(event_type, merge); } Event::Click { publisher, .. } => { - let clicks = initial_aggr.events.get("CLICK"); - let payout = get_payout(&channel, &ev, session); - let merge = merge_impression_ev(clicks, &publisher, &payout); - - initial_aggr.events.insert("CLICK".to_owned(), merge); + let clicks = initial_aggr.events.get(&event_type); + let payout = get_payout(&channel, &ev, session)?; + let merge = merge_impression_ev( + clicks, + payout.unwrap_or_else(|| (*publisher, Default::default())), + ); + + initial_aggr.events.insert(event_type, merge); } Event::Close => { let close_event = AggregateEvents { @@ -31,32 +38,33 @@ pub(crate) fn reduce( .into_iter() .collect(), }; - initial_aggr.events.insert("CLOSE".to_owned(), close_event); + initial_aggr.events.insert(event_type, close_event); } _ => {} }; + + Ok(()) } fn merge_impression_ev( impression: Option<&AggregateEvents>, - earner: &ValidatorId, - payout: &BigNum, + payout: (ValidatorId, BigNum), ) -> AggregateEvents { let mut impression = impression.map(Clone::clone).unwrap_or_default(); let event_count = impression .event_counts .get_or_insert_with(Default::default) - .entry(*earner) + .entry(payout.0) .or_insert_with(|| 0.into()); *event_count += &1.into(); let event_payouts = impression .event_payouts - .entry(*earner) + .entry(payout.0) .or_insert_with(|| 0.into()); - *event_payouts += payout; + *event_payouts += &payout.1; impression } diff --git a/sentry/src/payout.rs b/sentry/src/payout.rs index 6d59e414c..1e98c4f3b 100644 --- a/sentry/src/payout.rs +++ b/sentry/src/payout.rs @@ -1,437 +1,129 @@ use crate::Session; -use primitives::channel::PriceMultiplicationRules; -use primitives::sentry::Event; -use primitives::ValidatorId; -use primitives::{BigNum, Channel}; +use chrono::Utc; +use primitives::{ + sentry::Event, + targeting::{get_pricing_bounds, Error, Error as EvalError, Global, Input, Output, Rule}, + BigNum, Channel, ValidatorId, +}; +use std::{ + cmp::{max, min}, + convert::TryFrom, +}; + +type Result = std::result::Result, Error>; + +pub fn get_payout(channel: &Channel, event: &Event, session: &Session) -> Result { + let event_type = event.to_string(); -pub fn get_payout(channel: &Channel, event: &Event, session: &Session) -> BigNum { match event { - Event::Impression { publisher, .. } | Event::Click { publisher, .. } => { - let (min, max) = price_bounds(&channel, &event); + Event::Impression { + publisher, + ad_unit, + ad_slot, + .. + } + | Event::Click { + publisher, + ad_unit, + ad_slot, + .. + } => { + /* + const targetingRules = channel.targetingRules || channel.spec.targetingRules || [] + const eventType = ev.type.toUpperCase() + const [minPrice, maxPrice] = getPricingBounds(channel, eventType) + if (targetingRules.length === 0) return [balancesKey, minPrice] + + const adUnit = + Array.isArray(channel.spec.adUnits) && channel.spec.adUnits.find(u => u.ipfs === ev.adUnit) + const targetingInputBase = {*/ + let targeting_rules = if !channel.targeting_rules.is_empty() { + channel.targeting_rules.clone() + } else { + channel.spec.targeting_rules.clone() + }; - if !channel.spec.price_multiplication_rules.is_empty() { - payout( - &channel.spec.price_multiplication_rules, - &event, - &session, - max, - min, - &publisher, - ) + let pricing = get_pricing_bounds(&channel, &event_type); + + if targeting_rules.is_empty() { + Ok(Some((*publisher, pricing.min))) } else { - min + let ad_unit = ad_unit + .as_ref() + .and_then(|ipfs| channel.spec.ad_units.iter().find(|u| &u.ipfs == ipfs)); + + let input = Input { + ad_view: None, + global: Global { + // TODO: Check this one! + ad_slot_id: ad_slot.clone().unwrap_or_default(), + // TODO: Check this one! + ad_slot_type: ad_unit.map(|u| u.ad_type.clone()).unwrap_or_default(), + publisher_id: *publisher, + country: session.country.clone(), + event_type: event_type.clone(), + // **seconds** means calling `timestamp()` + seconds_since_epoch: u64::try_from(Utc::now().timestamp()).expect( + "The timestamp (i64) should not overflow or underflow the u64!", + ), + user_agent_os: session.os.clone(), + user_agent_browser_family: None, + // TODO: Check this one! + ad_unit: ad_unit.cloned(), + channel: channel.clone(), + status: None, + balances: None, + }, + // TODO: Check this one as well! + ad_slot: None, + }; + + let mut output = Output { + show: true, + boost: 1.0, + price: vec![(event_type.clone(), pricing.min.clone())] + .into_iter() + .collect(), + }; + + eval_multiple(&targeting_rules, &input, &mut output); + + if output.show { + let price = match output.price.get(&event_type) { + Some(output_price) => { + max(pricing.min, min(pricing.max, output_price.clone())) + } + None => max(pricing.min, pricing.max), + }; + + Ok(Some((*publisher, price))) + } else { + Ok(None) + } } } - _ => Default::default(), + _ => Ok(None), } } -fn payout( - rules: &[PriceMultiplicationRules], - event: &Event, - session: &Session, - max_price: BigNum, - min_price: BigNum, - publisher: &ValidatorId, -) -> BigNum { - let fixed_amount_rule = rules.iter().find_map(|rule| { - match (match_rule(rule, &event, &session, &publisher), &rule.amount) { - (true, Some(amount)) => Some(amount.clone()), - _ => None, +// @TODO: Logging & move to Targeting when ready +fn eval_multiple(rules: &[Rule], input: &Input, output: &mut Output) { + for rule in rules { + match rule.eval(input, output) { + Ok(_) => {} + Err(EvalError::UnknownVariable) => {} + Err(EvalError::TypeError) => todo!("OnTypeErr logging"), } - }); - let price_by_rules = match fixed_amount_rule { - Some(amount) => amount, - None => { - let exponent: f64 = 10.0; - // @TODO: Know-issue - `multiplier` and `value` can overflow, should return Error instead - let multiplier: f64 = rules.iter().filter_map(|rule| rule.multiplier).product(); - let value: u64 = (multiplier * exponent.powi(18)) as u64; - let result = min_price * BigNum::from(value); - - result / BigNum::from(10u64.pow(18)) + if !output.show { + return; } - }; - - max_price.min(price_by_rules) -} - -fn match_rule( - rule: &PriceMultiplicationRules, - ev_type: &Event, - session: &Session, - uid: &ValidatorId, -) -> bool { - let ev_type = match &rule.ev_type { - Some(event_types) => event_types.contains(&ev_type.to_string()), - _ => true, - }; - - let publisher = match &rule.publisher { - Some(publishers) => publishers.contains(&uid), - _ => true, - }; - - let os_type = match (&rule.os_type, &session.os) { - (Some(oses), Some(os)) => oses.contains(&os), - (Some(_), None) => false, - _ => true, - }; - - let country = match (&rule.country, &session.country) { - (Some(countries), Some(country)) => countries.contains(&country), - (Some(_), None) => false, - _ => true, - }; - - ev_type && publisher && os_type && country -} - -fn price_bounds(channel: &Channel, event: &Event) -> (BigNum, BigNum) { - let pricing_bounds = channel.spec.pricing_bounds.as_ref(); - match (event, pricing_bounds) { - (Event::Impression { .. }, Some(pricing_bounds)) => { - match pricing_bounds.impression.as_ref() { - Some(pricing) => (pricing.min.clone(), pricing.max.clone()), - _ => ( - channel.spec.min_per_impression.clone(), - channel.spec.max_per_impression.clone(), - ), - } - } - (Event::Impression { .. }, None) => ( - channel.spec.min_per_impression.clone(), - channel.spec.max_per_impression.clone(), - ), - (Event::Click { .. }, Some(pricing_bounds)) => match pricing_bounds.click.as_ref() { - Some(pricing) => (pricing.min.clone(), pricing.max.clone()), - _ => (Default::default(), Default::default()), - }, - _ => (Default::default(), Default::default()), } } -#[cfg(test)] -mod tests { - use super::*; - use primitives::channel::{Pricing, PricingBounds}; - use primitives::util::tests::prep_db::{DUMMY_CHANNEL, IDS}; - - #[test] - fn test_plain_events() { - let mut channel: Channel = DUMMY_CHANNEL.clone(); - channel.spec.pricing_bounds = Some(PricingBounds { - click: Some(Pricing { - min: BigNum::from(23), - max: BigNum::from(100), - }), - impression: None, - }); - - let cases: Vec<(Event, BigNum, String)> = vec![ - ( - Event::Impression { - publisher: IDS["publisher"], - ad_slot: None, - ad_unit: None, - referrer: None, - }, - BigNum::from(1), - "pricingBounds: impression event".to_string(), - ), - ( - Event::Click { - publisher: IDS["publisher"], - ad_slot: None, - ad_unit: None, - referrer: None, - }, - BigNum::from(23), - "pricingBounds: click event".to_string(), - ), - ( - Event::Close {}, - BigNum::from(0), - "pricingBounds: close event".to_string(), - ), - ]; - - let session = Session { - ip: None, - country: None, - referrer_header: None, - os: None, - }; - - cases.iter().for_each(|case| { - let (event, expected_result, message) = case; - let payout = get_payout(&channel, &event, &session); - assert!(&payout == expected_result, message.clone()); - }) - } - - #[test] - fn test_fixed_amount_price_rule_event() { - let mut channel: Channel = DUMMY_CHANNEL.clone(); - channel.spec.pricing_bounds = Some(PricingBounds { - click: Some(Pricing { - min: BigNum::from(23), - max: BigNum::from(100), - }), - impression: None, - }); - channel.spec.price_multiplication_rules = vec![PriceMultiplicationRules { - multiplier: None, - amount: Some(BigNum::from(10)), - os_type: None, - ev_type: Some(vec!["CLICK".to_string()]), - publisher: None, - country: Some(vec!["us".to_string()]), - }]; - - let cases: Vec<(Event, BigNum, String)> = vec![ - ( - Event::Impression { - publisher: IDS["publisher"], - ad_slot: None, - ad_unit: None, - referrer: None, - }, - BigNum::from(1), - "fixedAmount: impression".to_string(), - ), - ( - Event::Click { - publisher: IDS["publisher"], - ad_slot: None, - ad_unit: None, - referrer: None, - }, - BigNum::from(10), - "fixedAmount (country, publisher): click".to_string(), - ), - ]; - - let session = Session { - ip: None, - country: Some("us".to_string()), - referrer_header: None, - os: None, - }; - - cases.iter().for_each(|(event, expected_result, message)| { - println!("payout {}", expected_result.to_string()); - let payout = get_payout(&channel, &event, &session); - println!("payout {}", payout.to_string()); - assert!(&payout == expected_result, message.clone()); - }) - } - - #[test] - fn test_fixed_amount_exceed_rule_event() { - let mut channel: Channel = DUMMY_CHANNEL.clone(); - channel.spec.pricing_bounds = Some(PricingBounds { - click: Some(Pricing { - min: BigNum::from(23), - max: BigNum::from(100), - }), - impression: None, - }); - channel.spec.price_multiplication_rules = vec![PriceMultiplicationRules { - multiplier: None, - amount: Some(BigNum::from(1000)), - os_type: None, - ev_type: None, - publisher: None, - country: None, - }]; - - let cases: Vec<(Event, BigNum, String)> = vec![ - ( - Event::Impression { - publisher: IDS["publisher"], - ad_slot: None, - ad_unit: None, - referrer: None, - }, - BigNum::from(10), - "fixedAmount (all): price should not exceed maxPerImpressionPrice".to_string(), - ), - ( - Event::Click { - publisher: IDS["publisher"], - ad_slot: None, - ad_unit: None, - referrer: None, - }, - BigNum::from(100), - "fixedAmount (all): price should not exceed event pricingBound max".to_string(), - ), - ]; - - let session = Session { - ip: None, - country: Some("us".to_string()), - referrer_header: None, - os: None, - }; - - cases.iter().for_each(|case| { - let (event, expected_result, message) = case; - let payout = get_payout(&channel, &event, &session); - assert!(&payout == expected_result, message.clone()); - }) - } - - #[test] - fn test_pick_first_fixed_amount_rule_event() { - let mut channel: Channel = DUMMY_CHANNEL.clone(); - channel.spec.pricing_bounds = Some(PricingBounds { - click: Some(Pricing { - min: BigNum::from(23), - max: BigNum::from(100), - }), - impression: None, - }); - channel.spec.price_multiplication_rules = vec![ - PriceMultiplicationRules { - multiplier: None, - amount: Some(BigNum::from(10)), - os_type: None, - ev_type: Some(vec!["CLICK".to_string()]), - publisher: None, - country: Some(vec!["us".to_string()]), - }, - PriceMultiplicationRules { - multiplier: None, - amount: Some(BigNum::from(12)), - os_type: None, - ev_type: Some(vec!["CLICK".to_string()]), - publisher: Some(vec![IDS["publisher"]]), - country: Some(vec!["us".to_string()]), - }, - ]; - - let session = Session { - ip: None, - country: Some("us".to_string()), - referrer_header: None, - os: None, - }; - - let event = Event::Click { - publisher: IDS["publisher"], - ad_slot: None, - ad_unit: None, - referrer: None, - }; - - let payout = get_payout(&channel, &event, &session); - assert!( - payout == BigNum::from(10), - "fixedAmount (country, pulisher): should choose first fixedAmount rule" - ); - } - - #[test] - fn test_pick_fixed_amount_rule_over_multiplier_event() { - let mut channel: Channel = DUMMY_CHANNEL.clone(); - channel.spec.pricing_bounds = Some(PricingBounds { - click: Some(Pricing { - min: BigNum::from(23), - max: BigNum::from(100), - }), - impression: None, - }); - channel.spec.price_multiplication_rules = vec![ - PriceMultiplicationRules { - multiplier: Some(1.2), - amount: None, - os_type: Some(vec!["android".to_string()]), - ev_type: Some(vec!["CLICK".to_string()]), - publisher: Some(vec![IDS["publisher"]]), - country: Some(vec!["us".to_string()]), - }, - PriceMultiplicationRules { - multiplier: None, - amount: Some(BigNum::from(12)), - os_type: None, - ev_type: Some(vec!["CLICK".to_string()]), - publisher: Some(vec![IDS["publisher"]]), - country: Some(vec!["us".to_string()]), - }, - ]; - - let session = Session { - ip: None, - country: Some("us".to_string()), - referrer_header: None, - os: None, - }; - - let event = Event::Click { - publisher: IDS["publisher"], - ad_slot: None, - ad_unit: None, - referrer: None, - }; - - let payout = get_payout(&channel, &event, &session); - assert!( - payout == BigNum::from(12), - "fixedAmount (country, osType, publisher): choose fixedAmount rule over multiplier if present" - ); - } - - #[test] - fn test_apply_all_mutliplier_rules() { - let mut channel: Channel = DUMMY_CHANNEL.clone(); - - channel.spec.pricing_bounds = Some(PricingBounds { - click: Some(Pricing { - min: BigNum::from(100), - max: BigNum::from(1000), - }), - impression: None, - }); - channel.spec.price_multiplication_rules = vec![ - PriceMultiplicationRules { - multiplier: Some(1.2), - amount: None, - os_type: Some(vec!["android".to_string()]), - ev_type: Some(vec!["CLICK".to_string()]), - publisher: Some(vec![IDS["publisher"]]), - country: Some(vec!["us".to_string()]), - }, - PriceMultiplicationRules { - multiplier: Some(1.2), - amount: None, - os_type: None, - ev_type: None, - publisher: None, - country: None, - }, - ]; - - let session = Session { - ip: None, - country: Some("us".to_string()), - referrer_header: None, - os: None, - }; - - let event = Event::Click { - publisher: IDS["publisher"].clone(), - ad_slot: None, - ad_unit: None, - referrer: None, - }; - - let payout = get_payout(&channel, &event, &session); - assert!( - payout == BigNum::from(144), - "fixedAmount (country, osType, publisher): apply all multiplier rules" - ); - } -} +// #[cfg(test)] +// mod tests { +// use super::*; +// use primitives::channel::{Pricing, PricingBounds}; +// use primitives::util::tests::prep_db::{DUMMY_CHANNEL, IDS}; +// } From e514c09c308144022260449f717b07483dfc0eb1 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 24 Jul 2020 13:31:02 +0300 Subject: [PATCH 06/27] WIP adview-manager --- adview-manager/src/lib.rs | 598 +++++++++++++++++++++++--------------- 1 file changed, 371 insertions(+), 227 deletions(-) diff --git a/adview-manager/src/lib.rs b/adview-manager/src/lib.rs index 8013ea59b..1b68a7f63 100644 --- a/adview-manager/src/lib.rs +++ b/adview-manager/src/lib.rs @@ -1,173 +1,68 @@ #![deny(rust_2018_idioms)] #![deny(clippy::all)] -use adex_primitives::market::{Campaign, StatusType}; -use adex_primitives::{AdUnit, BigNum, ChannelId, SpecValidators, TargetingTag}; -use chrono::Utc; +use adex_primitives::{ + supermarket::units_for_slot::response::{AdUnit, Campaign, Response}, + targeting::{AdView, Input}, + BigNum, ChannelId, SpecValidators, +}; +use chrono::{DateTime, Utc}; +use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; +use std::convert::TryFrom; pub type TargetingScore = f64; pub type MinTargetingScore = TargetingScore; const IPFS_GATEWAY: &str = "https://ipfs.moonicorn.network/ipfs/"; +// How much time to wait before sending out an impression event +// Related: https://github.com/AdExNetwork/adex-adview-manager/issues/17, https://github.com/AdExNetwork/adex-adview-manager/issues/35, https://github.com/AdExNetwork/adex-adview-manager/issues/46 +const WAIT_FOR_IMPRESSION: u32 = 8000; +// The number of impressions (won auctions) kept in history +const HISTORY_LIMIT: u32 = 50; + +lazy_static! { +// Impression "stickiness" time: see https://github.com/AdExNetwork/adex-adview-manager/issues/65 +// 4 minutes allows ~4 campaigns to rotate, considering a default frequency cap of 15 minutes + pub static ref IMPRESSION_STICKINESS_TIME: chrono::Duration = chrono::Duration::milliseconds(240000); +} + #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct AdViewManagerOptions { +// const defaultOpts = { +// marketURL: 'https://market.moonicorn.network', +// whitelistedTokens: ['0x6B175474E89094C44Da98b954EedeAC495271d0F'], +// disableVideo: false, +// } +pub struct Options { // Defaulted via defaultOpts #[serde(rename = "marketURL")] pub market_url: String, - /// Defaulted - pub accepted_states: Vec, - /// Defaulted - pub min_per_impression: BigNum, - /// Defaulted - pub min_targeting_score: MinTargetingScore, - /// Defaulted - pub randomize: bool, + pub market_slot: String, pub publisher_addr: String, - pub whitelisted_token: String, - pub whitelisted_type: Option, - /// Defaulted - pub top_by_price: usize, - /// Defaulted - pub top_by_score: usize, - #[serde(default)] - pub targeting: Vec, + // All passed tokens must be of the same price and decimals, so that the amounts can be accurately compared + pub whitelisted_tokens: Vec, pub width: Option, pub height: Option, - pub fallback_unit: Option, + pub navigator_language: Option, /// Defaulted pub disabled_video: bool, + pub disabled_sticky: bool, } -impl AdViewManagerOptions { +impl Options { pub fn size(&self) -> Option<(u64, u64)> { self.width .and_then(|width| self.height.map(|height| (width, height))) } } -#[derive(Debug)] -pub struct UnitByPrice { - pub unit: AdUnit, - pub channel_id: ChannelId, - pub validators: SpecValidators, - pub min_targeting_score: MinTargetingScore, - pub min_per_impression: BigNum, -} - -#[derive(Debug)] -pub struct Unit { - pub unit: AdUnit, - pub channel_id: ChannelId, - pub validators: SpecValidators, - pub min_targeting_score: MinTargetingScore, - pub min_per_impression: BigNum, - pub targeting_score: TargetingScore, -} - -impl Unit { - pub fn new(by_price: UnitByPrice, targeting_score: TargetingScore) -> Self { - Self { - unit: by_price.unit, - channel_id: by_price.channel_id, - validators: by_price.validators, - min_targeting_score: by_price.min_targeting_score, - min_per_impression: by_price.min_per_impression, - targeting_score, - } - } -} - -pub fn apply_selection(campaigns: &[Campaign], options: &AdViewManagerOptions) -> Vec { - let eligible = campaigns.iter().filter(|campaign| { - options - .accepted_states - .contains(&campaign.status.status_type) - && campaign - .channel - .spec - .active_from - .map(|datetime| datetime < Utc::now()) - .unwrap_or(true) - && campaign.channel.deposit_asset == options.whitelisted_token - && campaign.channel.spec.min_per_impression >= options.min_per_impression - }); - - let mut units: Vec = eligible - // filter ad_units by whitelisted type, map then to UnitByPrice and flat_map them for each campaing - .flat_map(|campaign| { - campaign - .channel - .spec - .ad_units - .iter() - .filter(|unit| { - options - .whitelisted_type - .as_ref() - .map(|whitelisted_type| { - whitelisted_type != &unit.ad_type - && !(options.disabled_video && is_video(&unit)) - }) - .unwrap_or(false) - }) - .map(move |ad_unit| UnitByPrice { - unit: ad_unit.clone(), - channel_id: campaign.channel.id, - validators: campaign.channel.spec.validators.clone(), - min_targeting_score: ad_unit - .min_targeting_score - .or(campaign.channel.spec.min_targeting_score) - .unwrap_or_else(|| 0.into()), - min_per_impression: campaign.channel.spec.min_per_impression.clone(), - }) - }) - .collect(); - - // Sort - units.sort_by(|b, a| a.min_per_impression.cmp(&b.min_per_impression)); - // Top units - units.truncate(options.top_by_price); - - let mut by_score: Vec = units - .into_iter() - .filter_map(|by_price| { - let targeting_score = - calculate_target_score(&by_price.unit.targeting, &options.targeting); - if targeting_score >= options.min_targeting_score - && targeting_score >= by_price.min_targeting_score - { - Some(Unit::new(by_price, targeting_score)) - } else { - None - } - }) - .collect(); - by_score.sort_by(|a, b| { - a.targeting_score - .partial_cmp(&b.targeting_score) - .expect("Should always be comparable") - }); - by_score.truncate(options.top_by_score); - - by_score -} - -fn is_video(ad_unit: &AdUnit) -> bool { - ad_unit.media_mime.split('/').next() == Some("video") -} - -fn calculate_target_score(a: &[TargetingTag], b: &[TargetingTag]) -> TargetingScore { - a.iter() - .map(|x| -> TargetingScore { - match b.iter().find(|y| y.tag == x.tag) { - Some(b) => (&x.score * &b.score).into(), - None => 0.into(), - } - }) - .sum() +pub struct HistoryEntry { + time: DateTime, + unit_id: String, + channel_id: ChannelId, + slot_id: String, } #[derive(Serialize)] @@ -177,6 +72,9 @@ struct Event { event_type: String, publisher: String, ad_unit: String, + ad_slot: String, + #[serde(rename = "ref")] + referrer: String, } #[derive(Serialize)] @@ -184,20 +82,6 @@ struct EventBody { events: Vec, } -fn image_html( - event_body: &str, - on_load: &str, - size: &Option<(u64, u64)>, - image_url: &str, -) -> String { - let size = size - .map(|(width, height)| format!("width=\"{}\" height=\"{}\"", width, height)) - .unwrap_or_else(|| "".to_string()); - - format!("\"AdEx", - image_url = image_url, event_body = event_body, on_load = on_load, size = size) -} - fn normalize_url(url: &str) -> String { if url.starts_with("ipfs://") { url.replacen("ipfs://", IPFS_GATEWAY, 1) @@ -206,8 +90,16 @@ fn normalize_url(url: &str) -> String { } } +fn image_html(on_load: &str, size: &Option<(u64, u64)>, image_url: &str) -> String { + let size = size + .map(|(width, height)| format!("width=\"{}\" height=\"{}\"", width, height)) + .unwrap_or_else(|| "".to_string()); + + format!("\"AdEx", + image_url = image_url, on_load = on_load, size = size) +} + fn video_html( - event_body: &str, on_load: &str, size: &Option<(u64, u64)>, image_url: &str, @@ -217,106 +109,358 @@ fn video_html( .map(|(width, height)| format!("width=\"{}\" height=\"{}\"", width, height)) .unwrap_or_else(|| "".to_string()); - format!("", size = size, event_body = event_body, on_load = on_load, image_url = image_url, media_mime = media_mime) + format!( + "", + size = size, + on_load = on_load, + image_url = image_url, + media_mime = media_mime + ) +} + +fn adex_icon() -> &'static str { + r#" + + + + + + + + "# +} + +fn is_video(ad_unit: &AdUnit) -> bool { + ad_unit.media_mime.split('/').next() == Some("video") +} + +// @TODO: IMPL +// function randomizedSortPos(unit: Unit, seed: BN): BN { +// // using base32 is technically wrong (IDs are in base 58), but it works well enough for this purpose +// // kind of a LCG PRNG but without the state; using GCC's constraints as seen on stack overflow +// // takes around ~700ms for 100k iterations, yields very decent distribution (e.g. 724ms 50070, 728ms 49936) +// return new BN(unit.id, 32).mul(seed).add(new BN(12345)).mod(new BN(0x80000000)) +// } +fn randomized_sort_pos(_ad_unit: AdUnit, _seed: BigNum) -> BigNum { + todo!("Implement the randomized_sort_pos() function!") +} + +fn get_unit_html( + size: &Option<(u64, u64)>, + ad_unit: &AdUnit, + hostname: &str, + on_load: &str, + on_click: &str, +) -> String { + let image_url = normalize_url(&ad_unit.media_url); + + let element_html = if is_video(&ad_unit) { + video_html(on_load, size, &image_url, &ad_unit.media_mime) + } else { + image_html(on_load, size, &image_url) + }; + + // @TODO click protection page + let final_target_url = ad_unit.target_url.replace( + "utm_source=adex_PUBHOSTNAME", + &format!("utm_source=AdEx+({hostname})", hostname = hostname), + ); + + let max_min_size = match size { + Some((width, height)) => { + format!( + "max-width: {}px; min-width: {min_width}px; height: {}px;", + width, + height, + // u64 / 2 will floor the result! + min_width = width / 2 + ) + } + None => String::new(), + }; + + format!("
+ + {element_html} + + {adex_icon} +
", style=max_min_size, adex_icon=adex_icon(), final_target_url=final_target_url, on_click = on_click, element_html=element_html) } -pub fn get_html( - options: &AdViewManagerOptions, - ad_unit: AdUnit, +pub fn get_unit_html_with_events( + options: &Options, + ad_unit: &AdUnit, + hostname: &str, channel_id: ChannelId, validators: &SpecValidators, + no_impression: impl Into, ) -> String { - let ev_body = EventBody { + let get_body = |event_type: &str| EventBody { events: vec![Event { - event_type: "IMPRESSION".into(), + event_type: event_type.to_string(), publisher: options.publisher_addr.clone(), - ad_unit: ad_unit.ipfs.clone(), + ad_unit: ad_unit.id.clone(), + ad_slot: options.market_slot.clone(), + referrer: "document.referrer".to_string(), }], }; - let on_load: String = validators.iter().map(|validator| { - let fetch_opts = "{ method: 'POST', headers: { 'content-type': 'application/json' }, body: this.dataset.eventBody }"; - let fetch_url = format!("{}/channel/{}/events", validator.url, channel_id); + let get_fetch_code = |event_type: &str| -> String { + let body = serde_json::to_string(&get_body(event_type)) + .expect("It should always serialize EventBody"); - format!("fetch({}, {});", fetch_url, fetch_opts) - }).collect(); + let fetch_opts = format!("var fetchOpts = {{ method: 'POST', headers: {{ 'content-type': 'application/json' }}, body: {} }};", body); - let ev_body = serde_json::to_string(&ev_body).expect("should convert"); + let validators: String = validators + .iter() + .map(|validator| { + let fetch_url = format!( + "{}/channel/{}/events?pubAddr={}", + validator.url, channel_id, options.publisher_addr + ); - get_unit_html(&options.size(), ad_unit, &ev_body, &on_load) -} + format!("fetch('{}', fetchOpts)", fetch_url) + }) + .collect::>() + .join(";"); -fn get_unit_html( - size: &Option<(u64, u64)>, - ad_unit: AdUnit, - event_body: &str, - on_load: &str, -) -> String { - let image_url = normalize_url(&ad_unit.media_url); + format!("{}{}", fetch_opts, validators) + }; + let get_timeout_code = |event_type: &str| -> String { + format!( + "setTimeout(function() {{ {code} }}, {timeout})", + code = get_fetch_code(event_type), + timeout = WAIT_FOR_IMPRESSION + ) + }; - let element_html = if is_video(&ad_unit) { - video_html(event_body, on_load, size, &image_url, &ad_unit.media_mime) + let on_load = if no_impression.into() { + String::new() } else { - image_html(event_body, on_load, size, &image_url) + get_timeout_code("IMPRESSION") }; - let style_size = size - .map(|(width, height)| format!("width: {}; height: {};", width, height)) - .unwrap_or_else(|| "".to_string()); + get_unit_html( + &options.size(), + ad_unit, + hostname, + &on_load, + &get_fetch_code("CLICK"), + ) +} - let adex_icon = " - - - - - - - - "; - - let result = format!(" -
- {element_html} - {adex_icon} -
- ", target_url = ad_unit.target_url, size = style_size, element_html = element_html, adex_icon = adex_icon); - - result +pub struct Manager { + options: Options, + history: Vec, +} + +impl Manager { + pub fn new(options: Options, history: Vec) -> Self { + Self { options, history } + } + + pub fn get_targeting_input(&self, mut input: Input, channel_id: ChannelId) -> Input { + let seconds_since_campaign_impression = self + .history + .iter() + .rev() + .find_map(|h| { + if h.channel_id == channel_id { + let last_impression: chrono::Duration = Utc::now() - h.time; + + u64::try_from(last_impression.num_seconds()).ok() + } else { + None + } + }) + .unwrap_or(u64::MAX); + + input.ad_view = Some(AdView { + seconds_since_campaign_impression, + has_custom_preferences: false, + // TODO: Check this empty default! + navigator_language: self.options.navigator_language.clone().unwrap_or_default(), + }); + + input + } + + pub fn get_sticky_ad_unit( + &self, + campaigns: Vec, + hostname: &str, + ) -> Option { + if self.options.disabled_sticky { + return None; + } + + let stickiness_threshold = Utc::now() - *IMPRESSION_STICKINESS_TIME; + let sticky_entry = self + .history + .iter() + .find(|h| h.time > stickiness_threshold && h.slot_id == self.options.market_slot)?; + + let stick_campaign = campaigns + .iter() + .find(|c| c.channel.id == sticky_entry.channel_id)?; + + let unit = stick_campaign + .units_with_price + .iter() + .find_map(|u| { + if u.unit.id == sticky_entry.unit_id { + Some(u.unit.clone()) + } else { + None + } + }) + .expect("Something went terribly wrong. Data is corrupted! There should be an AdUnit"); + + let html = get_unit_html_with_events( + &self.options, + &unit, + hostname, + stick_campaign.channel.id, + &stick_campaign.channel.spec.validators, + true, + ); + + Some(StickyAdUnit { + unit, + price: 0.into(), + html, + is_sticky: true, + }) + } + + // private isCampaignSticky(campaign: any): boolean { + // if (this.options.disableSticky) return false + // const stickinessThreshold = Date.now() - IMPRESSION_STICKINESS_TIME + // return !!this.history.find(entry => entry.time > stickinessThreshold && entry.campaignId === campaign.id) + // } + fn is_campaign_sticky(channel_id: ChannelId) -> bool { + // let stickiness_threshold = Utc::now() - *IMPRESSION_STICKINESS_TIME; + todo!() + } + + // async getMarketDemandResp(): Promise { + // const marketURL = this.options.marketURL + // const depositAsset = this.options.whitelistedTokens.map(tokenAddr => `&depositAsset=${tokenAddr}`).join('') + // // @NOTE not the same as the WAF generator script in the Market (which uses `.slice(2, 12)`) + // const pubPrefix = this.options.publisherAddr.slice(2, 10) + // const url = `${marketURL}/units-for-slot/${this.options.marketSlot}?pubPrefix=${pubPrefix}${depositAsset}` + // const r = await this.fetch(url) + // if (r.status !== 200) throw new Error(`market returned status code ${r.status} at ${url}`) + // return r.json() + // } + pub async fn get_market_demand_resp() { + todo!() + } + + // async getNextAdUnit(): Promise { + // const { campaigns, targetingInputBase, acceptedReferrers, fallbackUnit } = await this.getMarketDemandResp() + // const hostname = targetingInputBase['adSlot.hostname'] + + // // Stickiness is when we keep showing an ad unit for a slot for some time in order to achieve fair impression value + // // see https://github.com/AdExNetwork/adex-adview-manager/issues/65 + // const stickyResult = this.getStickyAdUnit(campaigns, hostname) + // if (stickyResult) return { ...stickyResult, acceptedReferrers } + + // // If two or more units result in the same price, apply random selection between them: this is why we need the seed + // const seed = new BN(Math.random() * (0x80000000 - 1)) + + // // Apply targeting, now with adView.* variables, and sort the resulting ad units + // const unitsWithPrice = campaigns + // .map(campaign => { + // if (this.isCampaignSticky(campaign)) return [] + + // const campaignInputBase = this.getTargetingInput(targetingInputBase, campaign) + // const campaignInput = targetingInputGetter.bind(null, campaignInputBase, campaign) + // const onTypeErr = (e, rule) => console.error(`WARNING: rule for ${campaign.id} failing with:`, rule, e) + // return campaign.unitsWithPrice.filter(({ unit, price }) => { + // const input = campaignInput.bind(null, unit) + // const output = { + // show: true, + // 'price.IMPRESSION': new BN(price), + // } + // // NOTE: not using the price from the output on purpose + // // we trust what the server gives us since otherwise we may end up changing the price based on + // // adView-specific variables, which won't be consistent with the validator's price + // return evaluateMultiple(input, output, campaign.targetingRules, onTypeErr).show + // }).map(x => ({ ...x, campaignId: campaign.id })) + // }) + // .reduce((a, b) => a.concat(b), []) + // .filter(x => !(this.options.disableVideo && isVideo(x.unit))) + // .sort((b, a) => + // new BN(a.price).cmp(new BN(b.price)) + // || randomizedSortPos(a.unit, seed).cmp(randomizedSortPos(b.unit, seed)) + // ) + + // // Update history + // const auctionWinner = unitsWithPrice[0] + // if (auctionWinner) { + // this.history.push({ + // time: Date.now(), + // slotId: this.options.marketSlot, + // unitId: auctionWinner.unit.id, + // campaignId: auctionWinner.campaignId, + // }) + // this.history = this.history.slice(-HISTORY_LIMIT) + // } + + // // Return the results, with a fallback unit if there is one + // if (auctionWinner) { + // const { unit, price, campaignId } = auctionWinner + // const { validators } = campaigns.find(x => x.id === campaignId).spec + // return { + // unit, + // price, + // acceptedReferrers, + // html: getUnitHTMLWithEvents(this.options, { unit, hostname, campaignId, validators }) + // } + // } else if (fallbackUnit) { + // const unit = fallbackUnit + // return { + // unit, + // price: '0', + // acceptedReferrers, + // html: getUnitHTML(this.options, { unit, hostname }) + // } + // } else { + // return null + // } + // } + pub async fn get_next_ad_unit() -> Option { + todo!() + } +} + +pub struct StickyAdUnit { + pub unit: AdUnit, + pub price: BigNum, + pub html: String, + pub is_sticky: bool, } #[cfg(test)] mod test { use super::*; - use adex_primitives::ValidatorId; - use std::convert::TryFrom; fn get_ad_unit(media_mime: &str) -> AdUnit { - let owner = ValidatorId::try_from("0xce07CbB7e054514D590a0262C93070D838bFBA2e") - .expect("Should be valid ValidatorId string"); AdUnit { - ipfs: "".to_string(), - ad_type: "".to_string(), + id: "".to_string(), media_url: "".to_string(), media_mime: media_mime.to_string(), target_url: "".to_string(), - targeting: vec![], - min_targeting_score: None, - tags: vec![], - owner, - created: Utc::now(), - title: None, - description: None, - archived: false, - modified: None, } } From 9a245a12ae2838b0b17666da8d2f68c84daa37ea Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 30 Jul 2020 11:53:37 +0300 Subject: [PATCH 07/27] Input Source & Map --- adview-manager/src/lib.rs | 4 +- primitives/src/supermarket.rs | 5 +- primitives/src/targeting.rs | 86 ++++++++++++++++++++++++++++++-- primitives/src/targeting/eval.rs | 4 +- 4 files changed, 89 insertions(+), 10 deletions(-) diff --git a/adview-manager/src/lib.rs b/adview-manager/src/lib.rs index 1b68a7f63..455399a89 100644 --- a/adview-manager/src/lib.rs +++ b/adview-manager/src/lib.rs @@ -3,7 +3,7 @@ use adex_primitives::{ supermarket::units_for_slot::response::{AdUnit, Campaign, Response}, - targeting::{AdView, Input}, + targeting::{AdView, InputSource}, BigNum, ChannelId, SpecValidators, }; use chrono::{DateTime, Utc}; @@ -268,7 +268,7 @@ impl Manager { Self { options, history } } - pub fn get_targeting_input(&self, mut input: Input, channel_id: ChannelId) -> Input { + pub fn get_targeting_input(&self, mut input: InputSource, channel_id: ChannelId) -> InputSource { let seconds_since_campaign_impression = self .history .iter() diff --git a/primitives/src/supermarket.rs b/primitives/src/supermarket.rs index a794093fb..c4572894d 100644 --- a/primitives/src/supermarket.rs +++ b/primitives/src/supermarket.rs @@ -42,7 +42,7 @@ pub enum Finalized { pub mod units_for_slot { pub mod response { - use crate::{targeting::Rule, BigNum, ChannelId, ChannelSpec, SpecValidators, ValidatorId}; + use crate::{targeting::{Input, Rule, InputMap}, BigNum, ChannelId, ChannelSpec, SpecValidators, ValidatorId}; use chrono::{ serde::{ts_milliseconds, ts_milliseconds_option}, DateTime, Utc, @@ -53,8 +53,7 @@ pub mod units_for_slot { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Response { - // TODO: This should be Input, however, we only need the fields and not the Global: Channel, Status & BalancesMap - pub targeting_input_base: (), + pub targeting_input_base: InputMap, pub accepted_referrers: Vec, pub fallback_unit: AdUnit, pub campaigns: Vec, diff --git a/primitives/src/targeting.rs b/primitives/src/targeting.rs index ef13f7de9..0828a360f 100644 --- a/primitives/src/targeting.rs +++ b/primitives/src/targeting.rs @@ -7,11 +7,40 @@ use std::collections::HashMap; pub use eval::*; use serde_json::Number; +use serde::{Serialize}; mod eval; -#[derive(Debug, Clone)] -pub struct Input { +pub type InputMap = HashMap; + +#[derive(Debug)] +pub enum Input { + Map { + inner: InputMap, + deposit_asset: String, + }, + InputSource(InputSource), +} + +impl Input { + pub fn get(&self, key: &str) -> Result { + match self { + Input::Map{inner, ..} => inner.get(key).ok_or(Error::UnknownVariable).map(Clone::clone), + Input::InputSource(input) => input.try_get(key) + } + } + + pub fn deposit_asset(&self) -> Value { + match self { + Input::Map{deposit_asset, ..} => Value::new_string(deposit_asset), + Input::InputSource(input) => Value::new_string(&input.global.channel.deposit_asset) + } + } +} + +#[derive(Debug, Clone, Serialize)] +#[serde(into = "InputMap")] +pub struct InputSource { /// AdView scope, accessible only on the AdView pub ad_view: Option, /// Global scope, accessible everywhere @@ -20,7 +49,57 @@ pub struct Input { pub ad_slot: Option, } -impl Input { +impl From for InputMap { + fn from(input: Input) -> Self { + let mut map = Self::new(); + + let fields = [ + // AdView scope, accessible only on the AdView + "adView.secondsSinceCampaignImpression", + "adView.hasCustomPreferences", + "adView.navigatorLanguage", + // Global scope, accessible everywhere + "adSlotId", + "adSlotType", + "publisherId", + "country", + "eventType", + "secondsSinceEpoch", + "userAgentOS", + "userAgentBrowserFamily", + // Global scope, accessible everywhere, campaign-dependant + "adUnitId", + "advertiserId", + "campaignId", + "campaignTotalSpent", + "campaignSecondsActive", + "campaignSecondsDuration", + "campaignBudget", + "eventMinPrice", + "eventMaxPrice", + "publisherEarnedFromCampaign", + // adSlot scope, accessible on Supermarket and AdView + "adSlot.categories", + "adSlot.hostname", + "adSlot.alexaRank", + ]; + + for field in fields.iter() { + match input.try_get(field) { + Ok(value) => { + // we don't care if there is an old value, there shouldn't be one! + map.insert(field.to_string(), value); + }, + // if there is an Error, it will be `UnknownVariable` and we just skip it + Err(_) => {}, + } + } + + map + } +} + +impl InputSource { fn try_get(&self, key: &str) -> Result { let spec = &self.global.channel.spec; @@ -107,6 +186,7 @@ impl Input { Ok(Value::Number(seconds.into())) } + "depositAsset" => Ok(Value::new_string(&self.global.channel.deposit_asset)), "campaignBudget" => Ok(Value::BigNum(self.global.channel.deposit_amount.clone())), "eventMinPrice" => { let min = get_pricing_bounds(&self.global.channel, &self.global.event_type).min; diff --git a/primitives/src/targeting/eval.rs b/primitives/src/targeting/eval.rs index 25e247642..07f0e75c9 100644 --- a/primitives/src/targeting/eval.rs +++ b/primitives/src/targeting/eval.rs @@ -893,10 +893,10 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result .eval(input, output)? .ok_or(Error::TypeError)? .try_bignum()?; - let deposit_asset = &input.global.channel.deposit_asset; + let deposit_asset = input.deposit_asset()?.try_string()?; let divisor = DEPOSIT_ASSETS_MAP - .get(deposit_asset) + .get(&deposit_asset) .ok_or(Error::TypeError)?; let amount_in_usd = amount.div(divisor).to_f64().ok_or(Error::TypeError)?; let amount_as_number = Number::from_f64(amount_in_usd).ok_or(Error::TypeError)?; From f90aaf35249e29869bc759dbfb71fd12ed8b26ca Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Mon, 3 Aug 2020 09:43:56 +0300 Subject: [PATCH 08/27] adview-manager - Cargo - add some deps --- Cargo.lock | 4 ++++ adview-manager/Cargo.toml | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 15dd3cc40..c3489f16f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,8 +34,12 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "primitives 0.1.0", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", + "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/adview-manager/Cargo.toml b/adview-manager/Cargo.toml index 9961670bd..acfb414b7 100644 --- a/adview-manager/Cargo.toml +++ b/adview-manager/Cargo.toml @@ -5,9 +5,16 @@ name = "adview-manager" version = "0.1.0" [dependencies] +# Domain adex_primitives = {path = "../primitives", package = "primitives"} chrono = "0.4" num-bigint = {version = "0.3", features = ["serde"]} +# (De)Serialization & Http requests serde = {version = "^1.0", features = ['derive']} serde_json = "^1.0" +reqwest = { version = "0.10", features = ["json"] } +url = { version = "^2.1", features = ["serde"]} +# Other lazy_static = "1.4" +thiserror = "^1.0" +rand = "0.7" From c417756912dc78a58d783a91cd3b0ff32790ec4a Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 21 Aug 2020 16:14:11 +0300 Subject: [PATCH 09/27] WIP #312 #323 #322 #319 --- Cargo.lock | 445 ++++++++------ adview-manager/Cargo.toml | 2 + adview-manager/src/lib.rs | 370 +++++++---- primitives/Cargo.toml | 2 +- primitives/src/supermarket.rs | 17 +- primitives/src/targeting.rs | 845 ++++++++++++++++---------- primitives/src/targeting/eval.rs | 26 +- primitives/src/targeting/eval_test.rs | 107 ++-- primitives/src/validator.rs | 15 +- sentry/src/payout.rs | 23 +- 10 files changed, 1148 insertions(+), 704 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3489f16f..b814478c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,7 +11,7 @@ dependencies = [ "ethabi 8.0.0 (git+https://github.com/samparsky/ethabi?branch=graph-patches)", "ethkey 0.4.0 (git+https://github.com/paritytech/parity-ethereum)", "ethstore 0.2.1 (git+https://github.com/paritytech/parity-ethereum)", - "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-crypto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -30,6 +30,7 @@ dependencies = [ name = "adview-manager" version = "0.1.0" dependencies = [ + "async-std 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -143,45 +144,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "async-std" -version = "1.5.0" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "async-task 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "async-task 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-timer 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "kv-log-macro 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smol 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-futures 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "async-task" -version = "1.3.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "async-trait" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -190,7 +185,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -211,7 +206,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -221,7 +216,7 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -266,7 +261,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "async-trait 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -277,7 +272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "async-trait 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "bb8 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-postgres 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -352,6 +347,18 @@ dependencies = [ "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "blocking" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "waker-fn 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bumpalo" version = "3.2.0" @@ -397,6 +404,11 @@ name = "bytes" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cache-padded" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cc" version = "1.0.41" @@ -452,6 +464,14 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "concurrent-queue" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cache-padded 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "const-random" version = "0.1.8" @@ -481,7 +501,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -578,9 +598,9 @@ name = "derive_more" version = "0.99.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -625,7 +645,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -772,7 +792,7 @@ dependencies = [ "dir 0.1.2 (git+https://github.com/paritytech/parity-ethereum)", "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.4.0 (git+https://github.com/paritytech/parity-ethereum)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-crypto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wordlist 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -821,6 +841,11 @@ dependencies = [ "plain_hasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fastrand" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fixed-hash" version = "0.5.2" @@ -876,30 +901,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-channel" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-core" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -913,59 +938,58 @@ dependencies = [ [[package]] name = "futures-executor" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-io" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures-macro" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-sink" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures-task" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures-timer" -version = "2.0.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "futures-util" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -998,7 +1022,7 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1026,9 +1050,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1056,7 +1080,7 @@ name = "hermit-abi" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1204,9 +1228,9 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "h2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1311,9 +1335,9 @@ name = "impl-trait-for-tuples" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1329,7 +1353,7 @@ name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1357,10 +1381,10 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.36" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wasm-bindgen 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1425,7 +1449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.68" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1500,7 +1524,7 @@ name = "memchr" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1513,7 +1537,7 @@ name = "memmap" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1600,7 +1624,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1614,7 +1638,7 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1635,7 +1659,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.28 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1652,7 +1676,7 @@ version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1759,7 +1783,7 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1790,7 +1814,7 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.54 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1806,7 +1830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1894,8 +1918,8 @@ name = "parity-util-mem-derive" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1908,6 +1932,11 @@ dependencies = [ "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "parking_lot" version = "0.9.0" @@ -1934,7 +1963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1948,7 +1977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2024,9 +2053,9 @@ name = "pin-project-internal" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2036,7 +2065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "pin-utils" -version = "0.1.0-alpha.4" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2059,7 +2088,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2073,7 +2102,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "postgres-protocol 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "postgres-shared 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2159,7 +2188,7 @@ dependencies = [ "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "fake 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "merkletree 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2190,9 +2219,9 @@ name = "proc-macro-hack" version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2210,7 +2239,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.9" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2229,7 +2258,7 @@ name = "quote" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2237,7 +2266,7 @@ name = "rand" version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2247,7 +2276,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2260,7 +2289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2271,7 +2300,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2289,7 +2318,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2363,7 +2392,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2375,7 +2404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2436,8 +2465,8 @@ dependencies = [ "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2494,13 +2523,13 @@ dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2515,8 +2544,8 @@ dependencies = [ "tokio 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-futures 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "web-sys 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)", "winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2556,7 +2585,7 @@ version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2622,6 +2651,11 @@ name = "scoped-tls" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "scopeguard" version = "0.3.3" @@ -2690,7 +2724,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2711,12 +2745,12 @@ name = "sentry" version = "0.1.0" dependencies = [ "adapter 0.1.0", - "async-std 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "async-std 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "bb8 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "bb8-postgres 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2754,9 +2788,9 @@ name = "serde_derive" version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2885,13 +2919,33 @@ name = "smallvec" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "smol" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "async-task 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "blocking 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "concurrent-queue 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fastrand 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wepoll-sys-stjepang 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "socket2" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2953,10 +3007,10 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.16" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2977,9 +3031,9 @@ name = "synstructure" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3003,7 +3057,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3040,9 +3094,9 @@ name = "thiserror-impl" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3058,7 +3112,7 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3109,10 +3163,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3203,9 +3257,9 @@ name = "tokio-macros" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3217,7 +3271,7 @@ dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3346,7 +3400,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3362,7 +3416,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3377,8 +3431,8 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3390,8 +3444,8 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3525,7 +3579,7 @@ dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3564,6 +3618,11 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "waker-fn" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "walkdir" version = "2.3.1" @@ -3600,64 +3659,64 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasm-bindgen" -version = "0.2.59" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.59" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bumpalo 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.9" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "web-sys 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.59" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.59" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.59" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -3665,8 +3724,8 @@ name = "web-sys" version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "js-sys 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3721,6 +3780,14 @@ dependencies = [ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wepoll-sys-stjepang" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" @@ -3817,8 +3884,8 @@ dependencies = [ "checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum ascii 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" -"checksum async-std 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "538ecb01eb64eecd772087e5b6f7540cbc917f047727339a472dafed2185b267" -"checksum async-task 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0ac2c016b079e771204030951c366db398864f5026f84a44dafb0ff20f02085d" +"checksum async-std 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00d68a33ebc8b57800847d00787307f84a562224a14db069b0acefe4c2abbf5d" +"checksum async-task 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c17772156ef2829aadc587461c7753af20b7e8db1529bc66855add962a3b35d3" "checksum async-trait 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "750b1c38a1dfadd108da0f01c08f4cdc7ff1bb39b325f9c82cc972361780a6e1" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" @@ -3841,6 +3908,7 @@ dependencies = [ "checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" "checksum block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529" "checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +"checksum blocking 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9d17efb70ce4421e351d61aafd90c16a20fb5bfe339fcdc32a86816280e62ce0" "checksum bumpalo 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f359dc14ff8911330a51ef78022d376f25ed00248912803b58f00cb1c27f742" "checksum byte-slice-cast 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" @@ -3849,12 +3917,14 @@ dependencies = [ "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" +"checksum cache-padded 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" "checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +"checksum concurrent-queue 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" "checksum const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" "checksum const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" @@ -3894,6 +3964,7 @@ dependencies = [ "checksum fallible-iterator 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eb7217124812dc5672b7476d0c2d20cfe9f7c0f1ba0904b674a9762a0212f72e" "checksum fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" "checksum fastmap 0.1.0 (git+https://github.com/paritytech/parity-ethereum)" = "" +"checksum fastrand 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bd3bdaaf0a72155260a1c098989b60db1cbb22d6a628e64f16237aa4da93cc7" "checksum fixed-hash 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3367952ceb191f4ab95dd5685dc163ac539e36202f9fcfd0cb22f9f9c542fefc" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" @@ -3902,17 +3973,16 @@ dependencies = [ "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" -"checksum futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" -"checksum futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" -"checksum futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" +"checksum futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" +"checksum futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" +"checksum futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" -"checksum futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" -"checksum futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" -"checksum futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" -"checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" -"checksum futures-timer 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6" -"checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" +"checksum futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" +"checksum futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" +"checksum futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" +"checksum futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" +"checksum futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" +"checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" @@ -3950,7 +4020,7 @@ dependencies = [ "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" "checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum journaldb 0.2.0 (git+https://github.com/paritytech/parity-ethereum)" = "" -"checksum js-sys 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1cb931d43e71f560c81badb0191596562bafad2be06a3f9025b845c847c60df5" +"checksum js-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "85a7e2c92a4804dd459b86c339278d0fe87cf93757fae222c3fa3ae75458bc73" "checksum jsonrpc-core 14.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fe3b688648f1ef5d5072229e2d672ecb92cbff7d1c79bcf3fd5898f3f3df0970" "checksum keccak-hasher 0.1.1 (git+https://github.com/paritytech/parity-ethereum)" = "" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" @@ -3958,7 +4028,7 @@ dependencies = [ "checksum kvdb 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03080afe6f42cd996da9f568d6add5d7fb5ee2ea7fb7802d2d2cbd836958fd87" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" +"checksum libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)" = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" "checksum libsecp256k1 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962" "checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" @@ -4007,6 +4077,7 @@ dependencies = [ "checksum parity-util-mem 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9344bc978467339b9ae688f9dcf279d1aaa0ccfc88e9a780c729b765a82d57d5" "checksum parity-util-mem-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" "checksum parity-wordlist 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f45ab1896c154f80a23f22aa81134b881e18b8fb7ff106abe67ae53a161d54a0" +"checksum parking 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6cb300f271742d4a2a66c01b6b2fa0c83dfebd2e0bf11addb879a3547b4ed87c" "checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" @@ -4021,7 +4092,7 @@ dependencies = [ "checksum pin-project 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7804a463a8d9572f13453c516a5faea534a2403d7ced2f0c7e100eeff072772c" "checksum pin-project-internal 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "385322a45f2ecf3410c68d2a549a4a2685e8051d0f278e39743ff4e451cb9b3f" "checksum pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae" -"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" +"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum plain_hasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1e19e6491bdde87c2c43d70f4c194bc8a758f2eb732df00f61e43f7362e3b4cc" "checksum positioned-io 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c405a565f48a728dbb07fa1770e30791b0fa3e6344c1e5615225ce84049354d6" @@ -4035,7 +4106,7 @@ dependencies = [ "checksum proc-macro-hack 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f918f2b601f93baa836c1c2945faef682ba5b6d4828ecb45eeb7cc3c71b811b4" "checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" @@ -4079,6 +4150,7 @@ dependencies = [ "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" "checksum schannel 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "039c25b130bd8c1321ee2d7de7fde2659fa9c2744e4bb29711cfc852ea53cd19" "checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" +"checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" "checksum scrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656c79d0e90d0ab28ac86bf3c3d10bfbbac91450d3f190113b4e76d9fec3cfdd" @@ -4108,7 +4180,8 @@ dependencies = [ "checksum slog-term 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "124501187c410b6a46fe8a47a48435ae462fae4e02d03c558d358f40b17308cb" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" -"checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" +"checksum smol 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "620cbb3c6e34da57d3a248cda0cd01cd5848164dc062e764e65d06fe3ea7aed5" +"checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" "checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" "checksum stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" "checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" @@ -4117,7 +4190,7 @@ dependencies = [ "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" +"checksum syn 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" @@ -4177,19 +4250,21 @@ dependencies = [ "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum waker-fn 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9571542c2ce85ce642e6b58b3364da2fb53526360dfb7c211add4f5c23105ff7" "checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" "checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" "checksum want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum wasm-bindgen 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)" = "3557c397ab5a8e347d434782bcd31fc1483d927a6826804cec05cc792ee2519d" -"checksum wasm-bindgen-backend 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)" = "e0da9c9a19850d3af6df1cb9574970b566d617ecfaf36eb0b706b6f3ef9bd2f8" -"checksum wasm-bindgen-futures 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "457414a91863c0ec00090dba537f88ab955d93ca6555862c29b6d860990b8a8a" -"checksum wasm-bindgen-macro 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)" = "0f6fde1d36e75a714b5fe0cffbb78978f222ea6baebb726af13c78869fdb4205" -"checksum wasm-bindgen-macro-support 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)" = "25bda4168030a6412ea8a047e27238cadf56f0e53516e1e83fec0a8b7c786f6d" -"checksum wasm-bindgen-shared 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)" = "fc9f36ad51f25b0219a3d4d13b90eb44cd075dff8b6280cca015775d7acaddd8" +"checksum wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c" +"checksum wasm-bindgen-backend 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0" +"checksum wasm-bindgen-futures 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)" = "95f8d235a77f880bcef268d379810ea6c0af2eacfa90b1ad5af731776e0c4699" +"checksum wasm-bindgen-macro 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2" +"checksum wasm-bindgen-macro-support 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556" +"checksum wasm-bindgen-shared 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092" "checksum web-sys 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)" = "721c6263e2c66fd44501cc5efbfa2b7dfa775d13e4ea38c46299646ed1f9c70a" "checksum web3 0.8.0 (git+https://github.com/samparsky/rust-web3)" = "" "checksum websocket 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c9faed2bff8af2ea6b9f8b917d3d00b467583f6781fe3def174a9e33c879703" +"checksum wepoll-sys-stjepang 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd319e971980166b53e17b1026812ad66c6b54063be879eb182342b55284694" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/adview-manager/Cargo.toml b/adview-manager/Cargo.toml index acfb414b7..379e3d277 100644 --- a/adview-manager/Cargo.toml +++ b/adview-manager/Cargo.toml @@ -14,6 +14,8 @@ serde = {version = "^1.0", features = ['derive']} serde_json = "^1.0" reqwest = { version = "0.10", features = ["json"] } url = { version = "^2.1", features = ["serde"]} +# Async +async-std = "1.6" # Other lazy_static = "1.4" thiserror = "^1.0" diff --git a/adview-manager/src/lib.rs b/adview-manager/src/lib.rs index 455399a89..bd9d21ef4 100644 --- a/adview-manager/src/lib.rs +++ b/adview-manager/src/lib.rs @@ -2,17 +2,21 @@ #![deny(clippy::all)] use adex_primitives::{ - supermarket::units_for_slot::response::{AdUnit, Campaign, Response}, - targeting::{AdView, InputSource}, + supermarket::units_for_slot, + supermarket::units_for_slot::response::{AdUnit, Campaign}, + targeting::{self, input, Value}, BigNum, ChannelId, SpecValidators, }; +use async_std::{sync::RwLock, task::block_on}; use chrono::{DateTime, Utc}; use lazy_static::lazy_static; +use rand::Rng; +use reqwest::StatusCode; use serde::{Deserialize, Serialize}; -use std::convert::TryFrom; - -pub type TargetingScore = f64; -pub type MinTargetingScore = TargetingScore; +use std::{collections::VecDeque, convert::TryFrom, sync::Arc}; +use thiserror::Error; +use units_for_slot::response::UnitsWithPrice; +use url::Url; const IPFS_GATEWAY: &str = "https://ipfs.moonicorn.network/ipfs/"; @@ -58,10 +62,11 @@ impl Options { } } +#[derive(Debug, Clone)] pub struct HistoryEntry { time: DateTime, unit_id: String, - channel_id: ChannelId, + campaign_id: ChannelId, slot_id: String, } @@ -150,8 +155,9 @@ fn is_video(ad_unit: &AdUnit) -> bool { // // takes around ~700ms for 100k iterations, yields very decent distribution (e.g. 724ms 50070, 728ms 49936) // return new BN(unit.id, 32).mul(seed).add(new BN(12345)).mod(new BN(0x80000000)) // } -fn randomized_sort_pos(_ad_unit: AdUnit, _seed: BigNum) -> BigNum { - todo!("Implement the randomized_sort_pos() function!") +fn randomized_sort_pos(_ad_unit: &AdUnit, _seed: BigNum) -> BigNum { + // todo!("Implement the randomized_sort_pos() function!") + BigNum::from(10) } fn get_unit_html( @@ -235,6 +241,7 @@ pub fn get_unit_html_with_events( format!("{}{}", fetch_opts, validators) }; + let get_timeout_code = |event_type: &str| -> String { format!( "setTimeout(function() {{ {code} }}, {timeout})", @@ -258,23 +265,46 @@ pub fn get_unit_html_with_events( ) } +#[derive(Debug, Error)] +pub enum Error { + #[error("Request to the Market failed: status {status} at url {url}")] + Market { status: StatusCode, url: String }, + #[error(transparent)] + Request(#[from] reqwest::Error), +} + pub struct Manager { options: Options, - history: Vec, + /// Contains the Entries from Old to New + /// It always trims to HISTORY_LIMIT, removing the oldest (firstly inserted) elements from the History + history: Arc>>, + client: reqwest::Client, } impl Manager { - pub fn new(options: Options, history: Vec) -> Self { - Self { options, history } + pub fn new(options: Options, history: VecDeque) -> Result { + let client = reqwest::Client::builder().build()?; + + Ok(Self { + options, + history: Arc::new(RwLock::new(history)), + client, + }) } - pub fn get_targeting_input(&self, mut input: InputSource, channel_id: ChannelId) -> InputSource { + pub async fn get_targeting_input( + &self, + mut input: input::Input, + channel_id: ChannelId, + ) -> input::Input { let seconds_since_campaign_impression = self .history + .read() + .await .iter() .rev() .find_map(|h| { - if h.channel_id == channel_id { + if h.campaign_id == channel_id { let last_impression: chrono::Duration = Utc::now() - h.time; u64::try_from(last_impression.num_seconds()).ok() @@ -284,7 +314,7 @@ impl Manager { }) .unwrap_or(u64::MAX); - input.ad_view = Some(AdView { + input.set_ad_view(input::AdView { seconds_since_campaign_impression, has_custom_preferences: false, // TODO: Check this empty default! @@ -294,9 +324,9 @@ impl Manager { input } - pub fn get_sticky_ad_unit( + pub async fn get_sticky_ad_unit( &self, - campaigns: Vec, + campaigns: &[Campaign], hostname: &str, ) -> Option { if self.options.disabled_sticky { @@ -306,12 +336,15 @@ impl Manager { let stickiness_threshold = Utc::now() - *IMPRESSION_STICKINESS_TIME; let sticky_entry = self .history + .read() + .await .iter() - .find(|h| h.time > stickiness_threshold && h.slot_id == self.options.market_slot)?; + .find(|h| h.time > stickiness_threshold && h.slot_id == self.options.market_slot) + .cloned()?; let stick_campaign = campaigns .iter() - .find(|c| c.channel.id == sticky_entry.channel_id)?; + .find(|c| c.channel.id == sticky_entry.campaign_id)?; let unit = stick_campaign .units_with_price @@ -342,108 +375,217 @@ impl Manager { }) } - // private isCampaignSticky(campaign: any): boolean { - // if (this.options.disableSticky) return false - // const stickinessThreshold = Date.now() - IMPRESSION_STICKINESS_TIME - // return !!this.history.find(entry => entry.time > stickinessThreshold && entry.campaignId === campaign.id) - // } - fn is_campaign_sticky(channel_id: ChannelId) -> bool { - // let stickiness_threshold = Utc::now() - *IMPRESSION_STICKINESS_TIME; - todo!() + async fn is_campaign_sticky(&self, campaign_id: ChannelId) -> bool { + if self.options.disabled_sticky { + false + } else { + let stickiness_threshold = Utc::now() - *IMPRESSION_STICKINESS_TIME; + + self.history + .read() + .await + .iter() + .any(|h| h.time > stickiness_threshold && h.campaign_id == campaign_id) + } } - // async getMarketDemandResp(): Promise { - // const marketURL = this.options.marketURL - // const depositAsset = this.options.whitelistedTokens.map(tokenAddr => `&depositAsset=${tokenAddr}`).join('') - // // @NOTE not the same as the WAF generator script in the Market (which uses `.slice(2, 12)`) - // const pubPrefix = this.options.publisherAddr.slice(2, 10) - // const url = `${marketURL}/units-for-slot/${this.options.marketSlot}?pubPrefix=${pubPrefix}${depositAsset}` - // const r = await this.fetch(url) - // if (r.status !== 200) throw new Error(`market returned status code ${r.status} at ${url}`) - // return r.json() - // } - pub async fn get_market_demand_resp() { - todo!() + pub async fn get_market_demand_resp( + &self, + ) -> Result { + let pub_prefix: String = self + .options + .publisher_addr + .chars() + .skip(2) + .take(10) + .collect(); + + let deposit_asset = self + .options + .whitelisted_tokens + .iter() + .map(|token| format!("depositAsset={}", token)) + .collect::>() + .join("&"); + + let url = format!( + "{}/units-for-slot/{}?pubPrefix={}&{}", + self.options.market_url, self.options.market_slot, pub_prefix, deposit_asset + ); + + let market_response = self.client.get(&url).send().await?; + + if market_response.status() != StatusCode::OK { + Err(Error::Market { + status: market_response.status(), + url, + }) + } else { + let units_for_slot_response = market_response.json().await?; + + Ok(units_for_slot_response) + } } - // async getNextAdUnit(): Promise { - // const { campaigns, targetingInputBase, acceptedReferrers, fallbackUnit } = await this.getMarketDemandResp() - // const hostname = targetingInputBase['adSlot.hostname'] - - // // Stickiness is when we keep showing an ad unit for a slot for some time in order to achieve fair impression value - // // see https://github.com/AdExNetwork/adex-adview-manager/issues/65 - // const stickyResult = this.getStickyAdUnit(campaigns, hostname) - // if (stickyResult) return { ...stickyResult, acceptedReferrers } - - // // If two or more units result in the same price, apply random selection between them: this is why we need the seed - // const seed = new BN(Math.random() * (0x80000000 - 1)) - - // // Apply targeting, now with adView.* variables, and sort the resulting ad units - // const unitsWithPrice = campaigns - // .map(campaign => { - // if (this.isCampaignSticky(campaign)) return [] - - // const campaignInputBase = this.getTargetingInput(targetingInputBase, campaign) - // const campaignInput = targetingInputGetter.bind(null, campaignInputBase, campaign) - // const onTypeErr = (e, rule) => console.error(`WARNING: rule for ${campaign.id} failing with:`, rule, e) - // return campaign.unitsWithPrice.filter(({ unit, price }) => { - // const input = campaignInput.bind(null, unit) - // const output = { - // show: true, - // 'price.IMPRESSION': new BN(price), - // } - // // NOTE: not using the price from the output on purpose - // // we trust what the server gives us since otherwise we may end up changing the price based on - // // adView-specific variables, which won't be consistent with the validator's price - // return evaluateMultiple(input, output, campaign.targetingRules, onTypeErr).show - // }).map(x => ({ ...x, campaignId: campaign.id })) - // }) - // .reduce((a, b) => a.concat(b), []) - // .filter(x => !(this.options.disableVideo && isVideo(x.unit))) - // .sort((b, a) => - // new BN(a.price).cmp(new BN(b.price)) - // || randomizedSortPos(a.unit, seed).cmp(randomizedSortPos(b.unit, seed)) - // ) - - // // Update history - // const auctionWinner = unitsWithPrice[0] - // if (auctionWinner) { - // this.history.push({ - // time: Date.now(), - // slotId: this.options.marketSlot, - // unitId: auctionWinner.unit.id, - // campaignId: auctionWinner.campaignId, - // }) - // this.history = this.history.slice(-HISTORY_LIMIT) - // } - - // // Return the results, with a fallback unit if there is one - // if (auctionWinner) { - // const { unit, price, campaignId } = auctionWinner - // const { validators } = campaigns.find(x => x.id === campaignId).spec - // return { - // unit, - // price, - // acceptedReferrers, - // html: getUnitHTMLWithEvents(this.options, { unit, hostname, campaignId, validators }) - // } - // } else if (fallbackUnit) { - // const unit = fallbackUnit - // return { - // unit, - // price: '0', - // acceptedReferrers, - // html: getUnitHTML(this.options, { unit, hostname }) - // } - // } else { - // return null - // } - // } - pub async fn get_next_ad_unit() -> Option { - todo!() + pub async fn get_next_ad_unit(&self) -> Result, Error> { + let units_for_slot = self.get_market_demand_resp().await?; + let campaigns = &units_for_slot.campaigns; + let fallback_unit = units_for_slot.fallback_unit; + let targeting_input = input::Getter { + base: units_for_slot.targeting_input_base, + ad_unit: None, + channel: None, + last_approved: None, + deposit_asset: None, + }; + + let hostname = targeting_input + .try_get("adSlot.hostname") + .and_then(Value::try_string) + .unwrap_or_default(); + + // Stickiness is when we keep showing an ad unit for a slot for some time in order to achieve fair impression value + // see https://github.com/AdExNetwork/adex-adview-manager/issues/65 + let sticky_result = self.get_sticky_ad_unit(campaigns, &hostname).await; + if let Some(sticky) = sticky_result { + return Ok(Some(NextAdUnit { + unit: sticky.unit, + price: sticky.price, + accepted_referrers: units_for_slot.accepted_referrers, + html: sticky.html, + })); + } + + // If two or more units result in the same price, apply random selection between them: this is why we need the seed + let mut rng = rand::thread_rng(); + + let random: f64 = rng.gen::() * (0x80000000_u64 as f64 - 1.0); + let seed = BigNum::from(random as u64); + + // Apply targeting, now with adView.* variables, and sort the resulting ad units + let mut units_with_price: Vec<(UnitsWithPrice, ChannelId)> = campaigns + .iter() + .map(|campaign| { + // since we are in a Iterator.map(), we can't use async, so we block + if block_on(self.is_campaign_sticky(campaign.channel.id)) { + return vec![]; + } + let mut campaign_input = targeting_input.clone(); + let campaign_id = campaign.channel.id; + campaign_input.channel = Some(campaign.channel.clone()); + + campaign + .units_with_price + .iter() + .filter(|unit_with_price| { + campaign_input.ad_unit = Some(unit_with_price.unit.clone()); + + let mut output = targeting::Output { + show: true, + boost: 1.0, + price: vec![("IMPRESSION".to_string(), unit_with_price.price.clone())] + .into_iter() + .collect(), + }; + + // TODO: Logging for `eval_multiple` + targeting::eval_multiple( + &campaign.targeting_rules, + &input::Input::Getter(campaign_input.clone()), + &mut output, + ); + + output.show + }) + .map(|uwp| (uwp.clone(), campaign_id)) + .collect() + }) + .flatten() + .filter(|x| !(self.options.disabled_video && is_video(&x.0.unit))) + .collect(); + + units_with_price.sort_by(|b, a| { + (&a.0.price).cmp(&b.0.price) + // TODO: + // || randomized_sort_pos(&a.0.unit, seed).cmp(randomized_sort_pos(&b.0.unit, seed)) + }); + + // Update history + let auction_winner = units_with_price.get(0); + + if let Some((unit_with_price, campaign_id)) = auction_winner { + let history = self.history.read().await.clone(); + + let new_entry = HistoryEntry { + time: Utc::now(), + unit_id: unit_with_price.unit.id.clone(), + campaign_id: *campaign_id, + slot_id: self.options.market_slot.clone(), + }; + + *self.history.write().await = history + .into_iter() + .chain(std::iter::once(new_entry)) + // Reverse the iterator since we want to remove the oldest history entries + .rev() + .take(HISTORY_LIMIT as usize) + .collect::>() + // Keeps the same order, as the one we've started with! Old => New + .into_iter() + .rev() + .collect(); + } + + // Return the results, with a fallback unit if there is one + if let Some((unit_with_price, campaign_id)) = auction_winner { + let validators = campaigns + .iter() + .find_map(|campaign| { + if &campaign.channel.id == campaign_id { + Some(&campaign.channel.spec.validators) + } else { + None + } + }) + // TODO: Check what should happen here + .unwrap(); + + let html = get_unit_html_with_events( + &self.options, + &unit_with_price.unit, + &hostname, + *campaign_id, + validators, + false, + ); + + Ok(Some(NextAdUnit { + unit: unit_with_price.unit.clone(), + price: unit_with_price.price.clone(), + accepted_referrers: units_for_slot.accepted_referrers, + html, + })) + } else if let Some(fallback_unit) = fallback_unit { + let html = get_unit_html(&self.options.size(), &fallback_unit, &hostname, "", ""); + Ok(Some(NextAdUnit { + unit: fallback_unit, + price: 0.into(), + accepted_referrers: units_for_slot.accepted_referrers, + html, + })) + } else { + Ok(None) + } } } +pub struct NextAdUnit { + pub unit: AdUnit, + pub price: BigNum, + pub accepted_referrers: Vec, + pub html: String, +} + pub struct StickyAdUnit { pub unit: AdUnit, pub price: BigNum, diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 40bfafaaf..9b9720a27 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -41,6 +41,6 @@ postgres-types = { version = "0.1.0", optional = true } bytes = { version = "0.5", optional = true } tokio-postgres = { version = "0.5.1", optional = true, features = ["with-chrono-0_4", "with-serde_json-1"] } # Futures -futures = "0.3.1" +futures = "0.3" # Other lazy_static = "1.4.0" diff --git a/primitives/src/supermarket.rs b/primitives/src/supermarket.rs index c4572894d..1d5f49e47 100644 --- a/primitives/src/supermarket.rs +++ b/primitives/src/supermarket.rs @@ -42,7 +42,10 @@ pub enum Finalized { pub mod units_for_slot { pub mod response { - use crate::{targeting::{Input, Rule, InputMap}, BigNum, ChannelId, ChannelSpec, SpecValidators, ValidatorId}; + use crate::{ + targeting::{Map, Rule}, + BigNum, ChannelId, ChannelSpec, SpecValidators, ValidatorId, + }; use chrono::{ serde::{ts_milliseconds, ts_milliseconds_option}, DateTime, Utc, @@ -53,20 +56,20 @@ pub mod units_for_slot { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Response { - pub targeting_input_base: InputMap, + pub targeting_input_base: Map, pub accepted_referrers: Vec, - pub fallback_unit: AdUnit, + pub fallback_unit: Option, pub campaigns: Vec, } - #[derive(Debug, Serialize, Deserialize)] + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct UnitsWithPrice { pub unit: AdUnit, pub price: BigNum, } - #[derive(Debug, Serialize, Deserialize)] + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Campaign { #[serde(flatten)] @@ -75,7 +78,7 @@ pub mod units_for_slot { pub units_with_price: Vec, } - #[derive(Debug, Serialize, Deserialize)] + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Channel { pub id: ChannelId, @@ -97,7 +100,7 @@ pub mod units_for_slot { } } - #[derive(Debug, Serialize, Deserialize)] + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Spec { #[serde(with = "ts_milliseconds")] diff --git a/primitives/src/targeting.rs b/primitives/src/targeting.rs index 0828a360f..7bdccf8d8 100644 --- a/primitives/src/targeting.rs +++ b/primitives/src/targeting.rs @@ -1,240 +1,548 @@ -use crate::{ - channel::Pricing, supermarket::Status, AdUnit, BalancesMap, BigNum, Channel, ToETHChecksum, - ValidatorId, -}; -use chrono::Utc; -use std::collections::HashMap; +use crate::{channel::Pricing, BigNum, Channel}; pub use eval::*; use serde_json::Number; -use serde::{Serialize}; +use std::collections::HashMap; -mod eval; +pub use input::{Getter, Input, Map}; -pub type InputMap = HashMap; +mod eval; -#[derive(Debug)] -pub enum Input { - Map { - inner: InputMap, - deposit_asset: String, - }, - InputSource(InputSource), -} +pub mod input { + use super::{get_pricing_bounds, Error, Value}; + use crate::{ + supermarket::units_for_slot::response::{AdUnit as UFSAdUnit, Channel as UFSChannel}, + AdUnit, BalancesMap, ToETHChecksum, ValidatorId, + }; -impl Input { - pub fn get(&self, key: &str) -> Result { - match self { - Input::Map{inner, ..} => inner.get(key).ok_or(Error::UnknownVariable).map(Clone::clone), - Input::InputSource(input) => input.try_get(key) - } + use chrono::Utc; + use serde::Serialize; + use std::collections::HashMap; + use std::convert::TryFrom; + + pub type Map = HashMap; + + #[derive(Debug, Clone)] + pub struct Getter { + pub base: Map, + pub ad_unit: Option, + pub channel: Option, + pub last_approved: Option, + pub deposit_asset: Option, } - pub fn deposit_asset(&self) -> Value { - match self { - Input::Map{deposit_asset, ..} => Value::new_string(deposit_asset), - Input::InputSource(input) => Value::new_string(&input.global.channel.deposit_asset) - } - } -} + impl Getter { + /// This method will first check the set properties of Getter (ad_unit, channel, last_approved) + /// if they are set, it will use them, otherwise it will fallback to the base HashMap + /// containing the other keys of the Input + pub fn try_get(&self, key: &str) -> Result { + let channel = self.channel.as_ref(); + let balances_map = self.last_approved.as_ref(); + + // TODO: Replace all `channel.is_some()` & `channel.expect(..)` with `if let`, when it gets stabilized + match key { + "adUnitId" => { + let ipfs = self.ad_unit.as_ref().map(|ad_unit| ad_unit.id.clone()); + Ok(Value::String(ipfs.unwrap_or_default())) + } -#[derive(Debug, Clone, Serialize)] -#[serde(into = "InputMap")] -pub struct InputSource { - /// AdView scope, accessible only on the AdView - pub ad_view: Option, - /// Global scope, accessible everywhere - pub global: Global, - /// adSlot scope, accessible on Supermarket and AdView - pub ad_slot: Option, -} + "advertiserId" if channel.is_some() => { + let channel = channel.expect("We did check is_some(), this should never fail!"); -impl From for InputMap { - fn from(input: Input) -> Self { - let mut map = Self::new(); - - let fields = [ - // AdView scope, accessible only on the AdView - "adView.secondsSinceCampaignImpression", - "adView.hasCustomPreferences", - "adView.navigatorLanguage", - // Global scope, accessible everywhere - "adSlotId", - "adSlotType", - "publisherId", - "country", - "eventType", - "secondsSinceEpoch", - "userAgentOS", - "userAgentBrowserFamily", - // Global scope, accessible everywhere, campaign-dependant - "adUnitId", - "advertiserId", - "campaignId", - "campaignTotalSpent", - "campaignSecondsActive", - "campaignSecondsDuration", - "campaignBudget", - "eventMinPrice", - "eventMaxPrice", - "publisherEarnedFromCampaign", - // adSlot scope, accessible on Supermarket and AdView - "adSlot.categories", - "adSlot.hostname", - "adSlot.alexaRank", - ]; - - for field in fields.iter() { - match input.try_get(field) { - Ok(value) => { - // we don't care if there is an old value, there shouldn't be one! - map.insert(field.to_string(), value); - }, - // if there is an Error, it will be `UnknownVariable` and we just skip it - Err(_) => {}, + let creator = channel.creator.to_hex_prefix_string(); + Ok(Value::String(creator)) + } + + "campaignId" if channel.is_some() => { + let channel = channel.expect("We did check is_some(), this should never fail!"); + + Ok(Value::String(channel.id.to_string())) + } + "campaignTotalSpent" => Ok(Value::BigNum( + balances_map.map(|b| b.values().sum()).unwrap_or_default(), + )), + "campaignSecondsActive" if channel.is_some() => { + let spec = &channel + .expect("We did check is_some(), this should never fail!") + .spec; + let duration = Utc::now() - spec.active_from.unwrap_or(spec.created); + + let seconds = duration + .to_std() + .map(|duration| duration.as_secs()) + .unwrap_or(0); + + Ok(Value::Number(seconds.into())) + } + "campaignSecondsDuration" if channel.is_some() => { + let spec = &channel + .expect("We did check is_some(), this should never fail!") + .spec; + + let duration = + spec.withdraw_period_start - spec.active_from.unwrap_or(spec.created); + let seconds = duration + .to_std() + .map(|std_duration| std_duration.as_secs()) + .unwrap_or(0); + + Ok(Value::Number(seconds.into())) + } + "campaignBudget" if channel.is_some() => { + let channel = channel.expect("We did check is_some(), this should never fail!"); + + Ok(Value::BigNum(channel.deposit_amount.clone())) + } + // TODO: Should we be able to get the pricing bounds from Market's Channel/Campaign or directly use the Base? + // Skip the eventMinPrice & eventMaxPrice + // "eventMinPrice" if self.pricing_bounds.is_some() => { + + // let event_type = self + // .base + // .get("eventType") + // .ok_or(Error::UnknownVariable)? + // .clone() + // .try_string()?; + // let min = get_pricing_bounds(todo!(), &event_type).min; + + // Ok(Value::BigNum(min)) + // } + + // "eventMaxPrice" if self.pricing_bounds.is_some() => { + // let event_type = self + // .base + // .get("eventType") + // .ok_or(Error::UnknownVariable)? + // .clone() + // .try_string()?; + + // let max = get_pricing_bounds(todo!(), &event_type).max; + // Ok(Value::BigNum(max)) + // } + "publisherEarnedFromCampaign" if channel.is_some() => { + let publisher_id = + self.base.get("publisherId").ok_or(Error::UnknownVariable)?; + let publisher_id = ValidatorId::try_from(publisher_id.clone()) + .map_err(|_| Error::TypeError)?; + + let earned = balances_map + .and_then(|balances| balances.get(&publisher_id)) + .cloned() + .unwrap_or_default(); + + Ok(Value::BigNum(earned)) + } + // Otherwise we will look into the base HashMap + key => self + .base + .get(key) + .ok_or(Error::UnknownVariable) + .map(Clone::clone), } } + } - map + #[derive(Debug)] + pub enum Input { + /// Used for when we deserialize the input and we need to be able to get the same fields as the Source + Getter(Getter), + /// We have the deposit_asset from the Source.global.channel + Source(Box), } -} -impl InputSource { - fn try_get(&self, key: &str) -> Result { - let spec = &self.global.channel.spec; + impl Input { + /// - For Getter: + /// this method will call the `Getter::try_get()` method with the **currently** set properties + /// of the Getter + /// - For Source: + /// This method will call the `Source::try_get()` as well + pub fn try_get(&self, key: &str) -> Result { + match self { + Input::Getter(getter) => getter.try_get(key), + Input::Source(input) => input.try_get(key), + } + } - match key { - // AdView scope, accessible only on the AdView - "adView.secondsSinceCampaignImpression" => self - .ad_view - .as_ref() - .map(|ad_view| Value::Number(ad_view.seconds_since_campaign_impression.into())) - .ok_or(Error::UnknownVariable), - "adView.hasCustomPreferences" => self - .ad_view - .as_ref() - .map(|ad_view| Value::Bool(ad_view.has_custom_preferences)) - .ok_or(Error::UnknownVariable), - "adView.navigatorLanguage" => self - .ad_view - .as_ref() - .map(|ad_view| Value::String(ad_view.navigator_language.clone())) - .ok_or(Error::UnknownVariable), - // Global scope, accessible everywhere - "adSlotId" => Ok(Value::String(self.global.ad_slot_id.clone())), - "adSlotType" => Ok(Value::String(self.global.ad_slot_type.clone())), - "publisherId" => Ok(Value::String(self.global.publisher_id.to_checksum())), - "country" => self - .global - .country - .clone() - .ok_or(Error::UnknownVariable) - .map(Value::String), - "eventType" => Ok(Value::String(self.global.event_type.clone())), - "secondsSinceEpoch" => Ok(Value::Number(self.global.seconds_since_epoch.into())), - "userAgentOS" => self - .global - .user_agent_os - .clone() - .map(Value::String) - .ok_or(Error::UnknownVariable), - "userAgentBrowserFamily" => self - .global - .user_agent_browser_family - .clone() - .map(Value::String) - .ok_or(Error::UnknownVariable), - // Global scope, accessible everywhere, campaign-dependant - "adUnitId" => { - let ipfs = self + /// AdView scope, accessible only on the AdView + pub fn set_ad_view(&mut self, ad_view: AdView) { + match self { + Input::Getter(getter) => { + getter.base.insert( + "adView.secondsSinceCampaignImpression".to_string(), + Value::Number(ad_view.seconds_since_campaign_impression.into()), + ); + getter.base.insert( + "adView.hasCustomPreferences".to_string(), + Value::Bool(ad_view.has_custom_preferences), + ); + getter.base.insert( + "adView.navigatorLanguage".to_string(), + Value::String(ad_view.navigator_language), + ); + } + Input::Source(source) => source.ad_view = Some(ad_view), + } + } + + pub fn deposit_asset(&self) -> Option { + match self { + Input::Getter(getter) => getter.deposit_asset.clone(), + Input::Source(source) => source .global - .ad_unit + .channel .as_ref() - .map(|ad_unit| ad_unit.ipfs.clone()); - Ok(Value::String(ipfs.unwrap_or_default())) + .map(|c| c.deposit_asset.clone()), } - "advertiserId" => { - let creator = self.global.channel.creator.to_hex_prefix_string(); + } + } - Ok(Value::String(creator)) - } - "campaignId" => Ok(Value::String(self.global.channel.id.to_string())), - "campaignTotalSpent" => Ok(Value::BigNum( - self.global - .balances - .as_ref() - .map(|b| b.values().sum()) - .unwrap_or_default(), - )), - "campaignSecondsActive" => { - let duration = Utc::now() - spec.active_from.unwrap_or(spec.created); + #[derive(Debug, Clone, Serialize)] + #[serde(into = "Map")] + pub struct Source { + /// AdView scope, accessible only on the AdView + pub ad_view: Option, + /// Global scope, accessible everywhere + pub global: Global, + /// adSlot scope, accessible on Supermarket and AdView + pub ad_slot: Option, + } - let seconds = duration - .to_std() - .map(|duration| duration.as_secs()) - .unwrap_or(0); + #[derive(Debug, Clone)] + pub struct AdView { + pub seconds_since_campaign_impression: u64, + pub has_custom_preferences: bool, + pub navigator_language: String, + } - Ok(Value::Number(seconds.into())) - } - "campaignSecondsDuration" => { - let duration = - spec.withdraw_period_start - spec.active_from.unwrap_or(spec.created); - let seconds = duration - .to_std() - .map(|std_duration| std_duration.as_secs()) - .unwrap_or(0); - - Ok(Value::Number(seconds.into())) - } - "depositAsset" => Ok(Value::new_string(&self.global.channel.deposit_asset)), - "campaignBudget" => Ok(Value::BigNum(self.global.channel.deposit_amount.clone())), - "eventMinPrice" => { - let min = get_pricing_bounds(&self.global.channel, &self.global.event_type).min; - Ok(Value::BigNum(min)) - } - "eventMaxPrice" => { - let max = get_pricing_bounds(&self.global.channel, &self.global.event_type).max; - Ok(Value::BigNum(max)) + #[derive(Debug, Clone)] + pub struct Global { + /// Global scope, accessible everywhere + pub ad_slot_id: String, + pub ad_slot_type: String, + pub publisher_id: ValidatorId, + pub country: Option, + pub event_type: String, + pub seconds_since_epoch: u64, + pub user_agent_os: Option, + pub user_agent_browser_family: Option, + /// Global scope, accessible everywhere, campaign-dependant + pub ad_unit: Option, + /// We use the regular full Channel here + pub channel: Option, + pub balances: Option, + } + + #[derive(Debug, Clone)] + pub struct AdSlot { + pub categories: Vec, + pub hostname: String, + pub alexa_rank: Option, + } + + impl From for Map { + fn from(input_source: Source) -> Self { + let mut map = Self::new(); + + let fields = [ + // AdView scope, accessible only on the AdView + "adView.secondsSinceCampaignImpression", + "adView.hasCustomPreferences", + "adView.navigatorLanguage", + // Global scope, accessible everywhere + "adSlotId", + "adSlotType", + "publisherId", + "country", + "eventType", + "secondsSinceEpoch", + "userAgentOS", + "userAgentBrowserFamily", + // Global scope, accessible everywhere, campaign-dependant + "adUnitId", + "advertiserId", + "campaignId", + "campaignTotalSpent", + "campaignSecondsActive", + "campaignSecondsDuration", + "campaignBudget", + "eventMinPrice", + "eventMaxPrice", + "publisherEarnedFromCampaign", + // adSlot scope, accessible on Supermarket and AdView + "adSlot.categories", + "adSlot.hostname", + "adSlot.alexaRank", + ]; + + for field in fields.iter() { + // if there is an Error, it will be `UnknownVariable` and we just skip it + + if let Ok(value) = input_source.try_get(field) { + // we don't care if there is an old value, there shouldn't be one! + map.insert(field.to_string(), value); + } } - "publisherEarnedFromCampaign" => { - let earned = self + + map + } + } + + impl Source { + fn try_get(&self, key: &str) -> Result { + match key { + // AdView scope, accessible only on the AdView + "adView.secondsSinceCampaignImpression" => self + .ad_view + .as_ref() + .map(|ad_view| Value::Number(ad_view.seconds_since_campaign_impression.into())) + .ok_or(Error::UnknownVariable), + "adView.hasCustomPreferences" => self + .ad_view + .as_ref() + .map(|ad_view| Value::Bool(ad_view.has_custom_preferences)) + .ok_or(Error::UnknownVariable), + "adView.navigatorLanguage" => self + .ad_view + .as_ref() + .map(|ad_view| Value::String(ad_view.navigator_language.clone())) + .ok_or(Error::UnknownVariable), + // Global scope, accessible everywhere + "adSlotId" => Ok(Value::String(self.global.ad_slot_id.clone())), + "adSlotType" => Ok(Value::String(self.global.ad_slot_type.clone())), + "publisherId" => Ok(Value::String(self.global.publisher_id.to_checksum())), + "country" => self + .global + .country + .clone() + .ok_or(Error::UnknownVariable) + .map(Value::String), + "eventType" => Ok(Value::String(self.global.event_type.clone())), + "secondsSinceEpoch" => Ok(Value::Number(self.global.seconds_since_epoch.into())), + "userAgentOS" => self .global - .balances + .user_agent_os + .clone() + .map(Value::String) + .ok_or(Error::UnknownVariable), + "userAgentBrowserFamily" => self + .global + .user_agent_browser_family + .clone() + .map(Value::String) + .ok_or(Error::UnknownVariable), + // Global scope, accessible everywhere, campaign-dependant + "adUnitId" => { + let ipfs = self + .global + .ad_unit + .as_ref() + .map(|ad_unit| ad_unit.ipfs.clone()); + Ok(Value::String(ipfs.unwrap_or_default())) + } + "advertiserId" => self + .global + .channel .as_ref() - .and_then(|balances| balances.get(&self.global.publisher_id)) - .cloned() - .unwrap_or_default(); - - Ok(Value::BigNum(earned)) - } - // adSlot scope, accessible on Supermarket and AdView - "adSlot.categories" => self - .ad_slot - .as_ref() - .map(|ad_slot| { - let array = ad_slot - .categories - .iter() - .map(|string| Value::String(string.clone())) - .collect(); - Value::Array(array) - }) - .ok_or(Error::UnknownVariable), - "adSlot.hostname" => self - .ad_slot - .as_ref() - .map(|ad_slot| Value::String(ad_slot.hostname.clone())) - .ok_or(Error::UnknownVariable), - "adSlot.alexaRank" => { - let ad_slot = self.ad_slot.as_ref().ok_or(Error::UnknownVariable)?; - let alexa_rank = ad_slot.alexa_rank.ok_or(Error::UnknownVariable)?; - - match serde_json::Number::from_f64(alexa_rank) { - Some(number) => Ok(Value::Number(number)), - None => Err(Error::TypeError), + .map(|channel| Value::String(channel.creator.to_hex_prefix_string())) + .ok_or(Error::UnknownVariable), + "campaignId" => self + .global + .channel + .as_ref() + .map(|channel| Value::String(channel.id.to_string())) + .ok_or(Error::UnknownVariable), + "campaignTotalSpent" => Ok(Value::BigNum( + self.global + .balances + .as_ref() + .map(|b| b.values().sum()) + .unwrap_or_default(), + )), + "campaignSecondsActive" => self + .global + .channel + .as_ref() + .map(|channel| { + let duration = + Utc::now() - channel.spec.active_from.unwrap_or(channel.spec.created); + + let seconds = duration + .to_std() + .map(|duration| duration.as_secs()) + .unwrap_or(0); + + Value::Number(seconds.into()) + }) + .ok_or(Error::UnknownVariable), + "campaignSecondsDuration" => self + .global + .channel + .as_ref() + .map(|channel| { + let spec = &channel.spec; + let duration = + spec.withdraw_period_start - spec.active_from.unwrap_or(spec.created); + let seconds = duration + .to_std() + .map(|std_duration| std_duration.as_secs()) + .unwrap_or(0); + + Value::Number(seconds.into()) + }) + .ok_or(Error::UnknownVariable), + "campaignBudget" => self + .global + .channel + .as_ref() + .map(|channel| Value::BigNum(channel.deposit_amount.clone())) + .ok_or(Error::UnknownVariable), + "eventMinPrice" => self + .global + .channel + .as_ref() + .map(|channel| { + let min = get_pricing_bounds(channel, &self.global.event_type).min; + Value::BigNum(min) + }) + .ok_or(Error::UnknownVariable), + "eventMaxPrice" => self + .global + .channel + .as_ref() + .map(|channel| { + let max = get_pricing_bounds(channel, &self.global.event_type).max; + + Value::BigNum(max) + }) + .ok_or(Error::UnknownVariable), + "publisherEarnedFromCampaign" => { + let earned = self + .global + .balances + .as_ref() + .and_then(|balances| balances.get(&self.global.publisher_id)) + .cloned() + .unwrap_or_default(); + + Ok(Value::BigNum(earned)) + } + // adSlot scope, accessible on Supermarket and AdView + "adSlot.categories" => self + .ad_slot + .as_ref() + .map(|ad_slot| { + let array = ad_slot + .categories + .iter() + .map(|string| Value::String(string.clone())) + .collect(); + Value::Array(array) + }) + .ok_or(Error::UnknownVariable), + "adSlot.hostname" => self + .ad_slot + .as_ref() + .map(|ad_slot| Value::String(ad_slot.hostname.clone())) + .ok_or(Error::UnknownVariable), + "adSlot.alexaRank" => { + let ad_slot = self.ad_slot.as_ref().ok_or(Error::UnknownVariable)?; + let alexa_rank = ad_slot.alexa_rank.ok_or(Error::UnknownVariable)?; + + match serde_json::Number::from_f64(alexa_rank) { + Some(number) => Ok(Value::Number(number)), + None => Err(Error::TypeError), + } } + _unknown_field => Err(Error::UnknownVariable), } - _unknown_field => Err(Error::UnknownVariable), + } + } + + #[cfg(test)] + mod test { + use super::*; + use crate::util::tests::prep_db::{DUMMY_CHANNEL, IDS}; + use chrono::Utc; + + #[test] + fn test_try_get_of_input() { + let ad_unit = AdUnit { + ipfs: "Hash".to_string(), + ad_type: "legacy_300x250".to_string(), + media_url: "media_url".to_string(), + media_mime: "media_mime".to_string(), + target_url: "target_url".to_string(), + min_targeting_score: None, + owner: IDS["creator"], + created: Utc::now(), + title: None, + description: None, + archived: false, + modified: None, + }; + let input_balances = BalancesMap::default(); + let mut input = Source { + ad_view: Some(AdView { + seconds_since_campaign_impression: 10, + has_custom_preferences: false, + navigator_language: "bg".to_string(), + }), + global: Global { + ad_slot_id: "ad_slot_id Value".to_string(), + ad_slot_type: "ad_slot_type Value".to_string(), + publisher_id: IDS["leader"], + country: Some("bg".to_string()), + event_type: "IMPRESSION".to_string(), + seconds_since_epoch: 500, + user_agent_os: Some("os".to_string()), + user_agent_browser_family: Some("family".to_string()), + ad_unit: Some(ad_unit), + channel: Some(DUMMY_CHANNEL.clone()), + balances: Some(input_balances), + }, + ad_slot: None, + }; + + let ad_view_seconds_since_show = input + .try_get("adView.secondsSinceCampaignImpression") + .expect("Should get the ad_view.seconds_since_campaign_impression field"); + + let expected_number = serde_json::Number::from(10); + + assert_eq!(Value::Number(expected_number), ad_view_seconds_since_show); + + let ad_slot_id = input + .try_get("adSlotId") + .expect("Should get the global.ad_slot_id field"); + + assert_eq!(Value::String("ad_slot_id Value".to_string()), ad_slot_id); + + let get_unknown = input + .try_get("unknownField") + .expect_err("Should return Error"); + + assert_eq!(Error::UnknownVariable, get_unknown); + + let global_campaign_budget = input + .try_get("campaignBudget") + .expect("Should get the global.campaign_budget field"); + + assert_eq!( + Value::BigNum(DUMMY_CHANNEL.deposit_amount.clone()), + global_campaign_budget + ); + + assert_eq!( + Err(Error::UnknownVariable), + input.try_get("adSlot.alexaRank") + ); + let ad_slot = AdSlot { + categories: vec![], + hostname: "".to_string(), + alexa_rank: Some(20.0), + }; + input.ad_slot = Some(ad_slot); + assert!(input.try_get("adSlot.alexaRank").is_ok()); } } } @@ -261,38 +569,6 @@ pub fn get_pricing_bounds(channel: &Channel, event_type: &str) -> Pricing { }) } -#[derive(Debug, Clone)] -pub struct AdView { - pub seconds_since_campaign_impression: u64, - pub has_custom_preferences: bool, - pub navigator_language: String, -} - -#[derive(Debug, Clone)] -pub struct Global { - /// Global scope, accessible everywhere - pub ad_slot_id: String, - pub ad_slot_type: String, - pub publisher_id: ValidatorId, - pub country: Option, - pub event_type: String, - pub seconds_since_epoch: u64, - pub user_agent_os: Option, - pub user_agent_browser_family: Option, - /// Global scope, accessible everywhere, campaign-dependant - pub ad_unit: Option, - pub channel: Channel, - pub status: Option, - pub balances: Option, -} - -#[derive(Debug, Clone)] -pub struct AdSlot { - pub categories: Vec, - pub hostname: String, - pub alexa_rank: Option, -} - #[derive(Debug)] pub struct Output { /// Whether to show the ad @@ -351,93 +627,6 @@ impl From<&Channel> for Output { #[cfg(test)] mod test { use super::*; - use crate::{ - supermarket::Status, - util::tests::prep_db::{DUMMY_CHANNEL, IDS}, - }; - use chrono::Utc; - - #[test] - fn test_try_get_of_input() { - let ad_unit = AdUnit { - ipfs: "Hash".to_string(), - ad_type: "legacy_300x250".to_string(), - media_url: "media_url".to_string(), - media_mime: "media_mime".to_string(), - target_url: "target_url".to_string(), - min_targeting_score: None, - owner: IDS["creator"], - created: Utc::now(), - title: None, - description: None, - archived: false, - modified: None, - }; - let input_balances = BalancesMap::default(); - let mut input = Input { - ad_view: Some(AdView { - seconds_since_campaign_impression: 10, - has_custom_preferences: false, - navigator_language: "bg".to_string(), - }), - global: Global { - ad_slot_id: "ad_slot_id Value".to_string(), - ad_slot_type: "ad_slot_type Value".to_string(), - publisher_id: IDS["leader"], - country: Some("bg".to_string()), - event_type: "IMPRESSION".to_string(), - seconds_since_epoch: 500, - user_agent_os: Some("os".to_string()), - user_agent_browser_family: Some("family".to_string()), - ad_unit: Some(ad_unit), - channel: DUMMY_CHANNEL.clone(), - status: Some(Status::Initializing), - balances: Some(input_balances), - }, - ad_slot: None, - }; - - let ad_view_seconds_since_show = input - .try_get("adView.secondsSinceCampaignImpression") - .expect("Should get the ad_view.seconds_since_campaign_impression field"); - - let expected_number = serde_json::Number::from(10); - - assert_eq!(Value::Number(expected_number), ad_view_seconds_since_show); - - let ad_slot_id = input - .try_get("adSlotId") - .expect("Should get the global.ad_slot_id field"); - - assert_eq!(Value::String("ad_slot_id Value".to_string()), ad_slot_id); - - let get_unknown = input - .try_get("unknownField") - .expect_err("Should return Error"); - - assert_eq!(Error::UnknownVariable, get_unknown); - - let global_campaign_budget = input - .try_get("campaignBudget") - .expect("Should get the global.campaign_budget field"); - - assert_eq!( - Value::BigNum(DUMMY_CHANNEL.deposit_amount.clone()), - global_campaign_budget - ); - - assert_eq!( - Err(Error::UnknownVariable), - input.try_get("adSlot.alexaRank") - ); - let ad_slot = AdSlot { - categories: vec![], - hostname: "".to_string(), - alexa_rank: Some(20.0), - }; - input.ad_slot = Some(ad_slot); - assert!(input.try_get("adSlot.alexaRank").is_ok()); - } #[test] fn test_try_get_of_output() { diff --git a/primitives/src/targeting/eval.rs b/primitives/src/targeting/eval.rs index 07f0e75c9..3dea256c8 100644 --- a/primitives/src/targeting/eval.rs +++ b/primitives/src/targeting/eval.rs @@ -10,8 +10,6 @@ use std::{ str::FromStr, }; -pub type Map = serde_json::value::Map; - use super::{Input, Output}; #[cfg(test)] @@ -893,7 +891,10 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result .eval(input, output)? .ok_or(Error::TypeError)? .try_bignum()?; - let deposit_asset = input.deposit_asset()?.try_string()?; + + // if there is no way to get the deposit_asset, then fail with UnknownVariable + // since we can't calculate the price in USD + let deposit_asset = input.deposit_asset().ok_or(Error::UnknownVariable)?; let divisor = DEPOSIT_ASSETS_MAP .get(&deposit_asset) @@ -961,6 +962,25 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result Ok(value) } +/// Stops (i.e. it short-circuits) evaluating `Rule`s when `Output.show` becomes `false` +pub fn eval_multiple( + rules: &[Rule], + input: &Input, + output: &mut Output, +) -> Vec, Error>> { + let mut results = vec![]; + + for rule in rules { + results.push(rule.eval(input, output)); + + if !output.show { + break; + } + } + + results +} + enum MathOperator { Division, Multiplication, diff --git a/primitives/src/targeting/eval_test.rs b/primitives/src/targeting/eval_test.rs index 6b82f05a9..42af8724a 100644 --- a/primitives/src/targeting/eval_test.rs +++ b/primitives/src/targeting/eval_test.rs @@ -1,13 +1,12 @@ use super::*; use crate::{ - supermarket::Status, - targeting::{AdView, Global, Input}, + targeting::input, util::tests::prep_db::{DUMMY_CHANNEL, IDS}, AdUnit, BalancesMap, }; use chrono::Utc; -fn get_default_input() -> Input { +fn get_default_input() -> input::Source { let ad_unit = AdUnit { ipfs: "Hash".to_string(), ad_type: "legacy_300x250".to_string(), @@ -24,13 +23,13 @@ fn get_default_input() -> Input { }; let input_balances = BalancesMap::default(); - Input { - ad_view: Some(AdView { + input::Source { + ad_view: Some(input::AdView { seconds_since_campaign_impression: 10, has_custom_preferences: false, navigator_language: "bg".to_string(), }), - global: Global { + global: input::Global { ad_slot_id: "ad_slot_id Value".to_string(), ad_slot_type: "ad_slot_type Value".to_string(), publisher_id: IDS["leader"], @@ -40,8 +39,7 @@ fn get_default_input() -> Input { user_agent_os: Some("os".to_string()), user_agent_browser_family: Some("family".to_string()), ad_unit: Some(ad_unit), - channel: DUMMY_CHANNEL.clone(), - status: Some(Status::Initializing), + channel: Some(DUMMY_CHANNEL.clone()), balances: Some(input_balances), }, ad_slot: None, @@ -50,7 +48,6 @@ fn get_default_input() -> Input { mod dsl_test { use super::*; - use crate::targeting::AdSlot; #[test] fn deserialize_intersects_with_get_rule() { @@ -84,12 +81,13 @@ mod dsl_test { /// ``` #[test] fn test_intersects_eval() { - let mut input = get_default_input(); - input.ad_slot = Some(AdSlot { + let mut source = get_default_input(); + source.ad_slot = Some(input::AdSlot { categories: vec!["Bitcoin".to_string(), "Ethereum".to_string()], hostname: Default::default(), alexa_rank: Some(0.0), }); + let input = input::Input::Source(Box::new(source)); let mut output = Output { show: true, @@ -111,12 +109,13 @@ mod dsl_test { result.expect("Should return Non-NULL result!") ); - let mut input = get_default_input(); - input.ad_slot = Some(AdSlot { + let mut source = get_default_input(); + source.ad_slot = Some(input::AdSlot { categories: vec!["Advertisement".to_string(), "Programming".to_string()], hostname: Default::default(), alexa_rank: Some(0.0), }); + let input = input::Input::Source(Box::new(source)); let result = rules.eval(&input, &mut output).expect("Should eval rules"); @@ -128,7 +127,7 @@ mod dsl_test { #[test] fn test_and_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -152,7 +151,8 @@ mod dsl_test { #[test] fn test_if_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); + let mut output = Output { show: true, boost: 1.0, @@ -172,7 +172,7 @@ mod dsl_test { #[test] fn test_bn_eval_from_actual_number_value_string_bignum_or_number() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -199,7 +199,7 @@ mod dsl_test { #[test] fn test_bn_eval_from_actual_incorrect_value() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -239,7 +239,7 @@ mod dsl_test { }), }); - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output::from(&channel); assert_eq!(Some(&BigNum::from(1_000)), output.price.get("IMPRESSION")); @@ -254,7 +254,7 @@ mod dsl_test { #[test] fn test_get_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 42.0, @@ -280,7 +280,7 @@ mod math_functions { #[test] fn test_div_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -325,7 +325,7 @@ mod math_functions { } #[test] fn test_mul_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -368,7 +368,7 @@ mod math_functions { } #[test] fn test_mod_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -411,7 +411,7 @@ mod math_functions { } #[test] fn test_add_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -454,7 +454,7 @@ mod math_functions { } #[test] fn test_sub_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -497,7 +497,7 @@ mod math_functions { } #[test] fn test_min_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -540,7 +540,7 @@ mod math_functions { } #[test] fn test_max_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -583,7 +583,7 @@ mod math_functions { } #[test] fn test_lt_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -626,7 +626,7 @@ mod math_functions { } #[test] fn test_lte_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -669,7 +669,7 @@ mod math_functions { } #[test] fn test_gt_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -712,7 +712,7 @@ mod math_functions { } #[test] fn test_gte_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -755,7 +755,7 @@ mod math_functions { } #[test] fn test_between_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -803,7 +803,7 @@ mod math_functions { } #[test] fn test_muldiv_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -827,7 +827,7 @@ mod control_flow_and_logic { #[test] fn test_if_not_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -846,7 +846,7 @@ mod control_flow_and_logic { } #[test] fn test_if_else() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -874,7 +874,7 @@ mod control_flow_and_logic { } #[test] fn test_or_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -897,7 +897,7 @@ mod control_flow_and_logic { } #[test] fn test_xor_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -920,7 +920,7 @@ mod control_flow_and_logic { } #[test] fn test_not_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -938,7 +938,7 @@ mod control_flow_and_logic { } #[test] fn test_eq_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -1019,7 +1019,7 @@ mod control_flow_and_logic { } #[test] fn test_neq_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -1077,7 +1077,7 @@ mod control_flow_and_logic { } #[test] fn test_only_show_if_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -1093,7 +1093,7 @@ mod control_flow_and_logic { } #[test] fn test_do_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -1113,7 +1113,7 @@ mod string_and_array { use super::*; #[test] fn test_in_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -1153,7 +1153,7 @@ mod string_and_array { } #[test] fn test_nin_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -1193,7 +1193,7 @@ mod string_and_array { } #[test] fn test_at_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -1216,7 +1216,7 @@ mod string_and_array { } #[test] fn test_split_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -1252,7 +1252,7 @@ mod string_and_array { } #[test] fn test_starts_with_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -1293,7 +1293,7 @@ mod string_and_array { } #[test] fn test_ends_with_eval() { - let input = get_default_input(); + let input = input::Input::Source(Box::new(get_default_input())); let mut output = Output { show: true, boost: 1.0, @@ -1330,7 +1330,7 @@ mod string_and_array { #[test] fn test_get_price_in_usd_eval() { - let mut input = get_default_input(); + let source = get_default_input(); let mut output = Output { show: true, @@ -1338,7 +1338,16 @@ mod string_and_array { price: Default::default(), }; for (key, value) in &*DEPOSIT_ASSETS_MAP { - input.global.channel.deposit_asset = key.to_string(); + let mut source = source.clone(); + source + .global + .channel + .as_mut() + .expect("Should have Channel set for this test!") + .deposit_asset = key.to_string(); + + let input = input::Input::Source(Box::new(source)); + let amount_crypto = BigNum::from(100).mul(value); let amount_usd = Some(Value::Number( Number::from_f64(100.0).expect("should create a float"), diff --git a/primitives/src/validator.rs b/primitives/src/validator.rs index 0618245e6..1999453a4 100644 --- a/primitives/src/validator.rs +++ b/primitives/src/validator.rs @@ -3,7 +3,7 @@ use hex::FromHex; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt; -use crate::{BalancesMap, BigNum, DomainError, ToETHChecksum}; +use crate::{targeting::Value, BalancesMap, BigNum, DomainError, ToETHChecksum}; use std::convert::TryFrom; #[derive(Debug)] @@ -114,6 +114,7 @@ impl TryFrom<&str> for ValidatorId { impl TryFrom<&String> for ValidatorId { type Error = DomainError; + fn try_from(value: &String) -> Result { ValidatorId::try_from(value.as_str()) } @@ -125,6 +126,18 @@ impl fmt::Display for ValidatorId { } } +impl TryFrom for ValidatorId { + type Error = DomainError; + + fn try_from(value: Value) -> Result { + let string = value.try_string().map_err(|err| { + DomainError::InvalidArgument(format!("Value is not a string: {}", err)) + })?; + + Self::try_from(&string) + } +} + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct ValidatorDesc { diff --git a/sentry/src/payout.rs b/sentry/src/payout.rs index 1e98c4f3b..11a48eaf3 100644 --- a/sentry/src/payout.rs +++ b/sentry/src/payout.rs @@ -2,7 +2,7 @@ use crate::Session; use chrono::Utc; use primitives::{ sentry::Event, - targeting::{get_pricing_bounds, Error, Error as EvalError, Global, Input, Output, Rule}, + targeting::{get_pricing_bounds, Error, Error as EvalError, Input, Output, Rule, input}, BigNum, Channel, ValidatorId, }; use std::{ @@ -28,15 +28,6 @@ pub fn get_payout(channel: &Channel, event: &Event, session: &Session) -> Result ad_slot, .. } => { - /* - const targetingRules = channel.targetingRules || channel.spec.targetingRules || [] - const eventType = ev.type.toUpperCase() - const [minPrice, maxPrice] = getPricingBounds(channel, eventType) - if (targetingRules.length === 0) return [balancesKey, minPrice] - - const adUnit = - Array.isArray(channel.spec.adUnits) && channel.spec.adUnits.find(u => u.ipfs === ev.adUnit) - const targetingInputBase = {*/ let targeting_rules = if !channel.targeting_rules.is_empty() { channel.targeting_rules.clone() } else { @@ -52,9 +43,9 @@ pub fn get_payout(channel: &Channel, event: &Event, session: &Session) -> Result .as_ref() .and_then(|ipfs| channel.spec.ad_units.iter().find(|u| &u.ipfs == ipfs)); - let input = Input { + let source = input::Source { ad_view: None, - global: Global { + global: input::Global { // TODO: Check this one! ad_slot_id: ad_slot.clone().unwrap_or_default(), // TODO: Check this one! @@ -70,13 +61,13 @@ pub fn get_payout(channel: &Channel, event: &Event, session: &Session) -> Result user_agent_browser_family: None, // TODO: Check this one! ad_unit: ad_unit.cloned(), - channel: channel.clone(), - status: None, + channel: Some(channel.clone()), balances: None, }, // TODO: Check this one as well! - ad_slot: None, - }; + ad_slot: None, + }; + let input = input::Input::Source(Box::new(source)); let mut output = Output { show: true, From 8b4d81efcc4459dca39cb2274cbf05dd827f7fa7 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 27 Aug 2020 14:50:44 +0300 Subject: [PATCH 10/27] adview-manager - randomized_sort_pos --- adview-manager/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/adview-manager/src/lib.rs b/adview-manager/src/lib.rs index bd9d21ef4..3b4bbba4e 100644 --- a/adview-manager/src/lib.rs +++ b/adview-manager/src/lib.rs @@ -13,7 +13,7 @@ use lazy_static::lazy_static; use rand::Rng; use reqwest::StatusCode; use serde::{Deserialize, Serialize}; -use std::{collections::VecDeque, convert::TryFrom, sync::Arc}; +use std::{cmp::Ordering, collections::VecDeque, convert::TryFrom, sync::Arc}; use thiserror::Error; use units_for_slot::response::UnitsWithPrice; use url::Url; @@ -504,10 +504,10 @@ impl Manager { .filter(|x| !(self.options.disabled_video && is_video(&x.0.unit))) .collect(); - units_with_price.sort_by(|b, a| { - (&a.0.price).cmp(&b.0.price) - // TODO: - // || randomized_sort_pos(&a.0.unit, seed).cmp(randomized_sort_pos(&b.0.unit, seed)) + units_with_price.sort_by(|b, a| match (&a.0.price).cmp(&b.0.price) { + Ordering::Equal => randomized_sort_pos(&a.0.unit, seed.clone()) + .cmp(&randomized_sort_pos(&b.0.unit, seed.clone())), + ordering => ordering, }); // Update history From ae6b87e20941fceba9d19634da65d077addc87be Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 27 Aug 2020 15:06:04 +0300 Subject: [PATCH 11/27] fix payout & event_reducer test --- sentry/src/event_reducer.rs | 5 +++-- sentry/src/payout.rs | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sentry/src/event_reducer.rs b/sentry/src/event_reducer.rs index b35ae3f36..1353ffbb2 100644 --- a/sentry/src/event_reducer.rs +++ b/sentry/src/event_reducer.rs @@ -103,8 +103,9 @@ mod test { os: None, }; - for _ in 0..101 { - reduce(&channel, &mut event_aggr, &event, &session); + for i in 0..101 { + reduce(&channel, &mut event_aggr, &event, &session) + .expect(&format!("Should be able to reduce event #{}", i)); } assert_eq!(event_aggr.channel_id, channel.id); diff --git a/sentry/src/payout.rs b/sentry/src/payout.rs index 11a48eaf3..2e0cebb92 100644 --- a/sentry/src/payout.rs +++ b/sentry/src/payout.rs @@ -2,7 +2,7 @@ use crate::Session; use chrono::Utc; use primitives::{ sentry::Event, - targeting::{get_pricing_bounds, Error, Error as EvalError, Input, Output, Rule, input}, + targeting::{get_pricing_bounds, input, Error, Error as EvalError, Input, Output, Rule}, BigNum, Channel, ValidatorId, }; use std::{ @@ -65,8 +65,8 @@ pub fn get_payout(channel: &Channel, event: &Event, session: &Session) -> Result balances: None, }, // TODO: Check this one as well! - ad_slot: None, - }; + ad_slot: None, + }; let input = input::Input::Source(Box::new(source)); let mut output = Output { From 6b9c39eb27adbc935bddf09ee8b298e08dc12082 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 28 Aug 2020 13:54:32 +0300 Subject: [PATCH 12/27] payout::get_payout - test --- sentry/src/payout.rs | 124 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 111 insertions(+), 13 deletions(-) diff --git a/sentry/src/payout.rs b/sentry/src/payout.rs index 2e0cebb92..c9c5d324d 100644 --- a/sentry/src/payout.rs +++ b/sentry/src/payout.rs @@ -2,7 +2,7 @@ use crate::Session; use chrono::Utc; use primitives::{ sentry::Event, - targeting::{get_pricing_bounds, input, Error, Error as EvalError, Input, Output, Rule}, + targeting::{get_pricing_bounds, input, Error, Error as EvalError, Input, Output, Rule, eval_multiple}, BigNum, Channel, ValidatorId, }; use std::{ @@ -77,7 +77,7 @@ pub fn get_payout(channel: &Channel, event: &Event, session: &Session) -> Result .collect(), }; - eval_multiple(&targeting_rules, &input, &mut output); + eval_and_log(&targeting_rules, &input, &mut output); if output.show { let price = match output.price.get(&event_type) { @@ -97,13 +97,15 @@ pub fn get_payout(channel: &Channel, event: &Event, session: &Session) -> Result } } -// @TODO: Logging & move to Targeting when ready -fn eval_multiple(rules: &[Rule], input: &Input, output: &mut Output) { - for rule in rules { - match rule.eval(input, output) { +fn eval_and_log(/* logger: &Logger, channel_id: ChannelId, */rules: &[Rule], input: &Input, output: &mut Output) { + for result in eval_multiple(rules, input, output) { + match result { Ok(_) => {} Err(EvalError::UnknownVariable) => {} - Err(EvalError::TypeError) => todo!("OnTypeErr logging"), + Err(EvalError::TypeError) => { + todo!(); + // error!(logger, "`WARNING: rule for {:?} failing", channel_id; "rule" => rule, "err" => ?result) + } } if !output.show { @@ -112,9 +114,105 @@ fn eval_multiple(rules: &[Rule], input: &Input, output: &mut Output) { } } -// #[cfg(test)] -// mod tests { -// use super::*; -// use primitives::channel::{Pricing, PricingBounds}; -// use primitives::util::tests::prep_db::{DUMMY_CHANNEL, IDS}; -// } +#[cfg(test)] +mod test { + use super::*; + use primitives::channel::{Pricing, PricingBounds}; + use primitives::util::tests::prep_db::{DUMMY_CHANNEL, IDS}; + + #[test] + fn get_event_payouts_pricing_bounds_impression_event() { + let mut channel = DUMMY_CHANNEL.clone(); + channel.deposit_amount = 100.into(); + channel.spec.min_per_impression = 8.into(); + channel.spec.max_per_impression = 64.into(); + channel.spec.pricing_bounds = Some(PricingBounds { + impression: None, + click: Some(Pricing { + min: 23.into(), + max: 100.into(), + }), + }); + + let event = Event::Impression { + publisher: IDS["leader"], + ad_unit: None, + ad_slot: None, + referrer: None, + }; + + let session = Session { + ip: None, + country: None, + referrer_header: None, + os: None, + }; + + let payout = get_payout(&channel, &event, &session).expect("Should be OK"); + + let expected_option = Some((IDS["leader"], 8.into())); + assert_eq!(expected_option, payout, "pricingBounds: impression event"); + } + + #[test] + fn get_event_payouts_pricing_bounds_click_event() { + let mut channel = DUMMY_CHANNEL.clone(); + channel.deposit_amount = 100.into(); + channel.spec.min_per_impression = 8.into(); + channel.spec.max_per_impression = 64.into(); + channel.spec.pricing_bounds = Some(PricingBounds { + impression: None, + click: Some(Pricing { + min: 23.into(), + max: 100.into(), + }), + }); + + let event = Event::Click { + publisher: IDS["leader"], + ad_unit: None, + ad_slot: None, + referrer: None, + }; + + let session = Session { + ip: None, + country: None, + referrer_header: None, + os: None, + }; + + let payout = get_payout(&channel, &event, &session).expect("Should be OK"); + + let expected_option = Some((IDS["leader"], 23.into())); + assert_eq!(expected_option, payout, "pricingBounds: click event"); + } + + #[test] + fn get_event_payouts_pricing_bounds_close_event() { + let mut channel = DUMMY_CHANNEL.clone(); + channel.deposit_amount = 100.into(); + channel.spec.min_per_impression = 8.into(); + channel.spec.max_per_impression = 64.into(); + channel.spec.pricing_bounds = Some(PricingBounds { + impression: None, + click: Some(Pricing { + min: 23.into(), + max: 100.into(), + }), + }); + + let event = Event::Close; + + let session = Session { + ip: None, + country: None, + referrer_header: None, + os: None, + }; + + let payout = get_payout(&channel, &event, &session).expect("Should be OK"); + + assert_eq!(None, payout, "pricingBounds: click event"); + } +} From c3325fdce4e679af24962c886569e046e27fb917 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 4 Sep 2020 13:27:06 +0300 Subject: [PATCH 13/27] primitives - targeting - eval - add Logging for TypeError --- Cargo.lock | 7 +++--- adview-manager/Cargo.toml | 2 ++ adview-manager/src/lib.rs | 15 +++++++++--- primitives/src/lib.rs | 8 +++++++ primitives/src/targeting/eval.rs | 27 +++++++++++++++++++-- sentry/src/analytics_recorder.rs | 2 +- sentry/src/event_aggregator.rs | 8 ++++++- sentry/src/event_reducer.rs | 40 ++++++++++++++++++------------- sentry/src/payout.rs | 41 +++++++++++++------------------- 9 files changed, 100 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03b44023e..3319e82d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,6 +40,7 @@ dependencies = [ "reqwest 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -989,7 +990,7 @@ dependencies = [ "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1238,7 +1239,7 @@ dependencies = [ "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "pin-project 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)", - "socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3906,7 +3907,7 @@ dependencies = [ "checksum ascii 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" "checksum async-std 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00d68a33ebc8b57800847d00787307f84a562224a14db069b0acefe4c2abbf5d" "checksum async-task 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c17772156ef2829aadc587461c7753af20b7e8db1529bc66855add962a3b35d3" -"checksum async-trait 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "750b1c38a1dfadd108da0f01c08f4cdc7ff1bb39b325f9c82cc972361780a6e1" +"checksum async-trait 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "687c230d85c0a52504709705fc8a53e4a692b83a2184f03dae73e38e1e93a783" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" diff --git a/adview-manager/Cargo.toml b/adview-manager/Cargo.toml index 379e3d277..ea1b49a12 100644 --- a/adview-manager/Cargo.toml +++ b/adview-manager/Cargo.toml @@ -14,6 +14,8 @@ serde = {version = "^1.0", features = ['derive']} serde_json = "^1.0" reqwest = { version = "0.10", features = ["json"] } url = { version = "^2.1", features = ["serde"]} +# Logging +slog = { version = "^2.5.2" , features = ["max_level_trace"] } # Async async-std = "1.6" # Other diff --git a/adview-manager/src/lib.rs b/adview-manager/src/lib.rs index 3b4bbba4e..040a48438 100644 --- a/adview-manager/src/lib.rs +++ b/adview-manager/src/lib.rs @@ -13,6 +13,7 @@ use lazy_static::lazy_static; use rand::Rng; use reqwest::StatusCode; use serde::{Deserialize, Serialize}; +use slog::{error, Logger}; use std::{cmp::Ordering, collections::VecDeque, convert::TryFrom, sync::Arc}; use thiserror::Error; use units_for_slot::response::UnitsWithPrice; @@ -279,16 +280,22 @@ pub struct Manager { /// It always trims to HISTORY_LIMIT, removing the oldest (firstly inserted) elements from the History history: Arc>>, client: reqwest::Client, + logger: Logger, } impl Manager { - pub fn new(options: Options, history: VecDeque) -> Result { + pub fn new( + options: Options, + history: VecDeque, + logger: Logger, + ) -> Result { let client = reqwest::Client::builder().build()?; Ok(Self { options, history: Arc::new(RwLock::new(history)), client, + logger, }) } @@ -488,11 +495,13 @@ impl Manager { .collect(), }; - // TODO: Logging for `eval_multiple` - targeting::eval_multiple( + let on_type_error = |error, rule| error!(&self.logger, "Rule evaluation error for {:?}", campaign_id; "error" => ?error, "rule" => ?rule); + + targeting::eval_with_callback( &campaign.targeting_rules, &input::Input::Getter(campaign_input.clone()), &mut output, + Some(on_type_error) ); output.show diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index ecdbe6589..5d45d5325 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -21,8 +21,16 @@ pub mod targeting_tag; pub mod util { pub mod tests { + use slog::{o, Discard, Drain, Logger}; + pub mod prep_db; pub mod time; + + pub fn discard_logger() -> Logger { + let drain = Discard.fuse(); + + Logger::root(drain, o!()) + } } pub mod logging; diff --git a/primitives/src/targeting/eval.rs b/primitives/src/targeting/eval.rs index 3dea256c8..b1f31fd62 100644 --- a/primitives/src/targeting/eval.rs +++ b/primitives/src/targeting/eval.rs @@ -967,11 +967,11 @@ pub fn eval_multiple( rules: &[Rule], input: &Input, output: &mut Output, -) -> Vec, Error>> { +) -> Vec, (Error, Rule)>> { let mut results = vec![]; for rule in rules { - results.push(rule.eval(input, output)); + results.push(rule.eval(input, output).map_err(|err| (err, rule.clone()))); if !output.show { break; @@ -981,6 +981,29 @@ pub fn eval_multiple( results } +pub fn eval_with_callback( + rules: &[Rule], + input: &Input, + output: &mut Output, + on_type_error: Option, +) { + for result in eval_multiple(rules, input, output) { + match (result, on_type_error.as_ref()) { + (Ok(_), _) => {} + (Err((Error::UnknownVariable, _)), _) => {} + (Err((Error::TypeError, rule)), Some(on_type_error)) => { + on_type_error(Error::TypeError, rule) + } + // skip any other case, including Error::TypeError if there is no passed function + _ => {} + } + + if !output.show { + return; + } + } +} + enum MathOperator { Division, Multiplication, diff --git a/sentry/src/analytics_recorder.rs b/sentry/src/analytics_recorder.rs index ce0e43a24..6e3c6a296 100644 --- a/sentry/src/analytics_recorder.rs +++ b/sentry/src/analytics_recorder.rs @@ -35,7 +35,7 @@ pub async fn record( } => { let divisor = BigNum::from(10u64.pow(18)); // @Todo: Check this! - let pay_amount = get_payout(&channel, event, &session) + let pay_amount = get_payout(&logger, &channel, event, &session) .expect("should have payout") .map(|(_, payout)| payout) .unwrap_or_default() diff --git a/sentry/src/event_aggregator.rs b/sentry/src/event_aggregator.rs index d4a9be855..72d0ca3ea 100644 --- a/sentry/src/event_aggregator.rs +++ b/sentry/src/event_aggregator.rs @@ -144,7 +144,13 @@ impl EventAggregator { })?; events.iter().for_each(|ev| { - match event_reducer::reduce(&record.channel, &mut record.aggregate, ev, &session) { + match event_reducer::reduce( + &app.logger, + &record.channel, + &mut record.aggregate, + ev, + &session, + ) { Ok(_) => {} Err(err) => error!(&app.logger, "Event Reducer failed"; "error" => ?err ), } diff --git a/sentry/src/event_reducer.rs b/sentry/src/event_reducer.rs index 1353ffbb2..09782f3e8 100644 --- a/sentry/src/event_reducer.rs +++ b/sentry/src/event_reducer.rs @@ -1,9 +1,12 @@ -use crate::payout::get_payout; -use crate::Session; -use primitives::sentry::{AggregateEvents, Event, EventAggregate}; -use primitives::{BigNum, Channel, ValidatorId}; +use crate::{payout::get_payout, Session}; +use primitives::{ + sentry::{AggregateEvents, Event, EventAggregate}, + BigNum, Channel, ValidatorId, +}; +use slog::Logger; pub(crate) fn reduce( + logger: &Logger, channel: &Channel, initial_aggr: &mut EventAggregate, ev: &Event, @@ -13,8 +16,8 @@ pub(crate) fn reduce( match ev { Event::Impression { publisher, .. } => { let impression = initial_aggr.events.get(&event_type); - let payout = get_payout(&channel, &ev, session)?; - let merge = merge_impression_ev( + let payout = get_payout(logger, &channel, &ev, session)?; + let merge = merge_payable_event( impression, payout.unwrap_or_else(|| (*publisher, Default::default())), ); @@ -23,8 +26,8 @@ pub(crate) fn reduce( } Event::Click { publisher, .. } => { let clicks = initial_aggr.events.get(&event_type); - let payout = get_payout(&channel, &ev, session)?; - let merge = merge_impression_ev( + let payout = get_payout(logger, &channel, &ev, session)?; + let merge = merge_payable_event( clicks, payout.unwrap_or_else(|| (*publisher, Default::default())), ); @@ -46,13 +49,14 @@ pub(crate) fn reduce( Ok(()) } -fn merge_impression_ev( - impression: Option<&AggregateEvents>, +/// payable_event is either an IMPRESSION or a CLICK +fn merge_payable_event( + payable_event: Option<&AggregateEvents>, payout: (ValidatorId, BigNum), ) -> AggregateEvents { - let mut impression = impression.map(Clone::clone).unwrap_or_default(); + let mut payable_event = payable_event.cloned().unwrap_or_default(); - let event_count = impression + let event_count = payable_event .event_counts .get_or_insert_with(Default::default) .entry(payout.0) @@ -60,24 +64,28 @@ fn merge_impression_ev( *event_count += &1.into(); - let event_payouts = impression + let event_payouts = payable_event .event_payouts .entry(payout.0) .or_insert_with(|| 0.into()); *event_payouts += &payout.1; - impression + payable_event } #[cfg(test)] mod test { use super::*; use chrono::Utc; - use primitives::util::tests::prep_db::{DUMMY_CHANNEL, IDS}; + use primitives::util::tests::{ + discard_logger, + prep_db::{DUMMY_CHANNEL, IDS}, + }; use primitives::BigNum; #[test] fn test_reduce() { + let logger = discard_logger(); let mut channel: Channel = DUMMY_CHANNEL.clone(); channel.deposit_amount = 100.into(); // make immutable again @@ -104,7 +112,7 @@ mod test { }; for i in 0..101 { - reduce(&channel, &mut event_aggr, &event, &session) + reduce(&logger, &channel, &mut event_aggr, &event, &session) .expect(&format!("Should be able to reduce event #{}", i)); } diff --git a/sentry/src/payout.rs b/sentry/src/payout.rs index c9c5d324d..9bffc4bee 100644 --- a/sentry/src/payout.rs +++ b/sentry/src/payout.rs @@ -2,9 +2,10 @@ use crate::Session; use chrono::Utc; use primitives::{ sentry::Event, - targeting::{get_pricing_bounds, input, Error, Error as EvalError, Input, Output, Rule, eval_multiple}, + targeting::{eval_with_callback, get_pricing_bounds, input, Error, Output}, BigNum, Channel, ValidatorId, }; +use slog::{error, Logger}; use std::{ cmp::{max, min}, convert::TryFrom, @@ -12,7 +13,7 @@ use std::{ type Result = std::result::Result, Error>; -pub fn get_payout(channel: &Channel, event: &Event, session: &Session) -> Result { +pub fn get_payout(logger: &Logger, channel: &Channel, event: &Event, session: &Session) -> Result { let event_type = event.to_string(); match event { @@ -77,7 +78,9 @@ pub fn get_payout(channel: &Channel, event: &Event, session: &Session) -> Result .collect(), }; - eval_and_log(&targeting_rules, &input, &mut output); + let on_type_error = |error, rule| error!(logger, "Rule evaluation error for {:?}", channel.id; "error" => ?error, "rule" => ?rule); + + eval_with_callback(&targeting_rules, &input, &mut output, Some(on_type_error)); if output.show { let price = match output.price.get(&event_type) { @@ -97,31 +100,19 @@ pub fn get_payout(channel: &Channel, event: &Event, session: &Session) -> Result } } -fn eval_and_log(/* logger: &Logger, channel_id: ChannelId, */rules: &[Rule], input: &Input, output: &mut Output) { - for result in eval_multiple(rules, input, output) { - match result { - Ok(_) => {} - Err(EvalError::UnknownVariable) => {} - Err(EvalError::TypeError) => { - todo!(); - // error!(logger, "`WARNING: rule for {:?} failing", channel_id; "rule" => rule, "err" => ?result) - } - } - - if !output.show { - return; - } - } -} - #[cfg(test)] mod test { use super::*; use primitives::channel::{Pricing, PricingBounds}; - use primitives::util::tests::prep_db::{DUMMY_CHANNEL, IDS}; + use primitives::util::tests::{ + discard_logger, + prep_db::{DUMMY_CHANNEL, IDS}, + }; #[test] fn get_event_payouts_pricing_bounds_impression_event() { + let logger = discard_logger(); + let mut channel = DUMMY_CHANNEL.clone(); channel.deposit_amount = 100.into(); channel.spec.min_per_impression = 8.into(); @@ -148,7 +139,7 @@ mod test { os: None, }; - let payout = get_payout(&channel, &event, &session).expect("Should be OK"); + let payout = get_payout(&logger, &channel, &event, &session).expect("Should be OK"); let expected_option = Some((IDS["leader"], 8.into())); assert_eq!(expected_option, payout, "pricingBounds: impression event"); @@ -156,6 +147,7 @@ mod test { #[test] fn get_event_payouts_pricing_bounds_click_event() { + let logger = discard_logger(); let mut channel = DUMMY_CHANNEL.clone(); channel.deposit_amount = 100.into(); channel.spec.min_per_impression = 8.into(); @@ -182,7 +174,7 @@ mod test { os: None, }; - let payout = get_payout(&channel, &event, &session).expect("Should be OK"); + let payout = get_payout(&logger, &channel, &event, &session).expect("Should be OK"); let expected_option = Some((IDS["leader"], 23.into())); assert_eq!(expected_option, payout, "pricingBounds: click event"); @@ -190,6 +182,7 @@ mod test { #[test] fn get_event_payouts_pricing_bounds_close_event() { + let logger = discard_logger(); let mut channel = DUMMY_CHANNEL.clone(); channel.deposit_amount = 100.into(); channel.spec.min_per_impression = 8.into(); @@ -211,7 +204,7 @@ mod test { os: None, }; - let payout = get_payout(&channel, &event, &session).expect("Should be OK"); + let payout = get_payout(&logger, &channel, &event, &session).expect("Should be OK"); assert_eq!(None, payout, "pricingBounds: click event"); } From e8f8a9092eae08003afba35a0d17da2dc7423483 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Tue, 8 Sep 2020 13:18:20 +0300 Subject: [PATCH 14/27] sentry - analytics_recorder - check TODO and impl changes --- sentry/src/analytics_recorder.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sentry/src/analytics_recorder.rs b/sentry/src/analytics_recorder.rs index 6e3c6a296..1d2bb8a07 100644 --- a/sentry/src/analytics_recorder.rs +++ b/sentry/src/analytics_recorder.rs @@ -34,14 +34,18 @@ pub async fn record( referrer, } => { let divisor = BigNum::from(10u64.pow(18)); - // @Todo: Check this! - let pay_amount = get_payout(&logger, &channel, event, &session) - .expect("should have payout") - .map(|(_, payout)| payout) - .unwrap_or_default() - .div_floor(&divisor) - .to_f64() - .expect("should always have a payout"); + + let pay_amount = match get_payout(&channel, event, &session) { + Ok(Some((_, payout))) => payout.div_floor(&divisor) + .to_f64() + .expect("Should always have a payout in f64 after division"), + // This should never happen, as the conditions we are checking for in the .filter are the same as getPayout's + Ok(None) => return, + Err(err) => { + error!(&logger, "Getting the payout failed: {}", &err; "module" => "analytics-recorder", "err" => ?err); + return + }, + }; if let Some(ad_unit) = ad_unit { db.zincr( From 545c15797f3df1c56e9e03aa0053614aaaaaf65e Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 11 Sep 2020 15:00:42 +0300 Subject: [PATCH 15/27] sentry - analytics_recorder - pass Logger to get_payout --- sentry/src/analytics_recorder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry/src/analytics_recorder.rs b/sentry/src/analytics_recorder.rs index 1d2bb8a07..0e6469e31 100644 --- a/sentry/src/analytics_recorder.rs +++ b/sentry/src/analytics_recorder.rs @@ -35,7 +35,7 @@ pub async fn record( } => { let divisor = BigNum::from(10u64.pow(18)); - let pay_amount = match get_payout(&channel, event, &session) { + let pay_amount = match get_payout(&logger, &channel, event, &session) { Ok(Some((_, payout))) => payout.div_floor(&divisor) .to_f64() .expect("Should always have a payout in f64 after division"), From 2d7fbeda4b91ed397ae573613ea0ae1ffd0c5089 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Mon, 14 Sep 2020 13:29:46 +0300 Subject: [PATCH 16/27] primitives - ipfs - fix test --- primitives/src/ipfs.rs | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/primitives/src/ipfs.rs b/primitives/src/ipfs.rs index e28b1b431..c53de375d 100644 --- a/primitives/src/ipfs.rs +++ b/primitives/src/ipfs.rs @@ -163,18 +163,25 @@ impl fmt::Debug for Url { mod test { use super::*; - static TESTS_IPFS_V1: [&str; 4] = [ + // CID V0 + static TESTS_IPFS_V0: [&str; 4] = [ "QmcUVX7fvoLMM93uN2bD3wGTH8MXSxeL8hojYfL2Lhp7mR", "Qmasg8FrbuSQpjFu3kRnZF9beg8rEBFrqgi1uXDRwCbX5f", "QmQnu8zrHsuVvnTJsEgDHYA8c1MmRL7YLiMD8uzDUJKcNq", "QmYYBULc9QDEaDr8HAXvVWHDmFfL2GvyumYRr1g4ERBC96", ]; + // CID V1 + static TESTS_IPFS_V1: [&str; 1] = [ + // V1 of the V0 ipfs: `QmcUVX7fvoLMM93uN2bD3wGTH8MXSxeL8hojYfL2Lhp7mR` + "bafybeif2h3mynaf3ylgdbs6arf6mczqycargt5cqm3rmel3wpjarlswway", + ]; + #[test] fn ipfs_from_string_and_serialize_deserialize() { - for &ipfs_str in TESTS_IPFS_V1.iter() { + let check = |ipfs_str: &str, version: cid::Version| { let ipfs = IPFS::try_from(ipfs_str).expect("should be ok"); - assert_eq!(ipfs.0.version(), cid::Version::V0); + assert_eq!(ipfs.0.version(), version); assert_eq!(ipfs.0.to_string(), ipfs_str); let expected_json = format!("\"{}\"", ipfs); @@ -185,6 +192,15 @@ mod test { ipfs, serde_json::from_str(&actual_json).expect("Should Deserialize") ) + }; + + + for &ipfs_str in TESTS_IPFS_V0.iter() { + check(ipfs_str, cid::Version::V0) + } + + for &ipfs_str in TESTS_IPFS_V1.iter() { + check(ipfs_str, cid::Version::V1) } } @@ -216,15 +232,20 @@ mod test { } // Invalid cases - // CID V1 - Invalid scheme - valid IPFS + // CID V0 - Invalid scheme - valid IPFS assert_eq!( Err(UrlError::NoPrefix), "https://QmcUVX7fvoLMM93uN2bD3wGTH8MXSxeL8hojYfL2Lhp7mR".parse::() ); - // CID V1 - Invalid scheme - valid IPFS + // CID V0 - Invalid scheme - valid IPFS assert_eq!( Err(UrlError::IPFS(cid::Error::ParsingError)), "ipfs://NotValid".parse::() ); + // CID V1 - Invalid scheme - valid IPFS + assert_eq!( + Err(UrlError::NoPrefix), + "https://bafybeif2h3mynaf3ylgdbs6arf6mczqycargt5cqm3rmel3wpjarlswway".parse::() + ); } } From ba2a94f68172f7e1bf22fddddfb14c50e0e5130b Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Tue, 15 Sep 2020 12:27:33 +0300 Subject: [PATCH 17/27] Cargo.toml - primitives, adview-manager, sentry, validator_worker - Update deps --- Cargo.lock | 115 +++++++++++++++++------------------- adview-manager/Cargo.toml | 2 +- primitives/Cargo.toml | 6 +- sentry/Cargo.toml | 2 +- validator_worker/Cargo.toml | 6 +- 5 files changed, 62 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3969bc18f..4790f91ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,7 +34,7 @@ dependencies = [ "async-std 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "primitives 0.1.0", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -345,7 +345,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-padding 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -455,8 +455,8 @@ name = "chrono" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -695,7 +695,7 @@ name = "digest" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "generic-array 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1084,7 +1084,7 @@ name = "generic-array" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1092,15 +1092,15 @@ name = "generic-array" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "generic-array" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1181,6 +1181,11 @@ name = "hex" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "hex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "hmac" version = "0.5.0" @@ -1557,7 +1562,7 @@ dependencies = [ "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1804,26 +1809,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-bigint" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1832,18 +1826,17 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-complex" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1858,37 +1851,37 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-iter" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-rational" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2313,13 +2306,13 @@ dependencies = [ "cid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "fake 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "merkletree 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "postgres-types 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2875,7 +2868,7 @@ dependencies = [ "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "migrant_lib 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3658,7 +3651,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "typenum" -version = "1.11.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -3767,10 +3760,10 @@ dependencies = [ "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "primitives 0.1.0", "reqwest 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4182,7 +4175,7 @@ dependencies = [ "checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum generic-array 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)" = "60fb4bb6bba52f78a471264d9a3b7d026cc0af47b22cd2cffbc0b787ca003e63" +"checksum generic-array 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" "checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" @@ -4192,6 +4185,7 @@ dependencies = [ "checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" +"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" "checksum hmac 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44f3bdb08579d99d7dc761c0e266f13b5f2ab8c8c703b9fc9ef333cd8f48f55e" "checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" "checksum hmac-drbg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" @@ -4255,15 +4249,14 @@ dependencies = [ "checksum native-tls 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" -"checksum num 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" -"checksum num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +"checksum num 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab3e176191bc4faad357e3122c4747aa098ac880e88b168f106386128736cf4a" "checksum num-bigint 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b7f3fc75e3697059fb1bc465e3d8cca6cf92f56854f201158b3f9c77d5a3cfa0" -"checksum num-complex 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +"checksum num-complex 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b05ad05bd8977050b171b3f6b48175fea6e0565b7981059b486075e1026a9fb5" "checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" -"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" -"checksum num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" -"checksum num-rational 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" -"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +"checksum num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" +"checksum num-iter 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f" +"checksum num-rational 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b4d7360f362cfb50dde8143501e6940b22f644be75a4cc90b2d81968908138" +"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" "checksum once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" @@ -4440,7 +4433,7 @@ dependencies = [ "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" -"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" +"checksum typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" "checksum uint 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e75a4cdd7b87b28840dba13c483b9a88ee6bbf16ba5c951ee1ecfcf723078e0d" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" diff --git a/adview-manager/Cargo.toml b/adview-manager/Cargo.toml index ea1b49a12..adc88df7c 100644 --- a/adview-manager/Cargo.toml +++ b/adview-manager/Cargo.toml @@ -8,7 +8,7 @@ version = "0.1.0" # Domain adex_primitives = {path = "../primitives", package = "primitives"} chrono = "0.4" -num-bigint = {version = "0.3", features = ["serde"]} +num-integer = "0.1" # (De)Serialization & Http requests serde = {version = "^1.0", features = ['derive']} serde_json = "^1.0" diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 03989866f..5b4880a04 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -23,16 +23,16 @@ slog-async = "^2.3.0" thiserror = "^1.0" chrono = { version = "0.4", features = ["serde"] } time = "0.1.42" -hex = "0.3.2" # CID & multihash / multibase cid = "0.5" +hex = "0.4" merkletree = "0.10.0" tiny-keccak = "1.5" rust-crypto = "0.2" url = { version = "2.1", features = ["serde"]} # Numbers - BigNum, Numbers, Traits and Derives -num-bigint = { version = "0.2", features = ["serde"] } -num = "0.2.0" +num-bigint = { version = "^0.3", features = ["serde"] } +num = "0.3" num-traits = "0.2" num-derive = "0.2" # Fixtures diff --git a/sentry/Cargo.toml b/sentry/Cargo.toml index 870163b29..3b51fd072 100644 --- a/sentry/Cargo.toml +++ b/sentry/Cargo.toml @@ -12,7 +12,7 @@ async-std = "1.4.0" primitives = { path = "../primitives", features = ["postgres"] } adapter = { version = "0.1", path = "../adapter" } chrono = { version = "0.4", features = ["serde"] } -hex = "0.3.2" +hex = "0.4" # CLI clap = "2.33.0" # Server diff --git a/validator_worker/Cargo.toml b/validator_worker/Cargo.toml index 55eb88781..94e28d555 100644 --- a/validator_worker/Cargo.toml +++ b/validator_worker/Cargo.toml @@ -13,10 +13,10 @@ path = "src/lib.rs" primitives = { path = "../primitives" } adapter = { version = "0.1", path = "../adapter" } chrono = { version = "0.4", features = ["serde"] } -num = "0.2.0" -num-traits = "0.2.0" +num = "0.3" +num-traits = "0.2" # To/From Hex -hex = "0.3.2" +hex = "0.4" byteorder = "1.3" # Logging slog = { version = "^2.5.2" , features = ["max_level_trace"] } From 6886452ac09d9f21d0aec25ada268d3874d166f8 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Tue, 15 Sep 2020 12:28:25 +0300 Subject: [PATCH 18/27] primitives - AdUnit - use `primitives::IPFS` --- primitives/src/ad_unit.rs | 4 ++-- primitives/src/ipfs.rs | 13 +++++++++++++ primitives/src/supermarket.rs | 5 +++-- primitives/src/targeting.rs | 11 ++++++----- primitives/src/targeting/eval_test.rs | 4 ++-- primitives/src/util/tests/prep_db.rs | 13 ++++++++++++- sentry/src/payout.rs | 2 +- 7 files changed, 39 insertions(+), 13 deletions(-) diff --git a/primitives/src/ad_unit.rs b/primitives/src/ad_unit.rs index e5e0b56fe..86fd544e3 100644 --- a/primitives/src/ad_unit.rs +++ b/primitives/src/ad_unit.rs @@ -1,13 +1,13 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::ValidatorId; +use crate::{ValidatorId, IPFS}; #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct AdUnit { /// valid ipfs hash of spec props below - pub ipfs: String, + pub ipfs: IPFS, /// the type of the ad unit /// currently, possible values are: /// legacy_300x250, legacy_250x250, legacy_240x400, legacy_336x280, diff --git a/primitives/src/ipfs.rs b/primitives/src/ipfs.rs index c53de375d..5aae8a40a 100644 --- a/primitives/src/ipfs.rs +++ b/primitives/src/ipfs.rs @@ -5,6 +5,8 @@ use thiserror::Error; const URL_PREFIX: &str = "ipfs://"; +pub use cid::{Cid, Error}; + #[derive(Clone, Serialize, Deserialize, Eq, PartialEq)] #[serde(try_from = "String", into = "String")] pub struct IPFS(pub cid::Cid); @@ -43,6 +45,14 @@ impl TryFrom for IPFS { } } +impl TryFrom<&String> for IPFS { + type Error = cid::Error; + + fn try_from(value: &String) -> Result { + Self::try_from(value.as_str()) + } +} + impl<'a> TryFrom<&'a str> for IPFS { type Error = cid::Error; @@ -202,6 +212,9 @@ mod test { for &ipfs_str in TESTS_IPFS_V1.iter() { check(ipfs_str, cid::Version::V1) } + + // v0 != v1 + assert_ne!(IPFS::try_from(TESTS_IPFS_V0[0]), IPFS::try_from(TESTS_IPFS_V1[0])) } #[test] diff --git a/primitives/src/supermarket.rs b/primitives/src/supermarket.rs index 1d5f49e47..08af09bf9 100644 --- a/primitives/src/supermarket.rs +++ b/primitives/src/supermarket.rs @@ -42,9 +42,10 @@ pub enum Finalized { pub mod units_for_slot { pub mod response { + use crate::{ targeting::{Map, Rule}, - BigNum, ChannelId, ChannelSpec, SpecValidators, ValidatorId, + BigNum, ChannelId, ChannelSpec, SpecValidators, ValidatorId, IPFS, }; use chrono::{ serde::{ts_milliseconds, ts_milliseconds_option}, @@ -131,7 +132,7 @@ pub mod units_for_slot { #[serde(rename_all = "camelCase")] pub struct AdUnit { /// Same as `ipfs` - pub id: String, + pub id: IPFS, pub media_url: String, pub media_mime: String, pub target_url: String, diff --git a/primitives/src/targeting.rs b/primitives/src/targeting.rs index 7bdccf8d8..25cc40baf 100644 --- a/primitives/src/targeting.rs +++ b/primitives/src/targeting.rs @@ -43,7 +43,7 @@ pub mod input { match key { "adUnitId" => { let ipfs = self.ad_unit.as_ref().map(|ad_unit| ad_unit.id.clone()); - Ok(Value::String(ipfs.unwrap_or_default())) + Ok(Value::String(ipfs.map(|ipfs| ipfs.to_string()).unwrap_or_default())) } "advertiserId" if channel.is_some() => { @@ -336,8 +336,9 @@ pub mod input { .global .ad_unit .as_ref() - .map(|ad_unit| ad_unit.ipfs.clone()); - Ok(Value::String(ipfs.unwrap_or_default())) + .map(|ad_unit| ad_unit.ipfs.to_string()); + + Ok(Value::String(ipfs.unwrap_or_default())) } "advertiserId" => self .global @@ -461,13 +462,13 @@ pub mod input { #[cfg(test)] mod test { use super::*; - use crate::util::tests::prep_db::{DUMMY_CHANNEL, IDS}; + use crate::util::tests::prep_db::{DUMMY_CHANNEL, IDS, DUMMY_IPFS}; use chrono::Utc; #[test] fn test_try_get_of_input() { let ad_unit = AdUnit { - ipfs: "Hash".to_string(), + ipfs: DUMMY_IPFS[0].clone(), ad_type: "legacy_300x250".to_string(), media_url: "media_url".to_string(), media_mime: "media_mime".to_string(), diff --git a/primitives/src/targeting/eval_test.rs b/primitives/src/targeting/eval_test.rs index 42af8724a..45ec3bc3d 100644 --- a/primitives/src/targeting/eval_test.rs +++ b/primitives/src/targeting/eval_test.rs @@ -1,14 +1,14 @@ use super::*; use crate::{ targeting::input, - util::tests::prep_db::{DUMMY_CHANNEL, IDS}, + util::tests::prep_db::{DUMMY_CHANNEL, IDS, DUMMY_IPFS}, AdUnit, BalancesMap, }; use chrono::Utc; fn get_default_input() -> input::Source { let ad_unit = AdUnit { - ipfs: "Hash".to_string(), + ipfs: DUMMY_IPFS[0].clone(), ad_type: "legacy_300x250".to_string(), media_url: "media_url".to_string(), media_mime: "media_mime".to_string(), diff --git a/primitives/src/util/tests/prep_db.rs b/primitives/src/util/tests/prep_db.rs index 6fcb30fcf..e647681f7 100644 --- a/primitives/src/util/tests/prep_db.rs +++ b/primitives/src/util/tests/prep_db.rs @@ -1,7 +1,7 @@ use crate::{ channel::{Pricing, PricingBounds}, BigNum, Channel, ChannelId, ChannelSpec, EventSubmission, SpecValidators, ValidatorDesc, - ValidatorId, + ValidatorId, IPFS, }; use chrono::{TimeZone, Utc}; use fake::faker::{Faker, Number}; @@ -84,4 +84,15 @@ lazy_static! { }, } }; + + // CID V0 + pub static ref DUMMY_IPFS: [IPFS; 5] = [ + IPFS::try_from("QmcUVX7fvoLMM93uN2bD3wGTH8MXSxeL8hojYfL2Lhp7mR").expect("Valid IPFS V0"), + IPFS::try_from("Qmasg8FrbuSQpjFu3kRnZF9beg8rEBFrqgi1uXDRwCbX5f").expect("Valid IPFS V0"), + IPFS::try_from("QmQnu8zrHsuVvnTJsEgDHYA8c1MmRL7YLiMD8uzDUJKcNq").expect("Valid IPFS V0"), + IPFS::try_from("QmYYBULc9QDEaDr8HAXvVWHDmFfL2GvyumYRr1g4ERBC96").expect("Valid IPFS V0"), + // V1 of the V0 ipfs: `QmcUVX7fvoLMM93uN2bD3wGTH8MXSxeL8hojYfL2Lhp7mR` + IPFS::try_from("bafybeif2h3mynaf3ylgdbs6arf6mczqycargt5cqm3rmel3wpjarlswway").expect("Valid IPFS V1"), + ]; + } diff --git a/sentry/src/payout.rs b/sentry/src/payout.rs index 9bffc4bee..8bc9fb3bc 100644 --- a/sentry/src/payout.rs +++ b/sentry/src/payout.rs @@ -42,7 +42,7 @@ pub fn get_payout(logger: &Logger, channel: &Channel, event: &Event, session: &S } else { let ad_unit = ad_unit .as_ref() - .and_then(|ipfs| channel.spec.ad_units.iter().find(|u| &u.ipfs == ipfs)); + .and_then(|ipfs| channel.spec.ad_units.iter().find(|u| &u.ipfs.to_string() == ipfs)); let source = input::Source { ad_view: None, From 6a5150de407f827fa461b775c0c50ecd0151877e Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Tue, 15 Sep 2020 12:29:11 +0300 Subject: [PATCH 19/27] adview-manager - use `primitives::IPFS` & impl `randomized_sort_pos` --- adview-manager/src/lib.rs | 63 ++++++++++++++++++++++++++++----------- primitives/src/big_num.rs | 4 +++ 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/adview-manager/src/lib.rs b/adview-manager/src/lib.rs index 040a48438..8125ce634 100644 --- a/adview-manager/src/lib.rs +++ b/adview-manager/src/lib.rs @@ -5,16 +5,23 @@ use adex_primitives::{ supermarket::units_for_slot, supermarket::units_for_slot::response::{AdUnit, Campaign}, targeting::{self, input, Value}, - BigNum, ChannelId, SpecValidators, + BigNum, ChannelId, SpecValidators, IPFS, }; use async_std::{sync::RwLock, task::block_on}; use chrono::{DateTime, Utc}; use lazy_static::lazy_static; +use num_integer::Integer; use rand::Rng; use reqwest::StatusCode; use serde::{Deserialize, Serialize}; use slog::{error, Logger}; -use std::{cmp::Ordering, collections::VecDeque, convert::TryFrom, sync::Arc}; +use std::{ + cmp::Ordering, + collections::VecDeque, + convert::TryFrom, + ops::{Add, Mul}, + sync::Arc, +}; use thiserror::Error; use units_for_slot::response::UnitsWithPrice; use url::Url; @@ -44,7 +51,7 @@ pub struct Options { // Defaulted via defaultOpts #[serde(rename = "marketURL")] pub market_url: String, - pub market_slot: String, + pub market_slot: IPFS, pub publisher_addr: String, // All passed tokens must be of the same price and decimals, so that the amounts can be accurately compared pub whitelisted_tokens: Vec, @@ -66,9 +73,9 @@ impl Options { #[derive(Debug, Clone)] pub struct HistoryEntry { time: DateTime, - unit_id: String, + unit_id: IPFS, campaign_id: ChannelId, - slot_id: String, + slot_id: IPFS, } #[derive(Serialize)] @@ -77,8 +84,8 @@ struct Event { #[serde(rename = "type")] event_type: String, publisher: String, - ad_unit: String, - ad_slot: String, + ad_unit: IPFS, + ad_slot: IPFS, #[serde(rename = "ref")] referrer: String, } @@ -149,16 +156,15 @@ fn is_video(ad_unit: &AdUnit) -> bool { ad_unit.media_mime.split('/').next() == Some("video") } -// @TODO: IMPL -// function randomizedSortPos(unit: Unit, seed: BN): BN { -// // using base32 is technically wrong (IDs are in base 58), but it works well enough for this purpose -// // kind of a LCG PRNG but without the state; using GCC's constraints as seen on stack overflow -// // takes around ~700ms for 100k iterations, yields very decent distribution (e.g. 724ms 50070, 728ms 49936) -// return new BN(unit.id, 32).mul(seed).add(new BN(12345)).mod(new BN(0x80000000)) -// } -fn randomized_sort_pos(_ad_unit: &AdUnit, _seed: BigNum) -> BigNum { - // todo!("Implement the randomized_sort_pos() function!") - BigNum::from(10) +/// Does not copy the JS impl, instead it generates the BigNum from the IPFS CID bytes instead +fn randomized_sort_pos(ad_unit: &AdUnit, seed: BigNum) -> BigNum { + let bytes = ad_unit.id.0.to_bytes(); + + let unit_id = BigNum::from_bytes_be(&bytes); + + let x: BigNum = unit_id.mul(seed).add(BigNum::from(12345)); + + x.mod_floor(&BigNum::from(0x80000000)) } fn get_unit_html( @@ -605,10 +611,11 @@ pub struct StickyAdUnit { #[cfg(test)] mod test { use super::*; + use adex_primitives::util::tests::prep_db::DUMMY_IPFS; fn get_ad_unit(media_mime: &str) -> AdUnit { AdUnit { - id: "".to_string(), + id: DUMMY_IPFS[0].clone(), media_url: "".to_string(), media_mime: media_mime.to_string(), target_url: "".to_string(), @@ -633,4 +640,24 @@ mod test { // Non-IPFS case assert_eq!("http://123".to_string(), normalize_url("http://123")); } + + mod randomized_sort_pos { + + use super::*; + + #[test] + fn test_randomized_position() { + let ad_unit = AdUnit { + id: DUMMY_IPFS[0].clone(), + media_url: "ipfs://QmWWQSuPMS6aXCbZKpEjPHPUZN2NjB3YrhJTHsV4X3vb2t".to_string(), + media_mime: "image/jpeg".to_string(), + target_url: "https://google.com".to_string(), + }; + + let result = randomized_sort_pos(&ad_unit, 5.into()); + + // The seed is responsible for generating different results since the AdUnit IPFS can be the same + assert_eq!(BigNum::from(177_349_401), result); + } + } } diff --git a/primitives/src/big_num.rs b/primitives/src/big_num.rs index 38cdaa11c..a8863deaf 100644 --- a/primitives/src/big_num.rs +++ b/primitives/src/big_num.rs @@ -44,6 +44,10 @@ impl BigNum { pub fn to_str_radix(&self, radix: u32) -> String { self.0.to_str_radix(radix) } + + pub fn from_bytes_be(buf: &[u8]) -> Self { + Self(BigUint::from_bytes_be(buf)) + } } impl fmt::Debug for BigNum { From 69fba7950eef2e036027aa4af9bda923527b6eec Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Wed, 16 Sep 2020 13:58:18 +0300 Subject: [PATCH 20/27] adapter - Cargo - update `hex` to `0.4` --- Cargo.lock | 8 +------- adapter/Cargo.toml | 6 +++--- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4790f91ab..3ae93c733 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ dependencies = [ "ethkey 0.4.0 (git+https://github.com/paritytech/parity-ethereum)", "ethstore 0.2.1 (git+https://github.com/paritytech/parity-ethereum)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-crypto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "primitives 0.1.0", @@ -1176,11 +1176,6 @@ name = "hex" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "hex" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "hex" version = "0.4.2" @@ -4184,7 +4179,6 @@ dependencies = [ "checksum hashbrown 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead" "checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" -"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" "checksum hmac 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44f3bdb08579d99d7dc761c0e266f13b5f2ab8c8c703b9fc9ef333cd8f48f55e" "checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" diff --git a/adapter/Cargo.toml b/adapter/Cargo.toml index 3895e0922..af4fb7af6 100644 --- a/adapter/Cargo.toml +++ b/adapter/Cargo.toml @@ -5,12 +5,12 @@ authors = ["Lachezar Lechev , Omidiora Samuel Date: Wed, 16 Sep 2020 17:01:49 +0300 Subject: [PATCH 21/27] primitives - IPFS - V0 != V1 test --- primitives/src/ipfs.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/primitives/src/ipfs.rs b/primitives/src/ipfs.rs index 5aae8a40a..bceb942ae 100644 --- a/primitives/src/ipfs.rs +++ b/primitives/src/ipfs.rs @@ -204,7 +204,6 @@ mod test { ) }; - for &ipfs_str in TESTS_IPFS_V0.iter() { check(ipfs_str, cid::Version::V0) } @@ -214,7 +213,10 @@ mod test { } // v0 != v1 - assert_ne!(IPFS::try_from(TESTS_IPFS_V0[0]), IPFS::try_from(TESTS_IPFS_V1[0])) + assert_ne!( + IPFS::try_from(TESTS_IPFS_V0[0]), + IPFS::try_from(TESTS_IPFS_V1[0]) + ) } #[test] From 7fd8a4b9c39ba9cbb57367c7a90f07823af7643d Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Wed, 16 Sep 2020 17:06:10 +0300 Subject: [PATCH 22/27] More changes regarding IPFS --- adview-manager/src/lib.rs | 32 ++++++++++----------------- primitives/src/targeting.rs | 8 ++++--- primitives/src/targeting/eval_test.rs | 2 +- sentry/src/payout.rs | 10 ++++++--- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/adview-manager/src/lib.rs b/adview-manager/src/lib.rs index 8125ce634..afa119dc9 100644 --- a/adview-manager/src/lib.rs +++ b/adview-manager/src/lib.rs @@ -5,7 +5,7 @@ use adex_primitives::{ supermarket::units_for_slot, supermarket::units_for_slot::response::{AdUnit, Campaign}, targeting::{self, input, Value}, - BigNum, ChannelId, SpecValidators, IPFS, + BigNum, ChannelId, SpecValidators, ValidatorId, IPFS, }; use async_std::{sync::RwLock, task::block_on}; use chrono::{DateTime, Utc}; @@ -42,17 +42,13 @@ lazy_static! { #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -// const defaultOpts = { -// marketURL: 'https://market.moonicorn.network', -// whitelistedTokens: ['0x6B175474E89094C44Da98b954EedeAC495271d0F'], -// disableVideo: false, -// } +// TODO: Add Default Ops somehow? pub struct Options { // Defaulted via defaultOpts #[serde(rename = "marketURL")] - pub market_url: String, + pub market_url: Url, pub market_slot: IPFS, - pub publisher_addr: String, + pub publisher_addr: ValidatorId, // All passed tokens must be of the same price and decimals, so that the amounts can be accurately compared pub whitelisted_tokens: Vec, pub width: Option, @@ -83,7 +79,7 @@ pub struct HistoryEntry { struct Event { #[serde(rename = "type")] event_type: String, - publisher: String, + publisher: ValidatorId, ad_unit: IPFS, ad_slot: IPFS, #[serde(rename = "ref")] @@ -156,7 +152,7 @@ fn is_video(ad_unit: &AdUnit) -> bool { ad_unit.media_mime.split('/').next() == Some("video") } -/// Does not copy the JS impl, instead it generates the BigNum from the IPFS CID bytes instead +/// Does not copy the JS impl, instead it generates the BigNum from the IPFS CID bytes fn randomized_sort_pos(ad_unit: &AdUnit, seed: BigNum) -> BigNum { let bytes = ad_unit.id.0.to_bytes(); @@ -220,7 +216,7 @@ pub fn get_unit_html_with_events( let get_body = |event_type: &str| EventBody { events: vec![Event { event_type: event_type.to_string(), - publisher: options.publisher_addr.clone(), + publisher: options.publisher_addr, ad_unit: ad_unit.id.clone(), ad_slot: options.market_slot.clone(), referrer: "document.referrer".to_string(), @@ -405,13 +401,7 @@ impl Manager { pub async fn get_market_demand_resp( &self, ) -> Result { - let pub_prefix: String = self - .options - .publisher_addr - .chars() - .skip(2) - .take(10) - .collect(); + let pub_prefix: String = self.options.publisher_addr.to_hex_non_prefix_string(); let deposit_asset = self .options @@ -421,8 +411,10 @@ impl Manager { .collect::>() .join("&"); + + // Url adds a trailing `/` let url = format!( - "{}/units-for-slot/{}?pubPrefix={}&{}", + "{}units-for-slot/{}?pubPrefix={}&{}", self.options.market_url, self.options.market_slot, pub_prefix, deposit_asset ); @@ -562,7 +554,7 @@ impl Manager { None } }) - // TODO: Check what should happen here + // TODO: Check what should happen here if we don't find the Validator .unwrap(); let html = get_unit_html_with_events( diff --git a/primitives/src/targeting.rs b/primitives/src/targeting.rs index 25cc40baf..d476fdab0 100644 --- a/primitives/src/targeting.rs +++ b/primitives/src/targeting.rs @@ -43,7 +43,9 @@ pub mod input { match key { "adUnitId" => { let ipfs = self.ad_unit.as_ref().map(|ad_unit| ad_unit.id.clone()); - Ok(Value::String(ipfs.map(|ipfs| ipfs.to_string()).unwrap_or_default())) + Ok(Value::String( + ipfs.map(|ipfs| ipfs.to_string()).unwrap_or_default(), + )) } "advertiserId" if channel.is_some() => { @@ -338,7 +340,7 @@ pub mod input { .as_ref() .map(|ad_unit| ad_unit.ipfs.to_string()); - Ok(Value::String(ipfs.unwrap_or_default())) + Ok(Value::String(ipfs.unwrap_or_default())) } "advertiserId" => self .global @@ -462,7 +464,7 @@ pub mod input { #[cfg(test)] mod test { use super::*; - use crate::util::tests::prep_db::{DUMMY_CHANNEL, IDS, DUMMY_IPFS}; + use crate::util::tests::prep_db::{DUMMY_CHANNEL, DUMMY_IPFS, IDS}; use chrono::Utc; #[test] diff --git a/primitives/src/targeting/eval_test.rs b/primitives/src/targeting/eval_test.rs index 45ec3bc3d..5f47dfa2a 100644 --- a/primitives/src/targeting/eval_test.rs +++ b/primitives/src/targeting/eval_test.rs @@ -1,7 +1,7 @@ use super::*; use crate::{ targeting::input, - util::tests::prep_db::{DUMMY_CHANNEL, IDS, DUMMY_IPFS}, + util::tests::prep_db::{DUMMY_CHANNEL, DUMMY_IPFS, IDS}, AdUnit, BalancesMap, }; use chrono::Utc; diff --git a/sentry/src/payout.rs b/sentry/src/payout.rs index 8bc9fb3bc..c1a742670 100644 --- a/sentry/src/payout.rs +++ b/sentry/src/payout.rs @@ -40,9 +40,13 @@ pub fn get_payout(logger: &Logger, channel: &Channel, event: &Event, session: &S if targeting_rules.is_empty() { Ok(Some((*publisher, pricing.min))) } else { - let ad_unit = ad_unit - .as_ref() - .and_then(|ipfs| channel.spec.ad_units.iter().find(|u| &u.ipfs.to_string() == ipfs)); + let ad_unit = ad_unit.as_ref().and_then(|ipfs| { + channel + .spec + .ad_units + .iter() + .find(|u| &u.ipfs.to_string() == ipfs) + }); let source = input::Source { ad_view: None, From a55636ee0f4c847da1c55f234913e27aeebf702a Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Tue, 20 Oct 2020 18:57:59 +0300 Subject: [PATCH 23/27] primitives - targeting - eval - Value serialize to serde_json::Value --- primitives/src/targeting/eval.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/primitives/src/targeting/eval.rs b/primitives/src/targeting/eval.rs index b1f31fd62..3e543d851 100644 --- a/primitives/src/targeting/eval.rs +++ b/primitives/src/targeting/eval.rs @@ -83,7 +83,7 @@ impl Rule { } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[serde(try_from = "SerdeValue")] +#[serde(try_from = "SerdeValue", into = "SerdeValue")] pub enum Value { Bool(bool), Number(Number), @@ -124,6 +124,18 @@ impl TryFrom for Value { } } +impl Into for Value { + fn into(self) -> SerdeValue { + match self { + Value::Bool(bool) => SerdeValue::Bool(bool), + Value::Number(number) => SerdeValue::Number(number), + Value::String(string) => SerdeValue::String(string), + Value::Array(array) => SerdeValue::Array(array.into_iter().map(|value| value.into()).collect()), + Value::BigNum(bignum) => SerdeValue::String(bignum.to_string()) + } + } +} + #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] // TODO: https://github.com/AdExNetwork/adex-validator-stack-rust/issues/296 From cb89066632dab057843e119bd95aa022972c77a2 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Tue, 20 Oct 2020 19:29:18 +0300 Subject: [PATCH 24/27] derive Eq & PartialEq for primitives --- primitives/src/ad_unit.rs | 2 +- primitives/src/channel.rs | 10 +++++----- primitives/src/event_submission.rs | 6 +++--- primitives/src/supermarket.rs | 4 ++-- primitives/src/validator.rs | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/primitives/src/ad_unit.rs b/primitives/src/ad_unit.rs index 86fd544e3..a2f38218c 100644 --- a/primitives/src/ad_unit.rs +++ b/primitives/src/ad_unit.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::{ValidatorId, IPFS}; -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct AdUnit { /// valid ipfs hash of spec props below diff --git a/primitives/src/channel.rs b/primitives/src/channel.rs index 2d78de670..51dafc9f0 100644 --- a/primitives/src/channel.rs +++ b/primitives/src/channel.rs @@ -74,7 +74,7 @@ impl fmt::Display for ChannelId { } } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Channel { pub id: ChannelId, @@ -88,13 +88,13 @@ pub struct Channel { pub spec: ChannelSpec, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] pub struct Pricing { pub max: BigNum, pub min: BigNum, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] #[serde(rename_all = "UPPERCASE")] pub struct PricingBounds { #[serde(default, skip_serializing_if = "Option::is_none")] @@ -127,7 +127,7 @@ impl PricingBounds { } } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct ChannelSpec { #[serde(default, skip_serializing_if = "Option::is_none")] @@ -172,7 +172,7 @@ pub struct ChannelSpec { pub targeting_rules: Vec, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] /// A (leader, follower) tuple pub struct SpecValidators(ValidatorDesc, ValidatorDesc); diff --git a/primitives/src/event_submission.rs b/primitives/src/event_submission.rs index 3086242e5..d6205c615 100644 --- a/primitives/src/event_submission.rs +++ b/primitives/src/event_submission.rs @@ -1,13 +1,13 @@ use serde::{Deserialize, Serialize}; use std::time::Duration; -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] pub struct EventSubmission { #[serde(default)] pub allow: Vec, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Rule { #[serde(default)] @@ -16,7 +16,7 @@ pub struct Rule { pub rate_limit: Option, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct RateLimit { /// "ip", "uid" diff --git a/primitives/src/supermarket.rs b/primitives/src/supermarket.rs index 08af09bf9..5d8c3fbbb 100644 --- a/primitives/src/supermarket.rs +++ b/primitives/src/supermarket.rs @@ -1,6 +1,6 @@ use crate::{BalancesMap, Channel}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Campaign { pub channel: Channel, pub status: Status, @@ -128,7 +128,7 @@ pub mod units_for_slot { } } - #[derive(Debug, Serialize, Deserialize, Clone)] + #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct AdUnit { /// Same as `ipfs` diff --git a/primitives/src/validator.rs b/primitives/src/validator.rs index 1999453a4..32ade355c 100644 --- a/primitives/src/validator.rs +++ b/primitives/src/validator.rs @@ -138,7 +138,7 @@ impl TryFrom for ValidatorId { } } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct ValidatorDesc { pub id: ValidatorId, From 72059fa07e7397e74a01d569350cd49532593505 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 23 Oct 2020 13:18:31 +0300 Subject: [PATCH 25/27] primitives - supermarket - derive(PartialEq) --- primitives/src/supermarket.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/primitives/src/supermarket.rs b/primitives/src/supermarket.rs index 5d8c3fbbb..3f7acd564 100644 --- a/primitives/src/supermarket.rs +++ b/primitives/src/supermarket.rs @@ -54,7 +54,7 @@ pub mod units_for_slot { use serde::{Deserialize, Serialize}; use url::Url; - #[derive(Debug, Serialize, Deserialize)] + #[derive(Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Response { pub targeting_input_base: Map, @@ -63,14 +63,14 @@ pub mod units_for_slot { pub campaigns: Vec, } - #[derive(Debug, Clone, Serialize, Deserialize)] + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct UnitsWithPrice { pub unit: AdUnit, pub price: BigNum, } - #[derive(Debug, Clone, Serialize, Deserialize)] + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Campaign { #[serde(flatten)] @@ -79,7 +79,7 @@ pub mod units_for_slot { pub units_with_price: Vec, } - #[derive(Debug, Clone, Serialize, Deserialize)] + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Channel { pub id: ChannelId, @@ -101,7 +101,7 @@ pub mod units_for_slot { } } - #[derive(Debug, Clone, Serialize, Deserialize)] + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Spec { #[serde(with = "ts_milliseconds")] From 665bebbab49888d8d1a9a57745915ce67aa0997f Mon Sep 17 00:00:00 2001 From: simzzz Date: Mon, 26 Oct 2020 14:03:53 +0200 Subject: [PATCH 26/27] added total field and pages field to ChannelListResponse --- primitives/src/sentry.rs | 2 ++ sentry/src/db/channel.rs | 3 +++ sentry/src/routes/channel.rs | 1 + 3 files changed, 6 insertions(+) diff --git a/primitives/src/sentry.rs b/primitives/src/sentry.rs index 55822e21c..4428dbbe7 100644 --- a/primitives/src/sentry.rs +++ b/primitives/src/sentry.rs @@ -127,6 +127,8 @@ pub struct AggregateEvents { pub struct ChannelListResponse { pub channels: Vec, pub total_pages: u64, + pub total: u64, + pub page: u64, } #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] diff --git a/sentry/src/db/channel.rs b/sentry/src/db/channel.rs index 504020767..dd4bdc053 100644 --- a/sentry/src/db/channel.rs +++ b/sentry/src/db/channel.rs @@ -125,6 +125,7 @@ mod list_channels { creator: &Option, validator: &Option, valid_until_ge: &DateTime, + page: u64, ) -> Result> { let validator = validator.as_ref().map(|validator_id| { serde_json::Value::from_str(&format!(r#"[{{"id": "{}"}}]"#, validator_id)) @@ -168,6 +169,8 @@ mod list_channels { Ok(ChannelListResponse { total_pages, + total: total_pages, + page, channels, }) } diff --git a/sentry/src/routes/channel.rs b/sentry/src/routes/channel.rs index af15e5b87..9bc9931ca 100644 --- a/sentry/src/routes/channel.rs +++ b/sentry/src/routes/channel.rs @@ -89,6 +89,7 @@ pub async fn channel_list( &query.creator, &query.validator, &query.valid_until_ge, + query.page, ) .await?; From 99282901f2ab51fdec322f29c80a72c79b4e283c Mon Sep 17 00:00:00 2001 From: simzzz Date: Mon, 26 Oct 2020 19:50:08 +0200 Subject: [PATCH 27/27] manually getting current page instead of passing the variable around --- sentry/src/db/channel.rs | 3 +-- sentry/src/routes/channel.rs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/sentry/src/db/channel.rs b/sentry/src/db/channel.rs index dd4bdc053..ab983c610 100644 --- a/sentry/src/db/channel.rs +++ b/sentry/src/db/channel.rs @@ -125,7 +125,6 @@ mod list_channels { creator: &Option, validator: &Option, valid_until_ge: &DateTime, - page: u64, ) -> Result> { let validator = validator.as_ref().map(|validator_id| { serde_json::Value::from_str(&format!(r#"[{{"id": "{}"}}]"#, validator_id)) @@ -170,7 +169,7 @@ mod list_channels { Ok(ChannelListResponse { total_pages, total: total_pages, - page, + page: skip / limit as u64, channels, }) } diff --git a/sentry/src/routes/channel.rs b/sentry/src/routes/channel.rs index 9bc9931ca..af15e5b87 100644 --- a/sentry/src/routes/channel.rs +++ b/sentry/src/routes/channel.rs @@ -89,7 +89,6 @@ pub async fn channel_list( &query.creator, &query.validator, &query.valid_until_ge, - query.page, ) .await?;