Skip to content
This repository was archived by the owner on Jan 26, 2023. It is now read-only.

Commit 367cb3f

Browse files
authored
Impl allow-addr in (many-)ledger and kvstore (#259)
1 parent 2d7addf commit 367cb3f

File tree

17 files changed

+289
-67
lines changed

17 files changed

+289
-67
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ jobs:
8585
- bats/install
8686
- run:
8787
name: running BATs tests
88-
command: bats .
88+
command: bats *
8989
working_directory: ./tests/e2e/
9090
coverage:
9191
parameters:

src/many-kvstore/src/main.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use crate::module::account::AccountFeatureModule;
22
use clap::Parser;
33
use many_identity::verifiers::AnonymousVerifier;
4+
use many_identity::Address;
45
use many_identity_dsa::{CoseKeyIdentity, CoseKeyVerifier};
56
use many_modules::account::features::Feature;
67
use many_modules::{abci_backend, account, events, kvstore};
78
use many_server::transport::http::HttpServer;
89
use many_server::ManyServer;
10+
use std::collections::BTreeSet;
911
use std::net::SocketAddr;
1012
use std::path::PathBuf;
1113
use std::sync::{Arc, Mutex};
@@ -62,6 +64,12 @@ struct Opts {
6264
/// Use given logging strategy
6365
#[clap(long, arg_enum, default_value_t = LogStrategy::Terminal)]
6466
logmode: LogStrategy,
67+
68+
/// Path to a JSON file containing an array of MANY addresses
69+
/// Only addresses from this array will be able to execute commands, e.g., send, put, ...
70+
/// Any addresses will be able to execute queries, e.g., balance, get, ...
71+
#[clap(long)]
72+
allow_addrs: Option<PathBuf>,
6573
}
6674

6775
fn main() {
@@ -75,6 +83,7 @@ fn main() {
7583
persistent,
7684
clean,
7785
logmode,
86+
allow_addrs,
7887
} = Opts::parse();
7988

8089
let verbose_level = 2 + verbose - quiet;
@@ -143,7 +152,17 @@ fn main() {
143152
{
144153
let mut s = many.lock().unwrap();
145154
s.add_module(kvstore::KvStoreModule::new(module.clone()));
146-
s.add_module(kvstore::KvStoreCommandsModule::new(module.clone()));
155+
let kvstore_command_module = kvstore::KvStoreCommandsModule::new(module.clone());
156+
if let Some(path) = allow_addrs {
157+
let allow_addrs: BTreeSet<Address> =
158+
json5::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
159+
s.add_module(allow_addrs::AllowAddrsModule {
160+
inner: kvstore_command_module,
161+
allow_addrs,
162+
});
163+
} else {
164+
s.add_module(kvstore_command_module);
165+
}
147166
s.add_module(events::EventsModule::new(module.clone()));
148167

149168
s.add_module(AccountFeatureModule::new(

src/many-kvstore/src/module.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use std::path::Path;
2121
use tracing::info;
2222

2323
pub mod account;
24+
pub mod allow_addrs;
2425
mod event;
2526

2627
// The initial state schema, loaded from JSON.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use coset::CoseSign1;
2+
use many_error::ManyError;
3+
use many_identity::Address;
4+
use many_modules::{kvstore, ManyModule, ManyModuleInfo};
5+
use many_protocol::{RequestMessage, ResponseMessage};
6+
use std::collections::BTreeSet;
7+
use std::fmt::{Debug, Formatter};
8+
9+
pub struct AllowAddrsModule<T: kvstore::KvStoreCommandsModuleBackend> {
10+
pub inner: kvstore::KvStoreCommandsModule<T>,
11+
pub allow_addrs: BTreeSet<Address>,
12+
}
13+
14+
impl<T: kvstore::KvStoreCommandsModuleBackend> Debug for AllowAddrsModule<T> {
15+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
16+
f.write_str("AllowAddrsModule")
17+
}
18+
}
19+
20+
#[async_trait::async_trait]
21+
impl<T: kvstore::KvStoreCommandsModuleBackend> ManyModule for AllowAddrsModule<T> {
22+
fn info(&self) -> &ManyModuleInfo {
23+
self.inner.info()
24+
}
25+
26+
fn validate(&self, message: &RequestMessage, envelope: &CoseSign1) -> Result<(), ManyError> {
27+
self.inner.validate(message, envelope)
28+
}
29+
30+
async fn execute(&self, message: RequestMessage) -> Result<ResponseMessage, ManyError> {
31+
if !self.allow_addrs.contains(&message.from()) {
32+
return Err(ManyError::invalid_from_identity());
33+
}
34+
35+
self.inner.execute(message).await
36+
}
37+
}

src/many-ledger/src/main.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use many_modules::{abci_backend, account, events, idstore, ledger};
99
use many_protocol::ManyUrl;
1010
use many_server::transport::http::HttpServer;
1111
use many_server::ManyServer;
12+
use std::collections::BTreeSet;
1213
use std::net::SocketAddr;
1314
use std::path::PathBuf;
1415
use std::sync::{Arc, Mutex};
@@ -93,6 +94,12 @@ struct Opts {
9394
/// Use given logging strategy
9495
#[clap(long, arg_enum, default_value_t = LogStrategy::Terminal)]
9596
logmode: LogStrategy,
97+
98+
/// Path to a JSON file containing an array of MANY addresses
99+
/// Only addresses from this array will be able to execute commands, e.g., send, put, ...
100+
/// Any addresses will be able to execute queries, e.g., balance, get, ...
101+
#[clap(long)]
102+
allow_addrs: Option<PathBuf>,
96103
}
97104

98105
fn main() {
@@ -106,6 +113,7 @@ fn main() {
106113
persistent,
107114
clean,
108115
logmode,
116+
allow_addrs,
109117
..
110118
} = Opts::parse();
111119

@@ -203,7 +211,17 @@ fn main() {
203211
{
204212
let mut s = many.lock().unwrap();
205213
s.add_module(ledger::LedgerModule::new(module_impl.clone()));
206-
s.add_module(ledger::LedgerCommandsModule::new(module_impl.clone()));
214+
let ledger_command_module = ledger::LedgerCommandsModule::new(module_impl.clone());
215+
if let Some(path) = allow_addrs {
216+
let allow_addrs: BTreeSet<Address> =
217+
json5::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
218+
s.add_module(AllowAddrsModule {
219+
inner: ledger_command_module,
220+
allow_addrs,
221+
});
222+
} else {
223+
s.add_module(ledger_command_module);
224+
}
207225
s.add_module(events::EventsModule::new(module_impl.clone()));
208226

209227
let idstore_module = idstore::IdStoreModule::new(module_impl.clone());

src/many-ledger/src/module.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,36 @@ impl<T: idstore::IdStoreModuleBackend> ManyModule for IdStoreWebAuthnModule<T> {
856856
}
857857
}
858858

859+
pub struct AllowAddrsModule<T: ledger::LedgerCommandsModuleBackend> {
860+
pub inner: ledger::LedgerCommandsModule<T>,
861+
pub allow_addrs: BTreeSet<Address>,
862+
}
863+
864+
impl<T: ledger::LedgerCommandsModuleBackend> Debug for AllowAddrsModule<T> {
865+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
866+
f.write_str("AllowAddrsModule")
867+
}
868+
}
869+
870+
#[async_trait::async_trait]
871+
impl<T: ledger::LedgerCommandsModuleBackend> ManyModule for AllowAddrsModule<T> {
872+
fn info(&self) -> &ManyModuleInfo {
873+
self.inner.info()
874+
}
875+
876+
fn validate(&self, message: &RequestMessage, envelope: &CoseSign1) -> Result<(), ManyError> {
877+
self.inner.validate(message, envelope)
878+
}
879+
880+
async fn execute(&self, message: RequestMessage) -> Result<ResponseMessage, ManyError> {
881+
if !self.allow_addrs.contains(&message.from()) {
882+
return Err(ManyError::invalid_from_identity());
883+
}
884+
885+
self.inner.execute(message).await
886+
}
887+
}
888+
859889
#[cfg(test)]
860890
mod tests {
861891
use crate::json::InitialStateJson;

tests/e2e/kvstore/allow_addrs.bats

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
GIT_ROOT="$BATS_TEST_DIRNAME/../../../"
2+
3+
load '../../test_helper/load'
4+
load '../../test_helper/kvstore'
5+
6+
function setup() {
7+
mkdir "$BATS_TEST_ROOTDIR"
8+
9+
skip_if_missing_background_utilities
10+
11+
if ! [ $CI ]; then
12+
(
13+
cd "$GIT_ROOT"
14+
cargo build
15+
)
16+
fi
17+
18+
local ALLOW_ADDRS_CONFIG=$(generate_allow_addrs_config 1 2)
19+
20+
start_kvstore --pem "$(pem 0)" \
21+
--allow-addrs "$ALLOW_ADDRS_CONFIG"
22+
}
23+
24+
function teardown() {
25+
stop_background_run
26+
}
27+
28+
@test "$SUITE: allow addrs" {
29+
call_kvstore --pem=1 --port=8000 put "01" "one"
30+
call_kvstore --pem=1 --port=8000 get "01"
31+
assert_output --partial "one"
32+
33+
call_kvstore --pem=2 --port=8000 put "02" "two"
34+
call_kvstore --pem=2 --port=8000 get "02"
35+
assert_output --partial "two"
36+
37+
call_kvstore --pem=3 --port=8000 put "03" "three"
38+
assert_output --partial "The identity of the from field is invalid or unexpected."
39+
40+
call_kvstore --pem=3 --port=8000 get "02"
41+
assert_output --partial "two"
42+
43+
call_kvstore --pem=3 --port=8000 get "03"
44+
assert_output --partial "None"
45+
}
Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
GIT_ROOT="$BATS_TEST_DIRNAME/../../"
1+
GIT_ROOT="$BATS_TEST_DIRNAME/../../../"
22

3-
load '../test_helper/load'
4-
load '../test_helper/kvstore'
3+
load '../../test_helper/load'
4+
load '../../test_helper/kvstore'
55

66
function setup() {
77
mkdir "$BATS_TEST_ROOTDIR"
@@ -15,14 +15,7 @@ function setup() {
1515
)
1616
fi
1717

18-
run_in_background "$GIT_ROOT/target/debug/many-kvstore" \
19-
-v \
20-
--clean \
21-
--persistent "$(mktemp -d)" \
22-
--state "$GIT_ROOT/staging/kvstore_state.json5" \
23-
--pem "$(pem 0)"
24-
25-
wait_for_background_output "Running accept thread"
18+
start_kvstore --pem "$(pem 0)"
2619
}
2720

2821
function teardown() {

tests/e2e/ledger/allow_addrs.bats

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
GIT_ROOT="$BATS_TEST_DIRNAME/../../../"
2+
START_BALANCE=1000000
3+
MFX_ADDRESS=mqbfbahksdwaqeenayy2gxke32hgb7aq4ao4wt745lsfs6wiaaaaqnz
4+
5+
load '../../test_helper/load'
6+
load '../../test_helper/ledger'
7+
8+
function setup() {
9+
mkdir "$BATS_TEST_ROOTDIR"
10+
11+
skip_if_missing_background_utilities
12+
13+
if ! [ $CI ]; then
14+
(
15+
cd "$GIT_ROOT"
16+
cargo build
17+
)
18+
fi
19+
20+
local ALLOW_ADDRS_CONFIG=$(generate_allow_addrs_config 1 2)
21+
22+
start_ledger --pem "$(pem 0)" \
23+
--allow-addrs "$ALLOW_ADDRS_CONFIG" \
24+
"--balance-only-for-testing=$(identity 1):$START_BALANCE:$MFX_ADDRESS"
25+
}
26+
27+
function teardown() {
28+
stop_background_run
29+
}
30+
31+
@test "$SUITE: allow addrs" {
32+
check_consistency --pem=1 --balance=1000000 8000
33+
34+
call_ledger --pem=1 --port=8000 send "$(identity 2)" 2000 MFX
35+
check_consistency --pem=1 --balance=998000 8000
36+
check_consistency --pem=2 --balance=2000 8000
37+
38+
call_ledger --pem=2 --port=8000 send "$(identity 3)" 1000 MFX
39+
check_consistency --pem=1 --balance=998000 8000
40+
check_consistency --pem=2 --balance=1000 8000
41+
check_consistency --pem=3 --balance=1000 8000
42+
43+
call_ledger --pem=3 --port=8000 send "$(identity 1)" 500 MFX
44+
assert_output --partial "The identity of the from field is invalid or unexpected."
45+
46+
check_consistency --pem=1 --balance=998000 8000
47+
check_consistency --pem=2 --balance=1000 8000
48+
check_consistency --pem=3 --balance=1000 8000
49+
}
Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
GIT_ROOT="$BATS_TEST_DIRNAME/../../"
1+
GIT_ROOT="$BATS_TEST_DIRNAME/../../../"
22
START_BALANCE=100000000000
33
MFX_ADDRESS=mqbfbahksdwaqeenayy2gxke32hgb7aq4ao4wt745lsfs6wiaaaaqnz
44

5-
load '../test_helper/load'
6-
load '../test_helper/ledger'
5+
load '../../test_helper/load'
6+
load '../../test_helper/ledger'
77

88
function setup() {
99
mkdir "$BATS_TEST_ROOTDIR"
@@ -17,16 +17,9 @@ function setup() {
1717
)
1818
fi
1919

20-
run_in_background "$GIT_ROOT/target/debug/many-ledger" \
21-
-v \
22-
--clean \
23-
--persistent "$(mktemp -d)" \
24-
--state "$GIT_ROOT/staging/ledger_state.json5" \
25-
--pem "$(pem 0)" \
20+
start_ledger --pem "$(pem 0)" \
2621
"--balance-only-for-testing=$(identity 1):$START_BALANCE:$MFX_ADDRESS" \
2722
"--balance-only-for-testing=$(identity 2):$START_BALANCE:$MFX_ADDRESS"
28-
29-
wait_for_background_output "Running accept thread"
3023
}
3124

3225
function teardown() {

0 commit comments

Comments
 (0)