Skip to content

Commit 161ebf3

Browse files
committed
Added filtration by chain for channel list route
1 parent 29d7c8d commit 161ebf3

File tree

10 files changed

+217
-61
lines changed

10 files changed

+217
-61
lines changed

primitives/src/sentry.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ pub struct ValidationErrorResponse {
637637
}
638638

639639
pub mod channel_list {
640-
use crate::{Channel, ValidatorId};
640+
use crate::{Channel, ValidatorId, ChainId};
641641
use serde::{Deserialize, Serialize};
642642

643643
use super::Pagination;
@@ -657,6 +657,8 @@ pub mod channel_list {
657657
pub page: u64,
658658
/// filters the channels containing a specific validator if provided
659659
pub validator: Option<ValidatorId>,
660+
#[serde(default)]
661+
pub chains: Vec<ChainId>,
660662
}
661663
}
662664

sentry/migrations/20190806011140_initial-tables/up.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CREATE TABLE channels (
66
token varchar(42) NOT NULL,
77
-- Using varchar for U256 for simplicity
88
nonce varchar(78) NOT NULL,
9+
chain_id integer NOT NULL,
910
-- In order to be able to order the channels for the `GET channel` request
1011
created timestamp(2) with time zone NOT NULL,
1112
-- Do not rename the Primary key constraint (`channels_pkey`)!

sentry/src/db/accounting.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,22 +189,31 @@ mod test {
189189
ADVERTISER, ADVERTISER_2, CREATOR, DUMMY_CAMPAIGN, PUBLISHER, PUBLISHER_2,
190190
};
191191

192-
use crate::db::{
192+
use crate::{db::{
193193
insert_channel,
194194
tests_postgres::{setup_test_migrations, DATABASE_POOL},
195-
};
195+
}, test_util::setup_dummy_app};
196+
196197

197198
use super::*;
198199

199200
#[tokio::test]
200201
async fn insert_update_and_get_accounting() {
201202
let database = DATABASE_POOL.get().await.expect("Should get a DB pool");
203+
let app = setup_dummy_app().await;
202204

203205
setup_test_migrations(database.pool.clone())
204206
.await
205207
.expect("Migrations should succeed");
208+
209+
let channel_chain = app
210+
.config
211+
.find_chain_of(DUMMY_CAMPAIGN.channel.token)
212+
.expect("Channel token should be whitelisted in config!");
213+
let channel_context = channel_chain.with_channel(DUMMY_CAMPAIGN.channel);
214+
206215
// insert the channel into the DB
207-
let channel = insert_channel(&database.pool, DUMMY_CAMPAIGN.channel)
216+
let channel = insert_channel(&database.pool, &channel_context)
208217
.await
209218
.expect("Should insert");
210219

@@ -394,13 +403,21 @@ mod test {
394403
#[tokio::test]
395404
async fn test_spend_amount() {
396405
let database = DATABASE_POOL.get().await.expect("Should get a DB pool");
406+
let app = setup_dummy_app().await;
397407

398408
setup_test_migrations(database.pool.clone())
399409
.await
400410
.expect("Migrations should succeed");
401411

412+
let channel_chain = app
413+
.config
414+
.find_chain_of(DUMMY_CAMPAIGN.channel.token)
415+
.expect("Channel token should be whitelisted in config!");
416+
let channel_context = channel_chain.with_channel(DUMMY_CAMPAIGN.channel);
417+
418+
402419
// insert the channel into the DB
403-
let channel = insert_channel(&database.pool, DUMMY_CAMPAIGN.channel)
420+
let channel = insert_channel(&database.pool, &channel_context)
404421
.await
405422
.expect("Should insert");
406423

@@ -481,13 +498,20 @@ mod test {
481498
#[tokio::test]
482499
async fn test_spend_amount_with_multiple_spends() {
483500
let database = DATABASE_POOL.get().await.expect("Should get a DB pool");
501+
let app = setup_dummy_app().await;
484502

485503
setup_test_migrations(database.pool.clone())
486504
.await
487505
.expect("Migrations should succeed");
488506

507+
let channel_chain = app
508+
.config
509+
.find_chain_of(DUMMY_CAMPAIGN.channel.token)
510+
.expect("Channel token should be whitelisted in config!");
511+
let channel_context = channel_chain.with_channel(DUMMY_CAMPAIGN.channel);
512+
489513
// insert the channel into the DB
490-
let channel = insert_channel(&database.pool, DUMMY_CAMPAIGN.channel)
514+
let channel = insert_channel(&database.pool, &channel_context)
491515
.await
492516
.expect("Should insert");
493517

sentry/src/db/campaign.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -571,10 +571,10 @@ mod campaign_remaining {
571571

572572
#[cfg(test)]
573573
mod test {
574-
use crate::db::{
574+
use crate::{db::{
575575
insert_channel,
576576
tests_postgres::{setup_test_migrations, DATABASE_POOL},
577-
};
577+
}, test_util::setup_dummy_app};
578578
use chrono::TimeZone;
579579
use primitives::{
580580
campaign,
@@ -595,6 +595,7 @@ mod test {
595595

596596
#[tokio::test]
597597
async fn it_inserts_fetches_and_updates_a_campaign() {
598+
let app = setup_dummy_app().await;
598599
let database = DATABASE_POOL.get().await.expect("Should get a DB pool");
599600

600601
setup_test_migrations(database.pool.clone())
@@ -603,8 +604,15 @@ mod test {
603604

604605
let campaign = DUMMY_CAMPAIGN.clone();
605606

607+
let channel_chain = app
608+
.config
609+
.find_chain_of(DUMMY_CAMPAIGN.channel.token)
610+
.expect("Channel token should be whitelisted in config!");
611+
let channel_context = channel_chain.with_channel(DUMMY_CAMPAIGN.channel);
612+
613+
606614
// insert the channel into the DB
607-
let _channel = insert_channel(&database.pool, DUMMY_CAMPAIGN.channel)
615+
let _channel = insert_channel(&database.pool, &channel_context)
608616
.await
609617
.expect("Should insert");
610618

@@ -690,6 +698,7 @@ mod test {
690698
#[tokio::test]
691699
async fn it_lists_campaigns_properly() {
692700
let database = DATABASE_POOL.get().await.expect("Should get a DB pool");
701+
let app = setup_dummy_app().await;
693702

694703
setup_test_migrations(database.pool.clone())
695704
.await
@@ -699,10 +708,18 @@ mod test {
699708
let mut channel_with_different_leader = DUMMY_CAMPAIGN.channel;
700709
channel_with_different_leader.leader = IDS[&ADVERTISER_2];
701710

702-
insert_channel(&database, DUMMY_CAMPAIGN.channel)
711+
let channel_chain = app
712+
.config
713+
.find_chain_of(DUMMY_CAMPAIGN.channel.token)
714+
.expect("Channel token should be whitelisted in config!");
715+
let channel_context = channel_chain.clone().with_channel(DUMMY_CAMPAIGN.channel);
716+
let channel_context_different_leader = channel_chain.with_channel(channel_with_different_leader);
717+
718+
719+
insert_channel(&database, &channel_context)
703720
.await
704721
.expect("Should insert");
705-
insert_channel(&database, channel_with_different_leader)
722+
insert_channel(&database, &channel_context_different_leader)
706723
.await
707724
.expect("Should insert");
708725

sentry/src/db/channel.rs

Lines changed: 67 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use primitives::{Channel, ChannelId};
1+
use primitives::{Channel, ChannelId, ChainOf};
22

33
pub use list_channels::list_channels;
44

@@ -26,17 +26,19 @@ pub async fn get_channel_by_id(
2626
/// This call should never trigger a `SqlState::UNIQUE_VIOLATION`
2727
///
2828
/// ```sql
29-
/// INSERT INTO channels (id, leader, follower, guardian, token, nonce, created)
30-
/// VALUES ($1, $2, $3, $4, $5, $6, NOW())
29+
/// INSERT INTO channels (id, leader, follower, guardian, token, nonce, chain_id, created)
30+
/// VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())
3131
/// ON CONFLICT ON CONSTRAINT channels_pkey DO UPDATE SET created=EXCLUDED.created
3232
/// RETURNING leader, follower, guardian, token, nonce
3333
/// ```
34-
pub async fn insert_channel(pool: &DbPool, channel: Channel) -> Result<Channel, PoolError> {
34+
pub async fn insert_channel(pool: &DbPool, channel_chain: &ChainOf<Channel>) -> Result<Channel, PoolError> {
3535
let client = pool.get().await?;
36+
let chain_id = channel_chain.chain.chain_id;
37+
let channel = channel_chain.context;
3638

3739
// We use `EXCLUDED.created` in order to have to DO UPDATE otherwise it does not return the fields
3840
// when there is a CONFLICT
39-
let stmt = client.prepare("INSERT INTO channels (id, leader, follower, guardian, token, nonce, created) VALUES ($1, $2, $3, $4, $5, $6, NOW())
41+
let stmt = client.prepare("INSERT INTO channels (id, leader, follower, guardian, token, nonce, chain_id, created) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())
4042
ON CONFLICT ON CONSTRAINT channels_pkey DO UPDATE SET created=EXCLUDED.created RETURNING leader, follower, guardian, token, nonce").await?;
4143

4244
let row = client
@@ -49,6 +51,7 @@ pub async fn insert_channel(pool: &DbPool, channel: Channel) -> Result<Channel,
4951
&channel.guardian,
5052
&channel.token,
5153
&channel.nonce,
54+
&chain_id,
5255
],
5356
)
5457
.await?;
@@ -58,8 +61,8 @@ pub async fn insert_channel(pool: &DbPool, channel: Channel) -> Result<Channel,
5861

5962
mod list_channels {
6063
use primitives::{
61-
sentry::{channel_list::ChannelListResponse, Pagination},
62-
Channel, ValidatorId,
64+
sentry::{channel_list::{ChannelListResponse, ChannelListQuery}, Pagination},
65+
Channel,
6366
};
6467

6568
use crate::db::{DbPool, PoolError, TotalCount};
@@ -71,24 +74,36 @@ mod list_channels {
7174
pool: &DbPool,
7275
skip: u64,
7376
limit: u32,
74-
validator: Option<ValidatorId>,
77+
query: &ChannelListQuery,
7578
) -> Result<ChannelListResponse, PoolError> {
7679
let client = pool.get().await?;
80+
let mut where_clauses = vec![];
81+
if !query.chains.is_empty() {
82+
where_clauses.push(format!(
83+
"chain_id IN ({})",
84+
query
85+
.chains
86+
.iter()
87+
.map(|id| id.to_u32().to_string())
88+
.collect::<Vec<String>>()
89+
.join(",")
90+
));
91+
}
7792

7893
// To understand why we use Order by, see Postgres Documentation: https://www.postgresql.org/docs/8.1/queries-limit.html
79-
let rows = match validator {
94+
let rows = match query.validator {
8095
Some(validator) => {
81-
let where_clause = "(leader = $1 OR follower = $1)".to_string();
96+
where_clauses.push("(leader = $1 OR follower = $1)".to_string());
8297

8398
let statement = format!("SELECT leader, follower, guardian, token, nonce, created FROM channels WHERE {} ORDER BY created ASC LIMIT {} OFFSET {}",
84-
where_clause, limit, skip);
99+
where_clauses.join(" AND "), limit, skip);
85100
let stmt = client.prepare(&statement).await?;
86101

87102
client.query(&stmt, &[&validator.to_string()]).await?
88103
}
89104
None => {
90-
let statement = format!("SELECT id, leader, follower, guardian, token, nonce, created FROM channels ORDER BY created ASC LIMIT {} OFFSET {}",
91-
limit, skip);
105+
let statement = format!("SELECT id, leader, follower, guardian, token, nonce, created FROM channels WHERE {} ORDER BY created ASC LIMIT {} OFFSET {}",
106+
where_clauses.join(" AND "), limit, skip);
92107
let stmt = client.prepare(&statement).await?;
93108

94109
client.query(&stmt, &[]).await?
@@ -97,7 +112,7 @@ mod list_channels {
97112

98113
let channels = rows.iter().map(Channel::from).collect();
99114

100-
let total_count = list_channels_total_count(pool, validator).await?;
115+
let total_count = list_channels_total_count(pool, query).await?;
101116

102117
// fast ceil for total_pages
103118
let total_pages = if total_count == 0 {
@@ -117,25 +132,38 @@ mod list_channels {
117132

118133
async fn list_channels_total_count<'a>(
119134
pool: &DbPool,
120-
validator: Option<ValidatorId>,
135+
query: &ChannelListQuery,
121136
) -> Result<u64, PoolError> {
122137
let client = pool.get().await?;
123138

124-
let row = match validator {
139+
let mut where_clauses = vec![];
140+
if !query.chains.is_empty() {
141+
where_clauses.push(format!(
142+
"chain_id IN ({})",
143+
query
144+
.chains
145+
.iter()
146+
.map(|id| id.to_u32().to_string())
147+
.collect::<Vec<String>>()
148+
.join(",")
149+
));
150+
}
151+
152+
let row = match query.validator {
125153
Some(validator) => {
126-
let where_clause = "(leader = $1 OR follower = $1)".to_string();
154+
where_clauses.push("(leader = $1 OR follower = $1)".to_string());
127155

128156
let statement = format!(
129157
"SELECT COUNT(id)::varchar FROM channels WHERE {}",
130-
where_clause
158+
where_clauses.join(" AND ")
131159
);
132160
let stmt = client.prepare(&statement).await?;
133161

134162
client.query_one(&stmt, &[&validator.to_string()]).await?
135163
}
136164
None => {
137-
let statement = "SELECT COUNT(id)::varchar FROM channels";
138-
let stmt = client.prepare(statement).await?;
165+
let statement = format!("SELECT COUNT(id)::varchar FROM channels WHERE {}", where_clauses.join(" AND "));
166+
let stmt = client.prepare(&statement).await?;
139167

140168
client.query_one(&stmt, &[]).await?
141169
}
@@ -147,29 +175,36 @@ mod list_channels {
147175

148176
#[cfg(test)]
149177
mod test {
150-
use primitives::test_util::DUMMY_CAMPAIGN;
178+
use primitives::{test_util::DUMMY_CAMPAIGN, sentry::channel_list::ChannelListQuery, ChainId};
151179

152-
use crate::db::{
180+
use crate::{db::{
153181
insert_channel,
154182
tests_postgres::{setup_test_migrations, DATABASE_POOL},
155-
};
183+
}, test_util::setup_dummy_app};
156184

157185
use super::list_channels::list_channels;
158186

159187
#[tokio::test]
160188
async fn insert_and_list_channels_return_channels() {
189+
let app = setup_dummy_app().await;
161190
let database = DATABASE_POOL.get().await.expect("Should get database");
162191
setup_test_migrations(database.pool.clone())
163192
.await
164193
.expect("Should setup migrations");
165194

195+
let channel_chain = app
196+
.config
197+
.find_chain_of(DUMMY_CAMPAIGN.channel.token)
198+
.expect("Channel token should be whitelisted in config!");
199+
let channel_context = channel_chain.with_channel(DUMMY_CAMPAIGN.channel);
200+
166201
let actual_channel = {
167-
let insert = insert_channel(&database.pool, DUMMY_CAMPAIGN.channel)
202+
let insert = insert_channel(&database.pool, &channel_context)
168203
.await
169204
.expect("Should insert Channel");
170205

171206
// once inserted, the channel should only be returned by the function
172-
let only_select = insert_channel(&database.pool, DUMMY_CAMPAIGN.channel)
207+
let only_select = insert_channel(&database.pool, &channel_context)
173208
.await
174209
.expect("Should run insert with RETURNING on the Channel");
175210

@@ -178,7 +213,13 @@ mod test {
178213
only_select
179214
};
180215

181-
let response = list_channels(&database.pool, 0, 10, None)
216+
let query = ChannelListQuery {
217+
page: 0,
218+
validator: None,
219+
chains: vec![channel_context.chain.chain_id],
220+
};
221+
222+
let response = list_channels(&database.pool, 0, 10, &query)
182223
.await
183224
.expect("Should list Channels");
184225

0 commit comments

Comments
 (0)