Compare commits

...

9 Commits

Author SHA1 Message Date
mx dda00a0f16 removed old comments and commented out code 2023-01-23 11:09:01 +01:00
mx bbc6689a32 changed whitelist<vec> to standrd_whitelist bool in Service struct 2023-01-23 11:08:09 +01:00
mx 12345dbd2c added test for acl in delete() 2023-01-23 10:57:47 +01:00
mx 63a1123ef3 added acl to delete() 2023-01-23 10:46:33 +01:00
mx 3bfdf224d3 commit before mapping change 2023-01-10 14:08:08 +01:00
mx 0ab0efd974 *changed mapping of service to use client address instead of cosmos addr 2023-01-06 18:46:45 +01:00
mx 8b7ec0756e commit before mapping change 2023-01-06 17:46:36 +01:00
mx 062f1c28f4 *added config set on instantiation,
*removed greetQuery test function
2022-12-28 13:30:51 +01:00
mx 99fe1288f4 first commit of service provider directory contract proof of concept 2022-12-16 19:45:46 +01:00
10 changed files with 1081 additions and 260 deletions
+515 -259
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,5 +1,5 @@
[workspace]
members = ["coconut-bandwidth", "mixnet", "vesting", "multisig/cw3-flex-multisig", "multisig/cw4-group", "coconut-test", "coconut-dkg"]
members = ["coconut-bandwidth", "mixnet", "vesting", "multisig/cw3-flex-multisig", "multisig/cw4-group", "coconut-test", "coconut-dkg", "service-provider-directory"]
[profile.release]
opt-level = 3
@@ -0,0 +1,4 @@
[alias]
wasm = "build --target wasm32-unknown-unknown --release"
wasm-debug = "build --target wasm32-unknown-unknown"
@@ -0,0 +1,3 @@
/target
/Cargo.lock
/notes.txt
@@ -0,0 +1,17 @@
[package]
name = "storage2"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
cosmwasm-std = { version = "1.0.0-beta8", features = ["staking"] }
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
cw-storage-plus = "0.13.4"
cw2 = { version = "0.16.0" }
thiserror = "1"
[dev-dependencies]
cw-multi-test = "0.13.4"
@@ -0,0 +1,428 @@
use crate::error::ContractError;
use crate::msg::{QueryMsg, InstantiateMsg, ExecuteMsg, ServicesListResp, ConfigResponse};
use crate::state::{SERVICES, Service, CONFIG, Config};
use cosmwasm_std::{
to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult, Order
};
use cw2::set_contract_version;
use cosmwasm_std::Addr;
const CONTRACT_NAME: &str = "service-storage-poc";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
pub fn instantiate(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
let config = Config {
updater_role: msg.updater_role,
admin: msg.admin
};
CONFIG.save(deps.storage, &config)?;
Ok(Response::new())
}
pub fn execute(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: ExecuteMsg
) -> Result<Response, ContractError> {
use ExecuteMsg::*;
match msg {
Announce { client_address, standard_whitelist, owner } => exec::announce(_deps, _info, client_address, standard_whitelist, owner ),
Delete { client_address } => exec::delete(_deps, _info, client_address),
UpdateScore { client_address, new_score } => exec::update_score(_deps, _info, client_address, new_score)
}
}
mod exec {
use super::*;
pub fn announce(
deps: DepsMut,
info: MessageInfo,
client_address: String,
standard_whitelist: bool,
owner: Addr
) -> Result<Response, ContractError> {
let new_service = Service {
client_address: client_address.clone(),
standard_whitelist,
uptime_score: 0, // init @ 0 - no score on new service
owner
};
SERVICES.save(deps.storage, client_address.clone(), &new_service)?;
Ok(Response::new()
.add_attribute("action", "service announced")
)
}
/*
* TODO finish
*/
pub fn update_score(
deps: DepsMut,
info: MessageInfo,
client_address: String,
new_score: i8
) -> Result<Response, ContractError> {
let to_update = SERVICES.load(deps.storage, client_address.clone())?;
// update score & save
Ok(Response::new()
.add_attribute("action", "service updated")
)
}
pub fn delete(
deps: DepsMut,
info: MessageInfo,
client_address: String
) -> Result<Response, ContractError> {
let service_to_delete = SERVICES.load(deps.storage, client_address.clone())?;
if info.sender != service_to_delete.owner {
return Err(ContractError::Unauthorized {
sender: info.sender,
});
}
SERVICES.remove(deps.storage, client_address.clone());
Ok(Response::new()
.add_attribute("action", "service deleted")
)
}
}
pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
use QueryMsg::*;
match msg {
QueryAll {} => to_binary(&query::query_all(_deps, _env)?),
QueryConfig {} => to_binary(&query::query_config(_deps, _env)?)
}
}
mod query {
use crate::msg::ServicesInfo;
use super::*;
pub fn query_all(
deps: Deps,
_env: Env,
) -> StdResult<ServicesListResp> {
let services = SERVICES
.range(deps.storage, None, None, Order::Ascending)
.map(|item| {
item.map(|(owner, services)| ServicesInfo {
owner,
services
})
})
.collect::<StdResult<Vec<_>>>()?;
let resp = ServicesListResp{ services };
Ok(resp)
}
pub fn query_config(
_deps: Deps,
_env: Env,
) -> StdResult<ConfigResponse> {
let config = CONFIG.load(_deps.storage)?;
let resp = ConfigResponse {
updater_role: config.updater_role,
admin: config.admin
};
Ok(resp)
}
}
#[cfg(test)]
mod tests {
use cosmwasm_std::Addr;
use cw_multi_test::{App, ContractWrapper, Executor};
use crate::msg::ServicesInfo;
use super::*;
#[test]
fn set_config() {
let mut app = App::default();
let code = ContractWrapper::new(execute, instantiate, query);
let code_id = app.store_code(Box::new(code));
let addr = app
.instantiate_contract(
code_id,
Addr::unchecked("owner"),
&InstantiateMsg { updater_role: Addr::unchecked("updater"), admin: Addr::unchecked("admin") },
&[],
"Contract",
None,
)
.unwrap();
let resp: ConfigResponse = app
.wrap()
.query_wasm_smart(addr, &QueryMsg::QueryConfig {})
.unwrap();
assert_eq!(
resp,
ConfigResponse {
updater_role: Addr::unchecked("updater"),
admin: Addr::unchecked("admin")
}
);
}
#[test]
fn announce_and_query_service() {
let mut app = App::default();
let code = ContractWrapper::new(execute, instantiate, query);
let code_id = app.store_code(Box::new(code));
let addr = app
.instantiate_contract(
code_id,
Addr::unchecked("owner"),
&InstantiateMsg{ updater_role: Addr::unchecked("updater"), admin: Addr::unchecked("admin") },
&[],
"Contract",
None,
)
.unwrap();
let resp = app
.execute_contract(
Addr::unchecked("owner"),
addr.clone(),
&ExecuteMsg::Announce {
client_address: "nymAddress".to_owned(),
standard_whitelist: true,
owner: Addr::unchecked("owner")
},
&[],
)
.unwrap();
let wasm = resp.events.iter().find(|ev| ev.ty == "wasm").unwrap();
assert_eq!(
wasm.attributes
.iter()
.find(|attr| attr.key == "action")
.unwrap()
.value,
"service announced"
);
let query: ServicesListResp = app.wrap()
.query_wasm_smart(addr.clone(), &QueryMsg::QueryAll { })
.unwrap();
let test_service: Service = Service {
client_address: "nymAddress".to_string(),
standard_whitelist: true,
owner: Addr::unchecked("owner"),
uptime_score: 0
};
let expected = vec![
ServicesInfo {
owner: "nymAddress".to_string(),
services: test_service,
}
];
assert_eq!(
query,
ServicesListResp {
services: expected
}
);
}
#[test]
fn delete_service() {
let mut app = App::default();
let code = ContractWrapper::new(execute, instantiate, query);
let code_id = app.store_code(Box::new(code));
let addr = app
.instantiate_contract(
code_id,
Addr::unchecked("owner"),
&InstantiateMsg{ updater_role: Addr::unchecked("updater"), admin: Addr::unchecked("admin") },
&[],
"Contract",
None,
)
.unwrap();
app
.execute_contract(
Addr::unchecked("owner"),
addr.clone(),
&ExecuteMsg::Announce {
client_address: "nymAddress".to_string(),
standard_whitelist: true,
owner: Addr::unchecked("owner")
},
&[],
)
.unwrap();
let query: ServicesListResp = app.wrap()
.query_wasm_smart(addr.clone(), &QueryMsg::QueryAll { })
.unwrap();
let test_service: Service = Service {
client_address: "nymAddress".to_string(),
standard_whitelist: true,
owner: Addr::unchecked("owner"),
uptime_score: 0
};
let expected = vec![
ServicesInfo {
owner: "nymAddress".to_string(),
services: test_service,
}
];
assert_eq!(
query,
ServicesListResp {
services: expected
}
);
let delete_resp = app
.execute_contract(
Addr::unchecked("owner"),
addr.clone(),
&ExecuteMsg::Delete {
client_address: "nymAddress".to_string()
},
&[],
)
.unwrap();
let wasm = delete_resp.events.iter().find(|ev| ev.ty == "wasm").unwrap();
assert_eq!(
wasm.attributes
.iter()
.find(|attr| attr.key == "action")
.unwrap()
.value,
"service deleted"
);
let query: ServicesListResp = app.wrap()
.query_wasm_smart(addr.clone(), &QueryMsg::QueryAll { })
.unwrap();
let expected = vec![];
assert_eq!(
query,
ServicesListResp {
services: expected
}
);
}
#[test]
fn only_owner_can_delete_service() {
let mut app = App::default();
let code = ContractWrapper::new(execute, instantiate, query);
let code_id = app.store_code(Box::new(code));
let addr = app
.instantiate_contract(
code_id,
Addr::unchecked("owner"),
&InstantiateMsg{ updater_role: Addr::unchecked("updater"), admin: Addr::unchecked("admin") },
&[],
"Contract",
None,
)
.unwrap();
app
.execute_contract(
Addr::unchecked("owner"),
addr.clone(),
&ExecuteMsg::Announce {
client_address: "nymAddress".to_string(),
standard_whitelist: true,
owner: Addr::unchecked("owner")
},
&[],
)
.unwrap();
let query: ServicesListResp = app.wrap()
.query_wasm_smart(addr.clone(), &QueryMsg::QueryAll { })
.unwrap();
let test_service: Service = Service {
client_address: "nymAddress".to_string(),
standard_whitelist: true,
owner: Addr::unchecked("owner"),
uptime_score: 0
};
let expected = vec![
ServicesInfo {
owner: "nymAddress".to_string(),
services: test_service,
}
];
assert_eq!(
query,
ServicesListResp {
services: expected
}
);
let delete_resp = app
.execute_contract(
Addr::unchecked("not_owner"),
addr.clone(),
&ExecuteMsg::Delete {
client_address: "nymAddress".to_string()
},
&[],
)
.unwrap_err(); // we're **expecting** an error hence this will panic if delete_resp = Ok value
assert_eq!(
ContractError::Unauthorized {
sender: Addr::unchecked("not_owner")
},
delete_resp.downcast().unwrap()
);
}
}
@@ -0,0 +1,10 @@
use cosmwasm_std::{Addr, StdError};
use thiserror::Error;
#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
#[error("{0}")]
StdError(#[from] StdError),
#[error("{sender} is not owner of service")]
Unauthorized { sender: Addr },
}
@@ -0,0 +1,37 @@
use cosmwasm_std::{
entry_point, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
};
use error::{ContractError};
use crate::msg::ExecuteMsg;
mod contract;
mod msg;
mod state;
mod error;
#[entry_point]
pub fn instantiate(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: msg::InstantiateMsg,
) -> StdResult<Response> {
contract::instantiate(deps, env, info, msg)
}
#[entry_point]
pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg
) -> Result<Response, ContractError> {
contract::execute(deps, env, info, msg)
}
#[entry_point]
pub fn query(deps: Deps, env: Env, msg: msg::QueryMsg)
-> StdResult<Binary>
{
contract::query(deps, env, msg)
}
@@ -0,0 +1,46 @@
use cosmwasm_std::Addr;
use serde::{Deserialize, Serialize};
use crate::state::Service;
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub enum QueryMsg {
QueryAll {},
QueryConfig {},
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct GreetResp {
pub message: String,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct InstantiateMsg {
pub updater_role: Addr,
pub admin: Addr
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub enum ExecuteMsg {
Announce { client_address: String, standard_whitelist: bool, owner: Addr },
Delete { client_address: String },
UpdateScore { client_address: String, new_score: i8 }
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct ServicesInfo {
pub owner: String,
pub services: Service,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct ServicesListResp {
pub services: Vec<ServicesInfo>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct ConfigResponse {
pub updater_role: Addr,
pub admin: Addr
}
@@ -0,0 +1,20 @@
use cosmwasm_std::Addr;
use cw_storage_plus::{Item, Map};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
pub struct Service {
pub client_address: String,
pub standard_whitelist: bool,
pub uptime_score: u8,
pub owner: Addr
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
pub struct Config {
pub updater_role: Addr,
pub admin: Addr
}
pub const CONFIG: Item<Config> = Item::new("config");
pub const SERVICES: Map<String, Service> = Map::new("services");