diff --git a/Cargo.lock b/Cargo.lock index bc7d2fab..69efd942 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -237,6 +237,7 @@ dependencies = [ name = "babylon-bindings" version = "0.4.0" dependencies = [ + "babylon-apis", "cosmwasm-schema", "cosmwasm-std", ] @@ -2109,17 +2110,26 @@ name = "op-finality-gadget" version = "0.11.0" dependencies = [ "anybuf", + "anyhow", "babylon-apis", + "babylon-bindings", + "babylon-bindings-test", + "babylon-bitcoin", "babylon-merkle", + "babylon-proto", + "btc-staking", "cosmwasm-schema", "cosmwasm-std", "cosmwasm-vm", "cw-controllers", + "cw-multi-test", "cw-storage-plus", "cw-utils", + "derivative", "eots", "hex", "k256", + "prost 0.11.9", "test-utils", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 69f65a24..3c66e6b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ integration = "./scripts/integration_test.sh" [workspace.dependencies] anybuf = { version = "0.5.0" } +babylon-apis = { path = "./packages/apis" } babylon-proto = { path = "./packages/proto" } babylon-bitcoin = { path = "./packages/bitcoin" } babylon-btcstaking = { path = "./packages/btcstaking" } diff --git a/contracts/op-finality-gadget/Cargo.toml b/contracts/op-finality-gadget/Cargo.toml index 0bf067e4..b59e334e 100644 --- a/contracts/op-finality-gadget/Cargo.toml +++ b/contracts/op-finality-gadget/Cargo.toml @@ -24,6 +24,9 @@ library = [] [dependencies] babylon-apis = { path = "../../packages/apis" } babylon-merkle = { path = "../../packages/merkle" } +babylon-bindings = { path = "../../packages/bindings" } +babylon-bitcoin = { path = "../../packages/bitcoin" } +babylon-proto = { path = "../../packages/proto" } cosmwasm-schema = { workspace = true } cosmwasm-std = { workspace = true } cw-controllers = { workspace = true } @@ -33,8 +36,15 @@ eots = { path = "../../packages/eots" } hex = { workspace = true } k256 = { workspace = true } thiserror = { workspace = true } +prost = { workspace = true } anybuf = { workspace = true } [dev-dependencies] +babylon-bindings-test = { path = "../../packages/bindings-test" } +btc-staking = { path = "../btc-staking", features = [ "library" ] } cosmwasm-vm = { workspace = true } test-utils = { path = "../../packages/test-utils" } +anyhow = { workspace = true } +derivative = { workspace = true } + +cw-multi-test = { workspace = true } \ No newline at end of file diff --git a/contracts/op-finality-gadget/src/contract.rs b/contracts/op-finality-gadget/src/contract.rs index 98eb0c88..714604d7 100644 --- a/contracts/op-finality-gadget/src/contract.rs +++ b/contracts/op-finality-gadget/src/contract.rs @@ -1,11 +1,14 @@ use crate::error::ContractError; use crate::exec::admin::set_enabled; -use crate::exec::finality::{handle_finality_signature, handle_public_randomness_commit}; +use crate::exec::finality::{ + handle_finality_signature, handle_public_randomness_commit, handle_slashing, +}; use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; use crate::queries::{ query_block_voters, query_config, query_first_pub_rand_commit, query_last_pub_rand_commit, }; use crate::state::config::{Config, ADMIN, CONFIG, IS_ENABLED}; +use babylon_bindings::BabylonMsg; use cosmwasm_std::{ to_json_binary, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response, StdResult, }; @@ -16,7 +19,7 @@ pub fn instantiate( _env: Env, _info: MessageInfo, msg: InstantiateMsg, -) -> StdResult { +) -> StdResult> { let api = deps.api; ADMIN.set(deps.branch(), Some(api.addr_validate(&msg.admin)?))?; IS_ENABLED.save(deps.storage, &msg.is_enabled)?; @@ -51,7 +54,7 @@ pub fn execute( env: Env, info: MessageInfo, msg: ExecuteMsg, -) -> Result { +) -> Result, ContractError> { let api = deps.api; match msg { @@ -86,6 +89,7 @@ pub fn execute( &block_hash, &signature, ), + ExecuteMsg::Slashing { evidence } => handle_slashing(&evidence), ExecuteMsg::SetEnabled { enabled } => set_enabled(deps, info, enabled), ExecuteMsg::UpdateAdmin { admin } => ADMIN .execute_update_admin(deps, info, Some(api.addr_validate(&admin)?)) @@ -145,7 +149,6 @@ pub(crate) mod tests { let mut deps = mock_dependencies(); let init_admin = deps.api.addr_make(INIT_ADMIN); let new_admin = deps.api.addr_make(NEW_ADMIN); - // Create an InstantiateMsg with admin set to Some(INIT_ADMIN.into()) let instantiate_msg = InstantiateMsg { admin: init_admin.to_string(), // Admin provided diff --git a/contracts/op-finality-gadget/src/error.rs b/contracts/op-finality-gadget/src/error.rs index 051f9978..84fbc0c4 100644 --- a/contracts/op-finality-gadget/src/error.rs +++ b/contracts/op-finality-gadget/src/error.rs @@ -18,6 +18,16 @@ pub enum ContractError { HexError(#[from] FromHexError), #[error("The inclusion proof for height {0} does not correspond to the given height ({1})")] InvalidFinalitySigHeight(u64, u64), + #[error("Contract already has an open IBC channel")] + IbcChannelAlreadyOpen {}, + #[error("The contract only supports ordered channels")] + IbcUnorderedChannel {}, + #[error("Counterparty version must be `{version}`")] + IbcInvalidCounterPartyVersion { version: String }, + #[error("IBC method is not supported")] + IbcUnsupportedMethod {}, + #[error("IBC send timed out: dest: channel {0}, port {1}")] + IbcTimeout(String, String), #[error("The total amount of public randomnesses in the proof ({0}) does not match the amount of public committed randomness ({1})")] InvalidFinalitySigAmount(u64, u64), #[error("The start height ({0}) has overlap with the height of the highest public randomness committed ({1})")] @@ -30,6 +40,8 @@ pub enum ContractError { MissingPubRandCommit(String, u64), #[error("{0}")] SecP256K1Error(String), // TODO: inherit errors from k256 + #[error("Failed to extract secret key: {0}")] + SecretKeyExtractionError(String), #[error("{0}")] StdError(#[from] StdError), #[error("Failed to query block voters for block {0} with hash {1}. {2}")] diff --git a/contracts/op-finality-gadget/src/exec/admin.rs b/contracts/op-finality-gadget/src/exec/admin.rs index 0b0873a8..bf132cf4 100644 --- a/contracts/op-finality-gadget/src/exec/admin.rs +++ b/contracts/op-finality-gadget/src/exec/admin.rs @@ -1,3 +1,4 @@ +use babylon_bindings::BabylonMsg; use cosmwasm_std::{DepsMut, MessageInfo, Response}; use crate::{ @@ -14,7 +15,7 @@ pub fn set_enabled( deps: DepsMut, info: MessageInfo, enabled: bool, -) -> Result { +) -> Result, ContractError> { // Check caller is admin check_admin(&deps, info)?; // Check if the finality gadget is already in the desired state diff --git a/contracts/op-finality-gadget/src/exec/finality.rs b/contracts/op-finality-gadget/src/exec/finality.rs index a7f03e40..3a255014 100644 --- a/contracts/op-finality-gadget/src/exec/finality.rs +++ b/contracts/op-finality-gadget/src/exec/finality.rs @@ -1,17 +1,19 @@ use std::collections::HashSet; use crate::error::ContractError; +use crate::msg::ExecuteMsg; use crate::queries::query_last_pub_rand_commit; use crate::state::config::CONFIG; -use crate::state::finality::{BLOCK_VOTES, SIGNATURES}; +use crate::state::finality::{BLOCK_HASHES, BLOCK_VOTES, EVIDENCES, SIGNATURES}; use crate::state::public_randomness::{ get_pub_rand_commit_for_height, PUB_RAND_COMMITS, PUB_RAND_VALUES, }; use crate::utils::query_finality_provider; +use babylon_bindings::BabylonMsg; -use babylon_apis::finality_api::PubRandCommit; +use babylon_apis::finality_api::{Evidence, PubRandCommit}; use babylon_merkle::Proof; -use cosmwasm_std::{Deps, DepsMut, Env, Event, Response}; +use cosmwasm_std::{to_json_binary, Deps, DepsMut, Env, Event, Response, WasmMsg}; use k256::ecdsa::signature::Verifier; use k256::schnorr::{Signature, VerifyingKey}; use k256::sha2::{Digest, Sha256}; @@ -24,7 +26,7 @@ pub fn handle_public_randomness_commit( num_pub_rand: u64, commitment: &[u8], signature: &[u8], -) -> Result { +) -> Result, ContractError> { // Ensure the finality provider is registered check_fp_exist(deps.as_ref(), fp_pubkey_hex)?; @@ -111,14 +113,14 @@ pub(crate) fn verify_commitment_signature( #[allow(clippy::too_many_arguments)] pub fn handle_finality_signature( deps: DepsMut, - _env: Env, + env: Env, fp_btc_pk_hex: &str, height: u64, pub_rand: &[u8], proof: &Proof, block_hash: &[u8], signature: &[u8], -) -> Result { +) -> Result, ContractError> { // Ensure the finality provider exists check_fp_exist(deps.as_ref(), fp_btc_pk_hex)?; @@ -178,47 +180,45 @@ pub fn handle_finality_signature( // TODO?: Don't save public randomness values, to save storage space PUB_RAND_VALUES.save(deps.storage, (fp_btc_pk_hex, height), &pub_rand.to_vec())?; - // TODO: Verify whether the voted block is a fork or not - /* - indexedBlock, err := ms.GetBlock(ctx, req.BlockHeight) - if err != nil { - return nil, err - } - if !bytes.Equal(indexedBlock.AppHash, req.BlockAppHash) { - // the finality provider votes for a fork! + // Build the response + let mut res: Response = Response::new(); - // construct evidence - evidence := &types.Evidence{ - FpBtcPk: req.FpBtcPk, - BlockHeight: req.BlockHeight, - PubRand: req.PubRand, - CanonicalAppHash: indexedBlock.AppHash, - CanonicalFinalitySig: nil, - ForkAppHash: req.BlockAppHash, - ForkFinalitySig: signature, - } + // If this finality provider has signed the canonical block before, slash it via + // extracting its secret key, and emit an event + let canonical_sig: Option> = + SIGNATURES.may_load(deps.storage, (height, fp_btc_pk_hex))?; + let canonical_block_hash: Option> = + BLOCK_HASHES.may_load(deps.storage, (height, fp_btc_pk_hex))?; + if let (Some(canonical_sig), Some(canonical_block_hash)) = (canonical_sig, canonical_block_hash) + { + // the finality provider has voted for a fork before! + // If this evidence is at the same height as this signature, slash this finality provider - // if this finality provider has also signed canonical block, slash it - canonicalSig, err := ms.GetSig(ctx, req.BlockHeight, fpPK) - if err == nil { - //set canonical sig - evidence.CanonicalFinalitySig = canonicalSig - // slash this finality provider, including setting its voting power to - // zero, extracting its BTC SK, and emit an event - ms.slashFinalityProvider(ctx, req.FpBtcPk, evidence) - } + // construct evidence + let evidence = Evidence { + fp_btc_pk: hex::decode(fp_btc_pk_hex)?, + block_height: height, + pub_rand: pub_rand.to_vec(), + // TODO: we use block hash in place of app hash for now, to define new interface if needed + canonical_app_hash: canonical_block_hash, + canonical_finality_sig: canonical_sig, + fork_app_hash: block_hash.to_vec(), + fork_finality_sig: signature.to_vec(), + }; - // save evidence - ms.SetEvidence(ctx, evidence) + // set canonical sig to this evidence + EVIDENCES.save(deps.storage, (height, fp_btc_pk_hex), &evidence)?; - // NOTE: we should NOT return error here, otherwise the state change triggered in this tx - // (including the evidence) will be rolled back - return &types.MsgAddFinalitySigResponse{}, nil + // slash this finality provider, including setting its voting power to + // zero, extracting its BTC SK, and emit an event + let (msg, ev) = slash_finality_provider(&env, fp_btc_pk_hex, &evidence)?; + res = res.add_message(msg); + res = res.add_event(ev); } - */ // This signature is good, save the vote to the store SIGNATURES.save(deps.storage, (height, fp_btc_pk_hex), &signature.to_vec())?; + BLOCK_HASHES.save(deps.storage, (height, fp_btc_pk_hex), &block_hash.to_vec())?; // Check if the key (height, block_hash) exists let mut block_votes_fp_set = BLOCK_VOTES @@ -231,35 +231,14 @@ pub fn handle_finality_signature( // Save the updated set back to storage BLOCK_VOTES.save(deps.storage, (height, block_hash), &block_votes_fp_set)?; - // TODO: If this finality provider has signed the canonical block before, slash it via - // extracting its secret key, and emit an event - /* - if ms.HasEvidence(ctx, req.FpBtcPk, req.BlockHeight) { - // the finality provider has voted for a fork before! - // If this evidence is at the same height as this signature, slash this finality provider - - // get evidence - evidence, err := ms.GetEvidence(ctx, req.FpBtcPk, req.BlockHeight) - if err != nil { - panic(fmt.Errorf("failed to get evidence despite HasEvidence returns true")) - } - - // set canonical sig to this evidence - evidence.CanonicalFinalitySig = signature - ms.SetEvidence(ctx, evidence) - - // slash this finality provider, including setting its voting power to - // zero, extracting its BTC SK, and emit an event - ms.slashFinalityProvider(ctx, req.FpBtcPk, evidence) - } - */ - let event = Event::new("submit_finality_signature") .add_attribute("fp_pubkey_hex", fp_btc_pk_hex) .add_attribute("block_height", height.to_string()) .add_attribute("block_hash", hex::encode(block_hash)); - Ok(Response::new().add_event(event)) + res = res.add_event(event); + + Ok(res) } /// Verifies the finality signature message w.r.t. the public randomness commitment: @@ -328,13 +307,84 @@ fn check_fp_exist(deps: Deps, fp_pubkey_hex: &str) -> Result<(), ContractError> } } +/// `slash_finality_provider` slashes a finality provider with the given evidence including setting +/// its voting power to zero, extracting its BTC SK, and emitting an event +fn slash_finality_provider( + env: &Env, + fp_btc_pk_hex: &str, + evidence: &Evidence, +) -> Result<(WasmMsg, Event), ContractError> { + let pk = eots::PublicKey::from_hex(fp_btc_pk_hex)?; + let btc_sk = pk + .extract_secret_key( + &evidence.pub_rand, + &evidence.canonical_app_hash, + &evidence.canonical_finality_sig, + &evidence.fork_app_hash, + &evidence.fork_finality_sig, + ) + .map_err(|err| ContractError::SecretKeyExtractionError(err.to_string()))?; + + // Emit slashing event. + // Raises slashing event to babylon over IBC. + let msg = ExecuteMsg::Slashing { + evidence: evidence.clone(), + }; + let wasm_msg: WasmMsg = WasmMsg::Execute { + contract_addr: env.contract.address.to_string(), + msg: to_json_binary(&msg)?, + funds: vec![], + }; + + let ev = Event::new("slashed_finality_provider") + .add_attribute("module", "finality") + .add_attribute("finality_provider", fp_btc_pk_hex) + .add_attribute("block_height", evidence.block_height.to_string()) + .add_attribute( + "canonical_app_hash", + hex::encode(&evidence.canonical_app_hash), + ) + .add_attribute( + "canonical_finality_sig", + hex::encode(&evidence.canonical_finality_sig), + ) + .add_attribute("fork_app_hash", hex::encode(&evidence.fork_app_hash)) + .add_attribute( + "fork_finality_sig", + hex::encode(&evidence.fork_finality_sig), + ) + .add_attribute("secret_key", hex::encode(btc_sk.to_bytes())); + Ok((wasm_msg, ev)) +} + +pub(crate) fn handle_slashing(evidence: &Evidence) -> Result, ContractError> { + let mut res = Response::new(); + // Send msg to Babylon + + let msg = BabylonMsg::EquivocationEvidence { + evidence: Some(evidence.clone()), + }; + + // Convert to CosmosMsg + res = res + .add_message(msg) + .add_attribute("action", "equivocation_evidence"); + + Ok(res) +} + #[cfg(test)] pub(crate) mod tests { use super::*; + use cosmwasm_std::from_json; + use cosmwasm_std::testing::mock_env; + use std::collections::HashMap; use babylon_apis::finality_api::PubRandCommit; use hex::ToHex; - use test_utils::{get_add_finality_sig, get_pub_rand_commit, get_pub_rand_value}; + use test_utils::{ + get_add_finality_sig, get_add_finality_sig_2, get_pub_rand_commit, get_pub_rand_value, + }; /// Get public randomness public key, commitment, and signature information /// @@ -395,4 +445,86 @@ pub(crate) mod tests { ); assert!(res.is_ok()); } + + #[test] + fn verify_slashing_works() { + // Read test data + let (pk_hex, pub_rand, _) = get_public_randomness_commitment(); + let pub_rand_one = get_pub_rand_value(); + let add_finality_signature = get_add_finality_sig(); + let add_finality_signature_2 = get_add_finality_sig_2(); + let proof = add_finality_signature.proof.unwrap(); + + let initial_height = pub_rand.start_height; + let block_height = initial_height + proof.index.unsigned_abs(); + + // Create evidence struct + let evidence = Evidence { + fp_btc_pk: hex::decode(&pk_hex).unwrap(), + block_height, + pub_rand: pub_rand_one.to_vec(), + canonical_app_hash: add_finality_signature.block_app_hash.to_vec(), + canonical_finality_sig: add_finality_signature.finality_sig.to_vec(), + fork_app_hash: add_finality_signature_2.block_app_hash.to_vec(), + fork_finality_sig: add_finality_signature_2.finality_sig.to_vec(), + }; + + // Create mock environment + let env = mock_env(); // You'll need to add this mock helper + + // Test slash_finality_provider + let (wasm_msg, event) = slash_finality_provider(&env, &pk_hex, &evidence).unwrap(); + + // Verify the WasmMsg is correctly constructed + match wasm_msg { + WasmMsg::Execute { + contract_addr, + msg, + funds, + } => { + assert_eq!(contract_addr, env.contract.address.to_string()); + assert!(funds.is_empty()); + let msg_evidence = from_json::(&msg).unwrap(); + match msg_evidence { + ExecuteMsg::Slashing { + evidence: msg_evidence, + } => { + assert_eq!(evidence, msg_evidence); + } + _ => panic!("Expected Slashing msg"), + } + } + _ => panic!("Expected Execute msg"), + } + + // Verify the event attributes + assert_eq!(event.ty, "slashed_finality_provider"); + let attrs: HashMap<_, _> = event + .attributes + .iter() + .map(|a| (&a.key, &a.value)) + .collect(); + assert_eq!( + attrs.get(&"module".to_string()).unwrap().as_str(), + "finality" + ); + assert_eq!( + attrs + .get(&"finality_provider".to_string()) + .unwrap() + .as_str(), + &pk_hex + ); + assert_eq!( + attrs.get(&"block_height".to_string()).unwrap().as_str(), + &block_height.to_string() + ); + assert_eq!( + attrs + .get(&"canonical_app_hash".to_string()) + .unwrap() + .as_str(), + &hex::encode(&evidence.canonical_app_hash) + ); + } } diff --git a/contracts/op-finality-gadget/src/lib.rs b/contracts/op-finality-gadget/src/lib.rs index 9774c46f..cff1d9e9 100644 --- a/contracts/op-finality-gadget/src/lib.rs +++ b/contracts/op-finality-gadget/src/lib.rs @@ -1,3 +1,4 @@ +use babylon_bindings::BabylonMsg; use cosmwasm_std::{ entry_point, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response, StdResult, }; @@ -18,7 +19,7 @@ pub fn instantiate( env: Env, info: MessageInfo, msg: InstantiateMsg, -) -> StdResult { +) -> StdResult> { contract::instantiate(deps, env, info, msg) } @@ -33,6 +34,6 @@ pub fn execute( env: Env, info: MessageInfo, msg: ExecuteMsg, -) -> Result { +) -> Result, ContractError> { contract::execute(deps, env, info, msg) } diff --git a/contracts/op-finality-gadget/src/msg.rs b/contracts/op-finality-gadget/src/msg.rs index fa6c6300..42436878 100644 --- a/contracts/op-finality-gadget/src/msg.rs +++ b/contracts/op-finality-gadget/src/msg.rs @@ -4,6 +4,7 @@ use { cw_controllers::AdminResponse, std::collections::HashSet, }; +use babylon_apis::finality_api::Evidence; use cosmwasm_schema::{cw_serde, QueryResponses}; use cosmwasm_std::Binary; @@ -75,6 +76,12 @@ pub enum ExecuteMsg { block_hash: Binary, signature: Binary, }, + /// Slashing message. + /// + /// This message can be called by the admin only. + Slashing { + evidence: Evidence, + }, /// Enable or disable finality gadget. /// /// This message can be called by the admin only. @@ -91,3 +98,8 @@ pub enum ExecuteMsg { admin: String, }, } + +#[cw_serde] +pub struct FinalitySignatureResponse { + pub signature: Vec, +} diff --git a/contracts/op-finality-gadget/src/state/finality.rs b/contracts/op-finality-gadget/src/state/finality.rs index f3ebc5e7..645b0984 100644 --- a/contracts/op-finality-gadget/src/state/finality.rs +++ b/contracts/op-finality-gadget/src/state/finality.rs @@ -1,8 +1,15 @@ +use babylon_apis::finality_api::Evidence; use cw_storage_plus::Map; use std::collections::HashSet; /// Map of signatures by block height and fp pub(crate) const SIGNATURES: Map<(u64, &str), Vec> = Map::new("fp_sigs"); +/// Map of block hashes by block height and fp +pub(crate) const BLOCK_HASHES: Map<(u64, &str), Vec> = Map::new("block_hashes"); + /// Map of (block height, block hash) tuples to the list of fps that voted for this combination -pub(crate) const BLOCK_VOTES: Map<(u64, &[u8]), HashSet> = Map::new("block_hashes"); +pub(crate) const BLOCK_VOTES: Map<(u64, &[u8]), HashSet> = Map::new("block_votes"); + +/// Map of evidence by block height and fp +pub(crate) const EVIDENCES: Map<(u64, &str), Evidence> = Map::new("evidences"); diff --git a/packages/bindings-test/src/multitest.rs b/packages/bindings-test/src/multitest.rs index 64653de2..648bf82b 100644 --- a/packages/bindings-test/src/multitest.rs +++ b/packages/bindings-test/src/multitest.rs @@ -92,6 +92,10 @@ impl Module for BabylonModule { // FIXME? We don't do anything here Ok(AppResponse::default()) } + BabylonMsg::EquivocationEvidence { .. } => { + // FIXME? We don't do anything here + Ok(AppResponse::default()) + } } } diff --git a/packages/bindings/Cargo.toml b/packages/bindings/Cargo.toml index 79cbb957..8773ef05 100644 --- a/packages/bindings/Cargo.toml +++ b/packages/bindings/Cargo.toml @@ -11,3 +11,4 @@ license = "Apache-2.0" [dependencies] cosmwasm-std = { workspace = true } cosmwasm-schema = { workspace = true } +babylon-apis = { workspace = true } \ No newline at end of file diff --git a/packages/bindings/src/msg.rs b/packages/bindings/src/msg.rs index c05c963b..9cb09eb7 100644 --- a/packages/bindings/src/msg.rs +++ b/packages/bindings/src/msg.rs @@ -3,9 +3,9 @@ //! - ForkHeader: reporting a fork that has a valid quorum certificate //! - FinalizedHeader: reporting a BTC-finalised header. +use babylon_apis::finality_api::Evidence; use cosmwasm_schema::cw_serde; use cosmwasm_std::{Coin, CosmosMsg, Empty}; - /// BabylonMsg is the message that the Babylon contract can send to the Cosmos zone. /// The Cosmos zone has to integrate https://github.com/babylonlabs-io/wasmbinding for /// handling these messages @@ -21,7 +21,13 @@ pub enum BabylonMsg { /// It can only be sent from the finality contract. /// The rewards are minted to the staking contract address, so that they /// can be distributed across the active finality provider set - MintRewards { amount: Coin, recipient: String }, + MintRewards { + amount: Coin, + recipient: String, + }, + EquivocationEvidence { + evidence: Option, + }, } pub type BabylonSudoMsg = Empty; diff --git a/packages/proto/babylon b/packages/proto/babylon index de84d881..6682eeca 160000 --- a/packages/proto/babylon +++ b/packages/proto/babylon @@ -1 +1 @@ -Subproject commit de84d8817da424189fa5110ac00c2e3dc1333949 +Subproject commit 6682eecad96e65c65edb7c257325ec52a65b81fa diff --git a/packages/proto/buf.gen.rust.yaml b/packages/proto/buf.gen.rust.yaml index 78d9715f..506a9004 100644 --- a/packages/proto/buf.gen.rust.yaml +++ b/packages/proto/buf.gen.rust.yaml @@ -23,6 +23,7 @@ types: - babylon.finality.v1.PubRandCommit - babylon.finality.v1.MsgAddFinalitySig - babylon.finality.v1.MsgCommitPubRandList + - babylon.finality.v1.MsgEquivocationEvidence plugins: - plugin: buf.build/community/neoeinstein-prost:v0.2.3 out: src/gen diff --git a/packages/proto/src/gen/babylon.finality.v1.rs b/packages/proto/src/gen/babylon.finality.v1.rs index 78451791..bdfd2418 100644 --- a/packages/proto/src/gen/babylon.finality.v1.rs +++ b/packages/proto/src/gen/babylon.finality.v1.rs @@ -105,4 +105,12 @@ pub struct MsgAddFinalitySig { #[prost(bytes="bytes", tag="7")] pub finality_sig: ::prost::bytes::Bytes, } +/// MsgEquivocationEvidence is the message for handling evidence of equivocation +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgEquivocationEvidence { + /// evidence is the evidence of equivocation + #[prost(message, optional, tag="1")] + pub evidence: ::core::option::Option, +} // @@protoc_insertion_point(module)