Skip to content

Commit

Permalink
feat(minor-monitoring)!: register active worker set with monitoring (#…
Browse files Browse the repository at this point in the history
…352)

* chore: add execute message to monitoring, update confirm_worker_set

* feat: add query to monitoring, register_active_workerset_with_monitoring_success integration test

* refactor: remove chain_name from active worker set for prover map

* refactor: move two outdated prover unit tests to integration tests

* chore migrate update_signing_threshold_should_change_future_threshold to integration tests

* fix: remove unused imports

* test: add two unit tests and support function to monitoring

* refactor: add TestSetup struct to monitoring unit tests and cleanup

* chore: address new_signing_threshold out of interval

* chore: uncomment update_signing_threshold_should_change_future_threshold test

* chore: handle majority threshold error

* fix: add monitoring mock to prover

* refactor: address PR comments

* refactor: change PROVER_PER_CHAIN to keep one prover per chain

* refactor: update contracts/monitoring/src/msg.rs

Co-authored-by: CJ Cobb <[email protected]>

* refactor: remove execution logic from monitoring mock, combine integration tests

---------

Co-authored-by: CJ Cobb <[email protected]>
  • Loading branch information
maancham and cjcobb23 authored Apr 18, 2024
1 parent 07bc88f commit 4a497b4
Show file tree
Hide file tree
Showing 16 changed files with 401 additions and 176 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/monitoring/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ thiserror = { workspace = true }
[dev-dependencies]
cw-multi-test = "0.15.1"
integration-tests = { workspace = true }
tofn = { git = "https://github.com/axelarnetwork/tofn.git", branch = "update-deps" }

[lints]
workspace = true
242 changes: 180 additions & 62 deletions contracts/monitoring/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
use crate::state::{Config, CONFIG};
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult};
use cosmwasm_std::{to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response};

use crate::error::ContractError;
use crate::execute;
use crate::query;

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
Expand Down Expand Up @@ -37,110 +38,227 @@ pub fn execute(
execute::check_governance(&deps, info)?;
execute::register_prover(deps, chain_name, new_prover_addr)
}
ExecuteMsg::SetActiveVerifiers { next_worker_set } => {
execute::set_active_worker_set(deps, info, next_worker_set)
}
}
.map_err(axelar_wasm_std::ContractError::from)
}

#[cfg_attr(not(feature = "library"), entry_point)]
#[allow(dead_code)]
pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<Binary, ContractError> {
match msg {
QueryMsg::GetActiveVerifiersForChain { chain: _ } => {
todo!()
QueryMsg::GetActiveVerifiers { chain_name } => {
to_binary(&query::get_active_worker_set(deps, chain_name)?).map_err(|err| err.into())
}
}
}

#[cfg(test)]
mod tests {

use crate::error::ContractError;
use crate::query;
use axelar_wasm_std::Participant;
use connection_router_api::ChainName;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::Addr;
use cosmwasm_std::testing::{
mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage,
};
use cosmwasm_std::{Addr, Empty, HexBinary, OwnedDeps, Uint256};
use multisig::key::{KeyType, PublicKey};
use multisig::worker_set::WorkerSet;
use tofn::ecdsa::KeyPair;

use super::*;

#[test]
#[allow(clippy::arithmetic_side_effects)]
fn test_instantiation() {
let governance = "governance_for_monitoring";
struct TestSetup {
deps: OwnedDeps<MockStorage, MockApi, MockQuerier, Empty>,
env: Env,
prover: Addr,
chain_name: ChainName,
}

fn setup(governance: &str) -> TestSetup {
let mut deps = mock_dependencies();
let info = mock_info("instantiator", &[]);
let env = mock_env();

let res = instantiate(
deps.as_mut(),
env,
info,
InstantiateMsg {
governance_address: governance.to_string(),
},
);
let instantiate_msg = InstantiateMsg {
governance_address: governance.to_string(),
};

let res = instantiate(deps.as_mut(), env.clone(), info.clone(), instantiate_msg);
assert!(res.is_ok());

let config = CONFIG.load(deps.as_ref().storage).unwrap();
let eth_prover = Addr::unchecked("eth_prover");
let eth: ChainName = "Ethereum".to_string().try_into().unwrap();

TestSetup {
deps,
env,
prover: eth_prover,
chain_name: eth,
}
}

pub struct Worker {
pub addr: Addr,
pub supported_chains: Vec<ChainName>,
pub key_pair: KeyPair,
}

fn create_worker(
keypair_seed: u32,
worker_address: Addr,
supported_chains: Vec<ChainName>,
) -> Worker {
let seed_bytes = keypair_seed.to_be_bytes();
let mut result = [0; 64];
result[0..seed_bytes.len()].copy_from_slice(seed_bytes.as_slice());
let secret_recovery_key = result.as_slice().try_into().unwrap();

Worker {
addr: worker_address,
supported_chains,
key_pair: tofn::ecdsa::keygen(&secret_recovery_key, b"tofn nonce").unwrap(),
}
}

fn create_worker_set_from_workers(workers: &Vec<Worker>, block_height: u64) -> WorkerSet {
let mut pub_keys = vec![];
for worker in workers {
let encoded_verifying_key =
HexBinary::from(worker.key_pair.encoded_verifying_key().to_vec());
let pub_key = PublicKey::try_from((KeyType::Ecdsa, encoded_verifying_key)).unwrap();
pub_keys.push(pub_key);
}

let participants: Vec<Participant> = workers
.iter()
.map(|worker| Participant {
address: worker.addr.clone(),
weight: Uint256::one().try_into().unwrap(),
})
.collect();

WorkerSet::new(
participants.clone().into_iter().zip(pub_keys).collect(),
Uint256::from_u128(participants.len() as u128).mul_ceil((2u64, 3u64)),
block_height,
)
}

#[test]
#[allow(clippy::arithmetic_side_effects)]
fn test_instantiation() {
let governance = "governance_for_monitoring";
let test_setup = setup(governance);

let config = CONFIG.load(test_setup.deps.as_ref().storage).unwrap();
assert_eq!(config.governance, governance);
}

#[test]
fn add_prover_from_goverance_succeeds() {
fn add_prover_from_governance_succeeds() {
let governance = "governance_for_monitoring";
let mut deps = mock_dependencies();
let info = mock_info("instantiator", &[]);
let env = mock_env();
let mut test_setup = setup(governance);

let _ = instantiate(
deps.as_mut(),
env.clone(),
info,
InstantiateMsg {
governance_address: governance.to_string(),
let _res = execute(
test_setup.deps.as_mut(),
test_setup.env,
mock_info(governance, &[]),
ExecuteMsg::RegisterProverContract {
chain_name: test_setup.chain_name.clone(),
new_prover_addr: test_setup.prover.clone(),
},
);
)
.unwrap();

let eth_prover = Addr::unchecked("eth_prover");
let eth: ChainName = "Ethereum".to_string().try_into().unwrap();
let msg = ExecuteMsg::RegisterProverContract {
chain_name: eth.clone(),
new_prover_addr: eth_prover.clone(),
};
let _res = execute(deps.as_mut(), mock_env(), mock_info(governance, &[]), msg).unwrap();
let chain_provers = query::provers(deps.as_ref(), eth.clone()).unwrap();
assert_eq!(chain_provers, vec![eth_prover]);
let chain_provers =
query::provers(test_setup.deps.as_ref(), test_setup.chain_name.clone()).unwrap();
assert_eq!(chain_provers, test_setup.prover);
}

#[test]
fn add_prover_from_random_address_fails() {
let governance = "governance_for_monitoring";
let mut deps = mock_dependencies();
let info = mock_info("instantiator", &[]);
let env = mock_env();
let mut test_setup = setup(governance);

let _ = instantiate(
deps.as_mut(),
env.clone(),
info,
InstantiateMsg {
governance_address: governance.to_string(),
},
);

let eth_prover = Addr::unchecked("eth_prover");
let eth: ChainName = "Ethereum".to_string().try_into().unwrap();
let msg = ExecuteMsg::RegisterProverContract {
chain_name: eth.clone(),
new_prover_addr: eth_prover.clone(),
};
let res = execute(
deps.as_mut(),
env.clone(),
test_setup.deps.as_mut(),
test_setup.env,
mock_info("random_address", &[]),
msg,
ExecuteMsg::RegisterProverContract {
chain_name: test_setup.chain_name.clone(),
new_prover_addr: test_setup.prover.clone(),
},
);
assert_eq!(
res.unwrap_err().to_string(),
axelar_wasm_std::ContractError::from(ContractError::Unauthorized).to_string()
);
}

#[test]
fn set_and_get_populated_active_worker_set_success() {
let governance = "governance_for_monitoring";
let mut test_setup = setup(governance);

let new_worker = create_worker(
1,
Addr::unchecked("worker1"),
vec![test_setup.chain_name.clone()],
);
let new_worker_set =
create_worker_set_from_workers(&vec![new_worker], test_setup.env.block.height);

let res = execute(
test_setup.deps.as_mut(),
test_setup.env.clone(),
mock_info(governance, &[]),
ExecuteMsg::RegisterProverContract {
chain_name: test_setup.chain_name.clone(),
new_prover_addr: test_setup.prover.clone(),
},
);
assert!(res.is_ok());

let res = execute(
test_setup.deps.as_mut(),
test_setup.env.clone(),
mock_info(test_setup.prover.as_ref(), &[]),
ExecuteMsg::SetActiveVerifiers {
next_worker_set: new_worker_set.clone(),
},
);
assert!(res.is_ok());

let eth_active_worker_set =
query::get_active_worker_set(test_setup.deps.as_ref(), test_setup.chain_name.clone())
.unwrap();

assert_eq!(eth_active_worker_set, Some(new_worker_set));
}

#[test]
fn set_and_get_empty_active_worker_set_success() {
let governance = "governance_for_monitoring";
let mut test_setup = setup(governance);

let _response = execute(
test_setup.deps.as_mut(),
test_setup.env,
mock_info(governance, &[]),
ExecuteMsg::RegisterProverContract {
chain_name: test_setup.chain_name.clone(),
new_prover_addr: test_setup.prover.clone(),
},
);

let query_result =
query::get_active_worker_set(test_setup.deps.as_ref(), test_setup.chain_name.clone())
.unwrap();

assert_eq!(query_result, None);
}
}
3 changes: 3 additions & 0 deletions contracts/monitoring/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ pub enum ContractError {

#[error("no provers registered for chain {0}")]
NoProversRegisteredForChain(ChainName),

#[error("no active worker set registered")]
NoActiveWorkerSetRegistered,
}
17 changes: 11 additions & 6 deletions contracts/monitoring/src/execute.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use cosmwasm_std::{Addr, DepsMut, MessageInfo, Response};

use connection_router_api::ChainName;
use multisig::worker_set::WorkerSet;

use crate::error::ContractError;
use crate::state::{CONFIG, PROVERS_PER_CHAIN};
use crate::state::{ACTIVE_WORKERSET_FOR_PROVER, CONFIG, PROVER_PER_CHAIN};

pub fn check_governance(deps: &DepsMut, info: MessageInfo) -> Result<(), ContractError> {
let config = CONFIG.load(deps.storage)?;
Expand All @@ -18,11 +19,15 @@ pub fn register_prover(
chain_name: ChainName,
new_prover_addr: Addr,
) -> Result<Response, ContractError> {
let existing_provers = PROVERS_PER_CHAIN.may_load(deps.storage, chain_name.clone())?;
let mut provers = existing_provers.unwrap_or_else(Vec::new);

provers.push(new_prover_addr.clone());
PROVER_PER_CHAIN.save(deps.storage, chain_name.clone(), &(new_prover_addr))?;
Ok(Response::new())
}

PROVERS_PER_CHAIN.save(deps.storage, chain_name.clone(), &(provers))?;
pub fn set_active_worker_set(
deps: DepsMut,
info: MessageInfo,
next_worker_set: WorkerSet,
) -> Result<Response, ContractError> {
ACTIVE_WORKERSET_FOR_PROVER.save(deps.storage, info.sender, &(next_worker_set))?;
Ok(Response::new())
}
5 changes: 4 additions & 1 deletion contracts/monitoring/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ pub enum ExecuteMsg {
chain_name: ChainName,
new_prover_addr: Addr,
},
SetActiveVerifiers {
next_worker_set: WorkerSet,
},
}

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
#[returns(WorkerSet)]
GetActiveVerifiersForChain { chain: ChainName },
GetActiveVerifiers { chain_name: ChainName },
}
Loading

0 comments on commit 4a497b4

Please sign in to comment.