Skip to content

GET total_deposited + spender_leaf route completed + tests #416

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Aug 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e7489ea
GET total_deposited + spender_leaf route completed + tests
simzzz Jul 20, 2021
485e76c
fixed failing test
simzzz Jul 26, 2021
b2c5893
removed a comment, changed another comment
simzzz Jul 26, 2021
085b056
fixed params, channel_id and spender were swapped accidentially in ge…
simzzz Jul 27, 2021
6b8c575
renamed function + cargo fmt
simzzz Jul 27, 2021
d77045c
changed SpenderResponse to use Option for its fields + fixed default …
simzzz Jul 28, 2021
5703b6e
changed address in tests to more suitable one
simzzz Aug 5, 2021
a8ec98f
current progress - friday
simzzz Aug 9, 2021
31e20f3
committing current progress
simzzz Aug 11, 2021
1f659b8
Merge branch 'aip-61-adex-v5' into issue-391-get-spender-info
simzzz Aug 11, 2021
59210b3
final requested change
simzzz Aug 12, 2021
69201f2
added from_precision function for UnifiedNum, changed Spendable to us…
simzzz Aug 12, 2021
325c534
primitives - UnifiedNum - from_precision & to_unified_precision
elpiel Aug 12, 2021
cc5987d
changes to failing test
simzzz Aug 12, 2021
b9d7115
fixed failing test
simzzz Aug 13, 2021
cae048d
changes to precision and tests
simzzz Aug 13, 2021
3c09aca
primitives - UnifiedNum - clean up tests
elpiel Aug 16, 2021
85953d4
Merge pull request #419 from AdExNetwork/issue-391-unified-num-precis…
simzzz Aug 16, 2021
37fc3b8
requested changes from pr + cargo fmt
simzzz Aug 16, 2021
5f04f18
misc fixes and chanes to create/fetch spendable test
simzzz Aug 18, 2021
76a7c01
used default channel token in test
simzzz Aug 19, 2021
1473978
Merge branch 'aip-61-adex-v5' into issue-391-get-spender-info
simzzz Aug 19, 2021
dd19926
changed the way spender balances are retrieved from newstate + format…
simzzz Aug 19, 2021
79f02cc
clippy fixes
simzzz Aug 19, 2021
193a8dc
Merge branch 'aip-61-adex-v5' into issue-391-get-spender-info
simzzz Aug 24, 2021
a1a7886
fixed errors after merge, changed tests to use development, checking …
simzzz Aug 24, 2021
a2eb3eb
added .into_inner() to msg + cargo fmt
simzzz Aug 24, 2021
cb21b5b
test fixes
simzzz Aug 25, 2021
5d8b0fe
moved request appropriately
simzzz Aug 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions primitives/src/sentry.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
balances::BalancesState,
channel_v5::Channel as ChannelV5,
spender::Spender,
validator::{ApproveState, Heartbeat, MessageTypes, NewState, Type as MessageType},
Address, Balances, BigNum, Channel, ChannelId, ValidatorId, IPFS,
};
Expand Down Expand Up @@ -207,6 +208,12 @@ pub struct SuccessResponse {
pub success: bool,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct SpenderResponse {
pub spender: Spender,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct ValidatorMessage {
pub from: ValidatorId,
Expand Down
38 changes: 23 additions & 15 deletions primitives/src/spender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,23 @@ pub struct Deposit {
pub still_on_create2: UnifiedNum,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct SpenderLeaf {
pub total_spent: UnifiedNum,
// merkle_proof: [u8; 32], // TODO
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Spender {
pub total_deposited: UnifiedNum,
pub spender_leaf: Option<SpenderLeaf>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Spendable {
pub spender: Address,
pub channel: Channel,
#[serde(flatten)]
pub deposit: Deposit,
}

Expand All @@ -27,23 +39,19 @@ pub struct Aggregate {
}
#[cfg(feature = "postgres")]
mod postgres {
use std::convert::TryFrom;
use tokio_postgres::{Error, Row};

use super::*;
use tokio_postgres::Row;

impl TryFrom<Row> for Spendable {
type Error = Error;

fn try_from(row: Row) -> Result<Self, Self::Error> {
Ok(Spendable {
spender: row.try_get("spender")?,
channel: row.try_get("channel")?,
impl From<Row> for Spendable {
fn from(row: Row) -> Self {
Self {
spender: row.get("spender"),
channel: row.get("channel"),
deposit: Deposit {
total: row.try_get("total")?,
still_on_create2: row.try_get("still_on_create2")?,
total: row.get("total"),
still_on_create2: row.get("still_on_create2"),
},
})
}
}
}
}
40 changes: 38 additions & 2 deletions primitives/src/unified_num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,29 @@ impl UnifiedNum {
/// Transform the UnifiedNum precision 8 to a new precision
pub fn to_precision(self, precision: u8) -> BigNum {
let inner = BigNum::from(self.0);

match precision.cmp(&Self::PRECISION) {
Ordering::Equal => inner,
Ordering::Less => inner.div_floor(&BigNum::from(10).pow(Self::PRECISION - precision)),
Ordering::Greater => inner.mul(&BigNum::from(10).pow(precision - Self::PRECISION)),
}
}

/// Transform the BigNum of a given precision to UnifiedNum with precision 8
/// If the resulting value is larger that what UnifiedNum can hold, it will return `None`
pub fn from_precision(amount: BigNum, precision: u8) -> Option<Self> {
// conversation to the UnifiedNum precision is happening with BigNum
let from_precision = match precision.cmp(&Self::PRECISION) {
Ordering::Equal => amount,
Ordering::Less => amount.mul(&BigNum::from(10).pow(Self::PRECISION - precision)),
Ordering::Greater => {
amount.div_floor(&BigNum::from(10).pow(precision - Self::PRECISION))
}
};
// only at the end, see if it fits in `u64`
from_precision.to_u64().map(Self)
}

pub fn to_float_string(self) -> String {
let mut string_value = self.0.to_string();
let value_length = string_value.len();
Expand Down Expand Up @@ -361,7 +377,7 @@ mod test {
}

#[test]
fn test_convert_unified_num_to_new_precision() {
fn test_convert_unified_num_to_new_precision_and_from_precision() {
let dai_precision: u8 = 18;
let usdt_precision: u8 = 6;
let same_precision = UnifiedNum::PRECISION;
Expand All @@ -371,7 +387,13 @@ mod test {
// 321.00000000
let dai_unified = UnifiedNum::from(32_100_000_000_u64);
let dai_expected = BigNum::from(321_u64) * dai_power;
assert_eq!(dai_expected, dai_unified.to_precision(dai_precision));
let dai_bignum = dai_unified.to_precision(dai_precision);
assert_eq!(dai_expected, dai_bignum);
assert_eq!(
dai_unified,
UnifiedNum::from_precision(dai_bignum, dai_precision)
.expect("Should not overflow the UnifiedNum")
);

// 321.00000777 - should floor to 321.000007 (precision 6)
let usdt_unified = UnifiedNum::from(32_100_000_777_u64);
Expand All @@ -389,6 +411,20 @@ mod test {
same_unified.to_precision(same_precision),
"It should not make any adjustments to the precision"
);

// `u64::MAX + 1` should return `None`
let larger_bignum = BigNum::from(u64::MAX) + BigNum::from(1);

// USDT - 18446744073709.551616
assert!(UnifiedNum::from_precision(larger_bignum.clone(), usdt_precision).is_none());

assert_eq!(
// DAI - 18.446744073709551616 (MAX + 1)
Some(UnifiedNum::from(1844674407)),
// UnifiedNum - 18.44674407
UnifiedNum::from_precision(larger_bignum, dai_precision),
"Should floor the large BigNum"
);
}
}

Expand Down
8 changes: 4 additions & 4 deletions primitives/src/util/tests/prep_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ lazy_static! {
addresses
};

// These are the real Addresses of these stablecoins, however, they are only used for testing!
// These are the Goerli testnet Addresses of these stablecoins
pub static ref TOKENS: HashMap<String, Address> = {
let mut tokens = HashMap::new();

tokens.insert("DAI".into(), "0x6b175474e89094c44da98b954eedeac495271d0f".parse::<Address>().expect("Should parse"));
tokens.insert("USDT".into(), "0xdac17f958d2ee523a2206206994597c13d831ec7".parse::<Address>().expect("failed to parse id"));
tokens.insert("USDC".into(), "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48".parse::<Address>().expect("failed to parse id"));
tokens.insert("DAI".into(), "0x73967c6a0904aa032c103b4104747e88c566b1a2".parse::<Address>().expect("Should parse"));
tokens.insert("USDT".into(), "0x509ee0d083ddf8ac028f2a56731412edd63223b9".parse::<Address>().expect("failed to parse id"));
tokens.insert("USDC".into(), "0x44dcfcead37be45206af6079648988b29284b2c6".parse::<Address>().expect("failed to parse id"));
tokens
};

Expand Down
36 changes: 36 additions & 0 deletions sentry/src/db/event_aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use chrono::{DateTime, Utc};
use futures::pin_mut;
use primitives::{
balances::UncheckedState,
channel_v5::Channel as ChannelV5,
sentry::{EventAggregate, MessageResponse},
validator::{ApproveState, Heartbeat, NewState},
Address, BigNum, Channel, ChannelId, ValidatorId,
Expand Down Expand Up @@ -34,6 +35,23 @@ pub async fn latest_approve_state(
.map_err(PoolError::Backend)
}

pub async fn latest_approve_state_v5(
pool: &DbPool,
channel: &ChannelV5,
) -> Result<Option<MessageResponse<ApproveState>>, PoolError> {
let client = pool.get().await?;

let select = client.prepare("SELECT \"from\", msg, received FROM validator_messages WHERE channel_id = $1 AND \"from\" = $2 AND msg ->> 'type' = 'ApproveState' ORDER BY received DESC LIMIT 1").await?;
let rows = client
.query(&select, &[&channel.id(), &channel.follower])
.await?;

rows.get(0)
.map(MessageResponse::<ApproveState>::try_from)
.transpose()
.map_err(PoolError::Backend)
}

pub async fn latest_new_state(
pool: &DbPool,
channel: &Channel,
Expand All @@ -59,6 +77,24 @@ pub async fn latest_new_state(
.map_err(PoolError::Backend)
}

pub async fn latest_new_state_v5(
pool: &DbPool,
channel: &ChannelV5,
state_root: &str,
) -> Result<Option<MessageResponse<NewState<UncheckedState>>>, PoolError> {
let client = pool.get().await?;

let select = client.prepare("SELECT \"from\", msg, received FROM validator_messages WHERE channel_id = $1 AND \"from\" = $2 AND msg ->> 'type' = 'NewState' AND msg->> 'stateRoot' = $3 ORDER BY received DESC LIMIT 1").await?;
let rows = client
.query(&select, &[&channel.id(), &channel.leader, &state_root])
.await?;

rows.get(0)
.map(MessageResponse::<NewState<UncheckedState>>::try_from)
.transpose()
.map_err(PoolError::Backend)
}

pub async fn latest_heartbeats(
pool: &DbPool,
channel_id: &ChannelId,
Expand Down
27 changes: 24 additions & 3 deletions sentry/src/db/spendable.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::convert::TryFrom;

use primitives::{spender::Spendable, Address, ChannelId};

use super::{DbPool, PoolError};
Expand Down Expand Up @@ -43,7 +41,30 @@ pub async fn fetch_spendable(

let row = client.query_opt(&statement, &[spender, channel_id]).await?;

Ok(row.map(Spendable::try_from).transpose()?)
Ok(row.map(Spendable::from))
}

static UPDATE_SPENDABLE_STATEMENT: &str = "INSERT INTO spendable(spender, channel_id, channel, total, still_on_create2) VALUES($1, $2, $3, $4, $5) ON CONFLICT ON CONSTRAINT spendable_pkey DO UPDATE SET total = $4, still_on_create2 = $5 WHERE spendable.spender = $1 AND spendable.channel_id = $2 RETURNING spender, channel_id, channel, total, still_on_create2";

// Updates spendable entry deposit or inserts a new spendable entry if it doesn't exist
pub async fn update_spendable(pool: DbPool, spendable: &Spendable) -> Result<Spendable, PoolError> {
let client = pool.get().await?;
let statement = client.prepare(UPDATE_SPENDABLE_STATEMENT).await?;

let row = client
.query_one(
&statement,
&[
&spendable.spender,
&spendable.channel.id(),
&spendable.channel,
&spendable.deposit.total,
&spendable.deposit.still_on_create2,
],
)
.await?;

Ok(Spendable::from(row))
}

#[cfg(test)]
Expand Down
26 changes: 23 additions & 3 deletions sentry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ use routes::analytics::{advanced_analytics, advertiser_analytics, analytics, pub
use routes::campaign::{create_campaign, update_campaign};
use routes::cfg::config;
use routes::channel::{
channel_list, channel_validate, create_channel, create_validator_messages, last_approved,
channel_list, channel_validate, create_channel, create_validator_messages, get_spender_limits,
last_approved,
};
use slog::Logger;
use std::collections::HashMap;
Expand Down Expand Up @@ -63,6 +64,7 @@ lazy_static! {
static ref ADVERTISER_ANALYTICS_BY_CHANNEL_ID: Regex = Regex::new(r"^/analytics/for-advertiser/0x([a-zA-Z0-9]{64})/?$").expect("The regex should be valid");
static ref PUBLISHER_ANALYTICS_BY_CHANNEL_ID: Regex = Regex::new(r"^/analytics/for-publisher/0x([a-zA-Z0-9]{64})/?$").expect("The regex should be valid");
static ref CREATE_EVENTS_BY_CHANNEL_ID: Regex = Regex::new(r"^/channel/0x([a-zA-Z0-9]{64})/events/?$").expect("The regex should be valid");
static ref CHANNEL_SPENDER_LEAF_AND_TOTAL_DEPOSITED: Regex = Regex::new(r"^/v5/channel/0x([a-zA-Z0-9]{64})/spender/0x([a-zA-Z0-9]{40})/?$").expect("This regex should be valid");
}

static INSERT_EVENTS_BY_CAMPAIGN_ID: Lazy<Regex> = Lazy::new(|| {
Expand Down Expand Up @@ -373,6 +375,24 @@ async fn channels_router<A: Adapter + 'static>(
req = ChannelLoad.call(req, app).await?;

list_channel_event_aggregates(req, app).await
} else if let (Some(caps), &Method::GET) = (
CHANNEL_SPENDER_LEAF_AND_TOTAL_DEPOSITED.captures(&path),
method,
) {
let param = RouteParams(vec![
caps.get(1)
.map_or("".to_string(), |m| m.as_str().to_string()), // channel ID
caps.get(2)
.map_or("".to_string(), |m| m.as_str().to_string()), // spender addr
]);
req.extensions_mut().insert(param);
req = Chain::new()
.chain(AuthRequired)
.chain(ChannelLoad)
.apply(req, app)
.await?;

get_spender_limits(req, app).await
} else {
Err(ResponseError::NotFound)
}
Expand Down Expand Up @@ -513,9 +533,9 @@ pub mod test_util {
Application,
};

/// Uses production configuration to setup the correct Contract addresses for tokens.
/// Uses development and therefore the goreli testnet addresses of the tokens
pub async fn setup_dummy_app() -> Application<DummyAdapter> {
let config = configuration("production", None).expect("Should get Config");
let config = configuration("development", None).expect("Should get Config");
let adapter = DummyAdapter::init(
DummyAdapterOptions {
dummy_identity: IDS["leader"],
Expand Down
Loading