Skip to content

Commit

Permalink
feat(service-registry): add permission control to the service-registry (
Browse files Browse the repository at this point in the history
  • Loading branch information
cgorenflo authored Jul 24, 2024
1 parent b4cf22f commit b93c3db
Show file tree
Hide file tree
Showing 11 changed files with 225 additions and 200 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions contracts/service-registry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ cosmwasm-std = { workspace = true }
cw-storage-plus = { workspace = true }
cw2 = { workspace = true }
error-stack = { workspace = true }
msgs-derive = { workspace = true }
report = { workspace = true }
router-api = { workspace = true }
schemars = "0.8.10"
Expand Down
127 changes: 80 additions & 47 deletions contracts/service-registry/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
use axelar_wasm_std::FnExt;
use axelar_wasm_std::{permission_control, FnExt};
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
to_json_binary, Addr, BankMsg, Binary, Coin, Deps, DepsMut, Env, MessageInfo, Order,
QueryRequest, Response, Uint128, WasmQuery,
to_json_binary, Addr, BankMsg, Binary, Coin, Deps, DepsMut, Empty, Env, MessageInfo, Order,
QueryRequest, Response, Storage, Uint128, WasmQuery,
};
use error_stack::{bail, Report, ResultExt};

use crate::error::ContractError;
use crate::migrations;
use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
use crate::state::{AuthorizationState, BondingState, Config, Service, Verifier, CONFIG, SERVICES};
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
use crate::state::{AuthorizationState, BondingState, Service, Verifier, SERVICES, VERIFIERS};

mod execute;
mod migrations;
mod query;

const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME");
Expand All @@ -26,12 +27,9 @@ pub fn instantiate(
) -> Result<Response, axelar_wasm_std::error::ContractError> {
cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;

CONFIG.save(
deps.storage,
&Config {
governance: deps.api.addr_validate(&msg.governance_account)?,
},
)?;
let governance = deps.api.addr_validate(&msg.governance_account)?;
permission_control::set_governance(deps.storage, &governance)?;

Ok(Response::default())
}

Expand All @@ -42,7 +40,7 @@ pub fn execute(
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, axelar_wasm_std::error::ContractError> {
match msg {
match msg.ensure_permissions(deps.storage, &info.sender, match_verifier(&info.sender))? {
ExecuteMsg::RegisterService {
service_name,
coordinator_contract,
Expand All @@ -52,25 +50,21 @@ pub fn execute(
bond_denom,
unbonding_period_days,
description,
} => {
execute::require_governance(&deps, info)?;
execute::register_service(
deps,
service_name,
coordinator_contract,
min_num_verifiers,
max_num_verifiers,
min_verifier_bond,
bond_denom,
unbonding_period_days,
description,
)
}
} => execute::register_service(
deps,
service_name,
coordinator_contract,
min_num_verifiers,
max_num_verifiers,
min_verifier_bond,
bond_denom,
unbonding_period_days,
description,
),
ExecuteMsg::AuthorizeVerifiers {
verifiers,
service_name,
} => {
execute::require_governance(&deps, info)?;
let verifiers = verifiers
.into_iter()
.map(|veriier| deps.api.addr_validate(&veriier))
Expand All @@ -86,7 +80,6 @@ pub fn execute(
verifiers,
service_name,
} => {
execute::require_governance(&deps, info)?;
let verifiers = verifiers
.into_iter()
.map(|verifier| deps.api.addr_validate(&verifier))
Expand All @@ -102,7 +95,6 @@ pub fn execute(
verifiers,
service_name,
} => {
execute::require_governance(&deps, info)?;
let verifiers = verifiers
.into_iter()
.map(|verifier| deps.api.addr_validate(&verifier))
Expand Down Expand Up @@ -135,6 +127,23 @@ pub fn execute(
.then(Ok)
}

fn match_verifier(
sender: &Addr,
) -> impl FnOnce(&dyn Storage, &ExecuteMsg) -> Result<Addr, Report<permission_control::Error>> + '_
{
|storage: &dyn Storage, msg: &ExecuteMsg| {
let service_name = match msg {
ExecuteMsg::RegisterChainSupport { service_name, .. }
| ExecuteMsg::DeregisterChainSupport { service_name, .. } => service_name,
_ => bail!(permission_control::Error::WrongVariant),
};
VERIFIERS
.load(storage, (service_name, sender))
.map(|verifier| verifier.address)
.change_context(permission_control::Error::Unauthorized)
}
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<Binary, ContractError> {
match msg {
Expand Down Expand Up @@ -162,17 +171,20 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<Binary, ContractErr
pub fn migrate(
deps: DepsMut,
_env: Env,
msg: MigrateMsg,
_msg: Empty,
) -> Result<Response, axelar_wasm_std::error::ContractError> {
migrations::v0_4_1::migrate(deps.storage)?;

cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
migrations::v_0_4::migrate_services_coordinator_contract(deps.storage, msg.coordinator_contract)
.map_err(axelar_wasm_std::error::ContractError::from)

Ok(Response::default())
}

#[cfg(test)]
mod test {
use std::str::FromStr;

use axelar_wasm_std::error::err_contains;
use cosmwasm_std::testing::{
mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage,
};
Expand Down Expand Up @@ -211,13 +223,6 @@ mod test {
deps
}

pub fn assert_contract_err_strings_equal(
actual: impl Into<axelar_wasm_std::error::ContractError>,
expected: impl Into<axelar_wasm_std::error::ContractError>,
) {
assert_eq!(actual.into().to_string(), expected.into().to_string());
}

#[test]
fn register_service() {
let mut deps = setup();
Expand Down Expand Up @@ -255,7 +260,11 @@ mod test {
},
)
.unwrap_err();
assert_contract_err_strings_equal(err, ContractError::Unauthorized);
assert!(err_contains!(
err.report,
permission_control::Error,
permission_control::Error::PermissionDenied { .. }
));
}

#[test]
Expand Down Expand Up @@ -301,7 +310,11 @@ mod test {
},
)
.unwrap_err();
assert_contract_err_strings_equal(err, ContractError::Unauthorized);
assert!(err_contains!(
err.report,
permission_control::Error,
permission_control::Error::PermissionDenied { .. }
));
}

#[test]
Expand Down Expand Up @@ -1160,7 +1173,11 @@ mod test {
)
.unwrap_err();

assert_contract_err_strings_equal(err, ContractError::VerifierNotFound);
assert!(err_contains!(
err.report,
permission_control::Error,
permission_control::Error::WhitelistNotFound { .. }
));

let verifiers: Vec<WeightedVerifier> = from_json(
query(
Expand Down Expand Up @@ -1196,7 +1213,11 @@ mod test {
)
.unwrap_err();

assert_contract_err_strings_equal(err, ContractError::ServiceNotFound);
assert!(err_contains!(
err.report,
permission_control::Error,
permission_control::Error::WhitelistNotFound { .. }
));
}

#[test]
Expand Down Expand Up @@ -1319,7 +1340,11 @@ mod test {
)
.unwrap_err();

assert_contract_err_strings_equal(err, ContractError::WrongDenom);
assert!(err_contains!(
err.report,
ContractError,
ContractError::WrongDenom
));
}

#[test]
Expand Down Expand Up @@ -1948,7 +1973,11 @@ mod test {
},
)
.unwrap_err();
assert_contract_err_strings_equal(err, ContractError::VerifierJailed);
assert!(err_contains!(
err.report,
ContractError,
ContractError::VerifierJailed
));

// given a verifier passed unbonding period
let verifier2 = Addr::unchecked("verifier-2");
Expand Down Expand Up @@ -2030,6 +2059,10 @@ mod test {
},
)
.unwrap_err();
assert_contract_err_strings_equal(err, ContractError::VerifierJailed);
assert!(err_contains!(
err.report,
ContractError,
ContractError::VerifierJailed
));
}
}
16 changes: 0 additions & 16 deletions contracts/service-registry/src/contract/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@ use router_api::ChainName;
use super::*;
use crate::state::{self, AuthorizationState, Verifier, VERIFIERS};

pub fn require_governance(deps: &DepsMut, info: MessageInfo) -> Result<(), ContractError> {
let config = CONFIG.load(deps.storage)?;
if config.governance != info.sender {
return Err(ContractError::Unauthorized);
}
Ok(())
}

#[allow(clippy::too_many_arguments)]
pub fn register_service(
deps: DepsMut,
Expand Down Expand Up @@ -131,10 +123,6 @@ pub fn register_chains_support(
.may_load(deps.storage, &service_name)?
.ok_or(ContractError::ServiceNotFound)?;

VERIFIERS
.may_load(deps.storage, (&service_name, &info.sender))?
.ok_or(ContractError::VerifierNotFound)?;

state::register_chains_support(
deps.storage,
service_name.clone(),
Expand All @@ -155,10 +143,6 @@ pub fn deregister_chains_support(
.may_load(deps.storage, &service_name)?
.ok_or(ContractError::ServiceNotFound)?;

VERIFIERS
.may_load(deps.storage, (&service_name, &info.sender))?
.ok_or(ContractError::VerifierNotFound)?;

state::deregister_chains_support(deps.storage, service_name.clone(), chains, info.sender)?;

Ok(Response::new())
Expand Down
1 change: 1 addition & 0 deletions contracts/service-registry/src/contract/migrations/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod v0_4_1;
Loading

0 comments on commit b93c3db

Please sign in to comment.