Skip to content

Commit 8e8c24c

Browse files
authored
Merge pull request #400 from AdExNetwork/issue-382-channel-and-campaign
Issue #382 Channel and Campaign Database & Persistance
2 parents f8af066 + 21037aa commit 8e8c24c

File tree

19 files changed

+600
-228
lines changed

19 files changed

+600
-228
lines changed

adapter/src/ethereum/test_utils.rs

+2
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ pub async fn deploy_token_contract(
234234
let token_info = TokenInfo {
235235
min_token_units_for_deposit: BigNum::from(min_token_units),
236236
precision: NonZeroU8::new(18).expect("should create NonZeroU8"),
237+
// 0.000_1
238+
min_validator_fee: BigNum::from(100_000_000_000_000),
237239
};
238240

239241
Ok((token_info, token_contract.address(), token_contract))

docs/config/dev.toml

+15-7
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ validator_tick_timeout = 5000
1919
ip_rate_limit = { type = 'ip', timeframe = 20000 }
2020
sid_rate_limit = { type = 'sid', timeframe = 20000 }
2121

22-
ethereum_core_address = '0x333420fc6a897356e69b62417cd17ff012177d2b'
2322
# TODO: Replace with real contract address
2423
outpace_address = '0x333420fc6a897356e69b62417cd17ff012177d2b'
2524
# TODO: Replace with real contract address
@@ -29,21 +28,30 @@ ethereum_network = 'http://localhost:8545'
2928
ethereum_adapter_relayer = 'https://goerli-relayer.adex.network'
3029

3130
creators_whitelist = []
32-
minimal_deposit = "0"
33-
minimal_fee = "0"
3431
validators_whitelist = []
3532

3633
[[token_address_whitelist]]
37-
address = '0x73967c6a0904aa032c103b4104747e88c566b1a2' #DAI
34+
# DAI
35+
address = '0x73967c6a0904aa032c103b4104747e88c566b1a2'
36+
# 1 * 10^-10 = 0.0_000_000_001
3837
min_token_units_for_deposit = '100000000'
38+
min_validator_fee = '100000000'
3939
precision = 18
4040

4141
[[token_address_whitelist]]
42-
address = '0x509ee0d083ddf8ac028f2a56731412edd63223b9' #USDT
43-
min_token_units_for_deposit = '100000000'
42+
# USDT
43+
address = '0x509ee0d083ddf8ac028f2a56731412edd63223b9'
44+
# 1.000_000
45+
min_token_units_for_deposit = '1000000'
46+
# 0.001
47+
min_validator_fee = '1000'
4448
precision = 6
4549

4650
[[token_address_whitelist]]
47-
address = '0x44dcfcead37be45206af6079648988b29284b2c6' #USDC
51+
# USDC
52+
address = '0x44dcfcead37be45206af6079648988b29284b2c6'
53+
# 1.000_000
4854
min_token_units_for_deposit = '100000000'
55+
# 0.001
56+
min_validator_fee = '1000'
4957
precision = 6

docs/config/prod.toml

+21-9
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ validator_tick_timeout = 10000
1818

1919
ip_rate_limit = { type = 'ip', timeframe = 1200000 }
2020
sid_rate_limit = { type = 'sid', timeframe = 0 }
21-
ethereum_core_address = '0x333420fc6a897356e69b62417cd17ff012177d2b'
21+
2222
# TODO: Replace with real contract address
2323
outpace_address = '0x333420fc6a897356e69b62417cd17ff012177d2b'
2424
# TODO: Replace with real contract address
@@ -28,27 +28,39 @@ ethereum_network = 'http://localhost:8545'
2828
ethereum_adapter_relayer = 'https://relayer.adex.network'
2929

3030
creators_whitelist = []
31-
minimal_deposit = "0"
32-
minimal_fee = "0"
3331
validators_whitelist = []
3432

33+
3534
[[token_address_whitelist]]
36-
address = '0x6b175474e89094c44da98b954eedeac495271d0f' #DAI
35+
# DAI
36+
address = '0x6b175474e89094c44da98b954eedeac495271d0f'
37+
# 1 * 10^-10 = 0.0_000_000_001
3738
min_token_units_for_deposit = '100000000'
39+
min_validator_fee = '100000000'
3840
precision = 18
3941

4042
[[token_address_whitelist]]
41-
address = '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359' #SAI
43+
# SAI
44+
address = '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359'
45+
# 1 * 10^-10 = 0.0_000_000_001
4246
min_token_units_for_deposit = '100000000'
47+
min_validator_fee = '100000000'
4348
precision = 18
4449

4550
[[token_address_whitelist]]
46-
address = '0xdac17f958d2ee523a2206206994597c13d831ec7' #USDT
47-
min_token_units_for_deposit = '100000000'
51+
# USDT
52+
address = '0xdac17f958d2ee523a2206206994597c13d831ec7'
53+
# 1.000_000
54+
min_token_units_for_deposit = '1000000'
55+
# 0.001
56+
min_validator_fee = '1000'
4857
precision = 6
4958

5059
[[token_address_whitelist]]
51-
address = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' #USDC
60+
# USDC
61+
address = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
62+
# 1.000_000
5263
min_token_units_for_deposit = '100000000'
64+
# 0.001
65+
min_validator_fee = '1000'
5366
precision = 6
54-

primitives/src/ad_unit.rs

+31
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,34 @@ pub struct AdUnit {
5252
)]
5353
pub modified: Option<DateTime<Utc>>,
5454
}
55+
56+
#[cfg(feature = "postgres")]
57+
mod postgres {
58+
use super::AdUnit;
59+
60+
use bytes::BytesMut;
61+
use postgres_types::{accepts, to_sql_checked, FromSql, IsNull, Json, ToSql, Type};
62+
use std::error::Error;
63+
impl<'a> FromSql<'a> for AdUnit {
64+
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
65+
let json = <Json<Self> as FromSql>::from_sql(ty, raw)?;
66+
67+
Ok(json.0)
68+
}
69+
70+
accepts!(JSONB);
71+
}
72+
73+
impl ToSql for AdUnit {
74+
fn to_sql(
75+
&self,
76+
ty: &Type,
77+
w: &mut BytesMut,
78+
) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
79+
Json(self).to_sql(ty, w)
80+
}
81+
82+
accepts!(JSONB);
83+
to_sql_checked!();
84+
}
85+
}

primitives/src/adapter.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::{
2-
channel::ChannelError, channel_v5::Channel, Address,
3-
BigNum, DomainError, ValidatorId,
2+
channel::ChannelError, channel_v5::Channel, Address, BigNum, DomainError, ValidatorId,
43
};
54
use async_trait::async_trait;
65
use serde::{Deserialize, Serialize};

primitives/src/campaign.rs

+120-47
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ mod campaign_id {
3535
pub struct CampaignId([u8; 16]);
3636

3737
impl CampaignId {
38+
/// Generates randomly a `CampaignId` using `Uuid::new_v4().to_simple()`
3839
pub fn new() -> Self {
3940
Self::default()
4041
}
@@ -184,32 +185,26 @@ pub struct Campaign {
184185
}
185186

186187
impl Campaign {
187-
pub fn find_validator(&self, validator: ValidatorId) -> Option<&'_ ValidatorDesc> {
188+
pub fn find_validator(&self, validator: &ValidatorId) -> Option<ValidatorRole<'_>> {
188189
match (self.leader(), self.follower()) {
189-
(Some(leader), _) if leader.id == validator => Some(leader),
190-
(_, Some(follower)) if follower.id == validator => Some(follower),
190+
(Some(leader), _) if &leader.id == validator => Some(ValidatorRole::Leader(leader)),
191+
(_, Some(follower)) if &follower.id == validator => {
192+
Some(ValidatorRole::Follower(follower))
193+
}
191194
_ => None,
192195
}
193196
}
194197

195198
/// Matches the Channel.leader to the Campaign.spec.leader
196199
/// If they match it returns `Some`, otherwise, it returns `None`
197200
pub fn leader(&self) -> Option<&'_ ValidatorDesc> {
198-
if self.channel.leader == self.validators.leader().id {
199-
Some(self.validators.leader())
200-
} else {
201-
None
202-
}
201+
self.validators.find(&self.channel.leader)
203202
}
204203

205204
/// Matches the Channel.follower to the Campaign.spec.follower
206205
/// If they match it returns `Some`, otherwise, it returns `None`
207206
pub fn follower(&self) -> Option<&'_ ValidatorDesc> {
208-
if self.channel.follower == self.validators.follower().id {
209-
Some(self.validators.follower())
210-
} else {
211-
None
212-
}
207+
self.validators.find(&self.channel.follower)
213208
}
214209

215210
/// Returns the pricing of a given event
@@ -289,10 +284,10 @@ pub mod validators {
289284
use serde::{Deserialize, Serialize};
290285

291286
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
292-
/// A (leader, follower) tuple
287+
/// Unordered list of the validators representing the leader & follower
293288
pub struct Validators(ValidatorDesc, ValidatorDesc);
294289

295-
#[derive(Debug)]
290+
#[derive(Debug, PartialEq, Eq, Clone)]
296291
pub enum ValidatorRole<'a> {
297292
Leader(&'a ValidatorDesc),
298293
Follower(&'a ValidatorDesc),
@@ -308,33 +303,15 @@ pub mod validators {
308303
}
309304

310305
impl Validators {
311-
pub fn new(leader: ValidatorDesc, follower: ValidatorDesc) -> Self {
312-
Self(leader, follower)
313-
}
314-
315-
pub fn leader(&self) -> &ValidatorDesc {
316-
&self.0
306+
pub fn new(validators: (ValidatorDesc, ValidatorDesc)) -> Self {
307+
Self(validators.0, validators.1)
317308
}
318309

319-
pub fn follower(&self) -> &ValidatorDesc {
320-
&self.1
321-
}
322-
323-
pub fn find(&self, validator_id: &ValidatorId) -> Option<ValidatorRole<'_>> {
324-
if &self.leader().id == validator_id {
325-
Some(ValidatorRole::Leader(&self.leader()))
326-
} else if &self.follower().id == validator_id {
327-
Some(ValidatorRole::Follower(&self.follower()))
328-
} else {
329-
None
330-
}
331-
}
332-
333-
pub fn find_index(&self, validator_id: &ValidatorId) -> Option<u32> {
334-
if &self.leader().id == validator_id {
335-
Some(0)
336-
} else if &self.follower().id == validator_id {
337-
Some(1)
310+
pub fn find(&self, validator_id: &ValidatorId) -> Option<&ValidatorDesc> {
311+
if &self.0.id == validator_id {
312+
Some(&self.0)
313+
} else if &self.1.id == validator_id {
314+
Some(&self.1)
338315
} else {
339316
None
340317
}
@@ -346,8 +323,8 @@ pub mod validators {
346323
}
347324

348325
impl From<(ValidatorDesc, ValidatorDesc)> for Validators {
349-
fn from((leader, follower): (ValidatorDesc, ValidatorDesc)) -> Self {
350-
Self(leader, follower)
326+
fn from(validators: (ValidatorDesc, ValidatorDesc)) -> Self {
327+
Self(validators.0, validators.1)
351328
}
352329
}
353330

@@ -383,19 +360,115 @@ pub mod validators {
383360
0 => {
384361
self.index += 1;
385362

386-
Some(self.validators.leader())
363+
Some(&self.validators.0)
387364
}
388365
1 => {
389366
self.index += 1;
390367

391-
Some(self.validators.follower())
368+
Some(&self.validators.1)
392369
}
393370
_ => None,
394371
}
395372
}
396373
}
397374
}
398375

399-
// TODO: Postgres Campaign
400-
// TODO: Postgres CampaignSpec
401-
// TODO: Postgres Validators
376+
#[cfg(feature = "postgres")]
377+
mod postgres {
378+
use super::{Active, Campaign, CampaignId, PricingBounds, Validators};
379+
use bytes::BytesMut;
380+
use postgres_types::{accepts, to_sql_checked, FromSql, IsNull, Json, ToSql, Type};
381+
use std::error::Error;
382+
use tokio_postgres::Row;
383+
384+
impl From<&Row> for Campaign {
385+
fn from(row: &Row) -> Self {
386+
Self {
387+
id: row.get("id"),
388+
channel: row.get("channel"),
389+
creator: row.get("creator"),
390+
budget: row.get("budget"),
391+
validators: row.get("validators"),
392+
title: row.get("title"),
393+
pricing_bounds: row.get("pricing_bounds"),
394+
event_submission: row.get("event_submission"),
395+
ad_units: row.get::<_, Json<_>>("ad_units").0,
396+
targeting_rules: row.get("targeting_rules"),
397+
created: row.get("created"),
398+
active: Active {
399+
from: row.get("active_from"),
400+
to: row.get("active_to"),
401+
},
402+
}
403+
}
404+
}
405+
406+
impl<'a> FromSql<'a> for CampaignId {
407+
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
408+
let str_slice = <&str as FromSql>::from_sql(ty, raw)?;
409+
410+
Ok(str_slice.parse()?)
411+
}
412+
413+
accepts!(TEXT, VARCHAR);
414+
}
415+
416+
impl ToSql for CampaignId {
417+
fn to_sql(
418+
&self,
419+
ty: &Type,
420+
w: &mut BytesMut,
421+
) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
422+
self.to_string().to_sql(ty, w)
423+
}
424+
425+
accepts!(TEXT, VARCHAR);
426+
to_sql_checked!();
427+
}
428+
429+
impl<'a> FromSql<'a> for Validators {
430+
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
431+
let json = <Json<Self> as FromSql>::from_sql(ty, raw)?;
432+
433+
Ok(json.0)
434+
}
435+
436+
accepts!(JSONB);
437+
}
438+
439+
impl ToSql for Validators {
440+
fn to_sql(
441+
&self,
442+
ty: &Type,
443+
w: &mut BytesMut,
444+
) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
445+
Json(self).to_sql(ty, w)
446+
}
447+
448+
accepts!(JSONB);
449+
to_sql_checked!();
450+
}
451+
452+
impl<'a> FromSql<'a> for PricingBounds {
453+
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
454+
let json = <Json<Self> as FromSql>::from_sql(ty, raw)?;
455+
456+
Ok(json.0)
457+
}
458+
459+
accepts!(JSONB);
460+
}
461+
462+
impl ToSql for PricingBounds {
463+
fn to_sql(
464+
&self,
465+
ty: &Type,
466+
w: &mut BytesMut,
467+
) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
468+
Json(self).to_sql(ty, w)
469+
}
470+
471+
accepts!(JSONB);
472+
to_sql_checked!();
473+
}
474+
}

0 commit comments

Comments
 (0)