Skip to content

Commit

Permalink
feat(multisig-prover): add permission control to multisig-prover (#526)
Browse files Browse the repository at this point in the history
  • Loading branch information
cgorenflo authored Jul 22, 2024
1 parent ac966f1 commit 546b5e1
Show file tree
Hide file tree
Showing 12 changed files with 311 additions and 99 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/multisig-prover/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ gateway-api = { workspace = true }
hex = { version = "0.4.3", default-features = false, features = [] }
itertools = "0.11.0"
k256 = { version = "0.13.1", features = ["ecdsa"] }
msgs-derive = { workspace = true }
multisig = { workspace = true, features = ["library"] }
report = { workspace = true }
router-api = { workspace = true }
Expand Down
126 changes: 71 additions & 55 deletions contracts/multisig-prover/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use axelar_wasm_std::permission_control;
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
Expand All @@ -8,7 +9,10 @@ use error_stack::ResultExt;
use crate::error::ContractError;
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
use crate::state::{Config, CONFIG};
use crate::{execute, query, reply};
mod execute;
mod migrations;
mod query;
mod reply;

pub const START_MULTISIG_REPLY_ID: u64 = 1;

Expand All @@ -24,43 +28,29 @@ pub fn instantiate(
) -> Result<Response, axelar_wasm_std::ContractError> {
cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;

let config = make_config(&deps, msg)?;
CONFIG.save(deps.storage, &config)?;

Ok(Response::default())
}

fn make_config(
deps: &DepsMut,
msg: InstantiateMsg,
) -> Result<Config, axelar_wasm_std::ContractError> {
let admin = deps.api.addr_validate(&msg.admin_address)?;
let governance = deps.api.addr_validate(&msg.governance_address)?;
let gateway = deps.api.addr_validate(&msg.gateway_address)?;
let multisig = deps.api.addr_validate(&msg.multisig_address)?;
let coordinator = deps.api.addr_validate(&msg.coordinator_address)?;
let service_registry = deps.api.addr_validate(&msg.service_registry_address)?;
let voting_verifier = deps.api.addr_validate(&msg.voting_verifier_address)?;

Ok(Config {
admin,
governance,
gateway,
multisig,
coordinator,
service_registry,
voting_verifier,
let config = Config {
gateway: deps.api.addr_validate(&msg.gateway_address)?,
multisig: deps.api.addr_validate(&msg.multisig_address)?,
coordinator: deps.api.addr_validate(&msg.coordinator_address)?,
service_registry: deps.api.addr_validate(&msg.service_registry_address)?,
voting_verifier: deps.api.addr_validate(&msg.voting_verifier_address)?,
signing_threshold: msg.signing_threshold,
service_name: msg.service_name,
chain_name: msg
.chain_name
.parse()
.map_err(|_| ContractError::InvalidChainName)?,
chain_name: msg.chain_name.parse()?,
verifier_set_diff_threshold: msg.verifier_set_diff_threshold,
encoder: msg.encoder,
key_type: msg.key_type,
domain_separator: msg.domain_separator,
})
};
CONFIG.save(deps.storage, &config)?;

permission_control::set_admin(deps.storage, &deps.api.addr_validate(&msg.admin_address)?)?;
permission_control::set_governance(
deps.storage,
&deps.api.addr_validate(&msg.governance_address)?,
)?;

Ok(Response::default())
}

#[cfg_attr(not(feature = "library"), entry_point)]
Expand All @@ -70,29 +60,22 @@ pub fn execute(
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, axelar_wasm_std::ContractError> {
match msg {
ExecuteMsg::ConstructProof { message_ids } => execute::construct_proof(deps, message_ids),
ExecuteMsg::UpdateVerifierSet {} => {
execute::require_admin(&deps, info.clone())
.or_else(|_| execute::require_governance(&deps, info))?;
execute::update_verifier_set(deps, env)
match msg.ensure_permissions(deps.storage, &info.sender)? {
ExecuteMsg::ConstructProof { message_ids } => {
Ok(execute::construct_proof(deps, message_ids)?)
}
ExecuteMsg::UpdateVerifierSet {} => Ok(execute::update_verifier_set(deps, env)?),
ExecuteMsg::ConfirmVerifierSet {} => Ok(execute::confirm_verifier_set(deps, info.sender)?),
ExecuteMsg::UpdateSigningThreshold {
new_signing_threshold,
} => {
execute::require_governance(&deps, info)?;
Ok(execute::update_signing_threshold(
deps,
new_signing_threshold,
)?)
}
} => Ok(execute::update_signing_threshold(
deps,
new_signing_threshold,
)?),
ExecuteMsg::UpdateAdmin { new_admin_address } => {
execute::require_governance(&deps, info)?;
Ok(execute::update_admin(deps, new_admin_address)?)
}
}
.map_err(axelar_wasm_std::ContractError::from)
}

#[cfg_attr(not(feature = "library"), entry_point)]
Expand Down Expand Up @@ -131,19 +114,22 @@ pub fn migrate(
_env: Env,
_msg: Empty,
) -> Result<Response, axelar_wasm_std::ContractError> {
cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
migrations::v0_6_0::migrate(deps.storage)?;

cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
Ok(Response::default())
}

#[cfg(test)]
mod tests {
use axelar_wasm_std::{MajorityThreshold, Threshold, VerificationStatus};
use axelar_wasm_std::permission_control::Permission;
use axelar_wasm_std::{permission_control, MajorityThreshold, Threshold, VerificationStatus};
use cosmwasm_std::testing::{
mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage,
};
use cosmwasm_std::{
from_json, Addr, Empty, Fraction, OwnedDeps, SubMsgResponse, SubMsgResult, Uint128, Uint64,
from_json, Addr, Api, Empty, Fraction, OwnedDeps, SubMsgResponse, SubMsgResult, Uint128,
Uint64,
};
use multisig::msg::Signer;
use multisig::verifier_set::VerifierSet;
Expand Down Expand Up @@ -345,13 +331,30 @@ mod tests {
assert_eq!(res.messages.len(), 0);

let config = CONFIG.load(deps.as_ref().storage).unwrap();
assert_eq!(config.admin, admin);
assert_eq!(config.gateway, gateway_address);
assert_eq!(config.multisig, multisig_address);
assert_eq!(config.service_registry, service_registry_address);
assert_eq!(config.signing_threshold, signing_threshold);
assert_eq!(config.service_name, service_name);
assert_eq!(config.encoder, encoding)
assert_eq!(config.encoder, encoding);

assert_eq!(
permission_control::sender_role(
deps.as_ref().storage,
&deps.api.addr_validate(admin).unwrap()
)
.unwrap(),
Permission::Admin.into()
);

assert_eq!(
permission_control::sender_role(
deps.as_ref().storage,
&deps.api.addr_validate(governance).unwrap()
)
.unwrap(),
Permission::Governance.into()
);
}
}

Expand Down Expand Up @@ -413,7 +416,11 @@ mod tests {
assert!(res.is_err());
assert_eq!(
res.unwrap_err().to_string(),
axelar_wasm_std::ContractError::from(ContractError::Unauthorized).to_string()
axelar_wasm_std::ContractError::from(permission_control::Error::PermissionDenied {
expected: Permission::Elevated.into(),
actual: Permission::NoPrivilege.into()
})
.to_string()
);
}

Expand Down Expand Up @@ -864,7 +871,16 @@ mod tests {
let res = execute_update_admin(deps.as_mut(), GOVERNANCE, new_admin.to_string());
assert!(res.is_ok(), "{:?}", res);

let config = CONFIG.load(deps.as_ref().storage).unwrap();
assert_eq!(config.admin, Addr::unchecked(new_admin));
assert_eq!(
permission_control::sender_role(deps.as_ref().storage, &Addr::unchecked(new_admin))
.unwrap(),
Permission::Admin.into()
);

assert_eq!(
permission_control::sender_role(deps.as_ref().storage, &Addr::unchecked(ADMIN))
.unwrap(),
Permission::NoPrivilege.into()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::collections::{BTreeMap, HashSet};

use axelar_wasm_std::permission_control::Permission;
use axelar_wasm_std::snapshot::{Participant, Snapshot};
use axelar_wasm_std::{FnExt, MajorityThreshold, VerificationStatus};
use axelar_wasm_std::{permission_control, FnExt, MajorityThreshold, VerificationStatus};
use cosmwasm_std::{
to_json_binary, wasm_execute, Addr, DepsMut, Env, MessageInfo, QuerierWrapper, QueryRequest,
Response, Storage, SubMsg, WasmQuery,
to_json_binary, wasm_execute, Addr, DepsMut, Env, QuerierWrapper, QueryRequest, Response,
Storage, SubMsg, WasmQuery,
};
use itertools::Itertools;
use multisig::msg::Signer;
Expand All @@ -19,20 +20,6 @@ use crate::state::{
Config, CONFIG, CURRENT_VERIFIER_SET, NEXT_VERIFIER_SET, PAYLOAD, REPLY_TRACKER,
};

pub fn require_admin(deps: &DepsMut, info: MessageInfo) -> Result<(), ContractError> {
match CONFIG.load(deps.storage)?.admin {
admin if admin == info.sender => Ok(()),
_ => Err(ContractError::Unauthorized),
}
}

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

pub fn construct_proof(
deps: DepsMut,
message_ids: Vec<CrossChainId>,
Expand Down Expand Up @@ -322,7 +309,8 @@ pub fn confirm_verifier_set(deps: DepsMut, sender: Addr) -> Result<Response, Con

let verifier_set = NEXT_VERIFIER_SET.load(deps.storage)?;

if sender != config.governance {
let sender_role = permission_control::sender_role(deps.storage, &sender)?;
if !sender_role.contains(Permission::Governance) {
ensure_verifier_set_verification(&verifier_set, &config, &deps)?;
}

Expand Down Expand Up @@ -413,13 +401,8 @@ pub fn update_signing_threshold(
}

pub fn update_admin(deps: DepsMut, new_admin_address: String) -> Result<Response, ContractError> {
CONFIG.update(
deps.storage,
|mut config| -> Result<Config, ContractError> {
config.admin = deps.api.addr_validate(&new_admin_address)?;
Ok(config)
},
)?;
let new_admin = deps.api.addr_validate(&new_admin_address)?;
permission_control::set_admin(deps.storage, &new_admin)?;
Ok(Response::new())
}

Expand All @@ -432,8 +415,7 @@ mod tests {
use cosmwasm_std::Addr;
use router_api::ChainName;

use super::{different_set_in_progress, get_next_verifier_set};
use crate::execute::should_update_verifier_set;
use super::{different_set_in_progress, get_next_verifier_set, should_update_verifier_set};
use crate::state::{Config, NEXT_VERIFIER_SET};
use crate::test::test_data;

Expand Down Expand Up @@ -554,8 +536,6 @@ mod tests {

fn mock_config() -> Config {
Config {
admin: Addr::unchecked("doesn't matter"),
governance: Addr::unchecked("doesn't matter"),
gateway: Addr::unchecked("doesn't matter"),
multisig: Addr::unchecked("doesn't matter"),
coordinator: Addr::unchecked("doesn't matter"),
Expand Down
1 change: 1 addition & 0 deletions contracts/multisig-prover/src/contract/migrations/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub(crate) mod v0_6_0;
Loading

0 comments on commit 546b5e1

Please sign in to comment.