diff --git a/Cargo.lock b/Cargo.lock index 8b47dd0b1..57dbdc1fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "adapter" version = "0.1.0" @@ -844,9 +846,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06d4a9551359071d1890820e3571252b91229e0712e7c36b08940e603c5a8fc" +checksum = "757c0ded2af11d8e739c4daea1ac623dd1624b06c844cf3f5a39f1bdbd99bb12" dependencies = [ "darling_core", "darling_macro", @@ -854,9 +856,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b443e5fb0ddd56e0c9bfa47dc060c5306ee500cb731f2b91432dd65589a77684" +checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3" dependencies = [ "fnv", "ident_case", @@ -868,9 +870,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0220073ce504f12a70efc4e7cdaea9e9b1b324872e7ad96a208056d7a638b81" +checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc" dependencies = [ "darling_core", "quote", @@ -2585,9 +2587,9 @@ dependencies = [ [[package]] name = "parse-display" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7271152b3c46c07c729698e7a5248e2744466b3446d222c97a0b1315925a97b1" +checksum = "cc7e98ea043e0880940ef455c6c6e5710b4f670b4f0aeff6edf320bb01143fe9" dependencies = [ "once_cell", "parse-display-derive", @@ -2596,15 +2598,16 @@ dependencies = [ [[package]] name = "parse-display-derive" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6a9f3e41b237b77c99c09686481c235964ff5878229412b226c451f3e809f4f" +checksum = "962e8dc54ebea1392eb2f36a205f2efa9437bfe8e95d7a91f070044c363c9684" dependencies = [ "once_cell", "proc-macro2", "quote", "regex", "regex-syntax", + "structmeta", "syn", ] @@ -2904,9 +2907,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" dependencies = [ "unicode-xid", ] @@ -3223,21 +3226,20 @@ dependencies = [ [[package]] name = "regex" -version = "1.4.3" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local", ] [[package]] name = "regex-syntax" -version = "0.6.22" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "remove_dir_all" @@ -3583,19 +3585,20 @@ dependencies = [ [[package]] name = "serde_with" -version = "1.6.4" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b44be9227e214a0420707c9ca74c2d4991d9955bae9415a8f93f05cebf561be5" +checksum = "1ad9fdbb69badc8916db738c25efd04f0a65297d26c2f8de4b62e57b8c12bc72" dependencies = [ + "rustversion", "serde", "serde_with_macros", ] [[package]] name = "serde_with_macros" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48b35457e9d855d3dc05ef32a73e0df1e2c0fd72c38796a4ee909160c8eeec2" +checksum = "e1569374bd54623ec8bd592cf22ba6e03c0f177ff55fbc8c29a49e296e7adecf" dependencies = [ "darling", "proc-macro2", @@ -3836,6 +3839,29 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "structmeta" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55b4052fd036e3d1fe74ea978426a3f87997ba803e7a8e69ff0cf99f35a720a" +dependencies = [ + "proc-macro2", + "quote", + "structmeta-derive", + "syn", +] + +[[package]] +name = "structmeta-derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f55502dda4b5fd26b33f6810d7493b4f5d7859bca604bd07ff22a523cd257ee" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "subtle" version = "2.4.0" @@ -3844,9 +3870,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.63" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd9bc7ccc2688b3344c2f48b9b546648b25ce0b20fc717ee7fa7981a8ca9717" +checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" dependencies = [ "proc-macro2", "quote", diff --git a/adview-manager/src/lib.rs b/adview-manager/src/lib.rs index c3d3a0fed..cae144279 100644 --- a/adview-manager/src/lib.rs +++ b/adview-manager/src/lib.rs @@ -2,10 +2,11 @@ #![deny(clippy::all)] use adex_primitives::{ + campaign::Validators, supermarket::units_for_slot, supermarket::units_for_slot::response::{AdUnit, Campaign}, targeting::{self, input}, - BigNum, ChannelId, SpecValidators, ValidatorId, IPFS, + Address, BigNum, CampaignId, ToHex, UnifiedNum, IPFS, }; use async_std::{sync::RwLock, task::block_on}; use chrono::{DateTime, Utc}; @@ -23,7 +24,6 @@ use std::{ sync::Arc, }; use thiserror::Error; -use units_for_slot::response::UnitsWithPrice; use url::Url; const IPFS_GATEWAY: &str = "https://ipfs.moonicorn.network/ipfs/"; @@ -48,7 +48,7 @@ pub struct Options { #[serde(rename = "marketURL")] pub market_url: Url, pub market_slot: IPFS, - pub publisher_addr: ValidatorId, + pub publisher_addr: Address, // 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, @@ -70,7 +70,7 @@ impl Options { pub struct HistoryEntry { time: DateTime, unit_id: IPFS, - campaign_id: ChannelId, + campaign_id: CampaignId, slot_id: IPFS, } @@ -79,7 +79,7 @@ pub struct HistoryEntry { struct Event { #[serde(rename = "type")] event_type: String, - publisher: ValidatorId, + publisher: Address, ad_unit: IPFS, ad_slot: IPFS, #[serde(rename = "ref")] @@ -209,16 +209,16 @@ pub fn get_unit_html_with_events( options: &Options, ad_unit: &AdUnit, hostname: &str, - channel_id: ChannelId, - validators: &SpecValidators, + campaign_id: CampaignId, + validators: &Validators, no_impression: impl Into, ) -> String { let get_body = |event_type: &str| EventBody { events: vec![Event { event_type: event_type.to_string(), publisher: options.publisher_addr, - ad_unit: ad_unit.id.clone(), - ad_slot: options.market_slot.clone(), + ad_unit: ad_unit.id, + ad_slot: options.market_slot, referrer: "document.referrer".to_string(), }], }; @@ -234,7 +234,7 @@ pub fn get_unit_html_with_events( .map(|validator| { let fetch_url = format!( "{}/channel/{}/events?pubAddr={}", - validator.url, channel_id, options.publisher_addr + validator.url, campaign_id, options.publisher_addr ); format!("fetch('{}', fetchOpts)", fetch_url) @@ -304,7 +304,7 @@ impl Manager { pub async fn get_targeting_input( &self, mut input: input::Input, - channel_id: ChannelId, + campaign_id: CampaignId, ) -> input::Input { let seconds_since_campaign_impression = self .history @@ -313,7 +313,7 @@ impl Manager { .iter() .rev() .find_map(|h| { - if h.campaign_id == channel_id { + if h.campaign_id == campaign_id { let last_impression: chrono::Duration = Utc::now() - h.time; u64::try_from(last_impression.num_seconds()).ok() @@ -352,7 +352,7 @@ impl Manager { let stick_campaign = campaigns .iter() - .find(|c| c.channel.id == sticky_entry.campaign_id)?; + .find(|c| c.campaign.id == sticky_entry.campaign_id)?; let unit = stick_campaign .units_with_price @@ -370,8 +370,8 @@ impl Manager { &self.options, &unit, hostname, - stick_campaign.channel.id, - &stick_campaign.channel.spec.validators, + stick_campaign.campaign.id, + &stick_campaign.campaign.validators, true, ); @@ -383,7 +383,7 @@ impl Manager { }) } - async fn is_campaign_sticky(&self, campaign_id: ChannelId) -> bool { + async fn is_campaign_sticky(&self, campaign_id: CampaignId) -> bool { if self.options.disabled_sticky { false } else { @@ -400,7 +400,7 @@ impl Manager { pub async fn get_market_demand_resp( &self, ) -> Result { - let pub_prefix: String = self.options.publisher_addr.to_hex_non_prefix_string(); + let pub_prefix = self.options.publisher_addr.to_hex(); let deposit_asset = self .options @@ -432,7 +432,7 @@ impl Manager { 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 m_campaigns = &units_for_slot.campaigns; let fallback_unit = units_for_slot.fallback_unit; let targeting_input = units_for_slot.targeting_input_base; @@ -444,7 +444,7 @@ impl Manager { // 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; + let sticky_result = self.get_sticky_ad_unit(m_campaigns, &hostname).await; if let Some(sticky) = sticky_result { return Ok(Some(NextAdUnit { unit: sticky.unit, @@ -461,28 +461,28 @@ impl Manager { 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 + let mut units_with_price = m_campaigns .iter() - .map(|campaign| { + .map(|m_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)) { + if block_on(self.is_campaign_sticky(m_campaign.campaign.id)) { return vec![]; } - let campaign_id = campaign.channel.id; + let campaign_id = m_campaign.campaign.id; - let mut unit_input = targeting_input.clone().with_market_channel(campaign.channel.clone()); + let mut unit_input = targeting_input.clone().with_campaign(m_campaign.campaign.clone()); - campaign + m_campaign .units_with_price .iter() .filter(|unit_with_price| { - unit_input.ad_unit_id = Some(unit_with_price.unit.id.clone()); + unit_input.ad_unit_id = Some(unit_with_price.unit.id); let mut output = targeting::Output { show: true, boost: 1.0, - price: vec![("IMPRESSION".to_string(), unit_with_price.price.clone())] + price: vec![("IMPRESSION".to_string(), unit_with_price.price)] .into_iter() .collect(), }; @@ -490,7 +490,7 @@ impl Manager { 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, + &m_campaign.campaign.targeting_rules, &unit_input, &mut output, Some(on_type_error) @@ -503,7 +503,7 @@ impl Manager { }) .flatten() .filter(|x| !(self.options.disabled_video && is_video(&x.0.unit))) - .collect(); + .collect::>(); 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()) @@ -519,9 +519,9 @@ impl Manager { let new_entry = HistoryEntry { time: Utc::now(), - unit_id: unit_with_price.unit.id.clone(), + unit_id: unit_with_price.unit.id, campaign_id: *campaign_id, - slot_id: self.options.market_slot.clone(), + slot_id: self.options.market_slot, }; *self.history.write().await = history @@ -539,11 +539,11 @@ impl Manager { // Return the results, with a fallback unit if there is one if let Some((unit_with_price, campaign_id)) = auction_winner { - let validators = campaigns + let validators = m_campaigns .iter() - .find_map(|campaign| { - if &campaign.channel.id == campaign_id { - Some(&campaign.channel.spec.validators) + .find_map(|m_campaign| { + if &m_campaign.campaign.id == campaign_id { + Some(&m_campaign.campaign.validators) } else { None } @@ -562,7 +562,7 @@ impl Manager { Ok(Some(NextAdUnit { unit: unit_with_price.unit.clone(), - price: unit_with_price.price.clone(), + price: unit_with_price.price, accepted_referrers: units_for_slot.accepted_referrers, html, })) @@ -582,14 +582,14 @@ impl Manager { pub struct NextAdUnit { pub unit: AdUnit, - pub price: BigNum, + pub price: UnifiedNum, pub accepted_referrers: Vec, pub html: String, } pub struct StickyAdUnit { pub unit: AdUnit, - pub price: BigNum, + pub price: UnifiedNum, pub html: String, pub is_sticky: bool, } diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 214263e56..0a7edbf8e 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -17,7 +17,7 @@ serde_json = "1.0" serde-hex = "0.1.0" serde_millis = "0.1.1" # Used prefixes on field for targeting::Input, and `campaign::Active` -serde_with = "1.6" +serde_with = "1.9" # Configuration toml = "0.5" # Logging @@ -34,7 +34,7 @@ ethabi = "13.0.0" # For the nonce U256 ethereum-types = "0.11" # Macro for easier derive of Display & FromStr -parse-display = "^0.4.1" +parse-display = "^0.5.0" # CID & multihash / multibase cid = "0.6" hex = "0.4" diff --git a/primitives/src/balances_map.rs b/primitives/src/balances_map.rs index 506ae8612..9836fd596 100644 --- a/primitives/src/balances_map.rs +++ b/primitives/src/balances_map.rs @@ -109,8 +109,8 @@ mod test { let actual_json = serde_json::to_value(&unified_map).expect("Should serialize it"); let expected_json = json!({ - "0xC91763D7F14ac5c5dDfBCD012e0D2A61ab9bDED3":100, - "0xce07CbB7e054514D590a0262C93070D838bFBA2e":50 + "0xC91763D7F14ac5c5dDfBCD012e0D2A61ab9bDED3":"100", + "0xce07CbB7e054514D590a0262C93070D838bFBA2e":"50" }); assert_eq!(expected_json, actual_json); diff --git a/primitives/src/campaign.rs b/primitives/src/campaign.rs index 5774ec478..bbbb5b3c4 100644 --- a/primitives/src/campaign.rs +++ b/primitives/src/campaign.rs @@ -16,7 +16,7 @@ pub use { validators::{ValidatorRole, Validators}, }; -with_prefix!(prefix_active "active_"); +with_prefix!(pub prefix_active "active_"); mod campaign_id { use crate::ToHex; @@ -235,13 +235,13 @@ pub struct Active { } mod pricing { - use crate::BigNum; + use crate::UnifiedNum; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] pub struct Pricing { - pub min: BigNum, - pub max: BigNum, + pub min: UnifiedNum, + pub max: UnifiedNum, } #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] @@ -277,7 +277,7 @@ mod pricing { } } } -// TODO: Double check if we require all the methods and enums, as some parts are now in the `Campaign` +// TODO AIP#61: Double check if we require all the methods and enums, as some parts are now in the `Campaign` // This includes the matching of the Channel leader & follower to the Validators pub mod validators { use crate::{ValidatorDesc, ValidatorId}; diff --git a/primitives/src/channel_v5.rs b/primitives/src/channel_v5.rs index fa064a3cc..9f990d47d 100644 --- a/primitives/src/channel_v5.rs +++ b/primitives/src/channel_v5.rs @@ -42,7 +42,7 @@ pub struct Nonce(pub U256); impl Nonce { /// In Big-Endian - pub fn to_bytes(&self) -> [u8; 32] { + pub fn to_bytes(self) -> [u8; 32] { // the impl of From uses BigEndian self.0.into() } diff --git a/primitives/src/ipfs.rs b/primitives/src/ipfs.rs index cc86c01fa..d38dde392 100644 --- a/primitives/src/ipfs.rs +++ b/primitives/src/ipfs.rs @@ -7,7 +7,7 @@ const URL_PREFIX: &str = "ipfs://"; pub use cid::{Cid, Error}; -#[derive(Hash, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[derive(Hash, Copy, Clone, Serialize, Deserialize, Eq, PartialEq)] #[serde(try_from = "String", into = "String")] #[allow(clippy::upper_case_acronyms)] pub struct IPFS(pub cid::Cid); diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 0ede0b218..3bfa28602 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -6,7 +6,7 @@ pub use self::{ ad_slot::AdSlot, ad_unit::AdUnit, address::Address, - balances_map::BalancesMap, + balances_map::{BalancesMap, UnifiedMap}, big_num::BigNum, campaign::{Campaign, CampaignId}, channel::{Channel, ChannelId, ChannelSpec, SpecValidator, SpecValidators}, diff --git a/primitives/src/sentry.rs b/primitives/src/sentry.rs index da6bbacf2..9084811e8 100644 --- a/primitives/src/sentry.rs +++ b/primitives/src/sentry.rs @@ -318,18 +318,14 @@ pub mod channel_list { pub mod campaign_create { use chrono::{serde::ts_milliseconds, DateTime, Utc}; use serde::{Deserialize, Serialize}; - use serde_with::with_prefix; use crate::{ - campaign::{Active, PricingBounds, Validators}, + campaign::{prefix_active, Active, PricingBounds, Validators}, channel_v5::Channel, targeting::Rules, AdUnit, Address, Campaign, CampaignId, EventSubmission, UnifiedNum, }; - // use the same prefix for Active - with_prefix!(prefix_active "active_"); - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] /// All fields are present except the `CampaignId` which is randomly created /// This struct defines the Body of the request (in JSON) diff --git a/primitives/src/supermarket.rs b/primitives/src/supermarket.rs index 34bf1a97a..88b571f02 100644 --- a/primitives/src/supermarket.rs +++ b/primitives/src/supermarket.rs @@ -43,14 +43,7 @@ pub enum Finalized { pub mod units_for_slot { pub mod response { - use crate::{ - targeting::{Input, Rules}, - BigNum, ChannelId, ChannelSpec, SpecValidators, ValidatorId, IPFS, - }; - use chrono::{ - serde::{ts_milliseconds, ts_milliseconds_option}, - DateTime, Utc, - }; + use crate::{targeting::Input, UnifiedNum, IPFS}; use serde::{Deserialize, Serialize}; use url::Url; @@ -67,67 +60,18 @@ pub mod units_for_slot { #[serde(rename_all = "camelCase")] pub struct UnitsWithPrice { pub unit: AdUnit, - pub price: BigNum, + pub price: UnifiedNum, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Campaign { #[serde(flatten)] - pub channel: Channel, - pub targeting_rules: Rules, + pub campaign: crate::Campaign, + /// Supermarket Specific Campaign field pub units_with_price: Vec, } - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] - #[serde(rename_all = "camelCase")] - pub struct Channel { - pub id: ChannelId, - pub creator: ValidatorId, - pub deposit_asset: String, - pub deposit_amount: BigNum, - pub spec: Spec, - } - - impl From for Channel { - fn from(channel: crate::Channel) -> Self { - Self { - id: channel.id, - creator: channel.creator, - deposit_asset: channel.deposit_asset, - deposit_amount: channel.deposit_amount, - spec: channel.spec.into(), - } - } - } - - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] - #[serde(rename_all = "camelCase")] - pub struct Spec { - #[serde(with = "ts_milliseconds")] - pub withdraw_period_start: DateTime, - #[serde( - default, - skip_serializing_if = "Option::is_none", - with = "ts_milliseconds_option" - )] - pub active_from: Option>, - #[serde(with = "ts_milliseconds")] - pub created: DateTime, - pub validators: SpecValidators, - } - - impl From for Spec { - fn from(channel_spec: ChannelSpec) -> Self { - Self { - withdraw_period_start: channel_spec.withdraw_period_start, - active_from: channel_spec.active_from, - created: channel_spec.created, - validators: channel_spec.validators, - } - } - } - #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct AdUnit { @@ -141,7 +85,7 @@ pub mod units_for_slot { impl From<&crate::AdUnit> for AdUnit { fn from(ad_unit: &crate::AdUnit) -> Self { Self { - id: ad_unit.ipfs.clone(), + id: ad_unit.ipfs, media_url: ad_unit.media_url.clone(), media_mime: ad_unit.media_mime.clone(), target_url: ad_unit.target_url.clone(), diff --git a/primitives/src/targeting.rs b/primitives/src/targeting.rs index 159868473..283f649ed 100644 --- a/primitives/src/targeting.rs +++ b/primitives/src/targeting.rs @@ -1,4 +1,4 @@ -use crate::{campaign::Pricing, BigNum, Campaign}; +use crate::{campaign::Pricing, Campaign, UnifiedNum}; pub use eval::*; use serde_json::Number; @@ -34,7 +34,7 @@ pub struct Output { /// For example: price.IMPRESSION /// The default is the min of the bound of event type: /// Default: pricingBounds.IMPRESSION.min - pub price: HashMap, + pub price: HashMap, } impl Output { @@ -50,7 +50,7 @@ impl Output { .price .get(price_key.trim_start_matches("price.")) .ok_or(Error::UnknownVariable)?; - Ok(Value::BigNum(price.clone())) + Ok(Value::UnifiedNum(*price)) } _ => Err(Error::UnknownVariable), } @@ -95,7 +95,10 @@ mod test { )), output.try_get("boost") ); - assert_eq!(Ok(Value::BigNum(100.into())), output.try_get("price.one")); + assert_eq!( + Ok(Value::UnifiedNum(100.into())), + output.try_get("price.one") + ); assert_eq!(Err(Error::UnknownVariable), output.try_get("price.unknown")); assert_eq!(Err(Error::UnknownVariable), output.try_get("unknown")); } @@ -121,7 +124,10 @@ mod test { assert_eq!(true, output.show); assert_eq!(1.0, output.boost); - assert_eq!(Some(&BigNum::from(1_000)), output.price.get("IMPRESSION")); - assert_eq!(Some(&BigNum::from(3_000)), output.price.get("CLICK")); + assert_eq!( + Some(&UnifiedNum::from(1_000)), + output.price.get("IMPRESSION") + ); + assert_eq!(Some(&UnifiedNum::from(3_000)), output.price.get("CLICK")); } } diff --git a/primitives/src/targeting/eval.rs b/primitives/src/targeting/eval.rs index 29fe9cdbd..4843bbdb2 100644 --- a/primitives/src/targeting/eval.rs +++ b/primitives/src/targeting/eval.rs @@ -1,9 +1,7 @@ -use crate::{Address, BigNum}; -use lazy_static::lazy_static; +use crate::UnifiedNum; use serde::{Deserialize, Serialize}; use serde_json::{value::Value as SerdeValue, Number}; use std::{ - collections::HashMap, convert::TryFrom, fmt, ops::{Add, Div, Mul, Rem, Sub}, @@ -12,10 +10,7 @@ use std::{ pub use rules::Rules; -use super::{ - input::{campaign::Getter as ChannelGetter, Get}, - Input, Output, -}; +use super::{Input, Output}; #[cfg(test)] #[path = "eval_test.rs"] @@ -27,26 +22,6 @@ pub enum Error { UnknownVariable, } -lazy_static! { - pub static ref DAI_ADDR: Address = "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359" - .parse() - .expect("Valid Address"); - pub static ref USDT_ADDR: Address = "0xdac17f958d2ee523a2206206994597c13d831ec7" - .parse() - .expect("Valid Address"); - pub static ref USDC_ADDR: Address = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" - .parse() - .expect("Valid Address"); - pub static ref DEPOSIT_ASSETS_MAP: HashMap = { - let mut assets = HashMap::new(); - assets.insert(*DAI_ADDR, BigNum::from(10u64.pow(18))); - assets.insert(*USDT_ADDR, BigNum::from(10u64.pow(6))); - assets.insert(*USDC_ADDR, BigNum::from(10u64.pow(18))); - - assets - }; -} - trait Eval { fn eval(self, input: &Input, output: &mut Output) -> Result, Error>; } @@ -170,13 +145,13 @@ impl Rule { } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[serde(untagged, try_from = "SerdeValue", /* into = "SerdeValue" */)] +#[serde(untagged, try_from = "SerdeValue")] pub enum Value { Bool(bool), Number(Number), String(String), Array(Vec), - BigNum(BigNum), + UnifiedNum(UnifiedNum), } impl Value { @@ -196,8 +171,8 @@ impl TryFrom for Value { match serde_value { SerdeValue::Bool(bool) => Ok(Self::Bool(bool)), SerdeValue::Number(number) => Ok(Self::Number(number)), - // It's impossible to have a BigNumber literal in the rules, since they're JSON based (conform to serde_json::value::Value) - // However it is possible to obtain a BigNumber by invoking the Function::Bn + // It's impossible to have a UnifiedNum literal in the rules, since they're JSON based (conform to serde_json::value::Value) + // However it is possible to obtain a UnifiedNum by invoking the Function::Bn SerdeValue::String(string) => Ok(Value::String(string)), SerdeValue::Array(serde_array) => { let array = serde_array @@ -220,7 +195,7 @@ impl From for SerdeValue { Value::Array(array) => { Self::Array(array.into_iter().map(|value| value.into()).collect()) } - Value::BigNum(bignum) => Self::String(bignum.to_string()), + Value::UnifiedNum(unified) => Self::String(unified.to_string()), } } } @@ -272,7 +247,6 @@ pub enum Function { StartsWith(Box, Box), EndsWith(Box, Box), OnlyShowIf(Box), - GetPriceInUsd(Box), Intersects(Box, Box), /// Evaluates rule Do(Box), @@ -444,10 +418,6 @@ impl Function { pub fn new_bn(value: impl Into) -> Self { Self::Bn(value.into()) } - - pub fn new_get_price_in_usd(amount: impl Into) -> Self { - Self::GetPriceInUsd(Box::new(amount.into())) - } } impl Value { @@ -472,8 +442,8 @@ impl Value { } } - pub fn try_bignum(self) -> Result { - BigNum::try_from(self) + pub fn try_unified(self) -> Result { + UnifiedNum::try_from(self) } pub fn try_number(self) -> Result { @@ -484,14 +454,15 @@ impl Value { } } -impl TryFrom for BigNum { +/// The UnifiedNum can be extracted from the DSL either String or UnifiedNum +impl TryFrom for UnifiedNum { type Error = Error; fn try_from(value: Value) -> Result { match value { - Value::String(string) => BigNum::from_str(&string).map_err(|_| Error::TypeError), - Value::BigNum(big_num) => Ok(big_num), + Value::String(string) => UnifiedNum::from_str(&string).map_err(|_| Error::TypeError), + Value::UnifiedNum(unified) => Ok(unified), Value::Number(number) => { - BigNum::from_str(&number.to_string()).map_err(|_| Error::TypeError) + UnifiedNum::from_str(&number.to_string()).map_err(|_| Error::TypeError) } _ => Err(Error::TypeError), } @@ -505,7 +476,7 @@ impl TryFrom for BigNum { /// - Number /// - String /// - Array -/// - BigNum +/// - UnifiedNum /// - Mutates output /// - Throws an error fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result, Error> { @@ -529,15 +500,15 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let second_eval = second_rule.eval(input, output)?.ok_or(Error::TypeError)?; let value = match (first_eval, second_eval) { - (Value::BigNum(bignum), second_value) => { - let second_bignum = BigNum::try_from(second_value)?; + (Value::UnifiedNum(unified), second_value) => { + let second_unified = UnifiedNum::try_from(second_value)?; - Value::BigNum(bignum.div(second_bignum)) + Value::UnifiedNum(unified.div(second_unified)) } - (lhs_value, Value::BigNum(rhs_bignum)) => { - let lhs_bignum = BigNum::try_from(lhs_value)?; + (lhs_value, Value::UnifiedNum(rhs_unified)) => { + let lhs_unified = UnifiedNum::try_from(lhs_value)?; - Value::BigNum(lhs_bignum.div(rhs_bignum)) + Value::UnifiedNum(lhs_unified.div(rhs_unified)) } (Value::Number(lhs), Value::Number(rhs)) => { Value::Number(math_operator(lhs, rhs, MathOperator::Division)?) @@ -552,15 +523,15 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let second_eval = second_rule.eval(input, output)?.ok_or(Error::TypeError)?; let value = match (first_eval, second_eval) { - (Value::BigNum(bignum), rhs_value) => { - let rhs_bignum = BigNum::try_from(rhs_value)?; + (Value::UnifiedNum(unified), rhs_value) => { + let rhs_unified = UnifiedNum::try_from(rhs_value)?; - Value::BigNum(bignum.mul(rhs_bignum)) + Value::UnifiedNum(unified.mul(rhs_unified)) } - (lhs_value, Value::BigNum(rhs_bignum)) => { - let lhs_bignum = BigNum::try_from(lhs_value)?; + (lhs_value, Value::UnifiedNum(rhs_unified)) => { + let lhs_unified = UnifiedNum::try_from(lhs_value)?; - Value::BigNum(lhs_bignum.mul(rhs_bignum)) + Value::UnifiedNum(lhs_unified.mul(rhs_unified)) } (Value::Number(lhs), Value::Number(rhs)) => { Value::Number(math_operator(lhs, rhs, MathOperator::Multiplication)?) @@ -575,15 +546,15 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let second_eval = second_rule.eval(input, output)?.ok_or(Error::TypeError)?; let value = match (first_eval, second_eval) { - (Value::BigNum(bignum), rhs_value) => { - let rhs_bignum = BigNum::try_from(rhs_value)?; + (Value::UnifiedNum(unified), rhs_value) => { + let rhs_unified = UnifiedNum::try_from(rhs_value)?; - Value::BigNum(bignum.rem(rhs_bignum)) + Value::UnifiedNum(unified.rem(rhs_unified)) } - (lhs_value, Value::BigNum(rhs_bignum)) => { - let lhs_bignum = BigNum::try_from(lhs_value)?; + (lhs_value, Value::UnifiedNum(rhs_unified)) => { + let lhs_unified = UnifiedNum::try_from(lhs_value)?; - Value::BigNum(lhs_bignum.rem(rhs_bignum)) + Value::UnifiedNum(lhs_unified.rem(rhs_unified)) } (Value::Number(lhs), Value::Number(rhs)) => { Value::Number(math_operator(lhs, rhs, MathOperator::Modulus)?) @@ -598,15 +569,15 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let second_eval = second_rule.eval(input, output)?.ok_or(Error::TypeError)?; let value = match (first_eval, second_eval) { - (Value::BigNum(bignum), rhs_value) => { - let rhs_bignum = BigNum::try_from(rhs_value)?; + (Value::UnifiedNum(unified), rhs_value) => { + let rhs_unified = UnifiedNum::try_from(rhs_value)?; - Value::BigNum(bignum.add(rhs_bignum)) + Value::UnifiedNum(unified.add(rhs_unified)) } - (lhs_value, Value::BigNum(rhs_bignum)) => { - let lhs_bignum = BigNum::try_from(lhs_value)?; + (lhs_value, Value::UnifiedNum(rhs_unified)) => { + let lhs_unified = UnifiedNum::try_from(lhs_value)?; - Value::BigNum(lhs_bignum.add(rhs_bignum)) + Value::UnifiedNum(lhs_unified.add(rhs_unified)) } (Value::Number(lhs), Value::Number(rhs)) => { Value::Number(math_operator(lhs, rhs, MathOperator::Addition)?) @@ -621,15 +592,15 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let second_eval = second_rule.eval(input, output)?.ok_or(Error::TypeError)?; let value = match (first_eval, second_eval) { - (Value::BigNum(bignum), rhs_value) => { - let rhs_bignum = BigNum::try_from(rhs_value)?; + (Value::UnifiedNum(unified), rhs_value) => { + let rhs_unified = UnifiedNum::try_from(rhs_value)?; - Value::BigNum(bignum.sub(rhs_bignum)) + Value::UnifiedNum(unified.sub(rhs_unified)) } - (lhs_value, Value::BigNum(rhs_bignum)) => { - let lhs_bignum = BigNum::try_from(lhs_value)?; + (lhs_value, Value::UnifiedNum(rhs_unified)) => { + let lhs_unified = UnifiedNum::try_from(lhs_value)?; - Value::BigNum(lhs_bignum.sub(rhs_bignum)) + Value::UnifiedNum(lhs_unified.sub(rhs_unified)) } (Value::Number(lhs), Value::Number(rhs)) => { Value::Number(math_operator(lhs, rhs, MathOperator::Subtraction)?) @@ -644,15 +615,15 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let second_eval = second_rule.eval(input, output)?.ok_or(Error::TypeError)?; let value = match (first_eval, second_eval) { - (Value::BigNum(bignum), rhs_value) => { - let rhs_bignum = BigNum::try_from(rhs_value)?; + (Value::UnifiedNum(unified), rhs_value) => { + let rhs_unified = UnifiedNum::try_from(rhs_value)?; - Value::BigNum(bignum.max(rhs_bignum)) + Value::UnifiedNum(unified.max(rhs_unified)) } - (lhs_value, Value::BigNum(rhs_bignum)) => { - let lhs_bignum = BigNum::try_from(lhs_value)?; + (lhs_value, Value::UnifiedNum(rhs_unified)) => { + let lhs_unified = UnifiedNum::try_from(lhs_value)?; - Value::BigNum(lhs_bignum.max(rhs_bignum)) + Value::UnifiedNum(lhs_unified.max(rhs_unified)) } (Value::Number(lhs), Value::Number(rhs)) => { Value::Number(math_operator(lhs, rhs, MathOperator::Max)?) @@ -667,15 +638,15 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let second_eval = second_rule.eval(input, output)?.ok_or(Error::TypeError)?; let value = match (first_eval, second_eval) { - (Value::BigNum(bignum), rhs_value) => { - let rhs_bignum = BigNum::try_from(rhs_value)?; + (Value::UnifiedNum(unified), rhs_value) => { + let rhs_unified = UnifiedNum::try_from(rhs_value)?; - Value::BigNum(bignum.min(rhs_bignum)) + Value::UnifiedNum(unified.min(rhs_unified)) } - (lhs_value, Value::BigNum(rhs_bignum)) => { - let lhs_bignum = BigNum::try_from(lhs_value)?; + (lhs_value, Value::UnifiedNum(rhs_unified)) => { + let lhs_unified = UnifiedNum::try_from(lhs_value)?; - Value::BigNum(lhs_bignum.min(rhs_bignum)) + Value::UnifiedNum(lhs_unified.min(rhs_unified)) } (Value::Number(lhs), Value::Number(rhs)) => { Value::Number(math_operator(lhs, rhs, MathOperator::Min)?) @@ -760,15 +731,15 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let second_eval = second_rule.eval(input, output)?.ok_or(Error::TypeError)?; let value = match (first_eval, second_eval) { - (Value::BigNum(bignum), rhs_value) => { - let rhs_bignum = BigNum::try_from(rhs_value)?; + (Value::UnifiedNum(unified), rhs_value) => { + let rhs_unified = UnifiedNum::try_from(rhs_value)?; - Value::Bool(bignum.lt(&rhs_bignum)) + Value::Bool(unified.lt(&rhs_unified)) } - (lhs_value, Value::BigNum(rhs_bignum)) => { - let lhs_bignum = BigNum::try_from(lhs_value)?; + (lhs_value, Value::UnifiedNum(rhs_unified)) => { + let lhs_unified = UnifiedNum::try_from(lhs_value)?; - Value::Bool(lhs_bignum.lt(&rhs_bignum)) + Value::Bool(lhs_unified.lt(&rhs_unified)) } (Value::Number(lhs), Value::Number(rhs)) => { Value::Bool(compare_numbers(lhs, rhs, ComparisonOperator::Lt)?) @@ -783,15 +754,15 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let second_eval = second_rule.eval(input, output)?.ok_or(Error::TypeError)?; let value = match (first_eval, second_eval) { - (Value::BigNum(bignum), rhs_value) => { - let rhs_bignum = BigNum::try_from(rhs_value)?; + (Value::UnifiedNum(unified), rhs_value) => { + let rhs_unified = UnifiedNum::try_from(rhs_value)?; - Value::Bool(bignum.le(&rhs_bignum)) + Value::Bool(unified.le(&rhs_unified)) } - (lhs_value, Value::BigNum(rhs_bignum)) => { - let lhs_bignum = BigNum::try_from(lhs_value)?; + (lhs_value, Value::UnifiedNum(rhs_unified)) => { + let lhs_unified = UnifiedNum::try_from(lhs_value)?; - Value::Bool(lhs_bignum.le(&rhs_bignum)) + Value::Bool(lhs_unified.le(&rhs_unified)) } (Value::Number(lhs), Value::Number(rhs)) => { Value::Bool(compare_numbers(lhs, rhs, ComparisonOperator::Lte)?) @@ -806,15 +777,15 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let second_eval = second_rule.eval(input, output)?.ok_or(Error::TypeError)?; let value = match (first_eval, second_eval) { - (Value::BigNum(bignum), rhs_value) => { - let rhs_bignum = BigNum::try_from(rhs_value)?; + (Value::UnifiedNum(unified), rhs_value) => { + let rhs_unified = UnifiedNum::try_from(rhs_value)?; - Value::Bool(bignum.gt(&rhs_bignum)) + Value::Bool(unified.gt(&rhs_unified)) } - (lhs_value, Value::BigNum(rhs_bignum)) => { - let lhs_bignum = BigNum::try_from(lhs_value)?; + (lhs_value, Value::UnifiedNum(rhs_unified)) => { + let lhs_unified = UnifiedNum::try_from(lhs_value)?; - Value::Bool(lhs_bignum.gt(&rhs_bignum)) + Value::Bool(lhs_unified.gt(&rhs_unified)) } (Value::Number(lhs), Value::Number(rhs)) => { Value::Bool(compare_numbers(lhs, rhs, ComparisonOperator::Gt)?) @@ -829,15 +800,15 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let second_eval = second_rule.eval(input, output)?.ok_or(Error::TypeError)?; let value = match (first_eval, second_eval) { - (Value::BigNum(bignum), rhs_value) => { - let rhs_bignum = BigNum::try_from(rhs_value)?; + (Value::UnifiedNum(unified), rhs_value) => { + let rhs_unified = UnifiedNum::try_from(rhs_value)?; - Value::Bool(bignum.ge(&rhs_bignum)) + Value::Bool(unified.ge(&rhs_unified)) } - (lhs_value, Value::BigNum(rhs_bignum)) => { - let lhs_bignum = BigNum::try_from(lhs_value)?; + (lhs_value, Value::UnifiedNum(rhs_unified)) => { + let lhs_unified = UnifiedNum::try_from(lhs_value)?; - Value::Bool(lhs_bignum.ge(&rhs_bignum)) + Value::Bool(lhs_unified.ge(&rhs_unified)) } (Value::Number(lhs), Value::Number(rhs)) => { Value::Bool(compare_numbers(lhs, rhs, ComparisonOperator::Gte)?) @@ -852,15 +823,15 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let second_eval = second_rule.eval(input, output)?.ok_or(Error::TypeError)?; let value = match (first_eval, second_eval) { - (Value::BigNum(bignum), rhs_value) => { - let rhs_bignum = BigNum::try_from(rhs_value)?; + (Value::UnifiedNum(unified), rhs_value) => { + let rhs_unified = UnifiedNum::try_from(rhs_value)?; - Value::Bool(bignum.eq(&rhs_bignum)) + Value::Bool(unified.eq(&rhs_unified)) } - (lhs_value, Value::BigNum(rhs_bignum)) => { - let lhs_bignum = BigNum::try_from(lhs_value)?; + (lhs_value, Value::UnifiedNum(rhs_unified)) => { + let lhs_unified = UnifiedNum::try_from(lhs_value)?; - Value::Bool(lhs_bignum.eq(&rhs_bignum)) + Value::Bool(lhs_unified.eq(&rhs_unified)) } (Value::Number(lhs), Value::Number(rhs)) => { Value::Bool(compare_numbers(lhs, rhs, ComparisonOperator::Eq)?) @@ -994,37 +965,6 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result Function::Set(String::from("show"), new_rule).eval(input, output)? } - Function::GetPriceInUsd(amount_rule) => { - let amount = amount_rule - .eval(input, output)? - .ok_or(Error::TypeError)? - .try_bignum()?; - - // 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 = match &input.campaign { - Some(Get::Getter(ChannelGetter::Full(full_campaign))) => { - Ok(full_campaign.campaign.channel.token) - } - // - // TODO: AIP#61 Replace with Campaign - // - Some(Get::Getter(ChannelGetter::Market(channel))) => channel - .deposit_asset - .parse::
() - .map_err(|_| Error::TypeError), - // In case of a Values - we don't have the deposit_asset on hand so we fail in that case - // In case of None we also fail - _ => Err(Error::UnknownVariable), - }?; - - let divisor = DEPOSIT_ASSETS_MAP - .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)?; - Some(Value::Number(amount_as_number)) - } Function::Do(first_rule) => eval(input, output, first_rule)?, Function::Set(key, rule) => { // Output variables can be set any number of times by different rules, except `show` @@ -1050,7 +990,7 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let price = rule .eval(input, output)? .ok_or(Error::TypeError)? - .try_bignum()?; + .try_unified()?; // we do not care about any other old value output.price.insert("IMPRESSION".to_string(), price); @@ -1059,7 +999,7 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result let price = rule .eval(input, output)? .ok_or(Error::TypeError)? - .try_bignum()?; + .try_unified()?; // we do not care about any other old value output.price.insert("CLICK".to_string(), price); @@ -1075,9 +1015,9 @@ fn eval(input: &Input, output: &mut Output, rule: &Rule) -> Result Err(e) => return Err(e), }, Function::Bn(value) => { - let big_num = value.clone().try_bignum()?; + let unified = value.clone().try_unified()?; - Some(Value::BigNum(big_num)) + Some(Value::UnifiedNum(unified)) } }; diff --git a/primitives/src/targeting/eval_test.rs b/primitives/src/targeting/eval_test.rs index e756b5bca..021941dc1 100644 --- a/primitives/src/targeting/eval_test.rs +++ b/primitives/src/targeting/eval_test.rs @@ -4,11 +4,11 @@ use super::*; use crate::{ targeting::input, util::tests::prep_db::{ADDRESSES, DUMMY_CAMPAIGN, DUMMY_IPFS}, - BalancesMap, + UnifiedMap, }; fn get_default_input() -> Input { - let input_balances = BalancesMap::default(); + let input_balances = UnifiedMap::default(); let init_input = Input { ad_view: Some(input::AdView { @@ -226,13 +226,13 @@ mod dsl_test { }; let cases = vec![ - (Value::new_string("1000"), Value::BigNum(1000.into())), - (Value::new_number(2_000), Value::BigNum(2_000.into())), - (Value::BigNum(3.into()), Value::BigNum(3.into())), + (Value::new_string("1000"), Value::UnifiedNum(1000.into())), + (Value::new_number(2_000), Value::UnifiedNum(2_000.into())), + (Value::UnifiedNum(3.into()), Value::UnifiedNum(3.into())), // rounded floats should work! ( Value::Number(Number::from_f64(40.0).expect("should create float number")), - Value::BigNum(40.into()), + Value::UnifiedNum(40.into()), ), ]; @@ -254,7 +254,7 @@ mod dsl_test { let error_cases = vec![ Value::new_string("text"), - // BigNums can only be positive + // UnifiedNums can only be positive Value::new_number(-100), Value::Bool(true), Value::Array(vec![Value::Bool(false)]), @@ -288,14 +288,17 @@ mod dsl_test { let input = get_default_input(); let mut output = Output::from(&campaign); - assert_eq!(Some(&BigNum::from(1_000)), output.price.get("IMPRESSION")); + assert_eq!( + Some(&UnifiedNum::from(1_000)), + output.price.get("IMPRESSION") + ); - let set_to = Value::BigNum(BigNum::from(20)); + let set_to = Value::UnifiedNum(UnifiedNum::from(20)); let rule = Rule::Function(Function::new_set("price.IMPRESSION", set_to)); assert_eq!(Ok(None), rule.eval(&input, &mut output)); - assert_eq!(Some(&BigNum::from(20)), output.price.get("IMPRESSION")); + assert_eq!(Some(&UnifiedNum::from(20)), output.price.get("IMPRESSION")); } #[test] @@ -335,19 +338,19 @@ mod math_functions { let cases = vec![ ( - Value::BigNum(100.into()), - Value::BigNum(3.into()), - Value::BigNum(33.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(3.into()), + Value::UnifiedNum(33.into()), ), ( Value::new_number(100), - Value::BigNum(3.into()), - Value::BigNum(33.into()), + Value::UnifiedNum(3.into()), + Value::UnifiedNum(33.into()), ), ( - Value::BigNum(100.into()), + Value::UnifiedNum(100.into()), Value::new_number(3), - Value::BigNum(33.into()), + Value::UnifiedNum(33.into()), ), ( Value::Number(Number::from_f64(100.0).expect("should create float number")), @@ -380,19 +383,19 @@ mod math_functions { let cases = vec![ ( - Value::BigNum(3.into()), - Value::BigNum(1000.into()), - Value::BigNum(3000.into()), + Value::UnifiedNum(3.into()), + Value::UnifiedNum(1000.into()), + Value::UnifiedNum(3000.into()), ), ( Value::new_number(3), - Value::BigNum(1000.into()), - Value::BigNum(3000.into()), + Value::UnifiedNum(1000.into()), + Value::UnifiedNum(3000.into()), ), ( - Value::BigNum(3.into()), + Value::UnifiedNum(3.into()), Value::new_number(1000), - Value::BigNum(3000.into()), + Value::UnifiedNum(3000.into()), ), ( Value::Number(Number::from_f64(0.5).expect("should create float number")), @@ -423,19 +426,19 @@ mod math_functions { let cases = vec![ ( - Value::BigNum(10.into()), - Value::BigNum(5.into()), - Value::BigNum(0.into()), + Value::UnifiedNum(10.into()), + Value::UnifiedNum(5.into()), + Value::UnifiedNum(0.into()), ), ( Value::new_number(10), - Value::BigNum(3.into()), - Value::BigNum(1.into()), + Value::UnifiedNum(3.into()), + Value::UnifiedNum(1.into()), ), ( - Value::BigNum(10.into()), + Value::UnifiedNum(10.into()), Value::new_number(4), - Value::BigNum(2.into()), + Value::UnifiedNum(2.into()), ), ( Value::Number(Number::from_f64(10.0).expect("should create float number")), @@ -466,19 +469,19 @@ mod math_functions { let cases = vec![ ( - Value::BigNum(2.into()), - Value::BigNum(2.into()), - Value::BigNum(4.into()), + Value::UnifiedNum(2.into()), + Value::UnifiedNum(2.into()), + Value::UnifiedNum(4.into()), ), ( Value::new_number(2), - Value::BigNum(2.into()), - Value::BigNum(4.into()), + Value::UnifiedNum(2.into()), + Value::UnifiedNum(4.into()), ), ( - Value::BigNum(2.into()), + Value::UnifiedNum(2.into()), Value::new_number(2), - Value::BigNum(4.into()), + Value::UnifiedNum(4.into()), ), ( Value::Number(Number::from_f64(2.2).expect("should create float number")), @@ -509,19 +512,19 @@ mod math_functions { let cases = vec![ ( - Value::BigNum(10.into()), - Value::BigNum(2.into()), - Value::BigNum(8.into()), + Value::UnifiedNum(10.into()), + Value::UnifiedNum(2.into()), + Value::UnifiedNum(8.into()), ), ( Value::new_number(10), - Value::BigNum(10.into()), - Value::BigNum(0.into()), + Value::UnifiedNum(10.into()), + Value::UnifiedNum(0.into()), ), ( - Value::BigNum(10.into()), + Value::UnifiedNum(10.into()), Value::new_number(5), - Value::BigNum(5.into()), + Value::UnifiedNum(5.into()), ), ( Value::Number(Number::from_f64(8.4).expect("should create float number")), @@ -552,19 +555,19 @@ mod math_functions { let cases = vec![ ( - Value::BigNum(100.into()), - Value::BigNum(10.into()), - Value::BigNum(10.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(10.into()), + Value::UnifiedNum(10.into()), ), ( Value::new_number(10), - Value::BigNum(100.into()), - Value::BigNum(10.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(10.into()), ), ( - Value::BigNum(10.into()), + Value::UnifiedNum(10.into()), Value::new_number(10), - Value::BigNum(10.into()), + Value::UnifiedNum(10.into()), ), ( Value::Number(Number::from_f64(0.1).expect("should create float number")), @@ -595,19 +598,19 @@ mod math_functions { let cases = vec![ ( - Value::BigNum(100.into()), - Value::BigNum(10.into()), - Value::BigNum(100.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(10.into()), + Value::UnifiedNum(100.into()), ), ( Value::new_number(10), - Value::BigNum(100.into()), - Value::BigNum(100.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(100.into()), ), ( - Value::BigNum(10.into()), + Value::UnifiedNum(10.into()), Value::new_number(10), - Value::BigNum(10.into()), + Value::UnifiedNum(10.into()), ), ( Value::Number(Number::from_f64(0.1).expect("should create float number")), @@ -638,17 +641,17 @@ mod math_functions { let cases = vec![ ( - Value::BigNum(100.into()), - Value::BigNum(10.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(10.into()), Value::Bool(false), ), ( Value::new_number(100), - Value::BigNum(100.into()), + Value::UnifiedNum(100.into()), Value::Bool(false), ), ( - Value::BigNum(10.into()), + Value::UnifiedNum(10.into()), Value::new_number(100), Value::Bool(true), ), @@ -681,17 +684,17 @@ mod math_functions { let cases = vec![ ( - Value::BigNum(100.into()), - Value::BigNum(10.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(10.into()), Value::Bool(false), ), ( Value::new_number(100), - Value::BigNum(100.into()), + Value::UnifiedNum(100.into()), Value::Bool(true), ), ( - Value::BigNum(10.into()), + Value::UnifiedNum(10.into()), Value::new_number(100), Value::Bool(true), ), @@ -724,17 +727,17 @@ mod math_functions { let cases = vec![ ( - Value::BigNum(100.into()), - Value::BigNum(10.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(10.into()), Value::Bool(true), ), ( Value::new_number(100), - Value::BigNum(100.into()), + Value::UnifiedNum(100.into()), Value::Bool(false), ), ( - Value::BigNum(10.into()), + Value::UnifiedNum(10.into()), Value::new_number(100), Value::Bool(false), ), @@ -767,17 +770,17 @@ mod math_functions { let cases = vec![ ( - Value::BigNum(100.into()), - Value::BigNum(10.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(10.into()), Value::Bool(true), ), ( Value::new_number(100), - Value::BigNum(100.into()), + Value::UnifiedNum(100.into()), Value::Bool(true), ), ( - Value::BigNum(10.into()), + Value::UnifiedNum(10.into()), Value::new_number(100), Value::Bool(false), ), @@ -810,33 +813,33 @@ mod math_functions { let cases = vec![ ( - Value::BigNum(10.into()), - Value::BigNum(100.into()), - Value::BigNum(1.into()), + Value::UnifiedNum(10.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(1.into()), Value::Bool(false), ), ( - Value::BigNum(10.into()), - Value::BigNum(100.into()), - Value::BigNum(10.into()), + Value::UnifiedNum(10.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(10.into()), Value::Bool(true), ), ( - Value::BigNum(10.into()), - Value::BigNum(100.into()), - Value::BigNum(50.into()), + Value::UnifiedNum(10.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(50.into()), Value::Bool(true), ), ( - Value::BigNum(10.into()), - Value::BigNum(100.into()), - Value::BigNum(100.into()), + Value::UnifiedNum(10.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(100.into()), Value::Bool(true), ), ( - Value::BigNum(10.into()), - Value::BigNum(100.into()), - Value::BigNum(1000.into()), + Value::UnifiedNum(10.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(1000.into()), Value::Bool(false), ), ]; @@ -857,12 +860,12 @@ mod math_functions { }; let rule = Rule::Function(Function::new_muldiv( - Value::BigNum(10.into()), - Value::BigNum(10.into()), - Value::BigNum(2.into()), + Value::UnifiedNum(10.into()), + Value::UnifiedNum(10.into()), + Value::UnifiedNum(2.into()), )); assert_eq!( - Ok(Some(Value::BigNum(50.into()))), + Ok(Some(Value::UnifiedNum(50.into()))), rule.eval(&input, &mut output) ); } @@ -992,8 +995,16 @@ mod control_flow_and_logic { }; let cases = [ - (Value::BigNum(1.into()), Value::BigNum(1.into()), true), - (Value::BigNum(1.into()), Value::BigNum(2.into()), false), + ( + Value::UnifiedNum(1.into()), + Value::UnifiedNum(1.into()), + true, + ), + ( + Value::UnifiedNum(1.into()), + Value::UnifiedNum(2.into()), + false, + ), ( Value::Number(Number::from_f64(3.33).expect("should create float")), Value::Number(Number::from_f64(3.33).expect("should create float")), @@ -1073,8 +1084,16 @@ mod control_flow_and_logic { }; let cases = [ - (Value::BigNum(1.into()), Value::BigNum(1.into()), false), - (Value::BigNum(1.into()), Value::BigNum(2.into()), true), + ( + Value::UnifiedNum(1.into()), + Value::UnifiedNum(1.into()), + false, + ), + ( + Value::UnifiedNum(1.into()), + Value::UnifiedNum(2.into()), + true, + ), (Value::Bool(true), Value::Bool(true), false), (Value::Bool(true), Value::Bool(false), true), ( @@ -1145,10 +1164,10 @@ mod control_flow_and_logic { boost: 1.0, price: Default::default(), }; - let result = Value::BigNum(200.into()); + let result = Value::UnifiedNum(200.into()); let rule = Rule::Function(Function::new_add( - Value::BigNum(100.into()), - Value::BigNum(100.into()), + Value::UnifiedNum(100.into()), + Value::UnifiedNum(100.into()), )); let rule_do = Rule::Function(Function::new_do(rule)); assert_eq!(Ok(Some(result)), rule_do.eval(&input, &mut output)); @@ -1169,20 +1188,20 @@ mod string_and_array { let cases = vec![ ( vec![ - Value::BigNum(1.into()), - Value::BigNum(2.into()), - Value::BigNum(3.into()), + Value::UnifiedNum(1.into()), + Value::UnifiedNum(2.into()), + Value::UnifiedNum(3.into()), ], - Value::BigNum(1.into()), + Value::UnifiedNum(1.into()), true, ), ( vec![ - Value::BigNum(1.into()), - Value::BigNum(2.into()), - Value::BigNum(3.into()), + Value::UnifiedNum(1.into()), + Value::UnifiedNum(2.into()), + Value::UnifiedNum(3.into()), ], - Value::BigNum(0.into()), + Value::UnifiedNum(0.into()), false, ), ]; @@ -1367,27 +1386,4 @@ mod string_and_array { assert_eq!(Ok(expected), rule.eval(&input, &mut output)); } } - - #[test] - fn test_get_price_in_usd_eval() { - let mut output = Output { - show: true, - boost: 1.0, - price: Default::default(), - }; - for (key, value) in &*DEPOSIT_ASSETS_MAP { - let mut asset_campaign = DUMMY_CAMPAIGN.clone(); - asset_campaign.channel.token = *key; - let input = get_default_input().with_campaign(asset_campaign); - - let amount_crypto = BigNum::from(100).mul(value); - let amount_usd = Some(Value::Number( - Number::from_f64(100.0).expect("should create a float"), - )); - let rule = Rule::Function(Function::new_get_price_in_usd(Rule::Value(Value::BigNum( - amount_crypto, - )))); - assert_eq!(Ok(amount_usd), rule.eval(&input, &mut output)); - } - } } diff --git a/primitives/src/targeting/input.rs b/primitives/src/targeting/input.rs index 68d645c59..e1ad4dbef 100644 --- a/primitives/src/targeting/input.rs +++ b/primitives/src/targeting/input.rs @@ -1,3 +1,5 @@ +use self::campaign::FullCampaign; + use super::{Error, Value}; use crate::{Address, ToETHChecksum, IPFS}; use chrono::{serde::ts_seconds, DateTime, Utc}; @@ -47,23 +49,15 @@ pub struct Input { impl Input { /// Sets the Channel Getter pub fn with_campaign(mut self, campaign: crate::Campaign) -> Self { - self.campaign = Some(Get::Getter(campaign::Getter::from_campaign( - &self, campaign, - ))); - - self - } - - pub fn with_market_channel( - mut self, - channel: crate::supermarket::units_for_slot::response::Channel, - ) -> Self { - self.campaign = Some(Get::Getter(campaign::Getter::from_market(channel))); + self.campaign = Some(Get::Getter(FullCampaign { + campaign, + event_type: self.global.event_type.clone(), + })); self } - pub fn with_balances(mut self, balances: crate::BalancesMap) -> Self { + pub fn with_balances(mut self, balances: crate::UnifiedMap) -> Self { self.balances = Some(Get::Getter(balances::Getter { balances, publisher_id: self.global.publisher_id, @@ -106,8 +100,8 @@ impl GetField for Input { match field { Field::AdView(ad_view) => self.ad_view.get(ad_view), Field::Global(global) => self.global.get(global), - Field::Channel(channel) => self.campaign.get(channel).flatten(), - Field::Balances(balances) => self.balances.get(balances), + Field::Campaign(channel) => self.campaign.get(channel).flatten(), + Field::Balances(balances) => self.balances.get(balances).flatten(), Field::AdSlot(ad_slot) => self.ad_slot.get(ad_slot).flatten(), Field::AdUnit(ad_unit) => match ad_unit { field::AdUnit::AdUnitId => self @@ -215,9 +209,9 @@ pub mod campaign { use serde::Deserialize; use super::{field, Get, GetField, Value}; - use crate::{targeting::get_pricing_bounds, Address, BigNum, CampaignId, ToHex}; + use crate::{targeting::get_pricing_bounds, Address, CampaignId, ToHex, UnifiedNum}; - pub type GetCampaign = Get; + pub type GetCampaign = Get; #[derive(Debug, Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] @@ -226,9 +220,9 @@ pub mod campaign { pub campaign_id: CampaignId, pub campaign_seconds_active: u64, pub campaign_seconds_duration: u64, - pub campaign_budget: BigNum, - pub event_min_price: Option, - pub event_max_price: Option, + pub campaign_budget: UnifiedNum, + pub event_min_price: Option, + pub event_max_price: Option, } #[derive(Debug, Clone, PartialEq)] @@ -237,70 +231,26 @@ pub mod campaign { pub(super) event_type: String, } - #[derive(Debug, Clone, PartialEq)] - /// The Getter for a Field that requires Channel can be either: - /// - a Full Campaign - /// - a Channel coming from the Supermarket - /// Since only the Full Campaign can get the pricing bounds, - /// we wrap the Campaign as well as the event_type of the Input - pub enum Getter { - Full(FullCampaign), - // - // TODO: AIP#61 Change to Campaign - // - Market(crate::supermarket::units_for_slot::response::Channel), - } - - impl Getter { - /// Input is used to set the Event Type of the Getter - pub fn from_campaign(input: &super::Input, campaign: crate::Campaign) -> Self { - Self::Full(FullCampaign { - campaign, - event_type: input.global.event_type.clone(), - }) - } - - pub fn from_market(channel: crate::supermarket::units_for_slot::response::Channel) -> Self { - Self::Market(channel) - } - } - - impl GetField for Get { + impl GetField for Get { type Output = Option; - type Field = field::Channel; + type Field = field::Campaign; fn get(&self, field: &Self::Field) -> Self::Output { match field { - field::Channel::AdvertiserId => Some(Value::String(match self { - Get::Getter(getter) => match getter { - Getter::Full(FullCampaign { campaign, .. }) => { - campaign.creator.to_hex_prefixed() - } - Getter::Market(s_channel) => s_channel.creator.to_hex_prefixed(), - }, + field::Campaign::AdvertiserId => Some(Value::String(match self { + Get::Getter(FullCampaign { campaign, .. }) => { + campaign.creator.to_hex_prefixed() + } Get::Value(Values { advertiser_id, .. }) => advertiser_id.to_hex_prefixed(), })), - field::Channel::CampaignId => Some(Value::String(match self { - Get::Getter(getter) => match getter { - Getter::Full(FullCampaign { campaign, .. }) => { - campaign.id.to_hex_prefixed() - } - Getter::Market(s_channel) => s_channel.id.to_hex_prefixed(), - }, + field::Campaign::CampaignId => Some(Value::String(match self { + Get::Getter(FullCampaign { campaign, .. }) => campaign.id.to_hex_prefixed(), Get::Value(Values { campaign_id, .. }) => campaign_id.to_hex_prefixed(), })), - field::Channel::CampaignSecondsActive => Some(Value::Number(match self { - Get::Getter(getter) => { - let (active_from, created) = match getter { - Getter::Full(FullCampaign { campaign, .. }) => { - (campaign.active.from, campaign.created) - } - Getter::Market(s_channel) => { - (s_channel.spec.active_from, s_channel.spec.created) - } - }; - - let duration = chrono::Utc::now() - active_from.unwrap_or(created); + field::Campaign::CampaignSecondsActive => Some(Value::Number(match self { + Get::Getter(FullCampaign { campaign, .. }) => { + let duration = + chrono::Utc::now() - campaign.active.from.unwrap_or(campaign.created); let seconds = duration .to_std() @@ -314,20 +264,10 @@ pub mod campaign { .. }) => (*campaign_seconds_active).into(), })), - field::Channel::CampaignSecondsDuration => Some(Value::Number(match self { - Get::Getter(getter) => { - let (active_to, active_from, created) = match getter { - Getter::Full(FullCampaign { campaign, .. }) => { - (campaign.active.to, campaign.active.from, campaign.created) - } - Getter::Market(s_channel) => ( - s_channel.spec.withdraw_period_start, - s_channel.spec.active_from, - s_channel.spec.created, - ), - }; - - let duration = active_to - active_from.unwrap_or(created); + field::Campaign::CampaignSecondsDuration => Some(Value::Number(match self { + Get::Getter(FullCampaign { campaign, .. }) => { + let duration = + campaign.active.to - campaign.active.from.unwrap_or(campaign.created); let seconds = duration .to_std() @@ -341,36 +281,33 @@ pub mod campaign { .. }) => (*campaign_seconds_duration).into(), })), - field::Channel::CampaignBudget => Some(Value::BigNum(match self { - Get::Getter(getter) => match getter { - Getter::Full(FullCampaign { campaign, .. }) => campaign.budget.to_bignum(), - Getter::Market(s_channel) => s_channel.deposit_amount.clone(), - }, + field::Campaign::CampaignBudget => Some(Value::UnifiedNum(match self { + Get::Getter(FullCampaign { campaign, .. }) => campaign.budget, Get::Value(Values { campaign_budget, .. - }) => campaign_budget.clone(), + }) => *campaign_budget, })), - field::Channel::EventMinPrice => match self { - Get::Getter(Getter::Full(FullCampaign { + field::Campaign::EventMinPrice => match self { + Get::Getter(FullCampaign { campaign, event_type, - })) => Some(Value::BigNum(get_pricing_bounds(campaign, event_type).min)), - // The supermarket Channel, does not have enough information to return the event_min_price - Get::Getter(Getter::Market(_)) => None, + }) => Some(Value::UnifiedNum( + get_pricing_bounds(campaign, event_type).min, + )), Get::Value(Values { event_min_price, .. - }) => event_min_price.clone().map(Value::BigNum), + }) => event_min_price.map(Value::UnifiedNum), }, - field::Channel::EventMaxPrice => match self { - Get::Getter(Getter::Full(FullCampaign { + field::Campaign::EventMaxPrice => match self { + Get::Getter(FullCampaign { campaign, event_type, - })) => Some(Value::BigNum(get_pricing_bounds(campaign, event_type).max)), - // The supermarket Channel, does not have enough information to return the event_max_price - Get::Getter(Getter::Market(_)) => None, + }) => Some(Value::UnifiedNum( + get_pricing_bounds(campaign, event_type).max, + )), Get::Value(Values { event_max_price, .. - }) => event_max_price.clone().map(Value::BigNum), + }) => event_max_price.map(Value::UnifiedNum), }, } } @@ -379,7 +316,7 @@ pub mod campaign { pub mod balances { use super::{field, Get, GetField, Value}; - use crate::{Address, BalancesMap, BigNum}; + use crate::{Address, UnifiedMap, UnifiedNum}; use serde::Deserialize; pub type GetBalances = Get; @@ -387,39 +324,45 @@ pub mod balances { #[derive(Debug, Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Values { - pub campaign_total_spent: BigNum, - pub publisher_earned_from_campaign: BigNum, + pub campaign_total_spent: UnifiedNum, + pub publisher_earned_from_campaign: UnifiedNum, } #[derive(Debug, Clone, PartialEq)] pub struct Getter { - pub balances: BalancesMap, + pub balances: UnifiedMap, pub(super) publisher_id: Address, } impl GetField for Get { - type Output = Value; + type Output = Option; type Field = field::Balances; - fn get(&self, field: &Self::Field) -> Value { + fn get(&self, field: &Self::Field) -> Self::Output { match field { - field::Balances::CampaignTotalSpent => Value::BigNum(match self { - Get::Getter(Getter { balances, .. }) => balances.values().sum(), + field::Balances::CampaignTotalSpent => match self { + Get::Getter(Getter { balances, .. }) => balances + .values() + .sum::>() + .map(Value::UnifiedNum), Get::Value(Values { campaign_total_spent, .. - }) => campaign_total_spent.clone(), - }), - field::Balances::PublisherEarnedFromCampaign => Value::BigNum(match self { - Get::Getter(Getter { - balances, - publisher_id, - }) => balances.get(publisher_id).cloned().unwrap_or_default(), - Get::Value(Values { - publisher_earned_from_campaign, - .. - }) => publisher_earned_from_campaign.clone(), - }), + }) => Some(Value::UnifiedNum(*campaign_total_spent)), + }, + // Leave the default of `0` if the publisher is not found in the balances. + field::Balances::PublisherEarnedFromCampaign => { + Some(Value::UnifiedNum(match self { + Get::Getter(Getter { + balances, + publisher_id, + }) => balances.get(publisher_id).cloned().unwrap_or_default(), + Get::Value(Values { + publisher_earned_from_campaign, + .. + }) => *publisher_earned_from_campaign, + })) + } } } } @@ -430,7 +373,7 @@ mod test { use super::*; pub use crate::{ util::tests::prep_db::{ADDRESSES, DUMMY_CAMPAIGN as CAMPAIGN, DUMMY_IPFS as IPFS}, - AdUnit, BalancesMap, + AdUnit, UnifiedMap, }; use chrono::{TimeZone, Utc}; use serde_json::json; @@ -470,7 +413,7 @@ mod test { let actual_date = Utc.ymd(2020, 6, 6).and_hms(12, 0, 0); - let balances: BalancesMap = vec![ + let balances: UnifiedMap = vec![ (ADDRESSES["publisher"], 30.into()), (ADDRESSES["leader"], 10.into()), ] @@ -499,7 +442,7 @@ mod test { campaign_id: CAMPAIGN.id, campaign_seconds_active: 40633521, campaign_seconds_duration: 2509030800, - campaign_budget: CAMPAIGN.budget.to_bignum(), + campaign_budget: CAMPAIGN.budget, event_min_price: Some( CAMPAIGN .pricing("IMPRESSION") diff --git a/primitives/src/targeting/input/field.rs b/primitives/src/targeting/input/field.rs index d4d96986d..9add498df 100644 --- a/primitives/src/targeting/input/field.rs +++ b/primitives/src/targeting/input/field.rs @@ -21,14 +21,14 @@ pub const FIELDS: [Field; 24] = [ // Campaign-dependant - Global scope, accessible everywhere // AdUnit Field::AdUnit(AdUnit::AdUnitId), - // Channel - Field::Channel(Channel::AdvertiserId), - Field::Channel(Channel::CampaignId), - Field::Channel(Channel::CampaignSecondsActive), - Field::Channel(Channel::CampaignSecondsDuration), - Field::Channel(Channel::CampaignBudget), - Field::Channel(Channel::EventMinPrice), - Field::Channel(Channel::EventMaxPrice), + // Campaign + Field::Campaign(Campaign::AdvertiserId), + Field::Campaign(Campaign::CampaignId), + Field::Campaign(Campaign::CampaignSecondsActive), + Field::Campaign(Campaign::CampaignSecondsDuration), + Field::Campaign(Campaign::CampaignBudget), + Field::Campaign(Campaign::EventMinPrice), + Field::Campaign(Campaign::EventMaxPrice), // Balances Field::Balances(Balances::CampaignTotalSpent), Field::Balances(Balances::PublisherEarnedFromCampaign), @@ -54,7 +54,7 @@ pub enum Field { AdUnit(AdUnit), /// Global scope, accessible everywhere, campaign-dependant #[display("{0}")] - Channel(Channel), + Campaign(Campaign), /// Global scope, accessible everywhere, campaign-dependant #[display("{0}")] Balances(Balances), @@ -117,7 +117,7 @@ pub enum AdUnit { #[derive(Hash, Copy, Clone, Debug, Eq, PartialEq, DeriveFromStr, DeriveDisplay)] #[display(style = "camelCase")] -pub enum Channel { +pub enum Campaign { AdvertiserId, CampaignId, CampaignSecondsActive, @@ -127,7 +127,7 @@ pub enum Channel { EventMaxPrice, } -impl TryFrom for Channel { +impl TryFrom for Campaign { type Error = parse_display::ParseError; fn try_from(value: String) -> Result { @@ -135,8 +135,8 @@ impl TryFrom for Channel { } } -impl From for String { - fn from(channel: Channel) -> Self { +impl From for String { + fn from(channel: Campaign) -> Self { channel.to_string() } } @@ -318,7 +318,7 @@ mod test { SerdeValue::String("adUnitId".into()), ); test_field( - Field::Channel(Channel::CampaignBudget), + Field::Campaign(Campaign::CampaignBudget), SerdeValue::String("campaignBudget".into()), ); test_field( diff --git a/primitives/src/unified_num.rs b/primitives/src/unified_num.rs index 68cb18d57..69e7bf263 100644 --- a/primitives/src/unified_num.rs +++ b/primitives/src/unified_num.rs @@ -3,9 +3,11 @@ use num::{ pow::Pow, traits::CheckedRem, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Integer, One, }; use num_derive::{FromPrimitive, Num, NumCast, NumOps, ToPrimitive, Zero}; +use parse_display::{Display, FromStr, ParseError}; use serde::{Deserialize, Serialize}; use std::{ cmp::Ordering, + convert::TryFrom, fmt, iter::Sum, ops::{Add, AddAssign, Div, Mul, Sub}, @@ -19,6 +21,26 @@ use std::{ /// /// This number is (de)serialized as a Javascript number which is `f64`. /// As far as the numbers don't exceed `2**63`, the Javascript number should be sufficient without losing precision +/// +/// # Examples +/// +/// ```rust +/// use primitives::UnifiedNum; +/// use serde_json::Value; +/// +/// let unified_num = UnifiedNum::from(42_999_987_654_321); +/// +/// // Printing the unified num will show the value and the decimal point with precision of `UnifiedNum::PRECISION` (i.e. `8`) numbers after the decimal point +/// assert_eq!("42999987654321", &unified_num.to_string()); +/// +/// assert_eq!("429999.87654321", &unified_num.to_float_string()); +/// +/// // Printing the Debug of unified num will show the value and the decimal point with precision of `UnifiedNum::PRECISION` (i.e. `8`) numbers after the decimal point +/// assert_eq!("UnifiedNum(429999.87654321)".to_string(), format!("{:?}", &unified_num)); +/// +/// // JSON Serializing and Deserializing the `UnifiedNum` yields a string without any decimal points +/// assert_eq!(Value::String("42999987654321".to_string()), serde_json::to_value(unified_num).unwrap()); +/// ``` #[derive( Clone, Copy, @@ -33,14 +55,31 @@ use std::{ Eq, PartialOrd, Ord, + Display, + FromStr, Serialize, Deserialize, )] -#[serde(transparent)] +#[serde(into = "String", try_from = "String")] pub struct UnifiedNum(u64); +impl From for String { + fn from(unified_num: UnifiedNum) -> Self { + unified_num.to_string() + } +} + +impl TryFrom for UnifiedNum { + type Error = ParseError; + + fn try_from(value: String) -> Result { + value.parse() + } +} + impl UnifiedNum { pub const PRECISION: u8 = 8; + pub const DEBUG_DELIMITER: char = '.'; pub fn div_floor(&self, other: &Self) -> Self { Self(self.0.div_floor(&other.0)) @@ -50,11 +89,11 @@ impl UnifiedNum { Self(value) } - pub const fn to_u64(&self) -> u64 { + pub const fn to_u64(self) -> u64 { self.0 } - pub fn to_bignum(&self) -> BigNum { + pub fn to_bignum(self) -> BigNum { BigNum::from(self.0) } @@ -79,7 +118,7 @@ impl UnifiedNum { } /// Transform the UnifiedNum precision 8 to a new precision - pub fn to_precision(&self, precision: u8) -> BigNum { + pub fn to_precision(self, precision: u8) -> BigNum { let inner = BigNum::from(self.0); match precision.cmp(&Self::PRECISION) { Ordering::Equal => inner, @@ -87,33 +126,35 @@ impl UnifiedNum { Ordering::Greater => inner.mul(&BigNum::from(10).pow(precision - Self::PRECISION)), } } -} -impl From for UnifiedNum { - fn from(number: u64) -> Self { - Self(number) - } -} - -impl fmt::Display for UnifiedNum { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + pub fn to_float_string(self) -> String { let mut string_value = self.0.to_string(); let value_length = string_value.len(); let precision: usize = Self::PRECISION.into(); - if value_length > precision { - string_value.insert(value_length - precision, '.'); + let value = if value_length > precision { + string_value.insert(value_length - precision, Self::DEBUG_DELIMITER); - f.write_str(&string_value) + string_value } else { - write!(f, "0.{:0>8}", string_value) - } + format!("0{}{:0>8}", Self::DEBUG_DELIMITER, string_value) + }; + + value + } +} + +impl From for UnifiedNum { + fn from(number: u64) -> Self { + Self(number) } } impl fmt::Debug for UnifiedNum { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "UnifiedNum({})", self.to_string()) + let float_string = self.to_float_string(); + + write!(f, "UnifiedNum({})", float_string) } } @@ -289,21 +330,32 @@ mod test { } #[test] - fn unified_num_displays_and_de_serializes_correctly() { - let one = UnifiedNum::from(100_000_000); + fn unified_num_displays_debug_and_de_serializes_correctly() { + let zero = UnifiedNum::zero(); + let one = { + let manual_one = UnifiedNum::from(100_000_000); + let impl_one = UnifiedNum::one(); + assert_eq!(manual_one, impl_one); + + manual_one + }; let zero_point_one = UnifiedNum::from(10_000_000); let smallest_value = UnifiedNum::from(1); let random_value = UnifiedNum::from(144_903_000_567_000); - assert_eq!("1.00000000", &one.to_string()); - assert_eq!("1.00000000", &UnifiedNum::one().to_string()); - assert_eq!("0.00000000", &UnifiedNum::zero().to_string()); - assert_eq!("0.10000000", &zero_point_one.to_string()); - assert_eq!("0.00000001", &smallest_value.to_string()); - assert_eq!("1449030.00567000", &random_value.to_string()); + let dbg_format = |unified_num| -> String { format!("{:?}", unified_num) }; + + assert_eq!("UnifiedNum(1.00000000)", &dbg_format(&one)); + assert_eq!("UnifiedNum(0.00000000)", &dbg_format(&zero)); + assert_eq!("UnifiedNum(0.10000000)", &dbg_format(&zero_point_one)); + assert_eq!("UnifiedNum(0.00000001)", &dbg_format(&smallest_value)); + assert_eq!("UnifiedNum(1449030.00567000)", &dbg_format(&random_value)); + + let expected_one_string = "100000000".to_string(); + assert_eq!(&expected_one_string, &one.to_string()); assert_eq!( - serde_json::Value::Number(100_000_000.into()), + serde_json::Value::String(expected_one_string), serde_json::to_value(one).expect("Should serialize") ) } diff --git a/primitives/src/validator.rs b/primitives/src/validator.rs index 21c1ee2b3..81452b5c9 100644 --- a/primitives/src/validator.rs +++ b/primitives/src/validator.rs @@ -22,27 +22,13 @@ impl ValidatorId { self.0.as_bytes() } - pub fn to_address(&self) -> Address { + pub fn to_address(self) -> Address { self.0 } pub fn inner(&self) -> &[u8; 20] { &self.0.as_bytes() } - - /// To Hex non-`0x` prefixed string without **Checksum**ing the string - /// For backwards compatibility - /// TODO: Remove once we change all places this method is used at - pub fn to_hex_non_prefix_string(&self) -> String { - self.0.to_hex() - } - - /// To Hex `0x` prefixed string **without** __Checksum__ing the string - /// For backwards compatibility - /// TODO: Remove once we change all places this method is used at - pub fn to_hex_prefix_string(&self) -> String { - self.0.to_hex_prefixed() - } } impl ToETHChecksum for ValidatorId {} diff --git a/sentry/src/payout.rs b/sentry/src/payout.rs index ccc364467..9dd82a219 100644 --- a/sentry/src/payout.rs +++ b/sentry/src/payout.rs @@ -4,12 +4,12 @@ use primitives::{ sentry::Event, targeting::Input, targeting::{eval_with_callback, get_pricing_bounds, input, Error, Output}, - Address, BigNum, Campaign, + Address, Campaign, UnifiedNum, }; use slog::{error, Logger}; use std::cmp::{max, min}; -pub type Result = std::result::Result, Error>; +pub type Result = std::result::Result, Error>; pub fn get_payout( logger: &Logger,