Skip to content

Commit

Permalink
Merge pull request #148 from osmosis-labs/118/validator-state
Browse files Browse the repository at this point in the history
Refactor: validator state to support multiple states
  • Loading branch information
maurolacy authored Oct 19, 2023
2 parents b44e746 + 4f4efc8 commit 565a1e1
Show file tree
Hide file tree
Showing 16 changed files with 2,018 additions and 351 deletions.
46 changes: 35 additions & 11 deletions contracts/consumer/converter/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ use mesh_apis::price_feed_api;
use mesh_apis::virtual_staking_api;

use crate::error::ContractError;
use crate::ibc::{
add_validators_msg, jail_validators_msg, make_ibc_packet, tombstone_validators_msg, IBC_CHANNEL,
};
use crate::ibc::{make_ibc_packet, valset_update_msg, IBC_CHANNEL};
use crate::msg::ConfigResponse;
use crate::state::Config;

Expand Down Expand Up @@ -353,20 +351,20 @@ impl ConverterApi for ConverterContract<'_> {
&self,
ctx: ExecCtx,
additions: Vec<Validator>,
tombstoned: Vec<String>,
removals: Vec<String>,
updated: Vec<Validator>,
jailed: Vec<String>,
unjailed: Vec<String>,
tombstoned: Vec<String>,
) -> Result<Response, Self::Error> {
self.ensure_authorized(&ctx.deps, &ctx.info)?;

// Send over IBC to the Consumer
let channel = IBC_CHANNEL.load(ctx.deps.storage)?;

let mut resp = Response::new();
let mut event = Event::new("valset_update");

if !additions.is_empty() {
let add_msg = add_validators_msg(&ctx.env, &channel, &additions)?;
resp = resp.add_message(add_msg);
event = event.add_attribute(
"additions",
additions
Expand All @@ -376,16 +374,42 @@ impl ConverterApi for ConverterContract<'_> {
.join(","),
);
}
if !removals.is_empty() {
event = event.add_attribute("removals", removals.join(","));
}
if !updated.is_empty() {
event = event.add_attribute(
"updated",
updated
.iter()
.map(|v| v.address.clone())
.collect::<Vec<String>>()
.join(","),
);
}
if !jailed.is_empty() {
let jail_msg = jail_validators_msg(&ctx.env, &channel, &jailed)?;
resp = resp.add_message(jail_msg);
event = event.add_attribute("jailed", jailed.join(","));
}
if !unjailed.is_empty() {
event = event.add_attribute("unjailed", unjailed.join(","));
}
if !tombstoned.is_empty() {
let tomb_msg = tombstone_validators_msg(&ctx.env, &channel, &tombstoned)?;
resp = resp.add_message(tomb_msg);
event = event.add_attribute("tombstoned", tombstoned.join(","));
}
let mut resp = Response::new();
if !event.attributes.is_empty() {
let valset_msg = valset_update_msg(
&ctx.env,
&channel,
&additions,
&removals,
&updated,
&jailed,
&unjailed,
&tombstoned,
)?;
resp = resp.add_message(valset_msg);
}
resp = resp.add_event(event);
Ok(resp)
}
Expand Down
83 changes: 28 additions & 55 deletions contracts/consumer/converter/src/ibc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use cw_storage_plus::Item;

use mesh_apis::ibc::{
ack_success, validate_channel_order, AckWrapper, AddValidator, ConsumerPacket, ProtocolVersion,
ProviderPacket, RemoveValidator, StakeAck, TransferRewardsAck, UnstakeAck, PROTOCOL_NAME,
ProviderPacket, StakeAck, TransferRewardsAck, UnstakeAck, PROTOCOL_NAME,
};
use sylvia::types::ExecCtx;

Expand Down Expand Up @@ -115,75 +115,48 @@ pub fn ibc_channel_connect(

// Send a validator sync packet to arrive with the newly established channel
let validators = deps.querier.query_all_validators()?;
let msg = add_validators_msg(&env, &channel, &validators)?;
let msg = valset_update_msg(&env, &channel, &validators, &[], &[], &[], &[], &[])?;

Ok(IbcBasicResponse::new().add_message(msg))
}

pub(crate) fn add_validators_msg(
#[allow(clippy::too_many_arguments)]
pub(crate) fn valset_update_msg(
env: &Env,
channel: &IbcChannel,
validators: &[Validator],
additions: &[Validator],
removals: &[String],
updated: &[Validator],
jailed: &[String],
unjailed: &[String],
tombstoned: &[String],
) -> Result<IbcMsg, ContractError> {
let updates = validators
let additions = additions
.iter()
.map(|v| AddValidator {
valoper: v.address.clone(),
// TODO: not yet available in CosmWasm APIs. See https://github.com/CosmWasm/cosmwasm/issues/1828
pub_key: "TODO".to_string(),
// Use current height/time as start height/time (no slashing before mesh starts).
// Warning: These will be updated as well when updating an already existing validator.
start_height: env.block.height,
start_time: env.block.time.seconds(),
})
.collect();
let packet = ConsumerPacket::AddValidators(updates);
let msg = IbcMsg::SendPacket {
channel_id: channel.endpoint.channel_id.clone(),
data: to_binary(&packet)?,
timeout: packet_timeout_validator(env),
};
Ok(msg)
}

pub(crate) fn jail_validators_msg(
env: &Env,
channel: &IbcChannel,
validators: &[String],
) -> Result<IbcMsg, ContractError> {
let packet = ConsumerPacket::JailValidators(
validators
.iter()
.map(|v| RemoveValidator {
valoper: v.to_string(),
height: env.block.height,
time: env.block.time.seconds(),
})
.collect(),
);
let msg = IbcMsg::SendPacket {
channel_id: channel.endpoint.channel_id.clone(),
data: to_binary(&packet)?,
timeout: packet_timeout_validator(env),
let updated = updated
.iter()
.map(|v| AddValidator {
valoper: v.address.clone(),
// TODO: not yet available in CosmWasm APIs. See https://github.com/CosmWasm/cosmwasm/issues/1828
pub_key: "TODO".to_string(),
})
.collect();
let packet = ConsumerPacket::ValsetUpdate {
height: env.block.height,
time: env.block.time.seconds(),
additions,
removals: removals.to_vec(),
updated,
jailed: jailed.to_vec(),
unjailed: unjailed.to_vec(),
tombstoned: tombstoned.to_vec(),
};
Ok(msg)
}

pub(crate) fn tombstone_validators_msg(
env: &Env,
channel: &IbcChannel,
validators: &[String],
) -> Result<IbcMsg, ContractError> {
let packet = ConsumerPacket::TombstoneValidators(
validators
.iter()
.map(|v| RemoveValidator {
valoper: v.to_string(),
height: env.block.height,
time: env.block.time.seconds(),
})
.collect(),
);
let msg = IbcMsg::SendPacket {
channel_id: channel.endpoint.channel_id.clone(),
data: to_binary(&packet)?,
Expand Down
13 changes: 10 additions & 3 deletions contracts/consumer/converter/src/multitest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,13 +243,20 @@ fn valset_update_works() {
// Check that only the virtual staking contract can call this handler
let res = converter
.converter_api_proxy()
.valset_update(vec![], vec![], vec![])
.valset_update(vec![], vec![], vec![], vec![], vec![], vec![])
.call(owner);
assert_eq!(res.unwrap_err(), Unauthorized {});

let res = converter
.converter_api_proxy()
.valset_update(add_validators, rem_validators, vec![])
.valset_update(
add_validators,
rem_validators,
vec![],
vec![],
vec![],
vec![],
)
.call(virtual_staking.contract_addr.as_ref());

// This fails because of lack of IBC support in mt now.
Expand Down Expand Up @@ -304,7 +311,7 @@ fn unauthorized() {

let err = converter
.converter_api_proxy()
.valset_update(vec![], vec![], vec![])
.valset_update(vec![], vec![], vec![], vec![], vec![], vec![])
.call("mallory")
.unwrap_err();

Expand Down
8 changes: 5 additions & 3 deletions contracts/consumer/virtual-staking/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,15 @@ impl VirtualStakingContract<'_> {
Ok::<_, ContractError>(old)
})?;

// Send additions and tombstones to the Converter. Removals are non-permanent and ignored.
// Send jailed even when they are non-permanent, for slashing.
// Send all updates to the Converter.
let cfg = self.config.load(deps.storage)?;
let msg = converter_api::ExecMsg::ValsetUpdate {
additions: additions.to_vec(),
tombstoned: tombstoned.to_vec(),
removals: removals.to_vec(),
updated: updated.to_vec(),
jailed: jailed.to_vec(),
unjailed: unjailed.to_vec(),
tombstoned: tombstoned.to_vec(),
};
let msg = WasmMsg::Execute {
contract_addr: cfg.converter.to_string(),
Expand Down
Loading

0 comments on commit 565a1e1

Please sign in to comment.