Skip to content

Commit dcdf845

Browse files
authored
Merge pull request #244 from AdExNetwork/issue-243-contrafactual-accounts
Issue #243 contrafactual accounts
2 parents 059d102 + 6bb0d35 commit dcdf845

File tree

7 files changed

+113
-108
lines changed

7 files changed

+113
-108
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

adapter/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ tiny-keccak = "1.5"
2121
parity-crypto = { version = "0.4.2", features = ["publickey"] }
2222
ethstore = { version = "0.2.1", git = "https://github.com/elpiel/parity-ethereum"}
2323
ethkey = { version = "0.4.0", git = "https://github.com/elpiel/parity-ethereum"}
24+
# API client
25+
reqwest = { version = "0.10", features = ["json"] }
26+
2427
sha2 = "0.8.0"
2528
base64 = "0.10.1"
2629
lazy_static = "1.4.0"

adapter/src/ethereum.rs

Lines changed: 96 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use ethkey::Password;
55
use ethstore::SafeAccount;
66
use futures::compat::Future01CompatExt;
77
use futures::future::{BoxFuture, FutureExt};
8+
use futures::TryFutureExt;
89
use lazy_static::lazy_static;
910
use parity_crypto::publickey::{
1011
public_to_address, recover, verify_address, Address, Message, Signature,
@@ -15,8 +16,8 @@ use primitives::{
1516
config::Config,
1617
Channel, ToETHChecksum, ValidatorId,
1718
};
19+
use reqwest::Client;
1820
use serde::{Deserialize, Serialize};
19-
use serde_hex::{SerHexOpt, StrictPfx};
2021
use serde_json::Value;
2122
use std::convert::TryFrom;
2223
use std::error::Error;
@@ -34,10 +35,8 @@ use web3::{
3435
lazy_static! {
3536
static ref ADEXCORE_ABI: &'static [u8] =
3637
include_bytes!("../../lib/protocol-eth/abi/AdExCore.json");
37-
static ref IDENTITY_ABI: &'static [u8] =
38-
include_bytes!("../../lib/protocol-eth/abi/Identity.json");
3938
static ref CHANNEL_STATE_ACTIVE: U256 = 1.into();
40-
static ref PRIVILEGE_LEVEL_NONE: U256 = 0.into();
39+
static ref PRIVILEGE_LEVEL_NONE: u8 = 0;
4140
}
4241

4342
#[derive(Debug, Clone)]
@@ -49,6 +48,7 @@ pub struct EthereumAdapter {
4948
wallet: Option<SafeAccount>,
5049
event_loop: Arc<EventLoopHandle>,
5150
web3: Web3<Http>,
51+
relayer: RelayerClient,
5252
}
5353

5454
// Enables EthereumAdapter to be able to
@@ -78,6 +78,8 @@ impl EthereumAdapter {
7878
.map_err(|_| map_error("failed to init http transport"))?;
7979
let event_loop = Arc::new(eloop);
8080
let web3 = web3::Web3::new(transport);
81+
let relayer = RelayerClient::new(&config.ethereum_adapter_relayer)
82+
.map_err(|_| map_error("Client for Relayer couldn't be built"))?;
8183

8284
Ok(Self {
8385
address,
@@ -87,6 +89,7 @@ impl EthereumAdapter {
8789
config: config.to_owned(),
8890
event_loop,
8991
web3,
92+
relayer,
9093
})
9194
}
9295
}
@@ -219,32 +222,20 @@ impl Adapter for EthereumAdapter {
219222

220223
let sess = match &verified.payload.identity {
221224
Some(identity) => {
222-
let contract_address: Address = identity.into();
223-
let contract =
224-
Contract::from_json(self.web3.eth(), contract_address, &IDENTITY_ABI)
225-
.map_err(|_| map_error("failed to init identity contract"))?;
226-
227-
let privilege_level: U256 = contract
228-
.query(
229-
"privileges",
230-
(Token::Address(Address::from_slice(verified.from.inner())),),
231-
None,
232-
Options::default(),
233-
None,
234-
)
235-
.compat()
236-
.await
237-
.map_err(|_| map_error("failed query priviledge level on contract"))?;
238-
239-
if privilege_level == *PRIVILEGE_LEVEL_NONE {
225+
if self
226+
.relayer
227+
.has_privileges(&verified.from, identity)
228+
.await?
229+
{
230+
Session {
231+
era: verified.payload.era,
232+
uid: identity.to_owned(),
233+
}
234+
} else {
240235
return Err(AdapterError::Authorization(
241236
"insufficient privilege".to_string(),
242237
));
243238
}
244-
Session {
245-
era: verified.payload.era,
246-
uid: identity.into(),
247-
}
248239
}
249240
None => Session {
250241
era: verified.payload.era,
@@ -276,6 +267,53 @@ impl Adapter for EthereumAdapter {
276267
}
277268
}
278269

270+
#[derive(Debug, Clone)]
271+
struct RelayerClient {
272+
client: Client,
273+
relayer_url: String,
274+
}
275+
276+
impl RelayerClient {
277+
pub fn new(relayer_url: &str) -> Result<Self, reqwest::Error> {
278+
let client = Client::builder().build()?;
279+
280+
Ok(Self {
281+
relayer_url: relayer_url.to_string(),
282+
client,
283+
})
284+
}
285+
286+
/// Checks whether there are any privileges (i.e. > 0)
287+
pub async fn has_privileges(
288+
&self,
289+
from: &ValidatorId,
290+
identity: &ValidatorId,
291+
) -> Result<bool, AdapterError> {
292+
use reqwest::Response;
293+
use std::collections::HashMap;
294+
295+
let relay_url = format!(
296+
"{}/identity/by-owner/{}",
297+
self.relayer_url,
298+
from.to_checksum()
299+
);
300+
301+
let identities_owned: HashMap<ValidatorId, u8> = self
302+
.client
303+
.get(&relay_url)
304+
.send()
305+
.and_then(|res: Response| res.json())
306+
.await
307+
.map_err(|_| map_error("Fetching privileges failed"))?;
308+
309+
let has_privileges = identities_owned
310+
.get(identity)
311+
.map_or(false, |privileges| *privileges > 0);
312+
313+
Ok(has_privileges)
314+
}
315+
}
316+
279317
fn hash_message(message: &str) -> [u8; 32] {
280318
let eth = "\x19Ethereum Signed Message:\n";
281319
let message_length = message.len();
@@ -301,12 +339,8 @@ pub struct Payload {
301339
pub id: String,
302340
pub era: i64,
303341
pub address: String,
304-
#[serde(
305-
default,
306-
skip_serializing_if = "Option::is_none",
307-
with = "SerHexOpt::<StrictPfx>"
308-
)]
309-
pub identity: Option<[u8; 20]>,
342+
#[serde(default, skip_serializing_if = "Option::is_none")]
343+
pub identity: Option<ValidatorId>,
310344
}
311345

312346
#[derive(Clone, Debug)]
@@ -377,7 +411,7 @@ pub fn ewt_verify(
377411
let payload: Payload = serde_json::from_str(&payload_string)?;
378412

379413
let verified_payload = VerifyPayload {
380-
from: ValidatorId::try_from(&format!("{:?}", address))?,
414+
from: ValidatorId::from(address.as_fixed_bytes()),
381415
payload,
382416
};
383417

@@ -482,6 +516,33 @@ mod test {
482516
);
483517
}
484518

519+
#[tokio::test]
520+
#[ignore]
521+
async fn test_session_from_token() {
522+
use primitives::ToETHChecksum;
523+
let identity = ValidatorId::try_from("0x5B04DBc513F90CaAFAa09307Ad5e3C65EB4b26F0").unwrap();
524+
525+
let mut eth_adapter = setup_eth_adapter(None);
526+
eth_adapter.unlock().expect("should unlock eth adapter");
527+
let wallet = eth_adapter.wallet.clone();
528+
529+
let era = Utc::now().timestamp_millis() as f64 / 60000.0;
530+
let payload = Payload {
531+
id: eth_adapter.whoami().to_checksum(),
532+
era: era.floor() as i64,
533+
identity: Some(identity.clone()),
534+
address: eth_adapter.whoami().to_checksum(),
535+
};
536+
537+
let token = ewt_sign(&wallet.unwrap(), &eth_adapter.keystore_pwd, &payload)
538+
.map_err(|_| map_error("Failed to sign token"))
539+
.unwrap();
540+
541+
let session: Session = eth_adapter.session_from_token(&token).await.unwrap();
542+
543+
assert_eq!(session.uid, identity);
544+
}
545+
485546
#[tokio::test]
486547
async fn should_validate_valid_channel_properly() {
487548
let (_eloop, http) =
@@ -604,13 +665,10 @@ mod test {
604665
.await
605666
.expect("open channel");
606667

607-
let contract_addr = <[u8; 20]>::from_hex(&format!("{:?}", adex_contract.address())[2..])
608-
.expect("failed to deserialize contract addr");
609-
668+
let contract_addr = adex_contract.address().to_fixed_bytes();
610669
let channel_id = eth_channel.hash(&contract_addr).expect("hash hex");
611670
// set id to proper id
612-
valid_channel.id = ChannelId::from_hex(hex::encode(channel_id))
613-
.expect("prep_db: failed to deserialize channel id");
671+
valid_channel.id = ChannelId::from(channel_id);
614672

615673
// eth adapter
616674
let mut eth_adapter = setup_eth_adapter(Some(contract_addr));
@@ -623,68 +681,4 @@ mod test {
623681

624682
assert_eq!(result, true, "should validate valid channel correctly");
625683
}
626-
627-
#[tokio::test]
628-
async fn should_generate_session_from_token_with_identity() {
629-
// setup test payload
630-
let mut eth_adapter = setup_eth_adapter(None);
631-
eth_adapter.unlock().expect("should unlock eth adapter");
632-
633-
// part of address used in initializing ganache-cli
634-
let leader_account: Address = "Df08F82De32B8d460adbE8D72043E3a7e25A3B39"
635-
.parse()
636-
.expect("failed to parse leader account");
637-
638-
let eth_adapter_address: Address = eth_adapter
639-
.whoami()
640-
.to_hex_non_prefix_string()
641-
.parse()
642-
.expect("failed to parse eth adapter address");
643-
644-
let identity_bytecode = include_str!("../test/resources/identitybytecode.json");
645-
646-
// deploy identity contract
647-
let identity_contract = Contract::deploy(eth_adapter.web3.eth(), &IDENTITY_ABI)
648-
.expect("invalid token token contract")
649-
.confirmations(0)
650-
.options(Options::with(|opt| {
651-
opt.gas_price = Some(1.into());
652-
opt.gas = Some(6_721_975.into());
653-
}))
654-
.execute(
655-
identity_bytecode,
656-
(
657-
Token::Array(vec![Token::Address(eth_adapter_address)]),
658-
Token::Array(vec![Token::Uint(1.into())]),
659-
),
660-
leader_account,
661-
)
662-
.expect("Correct parameters are passed to the constructor.")
663-
.compat()
664-
.await
665-
.expect("failed to initialize identity contract");
666-
667-
// identity contract address
668-
let identity = <[u8; 20]>::from_hex(&format!("{:?}", identity_contract.address())[2..])
669-
.expect("failed to deserialize address");
670-
671-
let payload = Payload {
672-
id: eth_adapter.whoami().to_checksum(),
673-
era: 100_000,
674-
address: format!("{:?}", leader_account),
675-
identity: Some(identity),
676-
};
677-
678-
let wallet = eth_adapter.wallet.clone();
679-
let response = ewt_sign(&wallet.unwrap(), &eth_adapter.keystore_pwd, &payload)
680-
.expect("failed to generate ewt signature");
681-
682-
// verify since its with identity
683-
let session = eth_adapter
684-
.session_from_token(&response)
685-
.await
686-
.expect("failed generate session");
687-
688-
assert_eq!(session.uid.inner(), &identity);
689-
}
690684
}

docs/config/dev.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
max_channels=512
1+
# Maximum number of channels to return per request
2+
max_channels = 512
3+
24
channels_find_limit = 200
35
wait_time = 500
46

@@ -15,11 +17,12 @@ list_timeout = 5000
1517
fetch_timeout = 5000
1618
validator_tick_timeout = 5000
1719

18-
ip_rate_limit = {type='ip', timeframe=20000}
19-
sid_rate_limit = {type='sid', timeframe=20000}
20+
ip_rate_limit = { type = 'ip', timeframe = 20000 }
21+
sid_rate_limit = { type = 'sid', timeframe = 20000 }
2022

2123
ethereum_core_address = '0x333420fc6a897356e69b62417cd17ff012177d2b'
2224
ethereum_network = 'http://localhost:8545'
25+
ethereum_adapter_relayer = 'https://goerli-relayer.adex.network'
2326

2427
creators_whitelist = []
2528
minimal_deposit = "0"

docs/config/prod.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ list_timeout = 10000
1717
fetch_timeout = 10000
1818
validator_tick_timeout = 10000
1919

20-
ip_rate_limit = { type = "ip", timeframe = 20000 }
21-
sid_rate_limit = { type = "sid", timeframe = 0 }
20+
ip_rate_limit = { type = 'ip', timeframe = 20000 }
21+
sid_rate_limit = { type = 'sid', timeframe = 0 }
2222
ethereum_core_address = '0x333420fc6a897356e69b62417cd17ff012177d2b'
2323
ethereum_network = 'http://localhost:8545'
24-
token_address_whitelist = ['0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359']
24+
ethereum_adapter_relayer = 'https://relayer.adex.network'
2525

2626
creators_whitelist = []
2727
minimal_deposit = "0"
2828
minimal_fee = "0"
29+
token_address_whitelist = ['0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359']
2930
validators_whitelist = []

primitives/src/config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub struct Config {
4040
#[serde(with = "SerHex::<StrictPfx>")]
4141
pub ethereum_core_address: [u8; 20],
4242
pub ethereum_network: String,
43+
pub ethereum_adapter_relayer: String,
4344
pub validators_whitelist: Vec<ValidatorId>,
4445
}
4546

primitives/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,5 @@ pub trait ToETHChecksum: AsRef<[u8]> {
6363
eth_checksum::checksum(&hex::encode(self.as_ref()))
6464
}
6565
}
66+
67+
impl ToETHChecksum for &[u8; 20] {}

0 commit comments

Comments
 (0)