Skip to content

Commit

Permalink
Merge pull request #203 from hadronlabs-org/fix/inconsistent-validato…
Browse files Browse the repository at this point in the history
…r-set

Audit report. Fix inconsistent validator set
  • Loading branch information
oldremez authored Nov 28, 2024
2 parents d30ba8d + 89258d4 commit c41df39
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 43 deletions.
12 changes: 6 additions & 6 deletions contracts/factory/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -713,12 +713,12 @@ fn test_proxy_validators_set_update_validators_unauthorized() {
drop_staking_base::msg::validatorset::ValidatorData {
valoper_address: "valoper_address1".to_string(),
weight: 10u64,
on_top: Uint128::zero(),
on_top: Some(Uint128::zero()),
},
drop_staking_base::msg::validatorset::ValidatorData {
valoper_address: "valoper_address2".to_string(),
weight: 10u64,
on_top: Uint128::zero(),
on_top: Some(Uint128::zero()),
},
],
},
Expand Down Expand Up @@ -750,12 +750,12 @@ fn test_proxy_validators_set_update_validators() {
drop_staking_base::msg::validatorset::ValidatorData {
valoper_address: "valoper_address1".to_string(),
weight: 10u64,
on_top: Uint128::zero(),
on_top: Some(Uint128::zero()),
},
drop_staking_base::msg::validatorset::ValidatorData {
valoper_address: "valoper_address2".to_string(),
weight: 10u64,
on_top: Uint128::zero(),
on_top: Some(Uint128::zero()),
},
],
},
Expand All @@ -774,12 +774,12 @@ fn test_proxy_validators_set_update_validators() {
drop_staking_base::msg::validatorset::ValidatorData {
valoper_address: "valoper_address1".to_string(),
weight: 10u64,
on_top: Uint128::zero(),
on_top: Some(Uint128::zero()),
},
drop_staking_base::msg::validatorset::ValidatorData {
valoper_address: "valoper_address2".to_string(),
weight: 10u64,
on_top: Uint128::zero(),
on_top: Some(Uint128::zero()),
},
],
})
Expand Down
39 changes: 28 additions & 11 deletions contracts/val-ref/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::error::{ContractError, ContractResult};
use cosmwasm_std::{
attr, entry_point, to_json_binary, Binary, Decimal, Deps, DepsMut, Env, MessageInfo, Order,
Response, StdResult, SubMsg, WasmMsg,
Reply, Response, StdResult, SubMsg, WasmMsg,
};
use drop_helpers::answer::response;
use drop_staking_base::{
Expand All @@ -17,6 +17,8 @@ use neutron_sdk::bindings::{msg::NeutronMsg, query::NeutronQuery};
pub const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME");
pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

pub const EDIT_ON_TOP_REPLY_ID: u64 = 1;

#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)]
pub fn instantiate(
deps: DepsMut<NeutronQuery>,
Expand Down Expand Up @@ -89,16 +91,19 @@ fn execute_bond_hook(
&drop_staking_base::msg::core::QueryMsg::ExchangeRate {},
)?;
let on_top_increase = bond_hook.dasset_minted * exchange_rate;
messages.push(SubMsg::new(WasmMsg::Execute {
contract_addr: VALIDATORS_SET_ADDRESS.load(deps.storage)?.into_string(),
funds: vec![],
msg: to_json_binary(&ValidatorSetExecuteMsg::EditOnTop {
operations: vec![OnTopEditOperation::Add {
validator_address,
amount: on_top_increase,
}],
})?,
}));
messages.push(SubMsg::reply_on_error(
WasmMsg::Execute {
contract_addr: VALIDATORS_SET_ADDRESS.load(deps.storage)?.into_string(),
funds: vec![],
msg: to_json_binary(&ValidatorSetExecuteMsg::EditOnTop {
operations: vec![OnTopEditOperation::Add {
validator_address,
amount: on_top_increase,
}],
})?,
},
EDIT_ON_TOP_REPLY_ID,
));
attrs.push(attr("on_top_increase", on_top_increase));
} else {
attrs.push(attr("validator", "None"));
Expand Down Expand Up @@ -180,6 +185,18 @@ pub fn query(deps: Deps<NeutronQuery>, _env: Env, msg: QueryMsg) -> ContractResu
}
}

#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)]
pub fn reply(_deps: DepsMut, _env: Env, msg: Reply) -> ContractResult<Response> {
match msg.id {
EDIT_ON_TOP_REPLY_ID => Ok(response(
"reply",
CONTRACT_NAME,
[attr("edit_on_top_error", true.to_string())],
)),
id => Err(ContractError::UnknownReplyId { id }),
}
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> ContractResult<Response<NeutronMsg>> {
let version: semver::Version = CONTRACT_VERSION.parse()?;
Expand Down
3 changes: 3 additions & 0 deletions contracts/val-ref/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ pub enum ContractError {

#[error("Semver parsing error: {0}")]
SemVer(String),

#[error("unknown reply id: {id}")]
UnknownReplyId { id: u64 },
}

impl From<semver::Error> for ContractError {
Expand Down
32 changes: 19 additions & 13 deletions contracts/val-ref/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::{contract, error::ContractError};
use crate::{
contract::{self, EDIT_ON_TOP_REPLY_ID},
error::ContractError,
};
use cosmwasm_std::{
from_json,
testing::{mock_env, mock_info},
to_json_binary, Addr, Decimal, Event, Order, Response, StdResult, Uint128, WasmMsg,
to_json_binary, Addr, Decimal, Event, Order, Response, StdResult, SubMsg, Uint128, WasmMsg,
};
use drop_helpers::testing::mock_dependencies;
use drop_staking_base::{
Expand Down Expand Up @@ -262,17 +265,20 @@ fn execute_bond_hook_known_validator() {
assert_eq!(
response,
Response::new()
.add_message(WasmMsg::Execute {
contract_addr: String::from("validators_set"),
msg: to_json_binary(&ValidatorSetExecuteMsg::EditOnTop {
operations: vec![OnTopEditOperation::Add {
validator_address: String::from("valoperX"),
amount: Uint128::new(150),
}]
})
.unwrap(),
funds: vec![]
})
.add_submessage(SubMsg::reply_on_error(
WasmMsg::Execute {
contract_addr: String::from("validators_set"),
msg: to_json_binary(&ValidatorSetExecuteMsg::EditOnTop {
operations: vec![OnTopEditOperation::Add {
validator_address: String::from("valoperX"),
amount: Uint128::new(150),
}]
})
.unwrap(),
funds: vec![]
},
EDIT_ON_TOP_REPLY_ID
))
.add_event(
Event::new("drop-val-ref-execute-bond-hook").add_attributes([
("ref", "X"),
Expand Down
19 changes: 15 additions & 4 deletions contracts/validators-set/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use drop_staking_base::state::validatorset::{
use neutron_sdk::bindings::msg::NeutronMsg;
use neutron_sdk::bindings::query::NeutronQuery;

use std::collections::HashMap;

const CONTRACT_NAME: &str = concat!("crates.io:drop-staking__", env!("CARGO_PKG_NAME"));
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

Expand Down Expand Up @@ -138,14 +140,23 @@ fn execute_update_validators(

let total_count = validators.len();

// TODO: implement notification of the validator stats contract about new validators set
let old_validator_set: HashMap<String, ValidatorInfo> = VALIDATORS_SET
.range_raw(deps.storage, None, None, Order::Ascending)
.map(|item| item.map(|(_key, value)| (value.valoper_address.to_string(), value)))
.collect::<StdResult<_>>()?;

VALIDATORS_SET.clear(deps.storage);

for validator in validators {
let on_top_value = old_validator_set
.get(&validator.valoper_address)
.map(|validator_info| validator_info.on_top)
.unwrap_or_default();

let validator_info = ValidatorInfo {
valoper_address: validator.valoper_address,
weight: validator.weight,
on_top: validator.on_top,
on_top: validator.on_top.unwrap_or(on_top_value),
last_processed_remote_height: None,
last_processed_local_height: None,
last_validated_height: None,
Expand Down Expand Up @@ -330,12 +341,12 @@ fn execute_edit_on_top(
validator_info.on_top = validator_info.on_top.checked_add(amount)?;
validator_info
}
OnTopEditOperation::Subtract {
OnTopEditOperation::Set {
validator_address,
amount,
} => {
let mut validator_info = VALIDATORS_SET.load(deps.storage, &validator_address)?;
validator_info.on_top = validator_info.on_top.checked_sub(amount)?;
validator_info.on_top = amount;
validator_info
}
};
Expand Down
Loading

0 comments on commit c41df39

Please sign in to comment.