From cf1e86c3b5a18f7f6fdbdec85a3b2a2c453d2c5f Mon Sep 17 00:00:00 2001 From: Justin Kilpatrick Date: Tue, 13 Apr 2021 08:34:58 -0400 Subject: [PATCH 1/7] Add an event nonce to valset updated events This patch does somthing that we've tried to avoid for a while. Which is adding an event nonce to the validator set updated events. So as to make it possible to relay them into the Cosmos module oracle. This design change is driven by problems with validator set pruning. In the worst case validator sets can be produced every single block. But the worst case on the EVM chain is similarly bad. It could be halted for several hours or even days. In order to retain enough validator sets to ensure bridge continuity and also prune as many validator sets as safely possible we need this information. --- solidity/contracts/Gravity.sol | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/solidity/contracts/Gravity.sol b/solidity/contracts/Gravity.sol index dcc7ce54b..64509c8fe 100644 --- a/solidity/contracts/Gravity.sol +++ b/solidity/contracts/Gravity.sol @@ -70,6 +70,7 @@ contract Gravity is ReentrancyGuard { ); event ValsetUpdatedEvent( uint256 indexed _newValsetNonce, + uint256 _eventNonce, address[] _validators, uint256[] _powers ); @@ -116,6 +117,7 @@ contract Gravity is ReentrancyGuard { function lastBatchNonce(address _erc20Address) public view returns (uint256) { return state_lastBatchNonces[_erc20Address]; } + function lastLogicCallNonce(bytes32 _invalidation_id) public view returns (uint256) { return state_invalidationMapping[_invalidation_id]; } @@ -273,7 +275,8 @@ contract Gravity is ReentrancyGuard { // LOGS - emit ValsetUpdatedEvent(_newValsetNonce, _newValidators, _newPowers); + state_lastEventNonce = state_lastEventNonce.add(1); + emit ValsetUpdatedEvent(_newValsetNonce, state_lastEventNonce, _newValidators, _newPowers); } // submitBatch processes a batch of Cosmos -> Ethereum transactions by sending the tokens in the transactions @@ -298,7 +301,7 @@ contract Gravity is ReentrancyGuard { // a block height beyond which this batch is not valid // used to provide a fee-free timeout uint256 _batchTimeout - ) nonReentrant public { + ) public nonReentrant { // CHECKS scoped to reduce stack depth { // Check that the batch nonce is higher than the last nonce for this token @@ -407,7 +410,7 @@ contract Gravity is ReentrancyGuard { bytes32[] memory _r, bytes32[] memory _s, LogicCallArgs memory _args - ) public nonReentrant{ + ) public nonReentrant { // CHECKS scoped to reduce stack depth { // Check that the call has not timed out @@ -592,6 +595,6 @@ contract Gravity is ReentrancyGuard { // LOGS - emit ValsetUpdatedEvent(0, _validators, _powers); + emit ValsetUpdatedEvent(state_lastValsetNonce, state_lastEventNonce, _validators, _powers); } } From 021e5aa7455f8c85fa622a62629883fbdc966e16 Mon Sep 17 00:00:00 2001 From: Justin Kilpatrick Date: Tue, 13 Apr 2021 09:29:22 -0400 Subject: [PATCH 2/7] Use constants for Ethereum event signatures This patch moves the Ethereum event signatures into constants in the gravity_utils module rather than repeated string values peppered across the code. Should make it easier to deal with changes there in the future. --- .../gravity_utils/src/types/event_signatures.rs | 13 +++++++++++++ orchestrator/gravity_utils/src/types/mod.rs | 1 + .../orchestrator/src/ethereum_event_watcher.rs | 11 ++++++----- orchestrator/orchestrator/src/oracle_resync.rs | 15 ++++++++------- orchestrator/relayer/src/find_latest_valset.rs | 5 +++-- 5 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 orchestrator/gravity_utils/src/types/event_signatures.rs diff --git a/orchestrator/gravity_utils/src/types/event_signatures.rs b/orchestrator/gravity_utils/src/types/event_signatures.rs new file mode 100644 index 000000000..b188086c5 --- /dev/null +++ b/orchestrator/gravity_utils/src/types/event_signatures.rs @@ -0,0 +1,13 @@ +pub const TRANSACTION_BATCH_EXECUTED_EVENT_SIG: &str = + "TransactionBatchExecutedEvent(uint256,address,uint256)"; + +pub const SENT_TO_COSMOS_EVENT_SIG: &str = + "SendToCosmosEvent(address,address,bytes32,uint256,uint256)"; + +pub const ERC20_DEPLOYED_EVENT_SIG: &str = + "ERC20DeployedEvent(string,address,string,string,uint8,uint256)"; + +pub const LOGIC_CALL_EVENT_SIG: &str = "LogicCallEvent(bytes32,uint256,bytes,uint256)"; + +pub const VALSET_UPDATED_EVENT_SIG: &str = + "ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"; diff --git a/orchestrator/gravity_utils/src/types/mod.rs b/orchestrator/gravity_utils/src/types/mod.rs index 83021d3b9..ca62b9174 100644 --- a/orchestrator/gravity_utils/src/types/mod.rs +++ b/orchestrator/gravity_utils/src/types/mod.rs @@ -2,6 +2,7 @@ use clarity::Address as EthAddress; use num256::Uint256; mod batches; mod ethereum_events; +pub mod event_signatures; mod logic_call; mod signatures; mod valsets; diff --git a/orchestrator/orchestrator/src/ethereum_event_watcher.rs b/orchestrator/orchestrator/src/ethereum_event_watcher.rs index 709ce58e8..47301ec02 100644 --- a/orchestrator/orchestrator/src/ethereum_event_watcher.rs +++ b/orchestrator/orchestrator/src/ethereum_event_watcher.rs @@ -6,6 +6,7 @@ use cosmos_gravity::{query::get_last_event_nonce, send::send_ethereum_claims}; use deep_space::Contact; use deep_space::{coin::Coin, private_key::PrivateKey as CosmosPrivateKey}; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; +use gravity_utils::types::event_signatures::*; use gravity_utils::{ error::GravityError, types::{ @@ -38,7 +39,7 @@ pub async fn check_for_events( starting_block.clone(), Some(latest_block.clone()), vec![gravity_contract_address], - vec!["SendToCosmosEvent(address,address,bytes32,uint256,uint256)"], + vec![SENT_TO_COSMOS_EVENT_SIG], ) .await; trace!("Deposits {:?}", deposits); @@ -48,7 +49,7 @@ pub async fn check_for_events( starting_block.clone(), Some(latest_block.clone()), vec![gravity_contract_address], - vec!["TransactionBatchExecutedEvent(uint256,address,uint256)"], + vec![TRANSACTION_BATCH_EXECUTED_EVENT_SIG], ) .await; trace!("Batches {:?}", batches); @@ -58,7 +59,7 @@ pub async fn check_for_events( starting_block.clone(), Some(latest_block.clone()), vec![gravity_contract_address], - vec!["ValsetUpdatedEvent(uint256,address[],uint256[])"], + vec![VALSET_UPDATED_EVENT_SIG], ) .await; trace!("Valsets {:?}", valsets); @@ -68,7 +69,7 @@ pub async fn check_for_events( starting_block.clone(), Some(latest_block.clone()), vec![gravity_contract_address], - vec!["ERC20DeployedEvent(string,address,string,string,uint8,uint256)"], + vec![ERC20_DEPLOYED_EVENT_SIG], ) .await; trace!("ERC20 Deployments {:?}", erc20_deployed); @@ -78,7 +79,7 @@ pub async fn check_for_events( starting_block.clone(), Some(latest_block.clone()), vec![gravity_contract_address], - vec!["LogicCallEvent(bytes32,uint256,bytes,uint256)"], + vec![LOGIC_CALL_EVENT_SIG], ) .await; trace!("Logic call executions {:?}", logic_call_executed); diff --git a/orchestrator/orchestrator/src/oracle_resync.rs b/orchestrator/orchestrator/src/oracle_resync.rs index eda23354f..a4ed0089f 100644 --- a/orchestrator/orchestrator/src/oracle_resync.rs +++ b/orchestrator/orchestrator/src/oracle_resync.rs @@ -12,6 +12,7 @@ use web30::client::Web3; use crate::get_with_retry::get_block_number_with_retry; use crate::get_with_retry::get_last_event_nonce_with_retry; use crate::get_with_retry::RETRY_TIME; +use gravity_utils::types::event_signatures::*; /// This function retrieves the last event nonce this oracle has relayed to Cosmos /// it then uses the Ethereum indexes to determine what block the last entry @@ -54,7 +55,7 @@ pub async fn get_last_checked_block( end_search.clone(), Some(current_block.clone()), vec![gravity_contract_address], - vec!["TransactionBatchExecutedEvent(uint256,address,uint256)"], + vec![TRANSACTION_BATCH_EXECUTED_EVENT_SIG], ) .await; let send_to_cosmos_events = web3 @@ -62,7 +63,7 @@ pub async fn get_last_checked_block( end_search.clone(), Some(current_block.clone()), vec![gravity_contract_address], - vec!["SendToCosmosEvent(address,address,bytes32,uint256,uint256)"], + vec![SENT_TO_COSMOS_EVENT_SIG], ) .await; let erc20_deployed_events = web3 @@ -70,7 +71,7 @@ pub async fn get_last_checked_block( end_search.clone(), Some(current_block.clone()), vec![gravity_contract_address], - vec!["ERC20DeployedEvent(string,address,string,string,uint8,uint256)"], + vec![ERC20_DEPLOYED_EVENT_SIG], ) .await; let logic_call_executed_events = web3 @@ -78,7 +79,7 @@ pub async fn get_last_checked_block( end_search.clone(), Some(current_block.clone()), vec![gravity_contract_address], - vec!["LogicCallEvent(bytes32,uint256,bytes,uint256)"], + vec![LOGIC_CALL_EVENT_SIG], ) .await; @@ -93,7 +94,7 @@ pub async fn get_last_checked_block( end_search.clone(), Some(current_block.clone()), vec![gravity_contract_address], - vec!["ValsetUpdatedEvent(uint256,address[],uint256[])"], + vec![VALSET_UPDATED_EVENT_SIG], ) .await; if batch_events.is_err() @@ -162,12 +163,12 @@ pub async fn get_last_checked_block( // if we've found this event it is the first possible event from the contract // no other events can come before it, therefore either there's been a parsing error // or no events have been submitted on this chain yet. - if valset.nonce == 0 && last_event_nonce == 1u8.into() { + if valset.valset_nonce == 0 && last_event_nonce == 1u8.into() { return latest_block; } // if we're looking for a later event nonce and we find the deployment of the contract // we must have failed to parse the event we're looking for. The oracle can not start - if valset.nonce == 0 && last_event_nonce > 1u8.into() { + if valset.valset_nonce == 0 && last_event_nonce > 1u8.into() { panic!("Could not find the last event relayed by {}, Last Event nonce is {} but no event matching that could be found!", our_cosmos_address, last_event_nonce) } } diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index b834ac82b..b83373a4c 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -2,6 +2,7 @@ use clarity::Address as EthAddress; use clarity::{Address, Uint256}; use ethereum_gravity::utils::get_valset_nonce; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; +use gravity_utils::types::event_signatures::*; use gravity_utils::types::ValsetUpdatedEvent; use gravity_utils::{error::GravityError, types::Valset}; use tonic::transport::Channel; @@ -41,7 +42,7 @@ pub async fn find_latest_valset( end_search.clone(), Some(current_block.clone()), vec![gravity_contract_address], - vec!["ValsetUpdatedEvent(uint256,address[],uint256[])"], + vec![VALSET_UPDATED_EVENT_SIG], ) .await?; // by default the lowest found valset goes first, we want the highest. @@ -55,7 +56,7 @@ pub async fn find_latest_valset( match ValsetUpdatedEvent::from_log(event) { Ok(event) => { let valset = Valset { - nonce: event.nonce, + nonce: event.valset_nonce, members: event.members, }; check_if_valsets_differ(cosmos_chain_valset, &valset); From e77ff22d05c414b2d055babdaf88bea67edd3225 Mon Sep 17 00:00:00 2001 From: Justin Kilpatrick Date: Tue, 13 Apr 2021 10:15:25 -0400 Subject: [PATCH 3/7] Update Orchestrator event parsing for valset event This patch updates the event parsing in the orchestrator for the new valset update with event nonce. --- .../src/types/ethereum_events.rs | 56 +++++++++++++++---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index ab5e0511e..671766c84 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -1,17 +1,24 @@ -use std::unimplemented; +//! This file parses the Gravity contract ethereum events. Note that there is no Ethereum ABI unpacking implementation. Instead each event +//! is parsed directly from it's binary representation. This is technical debt within this implementation. It's quite easy to parse any +//! individual event manually but a generic decoder can be quite challenging to implement. A proper implementation would probably closely +//! mirror Serde and perhaps even become a serde crate for Ethereum ABI decoding +//! For now reference the ABI encoding document here https://docs.soliditylang.org/en/v0.8.3/abi-spec.html use super::ValsetMember; use crate::error::GravityError; use clarity::Address as EthAddress; +use deep_space::utils::bytes_to_hex_str; use deep_space::Address as CosmosAddress; use num256::Uint256; +use std::unimplemented; use web30::types::Log; /// A parsed struct representing the Ethereum event fired by the Gravity contract /// when the validator set is updated. #[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Hash)] pub struct ValsetUpdatedEvent { - pub nonce: u64, + pub valset_nonce: u64, + pub event_nonce: u64, pub members: Vec, } @@ -19,24 +26,37 @@ impl ValsetUpdatedEvent { /// This function is not an abi compatible bytes parser, but it's actually /// not hard at all to extract data like this by hand. pub fn from_log(input: &Log) -> Result { - // we have one indexed event so we should fine two indexes, one the event itself + // we have one indexed event so we should fined two indexes, one the event itself // and one the indexed nonce if input.topics.get(1).is_none() { return Err(GravityError::InvalidEventLogError( "Too few topics".to_string(), )); } - let nonce_data = &input.topics[1]; - let nonce = Uint256::from_bytes_be(nonce_data); - if nonce > u64::MAX.into() { + let valset_nonce_data = &input.topics[1]; + let valset_nonce = Uint256::from_bytes_be(valset_nonce_data); + if valset_nonce > u64::MAX.into() { return Err(GravityError::InvalidEventLogError( "Nonce overflow, probably incorrect parsing".to_string(), )); } - let nonce: u64 = nonce.to_string().parse().unwrap(); - // first two indexes contain event info we don't care about, third index is - // the length of the eth addresses array - let index_start = 2 * 32; + let valset_nonce: u64 = valset_nonce.to_string().parse().unwrap(); + + // first index is the event nonce, following two have event data we don't + // care about, fourth index contains the length of the eth address array + let index_start = 0; + let index_end = index_start + 32; + let nonce_data = &input.data[index_start..index_end]; + let event_nonce = Uint256::from_bytes_be(nonce_data); + if event_nonce > u64::MAX.into() { + return Err(GravityError::InvalidEventLogError( + "Nonce overflow, probably incorrect parsing".to_string(), + )); + } + let event_nonce: u64 = event_nonce.to_string().parse().unwrap(); + // first index is the event nonce, following two have event data we don't + // care about, fourth index contains the length of the eth address array + let index_start = 3 * 32; let index_end = index_start + 32; let eth_addresses_offset = index_start + 32; let len_eth_addresses = Uint256::from_bytes_be(&input.data[index_start..index_end]); @@ -46,7 +66,7 @@ impl ValsetUpdatedEvent { )); } let len_eth_addresses: usize = len_eth_addresses.to_string().parse().unwrap(); - let index_start = (3 + len_eth_addresses) * 32; + let index_start = (4 + len_eth_addresses) * 32; let index_end = index_start + 32; let powers_offset = index_start + 32; let len_powers = Uint256::from_bytes_be(&input.data[index_start..index_end]); @@ -97,7 +117,8 @@ impl ValsetUpdatedEvent { } Ok(ValsetUpdatedEvent { - nonce, + valset_nonce, + event_nonce, members: validators, }) } @@ -462,3 +483,14 @@ impl LogicCallExecutedEvent { ret } } + +/// Function used for debug printing hex dumps +/// of ethereum events +fn _debug_print_data(input: &[u8]) { + let count = input.len() / 32; + println!("data hex dump"); + for i in 0..count { + println!("0x{}", bytes_to_hex_str(&input[(i * 32)..((i * 32) + 32)])) + } + println!("end dump"); +} From b981eeb9da6202b02139f9143425a1fa60051517 Mon Sep 17 00:00:00 2001 From: Justin Kilpatrick Date: Tue, 13 Apr 2021 10:47:32 -0400 Subject: [PATCH 4/7] Set last observed validator set in Cosmos store This patch adds the MsgValsetUpdatedEvent to the cosmos module logic, this processes and stores the latest validator set as an event. We've resisted doing this for quite a long time. With concern that developers would want to use this value in ways it's not safe to use. But we need it for two purposes that it is safe to use for. 1) warnings about bridge highjacking 2) efficient pruning of validator sets without pruning too many sets --- module/proto/gravity/v1/attestation.proto | 1 + module/proto/gravity/v1/msgs.proto | 16 + module/x/gravity/handler.go | 3 + module/x/gravity/keeper/attestation.go | 22 + .../x/gravity/keeper/attestation_handler.go | 8 + module/x/gravity/keeper/msg_server.go | 40 ++ module/x/gravity/types/attestation.pb.go | 62 +- module/x/gravity/types/codec.go | 3 + module/x/gravity/types/key.go | 12 +- module/x/gravity/types/msgs.go | 58 +- module/x/gravity/types/msgs.pb.go | 672 +++++++++++++++--- 11 files changed, 781 insertions(+), 116 deletions(-) diff --git a/module/proto/gravity/v1/attestation.proto b/module/proto/gravity/v1/attestation.proto index 803586d9b..63419cde4 100644 --- a/module/proto/gravity/v1/attestation.proto +++ b/module/proto/gravity/v1/attestation.proto @@ -18,6 +18,7 @@ enum ClaimType { CLAIM_TYPE_WITHDRAW = 2; CLAIM_TYPE_ERC20_DEPLOYED = 3; CLAIM_TYPE_LOGIC_CALL_EXECUTED = 4; + CLAIM_TYPE_VALSET_UPDATED = 5; } // Attestation is an aggregate of `claims` that eventually becomes `observed` by diff --git a/module/proto/gravity/v1/msgs.proto b/module/proto/gravity/v1/msgs.proto index db28de400..4cf113e05 100644 --- a/module/proto/gravity/v1/msgs.proto +++ b/module/proto/gravity/v1/msgs.proto @@ -3,6 +3,7 @@ package gravity.v1; import "cosmos/base/v1beta1/coin.proto"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; +import "gravity/v1/types.proto"; option go_package = "github.com/cosmos/gravity-bridge/module/x/gravity/types"; // Msg defines the state transitions possible within gravity @@ -28,6 +29,9 @@ service Msg { rpc WithdrawClaim(MsgWithdrawClaim) returns (MsgWithdrawClaimResponse) { option (google.api.http).post = "/gravity/v1/withdraw_claim"; } + rpc ValsetUpdateClaim(MsgValsetUpdatedClaim) returns (MsgValsetUpdatedClaimResponse) { + option (google.api.http).post = "/gravity/v1/valset_updated_claim"; + } rpc ERC20DeployedClaim(MsgERC20DeployedClaim) returns (MsgERC20DeployedClaimResponse) { option (google.api.http).post = "/gravity/v1/erc20_deployed_claim"; @@ -226,6 +230,18 @@ message MsgLogicCallExecutedClaim { message MsgLogicCallExecutedClaimResponse {} +// This informs the Cosmos module that a validator +// set has been updated. +message MsgValsetUpdatedClaim { + uint64 event_nonce = 1; + uint64 valset_nonce = 2; + uint64 block_height = 3; + repeated BridgeValidator members = 4; + string orchestrator = 6; +} + +message MsgValsetUpdatedClaimResponse {} + // This call allows the sender (and only the sender) // to cancel a given MsgSendToEth and recieve a refund // of the tokens diff --git a/module/x/gravity/handler.go b/module/x/gravity/handler.go index 20591e28e..0635146e8 100644 --- a/module/x/gravity/handler.go +++ b/module/x/gravity/handler.go @@ -47,6 +47,9 @@ func NewHandler(k keeper.Keeper) sdk.Handler { case *types.MsgLogicCallExecutedClaim: res, err := msgServer.LogicCallExecutedClaim(sdk.WrapSDKContext(ctx), msg) return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgValsetUpdatedClaim: + res, err := msgServer.ValsetUpdateClaim(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) default: return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, fmt.Sprintf("Unrecognized Gravity Msg type: %v", msg.Type())) diff --git a/module/x/gravity/keeper/attestation.go b/module/x/gravity/keeper/attestation.go index 1f9e78430..695fd274f 100644 --- a/module/x/gravity/keeper/attestation.go +++ b/module/x/gravity/keeper/attestation.go @@ -237,6 +237,28 @@ func (k Keeper) SetLastObservedEthereumBlockHeight(ctx sdk.Context, ethereumHeig store.Set(types.LastObservedEthereumBlockHeightKey, k.cdc.MustMarshalBinaryBare(&height)) } +// GetLastObservedValset retrieves the last observed validator set from the store +// WARNING: This value is not an up to date validator set on Ethereum, it is a validator set +// that AT ONE POINT was the one in the Gravity bridge on Ethereum. If you assume that it's up +// to date you may break the bridge +func (k Keeper) GetLastObservedValset(ctx sdk.Context) *types.Valset { + store := ctx.KVStore(k.storeKey) + bytes := store.Get(types.LastObservedValsetKey) + + if len(bytes) == 0 { + return nil + } + valset := types.Valset{} + k.cdc.MustUnmarshalBinaryBare(bytes, &valset) + return &valset +} + +// SetLastObservedValset updates the last observed validator set in the store +func (k Keeper) SetLastObservedValset(ctx sdk.Context, valset types.Valset) { + store := ctx.KVStore(k.storeKey) + store.Set(types.LastObservedValsetKey, k.cdc.MustMarshalBinaryBare(&valset)) +} + // setLastObservedEventNonce sets the latest observed event nonce func (k Keeper) setLastObservedEventNonce(ctx sdk.Context, nonce uint64) { store := ctx.KVStore(k.storeKey) diff --git a/module/x/gravity/keeper/attestation_handler.go b/module/x/gravity/keeper/attestation_handler.go index 5ce06c0a3..8b274e17f 100644 --- a/module/x/gravity/keeper/attestation_handler.go +++ b/module/x/gravity/keeper/attestation_handler.go @@ -111,6 +111,14 @@ func (a AttestationHandler) Handle(ctx sdk.Context, att types.Attestation, claim // Add to denom-erc20 mapping a.keeper.setCosmosOriginatedDenomToERC20(ctx, claim.CosmosDenom, claim.TokenContract) + case *types.MsgValsetUpdatedClaim: + // TODO here we should check the contents of the validator set against + // the store, if they differ we should take some action to indicate to the + // user that bridge highjacking has occurred + a.keeper.SetLastObservedValset(ctx, types.Valset{ + Nonce: claim.ValsetNonce, + Members: claim.Members, + }) default: return sdkerrors.Wrapf(types.ErrInvalid, "event type: %s", claim.GetType()) diff --git a/module/x/gravity/keeper/msg_server.go b/module/x/gravity/keeper/msg_server.go index f50611195..b59cb063f 100644 --- a/module/x/gravity/keeper/msg_server.go +++ b/module/x/gravity/keeper/msg_server.go @@ -439,6 +439,46 @@ func (k msgServer) LogicCallExecutedClaim(c context.Context, msg *types.MsgLogic return &types.MsgLogicCallExecutedClaimResponse{}, nil } +// ValsetUpdatedClaim handles claims for executing a validator set update on Ethereum +func (k msgServer) ValsetUpdateClaim(c context.Context, msg *types.MsgValsetUpdatedClaim) (*types.MsgValsetUpdatedClaimResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + + orchaddr, _ := sdk.AccAddressFromBech32(msg.Orchestrator) + validator := k.GetOrchestratorValidator(ctx, orchaddr) + if validator == nil { + return nil, sdkerrors.Wrap(types.ErrUnknown, "validator") + } + + // return an error if the validator isn't in the active set + val := k.StakingKeeper.Validator(ctx, validator) + if val == nil || !val.IsBonded() { + return nil, sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, "validator not in acitve set") + } + + any, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return nil, err + } + + // Add the claim to the store + _, err = k.Attest(ctx, msg, any) + if err != nil { + return nil, sdkerrors.Wrap(err, "create attestation") + } + + // Emit the handle message event + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, msg.Type()), + // TODO: maybe return something better here? is this the right string representation? + sdk.NewAttribute(types.AttributeKeyAttestationID, string(types.GetAttestationKey(msg.EventNonce, msg.ClaimHash()))), + ), + ) + + return &types.MsgValsetUpdatedClaimResponse{}, nil +} + func (k msgServer) CancelSendToEth(c context.Context, msg *types.MsgCancelSendToEth) (*types.MsgCancelSendToEthResponse, error) { ctx := sdk.UnwrapSDKContext(c) sender, err := sdk.AccAddressFromBech32(msg.Sender) diff --git a/module/x/gravity/types/attestation.pb.go b/module/x/gravity/types/attestation.pb.go index 64cdb29f3..d3b3edf10 100644 --- a/module/x/gravity/types/attestation.pb.go +++ b/module/x/gravity/types/attestation.pb.go @@ -35,6 +35,7 @@ const ( CLAIM_TYPE_WITHDRAW ClaimType = 2 CLAIM_TYPE_ERC20_DEPLOYED ClaimType = 3 CLAIM_TYPE_LOGIC_CALL_EXECUTED ClaimType = 4 + CLAIM_TYPE_VALSET_UPDATED ClaimType = 5 ) var ClaimType_name = map[int32]string{ @@ -43,6 +44,7 @@ var ClaimType_name = map[int32]string{ 2: "CLAIM_TYPE_WITHDRAW", 3: "CLAIM_TYPE_ERC20_DEPLOYED", 4: "CLAIM_TYPE_LOGIC_CALL_EXECUTED", + 5: "CLAIM_TYPE_VALSET_UPDATED", } var ClaimType_value = map[string]int32{ @@ -51,6 +53,7 @@ var ClaimType_value = map[string]int32{ "CLAIM_TYPE_WITHDRAW": 2, "CLAIM_TYPE_ERC20_DEPLOYED": 3, "CLAIM_TYPE_LOGIC_CALL_EXECUTED": 4, + "CLAIM_TYPE_VALSET_UPDATED": 5, } func (x ClaimType) String() string { @@ -203,35 +206,36 @@ func init() { func init() { proto.RegisterFile("gravity/v1/attestation.proto", fileDescriptor_e3205613bbab7525) } var fileDescriptor_e3205613bbab7525 = []byte{ - // 448 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x92, 0x31, 0x6f, 0xd3, 0x40, - 0x14, 0xc7, 0x7d, 0x49, 0x1a, 0x35, 0xd7, 0xc5, 0x3a, 0xa2, 0xe0, 0x5a, 0xe0, 0x46, 0x19, 0x50, - 0x54, 0xa9, 0x3e, 0x5a, 0x06, 0x66, 0xd7, 0xbe, 0x82, 0x25, 0x43, 0x82, 0xeb, 0xaa, 0x94, 0x25, - 0xb2, 0x9d, 0xe3, 0x62, 0x35, 0xf6, 0x45, 0xf6, 0xc5, 0xc2, 0x33, 0x0b, 0x23, 0x5f, 0x01, 0xf1, - 0x65, 0x3a, 0x76, 0x44, 0x0c, 0x15, 0x4a, 0xbe, 0x08, 0x8a, 0xed, 0x86, 0x48, 0x4c, 0xf6, 0xff, - 0xff, 0x7b, 0xef, 0xee, 0xff, 0x9e, 0x0e, 0x3e, 0x63, 0xa9, 0x9f, 0x47, 0xa2, 0xc0, 0xf9, 0x29, - 0xf6, 0x85, 0xa0, 0x99, 0xf0, 0x45, 0xc4, 0x13, 0x7d, 0x91, 0x72, 0xc1, 0x11, 0xac, 0xa9, 0x9e, - 0x9f, 0xaa, 0x5d, 0xc6, 0x19, 0x2f, 0x6d, 0xbc, 0xf9, 0xab, 0x2a, 0xd4, 0x43, 0xc6, 0x39, 0x9b, - 0x53, 0x5c, 0xaa, 0x60, 0xf9, 0x19, 0xfb, 0x49, 0x51, 0xa1, 0xc1, 0x57, 0x00, 0x0f, 0x8c, 0x7f, - 0x47, 0x22, 0x15, 0xee, 0xf3, 0x20, 0xa3, 0x69, 0x4e, 0xa7, 0x0a, 0xe8, 0x83, 0xe1, 0xbe, 0xbb, - 0xd5, 0xa8, 0x0b, 0xf7, 0x72, 0x2e, 0x68, 0xa6, 0x34, 0xfa, 0xcd, 0x61, 0xc7, 0xad, 0x04, 0xea, - 0xc1, 0xf6, 0x8c, 0x46, 0x6c, 0x26, 0x94, 0x66, 0x1f, 0x0c, 0x5b, 0x6e, 0xad, 0xd0, 0x31, 0xdc, - 0x0b, 0xe7, 0x7e, 0x14, 0x2b, 0xad, 0x3e, 0x18, 0x1e, 0x9c, 0x75, 0xf5, 0x2a, 0x84, 0xfe, 0x18, - 0x42, 0x37, 0x92, 0xc2, 0xad, 0x4a, 0x06, 0x0b, 0x08, 0x89, 0x6b, 0x9e, 0xbd, 0xf4, 0xf8, 0x2d, - 0x2d, 0x33, 0x84, 0x3c, 0x11, 0xa9, 0x1f, 0x8a, 0x32, 0x43, 0xc7, 0xdd, 0x6a, 0x74, 0x01, 0xdb, - 0x7e, 0xcc, 0x97, 0x89, 0x50, 0x1a, 0x1b, 0x72, 0xae, 0xdf, 0x3d, 0x1c, 0x49, 0xbf, 0x1f, 0x8e, - 0x5e, 0xb0, 0x48, 0xcc, 0x96, 0x81, 0x1e, 0xf2, 0x18, 0x87, 0x3c, 0x8b, 0x79, 0x56, 0x7f, 0x4e, - 0xb2, 0xe9, 0x2d, 0x16, 0xc5, 0x82, 0x66, 0xba, 0x9d, 0x08, 0xb7, 0xee, 0x3e, 0xfe, 0x01, 0x60, - 0xc7, 0xdc, 0xdc, 0xed, 0x15, 0x0b, 0x8a, 0x54, 0xd8, 0x33, 0x1d, 0xc3, 0x7e, 0x37, 0xf1, 0x6e, - 0xc6, 0x64, 0x72, 0xf5, 0xfe, 0x72, 0x4c, 0x4c, 0xfb, 0xc2, 0x26, 0x96, 0x2c, 0xa1, 0x1e, 0x44, - 0x3b, 0xcc, 0x22, 0xe3, 0xd1, 0xa5, 0xed, 0xc9, 0x00, 0x3d, 0x85, 0x4f, 0x76, 0xfc, 0x6b, 0xdb, - 0x7b, 0x6b, 0xb9, 0xc6, 0xb5, 0xdc, 0x40, 0xcf, 0xe1, 0xe1, 0x0e, 0x28, 0xe7, 0xda, 0xb4, 0x39, - 0xa3, 0x1b, 0x62, 0xc9, 0x4d, 0x34, 0x80, 0xda, 0x0e, 0x76, 0x46, 0x6f, 0x6c, 0x73, 0x62, 0x1a, - 0x8e, 0x33, 0x21, 0x1f, 0x89, 0x79, 0xe5, 0x11, 0x4b, 0x6e, 0xa9, 0xad, 0x6f, 0x3f, 0x35, 0xe9, - 0xfc, 0xc3, 0xdd, 0x4a, 0x03, 0xf7, 0x2b, 0x0d, 0xfc, 0x59, 0x69, 0xe0, 0xfb, 0x5a, 0x93, 0xee, - 0xd7, 0x9a, 0xf4, 0x6b, 0xad, 0x49, 0x9f, 0x5e, 0xff, 0x3f, 0x6d, 0xfd, 0x08, 0x4e, 0x82, 0x34, - 0x9a, 0x32, 0x8a, 0x63, 0x3e, 0x5d, 0xce, 0x29, 0xfe, 0xf2, 0xe8, 0x57, 0x2b, 0x08, 0xda, 0xe5, - 0xf6, 0x5f, 0xfd, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x5a, 0x62, 0x07, 0x52, 0x02, 0x00, 0x00, + // 462 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x92, 0xbf, 0x6f, 0xd3, 0x40, + 0x14, 0xc7, 0x7d, 0xf9, 0xa5, 0xe6, 0xba, 0x58, 0x47, 0x14, 0x5c, 0x0b, 0xdc, 0x28, 0x03, 0x8a, + 0x2a, 0xd5, 0xa6, 0x65, 0x60, 0x76, 0xed, 0x2b, 0x58, 0x32, 0x24, 0x38, 0x0e, 0xa5, 0x2c, 0x96, + 0xed, 0x1c, 0x8e, 0xd5, 0xd8, 0x17, 0xd9, 0x17, 0x0b, 0xcf, 0x2c, 0x8c, 0xfc, 0x0f, 0xfc, 0x23, + 0x8c, 0x1d, 0x3b, 0x22, 0x86, 0x0a, 0x25, 0xff, 0x08, 0xf2, 0x8f, 0x86, 0x08, 0xa6, 0xbb, 0xef, + 0xfb, 0xbc, 0xf7, 0xee, 0x7b, 0xef, 0x0e, 0x3e, 0x09, 0x12, 0x37, 0x0b, 0x59, 0xae, 0x64, 0x67, + 0x8a, 0xcb, 0x18, 0x49, 0x99, 0xcb, 0x42, 0x1a, 0xcb, 0xab, 0x84, 0x32, 0x8a, 0x60, 0x4d, 0xe5, + 0xec, 0x4c, 0xec, 0x05, 0x34, 0xa0, 0x65, 0x58, 0x29, 0x76, 0x55, 0x86, 0x78, 0x14, 0x50, 0x1a, + 0x2c, 0x89, 0x52, 0x2a, 0x6f, 0xfd, 0x49, 0x71, 0xe3, 0xbc, 0x42, 0xc3, 0x2f, 0x00, 0x1e, 0xaa, + 0x7f, 0x5b, 0x22, 0x11, 0x1e, 0x50, 0x2f, 0x25, 0x49, 0x46, 0xe6, 0x02, 0x18, 0x80, 0xd1, 0x81, + 0xb5, 0xd3, 0xa8, 0x07, 0xdb, 0x19, 0x65, 0x24, 0x15, 0x1a, 0x83, 0xe6, 0xa8, 0x6b, 0x55, 0x02, + 0xf5, 0x61, 0x67, 0x41, 0xc2, 0x60, 0xc1, 0x84, 0xe6, 0x00, 0x8c, 0x5a, 0x56, 0xad, 0xd0, 0x09, + 0x6c, 0xfb, 0x4b, 0x37, 0x8c, 0x84, 0xd6, 0x00, 0x8c, 0x0e, 0xcf, 0x7b, 0x72, 0x65, 0x42, 0x7e, + 0x30, 0x21, 0xab, 0x71, 0x6e, 0x55, 0x29, 0xc3, 0x15, 0x84, 0xd8, 0xd2, 0xce, 0x9f, 0xdb, 0xf4, + 0x86, 0x94, 0x1e, 0x7c, 0x1a, 0xb3, 0xc4, 0xf5, 0x59, 0xe9, 0xa1, 0x6b, 0xed, 0x34, 0xba, 0x84, + 0x1d, 0x37, 0xa2, 0xeb, 0x98, 0x09, 0x8d, 0x82, 0x5c, 0xc8, 0xb7, 0xf7, 0xc7, 0xdc, 0xaf, 0xfb, + 0xe3, 0x67, 0x41, 0xc8, 0x16, 0x6b, 0x4f, 0xf6, 0x69, 0xa4, 0xf8, 0x34, 0x8d, 0x68, 0x5a, 0x2f, + 0xa7, 0xe9, 0xfc, 0x46, 0x61, 0xf9, 0x8a, 0xa4, 0xb2, 0x11, 0x33, 0xab, 0xae, 0x3e, 0xf9, 0x01, + 0x60, 0x57, 0x2b, 0xce, 0xb6, 0xf3, 0x15, 0x41, 0x22, 0xec, 0x6b, 0xa6, 0x6a, 0xbc, 0x71, 0xec, + 0xeb, 0x09, 0x76, 0x66, 0x6f, 0xa7, 0x13, 0xac, 0x19, 0x97, 0x06, 0xd6, 0x79, 0x0e, 0xf5, 0x21, + 0xda, 0x63, 0x3a, 0x9e, 0x8c, 0xa7, 0x86, 0xcd, 0x03, 0xf4, 0x18, 0x3e, 0xda, 0x8b, 0x5f, 0x19, + 0xf6, 0x6b, 0xdd, 0x52, 0xaf, 0xf8, 0x06, 0x7a, 0x0a, 0x8f, 0xf6, 0x40, 0x79, 0xaf, 0xa2, 0xcc, + 0x1c, 0x5f, 0x63, 0x9d, 0x6f, 0xa2, 0x21, 0x94, 0xf6, 0xb0, 0x39, 0x7e, 0x65, 0x68, 0x8e, 0xa6, + 0x9a, 0xa6, 0x83, 0x3f, 0x60, 0x6d, 0x66, 0x63, 0x9d, 0x6f, 0xfd, 0xd3, 0xe2, 0xbd, 0x6a, 0x4e, + 0xb1, 0xed, 0xcc, 0x26, 0xba, 0x5a, 0xe0, 0xb6, 0xd8, 0xfa, 0xfa, 0x5d, 0xe2, 0x2e, 0xde, 0xdd, + 0x6e, 0x24, 0x70, 0xb7, 0x91, 0xc0, 0xef, 0x8d, 0x04, 0xbe, 0x6d, 0x25, 0xee, 0x6e, 0x2b, 0x71, + 0x3f, 0xb7, 0x12, 0xf7, 0xf1, 0xe5, 0xff, 0xc3, 0xa8, 0xff, 0xc8, 0xa9, 0x97, 0x84, 0xf3, 0x80, + 0x28, 0x11, 0x9d, 0xaf, 0x97, 0x44, 0xf9, 0xfc, 0x10, 0xaf, 0x26, 0xe4, 0x75, 0xca, 0xc7, 0x79, + 0xf1, 0x27, 0x00, 0x00, 0xff, 0xff, 0xa3, 0x60, 0x0d, 0x45, 0x71, 0x02, 0x00, 0x00, } func (m *Attestation) Marshal() (dAtA []byte, err error) { diff --git a/module/x/gravity/types/codec.go b/module/x/gravity/types/codec.go index 375f2c159..d82d08d44 100644 --- a/module/x/gravity/types/codec.go +++ b/module/x/gravity/types/codec.go @@ -27,6 +27,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { &MsgERC20DeployedClaim{}, &MsgSetOrchestratorAddress{}, &MsgLogicCallExecutedClaim{}, + &MsgValsetUpdatedClaim{}, &MsgCancelSendToEth{}, ) @@ -37,6 +38,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { &MsgWithdrawClaim{}, &MsgERC20DeployedClaim{}, &MsgLogicCallExecutedClaim{}, + &MsgValsetUpdatedClaim{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) @@ -56,6 +58,7 @@ func RegisterCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgWithdrawClaim{}, "gravity/MsgWithdrawClaim", nil) cdc.RegisterConcrete(&MsgERC20DeployedClaim{}, "gravity/MsgERC20DeployedClaim", nil) cdc.RegisterConcrete(&MsgLogicCallExecutedClaim{}, "gravity/MsgLogicCallExecutedClaim", nil) + cdc.RegisterConcrete(&MsgValsetUpdatedClaim{}, "gravity/MsgValsetUpdatedClaim", nil) cdc.RegisterConcrete(&OutgoingTxBatch{}, "gravity/OutgoingTxBatch", nil) cdc.RegisterConcrete(&MsgCancelSendToEth{}, "gravity/MsgCancelSendToEth", nil) cdc.RegisterConcrete(&OutgoingTransferTx{}, "gravity/OutgoingTransferTx", nil) diff --git a/module/x/gravity/types/key.go b/module/x/gravity/types/key.go index 6b947a9b0..c884db91c 100644 --- a/module/x/gravity/types/key.go +++ b/module/x/gravity/types/key.go @@ -91,9 +91,6 @@ var ( // KeyOutgoingLogicConfirm indexes the outgoing logic confirms KeyOutgoingLogicConfirm = []byte{0xae} - // LastObservedEthereumBlockHeightKey indexes the latest Ethereum block height - LastObservedEthereumBlockHeightKey = []byte{0xf9} - // DenomToERC20Key prefixes the index of Cosmos originated asset denoms to ERC20s DenomToERC20Key = []byte{0xf3} @@ -111,6 +108,15 @@ var ( // LastUnBondingBlockHeight indexes the last validator unbonding block height LastUnBondingBlockHeight = []byte{0xf8} + + // LastObservedEthereumBlockHeightKey indexes the latest Ethereum block height + LastObservedEthereumBlockHeightKey = []byte{0xf9} + + // LastObservedValsetNonceKey indexes the latest observed valset nonce + // HERE THERE BE DRAGONS, do not use this value as an up to date validator set + // on Ethereum it will always lag significantly and may be totally wrong at some + // times. + LastObservedValsetKey = []byte{0xfa} ) // GetOrchestratorAddressKey returns the following key format diff --git a/module/x/gravity/types/msgs.go b/module/x/gravity/types/msgs.go index 7bd4f4424..c5d2bd317 100644 --- a/module/x/gravity/types/msgs.go +++ b/module/x/gravity/types/msgs.go @@ -558,7 +558,63 @@ func (b *MsgLogicCallExecutedClaim) ClaimHash() []byte { return tmhash.Sum([]byte(path)) } -// NewMsgSetOrchestratorAddress returns a new msgSetOrchestratorAddress +// EthereumClaim implementation for MsgValsetUpdatedClaim +// ====================================================== + +// GetType returns the type of the claim +func (e *MsgValsetUpdatedClaim) GetType() ClaimType { + return CLAIM_TYPE_VALSET_UPDATED +} + +// ValidateBasic performs stateless checks +func (e *MsgValsetUpdatedClaim) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(e.Orchestrator); err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, e.Orchestrator) + } + if e.EventNonce == 0 { + return fmt.Errorf("nonce == 0") + } + return nil +} + +// GetSignBytes encodes the message for signing +func (msg MsgValsetUpdatedClaim) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +func (msg MsgValsetUpdatedClaim) GetClaimer() sdk.AccAddress { + err := msg.ValidateBasic() + if err != nil { + panic("MsgERC20DeployedClaim failed ValidateBasic! Should have been handled earlier") + } + + val, _ := sdk.AccAddressFromBech32(msg.Orchestrator) + return val +} + +// GetSigners defines whose signature is required +func (msg MsgValsetUpdatedClaim) GetSigners() []sdk.AccAddress { + acc, err := sdk.AccAddressFromBech32(msg.Orchestrator) + if err != nil { + panic(err) + } + + return []sdk.AccAddress{acc} +} + +// Type should return the action +func (msg MsgValsetUpdatedClaim) Type() string { return "Valset_Updated_Claim" } + +// Route should return the name of the module +func (msg MsgValsetUpdatedClaim) Route() string { return RouterKey } + +// Hash implements BridgeDeposit.Hash +func (b *MsgValsetUpdatedClaim) ClaimHash() []byte { + path := fmt.Sprintf("%d/%d/%d/%s/", b.ValsetNonce, b.EventNonce, b.BlockHeight, b.Members) + return tmhash.Sum([]byte(path)) +} + +// NewMsgCancelSendToEth returns a new msgSetOrchestratorAddress func NewMsgCancelSendToEth(val sdk.ValAddress, id uint64) *MsgCancelSendToEth { return &MsgCancelSendToEth{ TransactionId: id, diff --git a/module/x/gravity/types/msgs.pb.go b/module/x/gravity/types/msgs.pb.go index beb5ecf42..dcc7b0986 100644 --- a/module/x/gravity/types/msgs.pb.go +++ b/module/x/gravity/types/msgs.pb.go @@ -1205,6 +1205,120 @@ func (m *MsgLogicCallExecutedClaimResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgLogicCallExecutedClaimResponse proto.InternalMessageInfo +// This informs the Cosmos module that a validator +// set has been updated. +type MsgValsetUpdatedClaim struct { + EventNonce uint64 `protobuf:"varint,1,opt,name=event_nonce,json=eventNonce,proto3" json:"event_nonce,omitempty"` + ValsetNonce uint64 `protobuf:"varint,2,opt,name=valset_nonce,json=valsetNonce,proto3" json:"valset_nonce,omitempty"` + BlockHeight uint64 `protobuf:"varint,3,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"` + Members []*BridgeValidator `protobuf:"bytes,4,rep,name=members,proto3" json:"members,omitempty"` + Orchestrator string `protobuf:"bytes,6,opt,name=orchestrator,proto3" json:"orchestrator,omitempty"` +} + +func (m *MsgValsetUpdatedClaim) Reset() { *m = MsgValsetUpdatedClaim{} } +func (m *MsgValsetUpdatedClaim) String() string { return proto.CompactTextString(m) } +func (*MsgValsetUpdatedClaim) ProtoMessage() {} +func (*MsgValsetUpdatedClaim) Descriptor() ([]byte, []int) { + return fileDescriptor_2f8523f2f6feb451, []int{20} +} +func (m *MsgValsetUpdatedClaim) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgValsetUpdatedClaim) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgValsetUpdatedClaim.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgValsetUpdatedClaim) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgValsetUpdatedClaim.Merge(m, src) +} +func (m *MsgValsetUpdatedClaim) XXX_Size() int { + return m.Size() +} +func (m *MsgValsetUpdatedClaim) XXX_DiscardUnknown() { + xxx_messageInfo_MsgValsetUpdatedClaim.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgValsetUpdatedClaim proto.InternalMessageInfo + +func (m *MsgValsetUpdatedClaim) GetEventNonce() uint64 { + if m != nil { + return m.EventNonce + } + return 0 +} + +func (m *MsgValsetUpdatedClaim) GetValsetNonce() uint64 { + if m != nil { + return m.ValsetNonce + } + return 0 +} + +func (m *MsgValsetUpdatedClaim) GetBlockHeight() uint64 { + if m != nil { + return m.BlockHeight + } + return 0 +} + +func (m *MsgValsetUpdatedClaim) GetMembers() []*BridgeValidator { + if m != nil { + return m.Members + } + return nil +} + +func (m *MsgValsetUpdatedClaim) GetOrchestrator() string { + if m != nil { + return m.Orchestrator + } + return "" +} + +type MsgValsetUpdatedClaimResponse struct { +} + +func (m *MsgValsetUpdatedClaimResponse) Reset() { *m = MsgValsetUpdatedClaimResponse{} } +func (m *MsgValsetUpdatedClaimResponse) String() string { return proto.CompactTextString(m) } +func (*MsgValsetUpdatedClaimResponse) ProtoMessage() {} +func (*MsgValsetUpdatedClaimResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2f8523f2f6feb451, []int{21} +} +func (m *MsgValsetUpdatedClaimResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgValsetUpdatedClaimResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgValsetUpdatedClaimResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgValsetUpdatedClaimResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgValsetUpdatedClaimResponse.Merge(m, src) +} +func (m *MsgValsetUpdatedClaimResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgValsetUpdatedClaimResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgValsetUpdatedClaimResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgValsetUpdatedClaimResponse proto.InternalMessageInfo + // This call allows the sender (and only the sender) // to cancel a given MsgSendToEth and recieve a refund // of the tokens @@ -1217,7 +1331,7 @@ func (m *MsgCancelSendToEth) Reset() { *m = MsgCancelSendToEth{} } func (m *MsgCancelSendToEth) String() string { return proto.CompactTextString(m) } func (*MsgCancelSendToEth) ProtoMessage() {} func (*MsgCancelSendToEth) Descriptor() ([]byte, []int) { - return fileDescriptor_2f8523f2f6feb451, []int{20} + return fileDescriptor_2f8523f2f6feb451, []int{22} } func (m *MsgCancelSendToEth) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1267,7 +1381,7 @@ func (m *MsgCancelSendToEthResponse) Reset() { *m = MsgCancelSendToEthRe func (m *MsgCancelSendToEthResponse) String() string { return proto.CompactTextString(m) } func (*MsgCancelSendToEthResponse) ProtoMessage() {} func (*MsgCancelSendToEthResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_2f8523f2f6feb451, []int{21} + return fileDescriptor_2f8523f2f6feb451, []int{23} } func (m *MsgCancelSendToEthResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1317,6 +1431,8 @@ func init() { proto.RegisterType((*MsgERC20DeployedClaimResponse)(nil), "gravity.v1.MsgERC20DeployedClaimResponse") proto.RegisterType((*MsgLogicCallExecutedClaim)(nil), "gravity.v1.MsgLogicCallExecutedClaim") proto.RegisterType((*MsgLogicCallExecutedClaimResponse)(nil), "gravity.v1.MsgLogicCallExecutedClaimResponse") + proto.RegisterType((*MsgValsetUpdatedClaim)(nil), "gravity.v1.MsgValsetUpdatedClaim") + proto.RegisterType((*MsgValsetUpdatedClaimResponse)(nil), "gravity.v1.MsgValsetUpdatedClaimResponse") proto.RegisterType((*MsgCancelSendToEth)(nil), "gravity.v1.MsgCancelSendToEth") proto.RegisterType((*MsgCancelSendToEthResponse)(nil), "gravity.v1.MsgCancelSendToEthResponse") } @@ -1324,87 +1440,93 @@ func init() { func init() { proto.RegisterFile("gravity/v1/msgs.proto", fileDescriptor_2f8523f2f6feb451) } var fileDescriptor_2f8523f2f6feb451 = []byte{ - // 1280 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4d, 0x6f, 0xdb, 0x46, - 0x13, 0x36, 0x6d, 0xd9, 0x89, 0xc7, 0x72, 0x9c, 0x97, 0xaf, 0xe3, 0x48, 0x8c, 0x23, 0xd9, 0x4c, - 0x6c, 0xa7, 0x40, 0x2d, 0xc6, 0xee, 0x21, 0xb7, 0x16, 0xb5, 0x9c, 0xa0, 0x01, 0xea, 0x14, 0x95, - 0x8b, 0x16, 0xe8, 0x85, 0xa0, 0xc8, 0x09, 0x49, 0x84, 0xe4, 0xaa, 0xdc, 0x95, 0x1c, 0x5f, 0x02, - 0xb4, 0xd7, 0xf6, 0xd0, 0x8f, 0x6b, 0xfb, 0x1b, 0x7a, 0xef, 0xb1, 0xa7, 0x9c, 0x8a, 0x00, 0xbd, - 0x14, 0x2d, 0x10, 0x14, 0x49, 0x7f, 0x48, 0xc1, 0xdd, 0x15, 0xc5, 0x2f, 0xc5, 0x3e, 0xb8, 0x27, - 0x89, 0xb3, 0xc3, 0x99, 0xe7, 0x79, 0x66, 0x76, 0x76, 0x09, 0xd7, 0xdc, 0xd8, 0x1a, 0xf9, 0xec, - 0xd4, 0x18, 0xed, 0x19, 0x21, 0x75, 0x69, 0x67, 0x10, 0x13, 0x46, 0x54, 0x90, 0xe6, 0xce, 0x68, - 0x4f, 0x6b, 0xd9, 0x84, 0x86, 0x84, 0x1a, 0x7d, 0x8b, 0xa2, 0x31, 0xda, 0xeb, 0x23, 0xb3, 0xf6, - 0x0c, 0x9b, 0xf8, 0x91, 0xf0, 0xd5, 0x56, 0x5d, 0xe2, 0x12, 0xfe, 0xd7, 0x48, 0xfe, 0x49, 0xeb, - 0xba, 0x4b, 0x88, 0x1b, 0xa0, 0x61, 0x0d, 0x7c, 0xc3, 0x8a, 0x22, 0xc2, 0x2c, 0xe6, 0x93, 0x48, - 0xc6, 0xd7, 0x9f, 0x41, 0xf3, 0x88, 0xba, 0xc7, 0xc8, 0x3e, 0x8a, 0x6d, 0x0f, 0x29, 0x8b, 0x2d, - 0x46, 0xe2, 0xf7, 0x1d, 0x27, 0x46, 0x4a, 0xd5, 0x75, 0x58, 0x1c, 0x59, 0x81, 0xef, 0x24, 0xb6, - 0x86, 0xb2, 0xa1, 0xdc, 0x59, 0xec, 0x4d, 0x0c, 0xaa, 0x0e, 0x75, 0x92, 0x79, 0xa9, 0x31, 0xcb, - 0x1d, 0x72, 0x36, 0xb5, 0x0d, 0x4b, 0xc8, 0x3c, 0xd3, 0x12, 0x01, 0x1b, 0x73, 0xdc, 0x05, 0x90, - 0x79, 0x32, 0x85, 0x7e, 0x0b, 0x36, 0xa7, 0xe6, 0xef, 0x21, 0x1d, 0x90, 0x88, 0xa2, 0xfe, 0xb5, - 0x02, 0x57, 0x8f, 0xa8, 0xfb, 0xa9, 0x15, 0x50, 0x64, 0x5d, 0x12, 0x3d, 0xf6, 0xe3, 0x50, 0x5d, - 0x85, 0xf9, 0x88, 0x44, 0x36, 0x72, 0x60, 0xb5, 0x9e, 0x78, 0xb8, 0x10, 0x50, 0x09, 0x6f, 0xea, - 0xbb, 0x91, 0xc5, 0x86, 0x31, 0x36, 0x6a, 0x82, 0x77, 0x6a, 0xd0, 0x35, 0x68, 0x14, 0xc1, 0xa4, - 0x48, 0x7f, 0x51, 0xa0, 0xce, 0xf9, 0x44, 0xce, 0x27, 0xe4, 0x3e, 0xf3, 0xd4, 0x35, 0x58, 0xa0, - 0x18, 0x39, 0x38, 0xd6, 0x4f, 0x3e, 0xa9, 0x4d, 0xb8, 0x9c, 0x60, 0x70, 0x90, 0x32, 0x89, 0xf1, - 0x12, 0x32, 0xef, 0x10, 0x29, 0x53, 0xef, 0xc1, 0x82, 0x15, 0x92, 0x61, 0xc4, 0x38, 0xb2, 0xa5, - 0xfd, 0x66, 0x47, 0xd4, 0xbd, 0x93, 0xd4, 0xbd, 0x23, 0xeb, 0xde, 0xe9, 0x12, 0x3f, 0x3a, 0xa8, - 0x3d, 0x7f, 0xd9, 0x9e, 0xe9, 0x49, 0x77, 0xf5, 0x5d, 0x80, 0x7e, 0xec, 0x3b, 0x2e, 0x9a, 0x8f, - 0x51, 0xe0, 0x3e, 0xc7, 0xcb, 0x8b, 0xe2, 0x95, 0x07, 0x88, 0xfa, 0x1a, 0xac, 0x66, 0xb1, 0xa7, - 0xa4, 0xde, 0x83, 0x95, 0x23, 0xea, 0xf6, 0xf0, 0x8b, 0x21, 0x52, 0x76, 0x60, 0x31, 0x7b, 0x3a, - 0xad, 0x55, 0x98, 0x77, 0x30, 0x22, 0xa1, 0xe4, 0x24, 0x1e, 0xf4, 0x26, 0x5c, 0x2f, 0x04, 0x48, - 0x63, 0xff, 0xac, 0xf0, 0xe0, 0x52, 0x47, 0x11, 0xbc, 0xba, 0xb2, 0x5b, 0x70, 0x85, 0x91, 0x27, - 0x18, 0x99, 0x36, 0x89, 0x58, 0x6c, 0xd9, 0x63, 0xdd, 0x96, 0xb9, 0xb5, 0x2b, 0x8d, 0xea, 0x4d, - 0x48, 0x2a, 0x69, 0x26, 0xe5, 0xc2, 0x58, 0xd6, 0x76, 0x11, 0x99, 0x77, 0xcc, 0x0d, 0xa5, 0xfe, - 0xa8, 0x55, 0xf4, 0x47, 0xae, 0xfc, 0xf3, 0xc5, 0xf2, 0x0b, 0x32, 0x59, 0xc0, 0x29, 0x99, 0xdf, - 0x14, 0xf8, 0xff, 0x64, 0xed, 0x43, 0xe2, 0xfa, 0x76, 0xd7, 0x0a, 0x02, 0x75, 0x07, 0x56, 0xfc, - 0x48, 0x6e, 0x1c, 0x9f, 0x44, 0xa6, 0xef, 0x48, 0xd9, 0xae, 0x64, 0xcd, 0x0f, 0x1d, 0x75, 0x17, - 0xd4, 0x9c, 0xa3, 0x90, 0x61, 0x96, 0xcb, 0xf0, 0xbf, 0xec, 0xca, 0x23, 0x2e, 0xc9, 0x7f, 0xce, - 0xf5, 0x26, 0xdc, 0xa8, 0xe0, 0x33, 0xe9, 0xf6, 0x59, 0x5e, 0xbc, 0x43, 0x1c, 0x10, 0xea, 0xb3, - 0x6e, 0x60, 0xf9, 0x21, 0xdf, 0x5c, 0x23, 0x8c, 0x98, 0x99, 0x2d, 0x21, 0x70, 0x93, 0x00, 0xbd, - 0x09, 0xf5, 0x7e, 0x40, 0xec, 0x27, 0xa6, 0x87, 0xbe, 0xeb, 0x31, 0xc9, 0x6e, 0x89, 0xdb, 0x3e, - 0xe0, 0xa6, 0x8a, 0x52, 0xcf, 0x55, 0x95, 0xfa, 0x41, 0xba, 0x51, 0x38, 0xb3, 0x83, 0x4e, 0xd2, - 0xd0, 0x7f, 0xbe, 0x6c, 0x6f, 0xbb, 0x3e, 0xf3, 0x86, 0xfd, 0x8e, 0x4d, 0x42, 0x43, 0x8e, 0x4c, - 0xf1, 0xb3, 0x4b, 0x9d, 0x27, 0x06, 0x3b, 0x1d, 0x20, 0xed, 0x3c, 0x8c, 0x58, 0xba, 0x6f, 0x76, - 0x60, 0x05, 0x99, 0x87, 0x31, 0x0e, 0x43, 0x53, 0x76, 0xb5, 0x50, 0xe2, 0xca, 0xd8, 0x7c, 0x2c, - 0xba, 0x7b, 0x07, 0x56, 0x44, 0x20, 0x33, 0x46, 0x1b, 0xfd, 0x11, 0xc6, 0x8d, 0x05, 0xe1, 0x28, - 0xcc, 0x3d, 0x69, 0x2d, 0x29, 0x7f, 0xa9, 0xac, 0xbc, 0xec, 0xa3, 0xac, 0x76, 0xa9, 0xae, 0xbf, - 0x8a, 0x79, 0xf7, 0x99, 0xcf, 0x3c, 0x27, 0xb6, 0x4e, 0x2e, 0x4e, 0xd8, 0x36, 0x2c, 0xf5, 0x93, - 0x8e, 0x95, 0x31, 0xe6, 0x44, 0x0c, 0x6e, 0x7a, 0x34, 0x65, 0x93, 0xd5, 0xaa, 0x94, 0x2f, 0xf2, - 0x9b, 0xaf, 0xe0, 0x27, 0xc6, 0x64, 0x8e, 0x43, 0x4a, 0xf0, 0xbb, 0x59, 0xb8, 0x76, 0x44, 0xdd, - 0xfb, 0xbd, 0xee, 0xfe, 0xdd, 0x43, 0x1c, 0x04, 0xe4, 0x14, 0x9d, 0x8b, 0x63, 0xb9, 0x09, 0x75, - 0x59, 0x26, 0x31, 0x8b, 0x44, 0xf3, 0x2c, 0x09, 0xdb, 0x61, 0x62, 0x3a, 0x2f, 0x4f, 0x15, 0x6a, - 0x91, 0x15, 0x8e, 0x37, 0x06, 0xff, 0xcf, 0x47, 0xdf, 0x69, 0xd8, 0x27, 0x81, 0xac, 0xbd, 0x7c, - 0x52, 0x35, 0xb8, 0xec, 0xa0, 0xed, 0x87, 0x56, 0x40, 0x79, 0xbd, 0x6b, 0xbd, 0xf4, 0xb9, 0xa4, - 0xd7, 0xe5, 0x0a, 0xbd, 0xda, 0x70, 0xb3, 0x52, 0x92, 0x54, 0xb4, 0xbf, 0x14, 0x7e, 0x56, 0xa7, - 0xdb, 0xf0, 0xfe, 0x53, 0xb4, 0x87, 0xec, 0x22, 0x85, 0xab, 0x98, 0x53, 0x89, 0x76, 0xf5, 0x73, - 0xce, 0xa9, 0xda, 0xb4, 0x39, 0x75, 0x9e, 0x76, 0x11, 0x17, 0x81, 0x6a, 0x72, 0xa9, 0x04, 0xc7, - 0xa0, 0x26, 0xf3, 0xc8, 0x8a, 0x6c, 0x0c, 0x26, 0x67, 0x6c, 0x52, 0xcc, 0xd8, 0x8a, 0xa8, 0x65, - 0x67, 0xa7, 0x6b, 0xad, 0xb7, 0x9c, 0xb1, 0x3e, 0x74, 0x32, 0x67, 0xd6, 0x6c, 0xf6, 0xcc, 0xd2, - 0xd7, 0x41, 0x2b, 0x07, 0x1d, 0xa7, 0xdc, 0xff, 0x7e, 0x09, 0xe6, 0x8e, 0xa8, 0xab, 0x9e, 0xc0, - 0x72, 0xfe, 0xfe, 0xb1, 0xde, 0x99, 0x5c, 0xcd, 0x3a, 0xc5, 0x0b, 0x81, 0x76, 0xfb, 0x4d, 0xab, - 0x29, 0x1f, 0xfd, 0xab, 0xdf, 0xff, 0xf9, 0x61, 0x76, 0x5d, 0xd7, 0x8c, 0xcc, 0xed, 0x6f, 0xc4, - 0x5d, 0x93, 0xce, 0xe4, 0x79, 0x3c, 0x58, 0x9c, 0x50, 0x6d, 0x14, 0xc2, 0xa6, 0x2b, 0xda, 0xc6, - 0xb4, 0x95, 0x34, 0x59, 0x9b, 0x27, 0x6b, 0xea, 0xd7, 0xb3, 0xc9, 0x12, 0x0d, 0x4c, 0x46, 0x4c, - 0x64, 0x9e, 0x4a, 0xa1, 0x9e, 0x3b, 0xe4, 0x6f, 0x14, 0x42, 0x66, 0x17, 0xb5, 0x5b, 0x6f, 0x58, - 0x4c, 0x53, 0x6e, 0xf2, 0x94, 0x37, 0xf4, 0x66, 0x36, 0x65, 0x2c, 0x3c, 0x4d, 0x3e, 0x76, 0x92, - 0xa4, 0xb9, 0xc3, 0xbf, 0x98, 0x34, 0xbb, 0x58, 0x4a, 0x5a, 0x79, 0x0a, 0x57, 0x26, 0x95, 0x6a, - 0xca, 0xa4, 0xcf, 0xe0, 0x6a, 0xe9, 0x90, 0x6e, 0x57, 0xc7, 0x4e, 0x1d, 0xb4, 0x9d, 0x33, 0x1c, - 0x52, 0x00, 0x1b, 0x1c, 0x80, 0xa6, 0x37, 0x4a, 0x00, 0x42, 0x33, 0x48, 0xbc, 0x13, 0xd2, 0xb9, - 0x43, 0xb3, 0x48, 0x3a, 0xbb, 0x58, 0x22, 0x5d, 0x79, 0x64, 0x54, 0x92, 0x76, 0x84, 0xa7, 0x69, - 0xf3, 0x24, 0x27, 0xb0, 0x9c, 0x3f, 0x51, 0x8a, 0x1d, 0x9c, 0x5b, 0x2d, 0x75, 0x70, 0xf5, 0x24, - 0xaf, 0xec, 0xe0, 0x13, 0xe9, 0x2a, 0x13, 0x7f, 0xa3, 0x80, 0x5a, 0x31, 0xea, 0x37, 0x0b, 0x09, - 0xca, 0x2e, 0xda, 0x5b, 0x67, 0xba, 0xa4, 0x40, 0xee, 0x70, 0x20, 0xba, 0xbe, 0x91, 0x05, 0x82, - 0xb1, 0xbd, 0x7f, 0xd7, 0x74, 0xe4, 0x0b, 0x12, 0xce, 0x4f, 0x0a, 0xac, 0x4d, 0x19, 0xa2, 0x5b, - 0x85, 0x7c, 0xd5, 0x6e, 0xda, 0xee, 0xb9, 0xdc, 0x52, 0x68, 0xbb, 0x1c, 0xda, 0x8e, 0xbe, 0x95, - 0x85, 0xc6, 0x1b, 0xc1, 0xb4, 0xad, 0x20, 0x30, 0x51, 0xbe, 0x25, 0xf1, 0xfd, 0xa8, 0xc0, 0xda, - 0x94, 0x0f, 0xb2, 0xad, 0xd2, 0x26, 0xaf, 0x72, 0x2b, 0xe1, 0x3b, 0xe3, 0xf3, 0xea, 0x6d, 0x8e, - 0x6f, 0x5b, 0xbf, 0x9d, 0x1f, 0x0c, 0xcc, 0xcc, 0x0e, 0xe8, 0xf1, 0xe7, 0x92, 0xfa, 0xa5, 0x02, - 0x2b, 0xc5, 0x09, 0xdc, 0x2a, 0x6e, 0x8d, 0xfc, 0xba, 0xb6, 0xfd, 0xe6, 0xf5, 0x14, 0xc9, 0x36, - 0x47, 0xb2, 0xa1, 0xb7, 0x72, 0x3b, 0x87, 0x3b, 0x9b, 0x99, 0x49, 0x75, 0xf0, 0xf1, 0xf3, 0x57, - 0x2d, 0xe5, 0xc5, 0xab, 0x96, 0xf2, 0xf7, 0xab, 0x96, 0xf2, 0xed, 0xeb, 0xd6, 0xcc, 0x8b, 0xd7, - 0xad, 0x99, 0x3f, 0x5e, 0xb7, 0x66, 0x3e, 0xbf, 0x57, 0xbe, 0xfb, 0xc9, 0x50, 0xbb, 0xe2, 0x43, - 0xc7, 0x08, 0x89, 0x33, 0x0c, 0xd0, 0x78, 0x9a, 0xa6, 0xe0, 0x17, 0xc2, 0xfe, 0x02, 0xff, 0x1e, - 0x7e, 0xe7, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa9, 0x09, 0x75, 0xd0, 0x88, 0x0f, 0x00, 0x00, + // 1374 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4f, 0x6f, 0xdc, 0x54, + 0x10, 0x8f, 0x93, 0x4d, 0xda, 0xcc, 0x6e, 0x9a, 0xd6, 0xa4, 0xe9, 0xc6, 0x49, 0x77, 0x13, 0xb7, + 0x49, 0x8a, 0x44, 0x76, 0x9b, 0x20, 0xd4, 0x1b, 0x88, 0x24, 0xad, 0xa8, 0x44, 0x8a, 0xd8, 0x40, + 0x91, 0xb8, 0x58, 0x5e, 0x7b, 0x6a, 0x5b, 0xb5, 0xfd, 0x16, 0xbf, 0xb7, 0x9b, 0xe6, 0x52, 0x09, + 0xae, 0xe5, 0x00, 0xe2, 0x0a, 0x12, 0xdf, 0x80, 0x3b, 0x47, 0x4e, 0x3d, 0xa1, 0x4a, 0x5c, 0xf8, + 0x23, 0x55, 0xa8, 0xe5, 0x83, 0x20, 0xbf, 0xf7, 0xd6, 0xeb, 0x7f, 0x9b, 0x04, 0x29, 0x9c, 0xb2, + 0x9e, 0x37, 0x9e, 0xf9, 0xfd, 0x66, 0xe6, 0xcd, 0x8c, 0x03, 0x57, 0x9d, 0xc8, 0x1c, 0x78, 0xec, + 0xb8, 0x3d, 0xd8, 0x6e, 0x07, 0xd4, 0xa1, 0xad, 0x5e, 0x44, 0x18, 0x51, 0x41, 0x8a, 0x5b, 0x83, + 0x6d, 0xad, 0x61, 0x11, 0x1a, 0x10, 0xda, 0xee, 0x9a, 0x14, 0xdb, 0x83, 0xed, 0x2e, 0x32, 0x73, + 0xbb, 0x6d, 0x11, 0x2f, 0x14, 0xba, 0xda, 0x82, 0x43, 0x1c, 0xc2, 0x7f, 0xb6, 0xe3, 0x5f, 0x52, + 0xba, 0xe2, 0x10, 0xe2, 0xf8, 0xd8, 0x36, 0x7b, 0x5e, 0xdb, 0x0c, 0x43, 0xc2, 0x4c, 0xe6, 0x91, + 0x50, 0xda, 0xd7, 0x16, 0x53, 0x6e, 0xd9, 0x71, 0x0f, 0xa5, 0x5c, 0x7f, 0x0a, 0x4b, 0x07, 0xd4, + 0x39, 0x44, 0xf6, 0x51, 0x64, 0xb9, 0x48, 0x59, 0x64, 0x32, 0x12, 0xbd, 0x6f, 0xdb, 0x11, 0x52, + 0xaa, 0xae, 0xc0, 0xec, 0xc0, 0xf4, 0x3d, 0x3b, 0x96, 0xd5, 0x95, 0x55, 0xe5, 0xd6, 0x6c, 0x67, + 0x24, 0x50, 0x75, 0xa8, 0x91, 0xd4, 0x4b, 0xf5, 0x49, 0xae, 0x90, 0x91, 0xa9, 0x4d, 0xa8, 0x22, + 0x73, 0x0d, 0x53, 0x18, 0xac, 0x4f, 0x71, 0x15, 0x40, 0xe6, 0x4a, 0x17, 0xfa, 0x0d, 0x58, 0x1b, + 0xeb, 0xbf, 0x83, 0xb4, 0x47, 0x42, 0x8a, 0xfa, 0x33, 0x05, 0x2e, 0x1f, 0x50, 0xe7, 0xa1, 0xe9, + 0x53, 0x64, 0x7b, 0x24, 0x7c, 0xe4, 0x45, 0x81, 0xba, 0x00, 0xd3, 0x21, 0x09, 0x2d, 0xe4, 0xc0, + 0x2a, 0x1d, 0xf1, 0x70, 0x2e, 0xa0, 0x62, 0xde, 0xd4, 0x73, 0x42, 0x93, 0xf5, 0x23, 0xac, 0x57, + 0x04, 0xef, 0x44, 0xa0, 0x6b, 0x50, 0xcf, 0x83, 0x49, 0x90, 0xfe, 0xac, 0x40, 0x8d, 0xf3, 0x09, + 0xed, 0x4f, 0xc8, 0x5d, 0xe6, 0xaa, 0x8b, 0x30, 0x43, 0x31, 0xb4, 0x71, 0x18, 0x3f, 0xf9, 0xa4, + 0x2e, 0xc1, 0xc5, 0x18, 0x83, 0x8d, 0x94, 0x49, 0x8c, 0x17, 0x90, 0xb9, 0xfb, 0x48, 0x99, 0x7a, + 0x07, 0x66, 0xcc, 0x80, 0xf4, 0x43, 0xc6, 0x91, 0x55, 0x77, 0x96, 0x5a, 0xa2, 0x1e, 0x5a, 0x71, + 0x3d, 0xb4, 0x64, 0x3d, 0xb4, 0xf6, 0x88, 0x17, 0xee, 0x56, 0x9e, 0xbf, 0x6c, 0x4e, 0x74, 0xa4, + 0xba, 0xfa, 0x2e, 0x40, 0x37, 0xf2, 0x6c, 0x07, 0x8d, 0x47, 0x28, 0x70, 0x9f, 0xe1, 0xe5, 0x59, + 0xf1, 0xca, 0x3d, 0x44, 0x7d, 0x11, 0x16, 0xd2, 0xd8, 0x13, 0x52, 0xef, 0xc1, 0xfc, 0x01, 0x75, + 0x3a, 0xf8, 0x45, 0x1f, 0x29, 0xdb, 0x35, 0x99, 0x35, 0x9e, 0xd6, 0x02, 0x4c, 0xdb, 0x18, 0x92, + 0x40, 0x72, 0x12, 0x0f, 0xfa, 0x12, 0x5c, 0xcb, 0x19, 0x48, 0x6c, 0xff, 0xa4, 0x70, 0xe3, 0x32, + 0x8e, 0xc2, 0x78, 0x79, 0x66, 0xd7, 0xe1, 0x12, 0x23, 0x8f, 0x31, 0x34, 0x2c, 0x12, 0xb2, 0xc8, + 0xb4, 0x86, 0x71, 0x9b, 0xe3, 0xd2, 0x3d, 0x29, 0x54, 0xaf, 0x43, 0x9c, 0x49, 0x23, 0x4e, 0x17, + 0x46, 0x32, 0xb7, 0xb3, 0xc8, 0xdc, 0x43, 0x2e, 0x28, 0xd4, 0x47, 0xa5, 0xa4, 0x3e, 0x32, 0xe9, + 0x9f, 0xce, 0xa7, 0x5f, 0x90, 0x49, 0x03, 0x4e, 0xc8, 0xfc, 0xaa, 0xc0, 0x1b, 0xa3, 0xb3, 0x0f, + 0x89, 0xe3, 0x59, 0x7b, 0xa6, 0xef, 0xab, 0x9b, 0x30, 0xef, 0x85, 0xf2, 0xe2, 0x78, 0x24, 0x34, + 0x3c, 0x5b, 0x86, 0xed, 0x52, 0x5a, 0x7c, 0xdf, 0x56, 0xb7, 0x40, 0xcd, 0x28, 0x8a, 0x30, 0x4c, + 0xf2, 0x30, 0x5c, 0x49, 0x9f, 0x3c, 0xe0, 0x21, 0xf9, 0xdf, 0xb9, 0x5e, 0x87, 0xe5, 0x12, 0x3e, + 0xa3, 0x6a, 0x9f, 0xe4, 0xc9, 0xdb, 0xc7, 0x1e, 0xa1, 0x1e, 0xdb, 0xf3, 0x4d, 0x2f, 0xe0, 0x97, + 0x6b, 0x80, 0x21, 0x33, 0xd2, 0x29, 0x04, 0x2e, 0x12, 0xa0, 0xd7, 0xa0, 0xd6, 0xf5, 0x89, 0xf5, + 0xd8, 0x70, 0xd1, 0x73, 0x5c, 0x26, 0xd9, 0x55, 0xb9, 0xec, 0x03, 0x2e, 0x2a, 0x49, 0xf5, 0x54, + 0x59, 0xaa, 0xef, 0x25, 0x17, 0x85, 0x33, 0xdb, 0x6d, 0xc5, 0x05, 0xfd, 0xe7, 0xcb, 0xe6, 0x86, + 0xe3, 0x31, 0xb7, 0xdf, 0x6d, 0x59, 0x24, 0x68, 0xcb, 0x56, 0x2a, 0xfe, 0x6c, 0x51, 0xfb, 0xb1, + 0xec, 0x7e, 0xf7, 0x43, 0x96, 0xdc, 0x9b, 0x4d, 0x98, 0x47, 0xe6, 0x62, 0x84, 0xfd, 0xc0, 0x90, + 0x55, 0x2d, 0x22, 0x71, 0x69, 0x28, 0x3e, 0x14, 0xd5, 0xbd, 0x09, 0xf3, 0xc2, 0x90, 0x11, 0xa1, + 0x85, 0xde, 0x00, 0xa3, 0xfa, 0x8c, 0x50, 0x14, 0xe2, 0x8e, 0x94, 0x16, 0x22, 0x7f, 0xa1, 0x18, + 0x79, 0x59, 0x47, 0xe9, 0xd8, 0x25, 0x71, 0xfd, 0x45, 0xf4, 0xbb, 0xcf, 0x3c, 0xe6, 0xda, 0x91, + 0x79, 0x74, 0x7e, 0x81, 0x6d, 0x42, 0xb5, 0x1b, 0x57, 0xac, 0xb4, 0x31, 0x25, 0x6c, 0x70, 0xd1, + 0x83, 0x31, 0x97, 0xac, 0x52, 0x16, 0xf9, 0x3c, 0xbf, 0xe9, 0x12, 0x7e, 0xa2, 0x4d, 0x66, 0x38, + 0x24, 0x04, 0xbf, 0x9d, 0x84, 0xab, 0x07, 0xd4, 0xb9, 0xdb, 0xd9, 0xdb, 0xb9, 0xbd, 0x8f, 0x3d, + 0x9f, 0x1c, 0xa3, 0x7d, 0x7e, 0x2c, 0xd7, 0xa0, 0x26, 0xd3, 0x24, 0x7a, 0x91, 0x28, 0x9e, 0xaa, + 0x90, 0xed, 0xc7, 0xa2, 0xb3, 0xf2, 0x54, 0xa1, 0x12, 0x9a, 0xc1, 0xf0, 0x62, 0xf0, 0xdf, 0xbc, + 0xf5, 0x1d, 0x07, 0x5d, 0xe2, 0xcb, 0xdc, 0xcb, 0x27, 0x55, 0x83, 0x8b, 0x36, 0x5a, 0x5e, 0x60, + 0xfa, 0x94, 0xe7, 0xbb, 0xd2, 0x49, 0x9e, 0x0b, 0xf1, 0xba, 0x58, 0x12, 0xaf, 0x26, 0x5c, 0x2f, + 0x0d, 0x49, 0x12, 0xb4, 0xbf, 0x14, 0x3e, 0xab, 0x93, 0x6b, 0x78, 0xf7, 0x09, 0x5a, 0x7d, 0x76, + 0x9e, 0x81, 0x2b, 0xe9, 0x53, 0x71, 0xec, 0x6a, 0x67, 0xec, 0x53, 0x95, 0x71, 0x7d, 0xea, 0x2c, + 0xe5, 0x22, 0x16, 0x81, 0x72, 0x72, 0x49, 0x08, 0xfe, 0x50, 0x78, 0xdd, 0x88, 0xd9, 0xfb, 0x69, + 0xcf, 0x36, 0xff, 0x13, 0xfd, 0x01, 0x7f, 0x2d, 0xd3, 0x54, 0xab, 0x42, 0x56, 0x1e, 0xa1, 0xa9, + 0x62, 0x84, 0xde, 0x81, 0x0b, 0x01, 0x06, 0x5d, 0x8c, 0x68, 0xbd, 0xb2, 0x3a, 0x75, 0xab, 0xba, + 0xb3, 0xdc, 0x1a, 0x2d, 0x6e, 0xad, 0x5d, 0x3e, 0x4a, 0x1f, 0x0e, 0x37, 0xa4, 0xce, 0x50, 0xb7, + 0x10, 0x80, 0x99, 0xb1, 0xf9, 0x2f, 0x52, 0x4b, 0xc8, 0x1f, 0x82, 0x1a, 0x37, 0x63, 0x33, 0xb4, + 0xd0, 0x1f, 0x2d, 0x18, 0x71, 0x25, 0x47, 0x66, 0x48, 0x4d, 0x2b, 0x3d, 0x5a, 0x2a, 0x9d, 0xb9, + 0x94, 0xf4, 0xbe, 0x9d, 0x1a, 0xd8, 0x93, 0xe9, 0x81, 0xad, 0xaf, 0x80, 0x56, 0x34, 0x3a, 0x74, + 0xb9, 0xf3, 0x63, 0x0d, 0xa6, 0x0e, 0xa8, 0xa3, 0x1e, 0xc1, 0x5c, 0x76, 0xf9, 0x5a, 0x49, 0xd3, + 0xce, 0x6f, 0x43, 0xda, 0xcd, 0x93, 0x4e, 0x13, 0x3e, 0xfa, 0x57, 0xbf, 0xfd, 0xf3, 0xdd, 0xe4, + 0x8a, 0xae, 0xb5, 0x53, 0xbb, 0xa9, 0xcc, 0x91, 0x25, 0xfd, 0xb8, 0x30, 0x3b, 0xa2, 0x5a, 0xcf, + 0x99, 0x4d, 0x4e, 0xb4, 0xd5, 0x71, 0x27, 0x89, 0xb3, 0x26, 0x77, 0xb6, 0xa4, 0x5f, 0x4b, 0x3b, + 0x8b, 0x63, 0x60, 0x30, 0x62, 0x20, 0x73, 0x55, 0x0a, 0xb5, 0xcc, 0x86, 0xb3, 0x9c, 0x33, 0x99, + 0x3e, 0xd4, 0x6e, 0x9c, 0x70, 0x98, 0xb8, 0x5c, 0xe3, 0x2e, 0x97, 0xf5, 0xa5, 0xb4, 0xcb, 0x48, + 0x68, 0x1a, 0xbc, 0xe7, 0xc6, 0x4e, 0x33, 0x9b, 0x4f, 0xde, 0x69, 0xfa, 0xb0, 0xe0, 0xb4, 0x74, + 0x05, 0x29, 0x75, 0x2a, 0xa3, 0x29, 0x9d, 0x3e, 0x85, 0xcb, 0x85, 0x0d, 0xa5, 0x59, 0x6e, 0x3b, + 0x51, 0xd0, 0x36, 0x4f, 0x51, 0x48, 0x00, 0xac, 0x72, 0x00, 0x9a, 0x5e, 0x2f, 0x00, 0x08, 0x0c, + 0x3f, 0xd6, 0x8e, 0x49, 0x67, 0x36, 0x86, 0x3c, 0xe9, 0xf4, 0x61, 0x81, 0x74, 0xe9, 0xbc, 0x2c, + 0x25, 0x6d, 0x0b, 0x4d, 0xc3, 0xe2, 0x4e, 0x8e, 0x60, 0x2e, 0x3b, 0x4e, 0xf3, 0x15, 0x9c, 0x39, + 0x2d, 0x54, 0x70, 0xf9, 0x18, 0x2b, 0xad, 0xe0, 0x23, 0xa9, 0x2a, 0x1d, 0x3f, 0x53, 0xe0, 0x4a, + 0xfa, 0x52, 0x0b, 0xef, 0x6b, 0xa5, 0x37, 0x24, 0x7d, 0xed, 0xb5, 0x37, 0x4f, 0x55, 0x49, 0x70, + 0xdc, 0xe2, 0x38, 0x74, 0x7d, 0xb5, 0xe4, 0x26, 0xf5, 0xc5, 0x0b, 0x12, 0xcd, 0xd7, 0x0a, 0xa8, + 0x25, 0x53, 0x37, 0x0f, 0xa7, 0xa8, 0x52, 0x80, 0x73, 0xc2, 0xa0, 0x2a, 0x85, 0x83, 0x91, 0xb5, + 0x73, 0xdb, 0xb0, 0xe5, 0x0b, 0x12, 0xce, 0x0f, 0x0a, 0x2c, 0x8e, 0x99, 0x67, 0xeb, 0x39, 0x7f, + 0xe5, 0x6a, 0xda, 0xd6, 0x99, 0xd4, 0x12, 0x68, 0x5b, 0x1c, 0xda, 0xa6, 0xbe, 0x9e, 0x86, 0xc6, + 0xcb, 0xd2, 0xb0, 0x4c, 0xdf, 0x37, 0x50, 0xbe, 0x25, 0xf1, 0x7d, 0xaf, 0xc0, 0xe2, 0x98, 0x6f, + 0xe3, 0xf5, 0x42, 0xcb, 0x29, 0x53, 0x2b, 0xe0, 0x3b, 0xe5, 0x4b, 0xf7, 0x2d, 0x8e, 0x6f, 0x43, + 0xbf, 0x99, 0x6d, 0x53, 0xcc, 0x48, 0x8f, 0x8a, 0xe1, 0x97, 0xab, 0xfa, 0xa5, 0x02, 0xf3, 0xf9, + 0x79, 0xd0, 0xc8, 0x5f, 0xd4, 0xec, 0xb9, 0xb6, 0x71, 0xf2, 0x79, 0x82, 0x64, 0x83, 0x23, 0x59, + 0xd5, 0x1b, 0x99, 0x7b, 0xcc, 0x95, 0x8d, 0x54, 0xdf, 0xdc, 0xfd, 0xf8, 0xf9, 0xab, 0x86, 0xf2, + 0xe2, 0x55, 0x43, 0xf9, 0xfb, 0x55, 0x43, 0xf9, 0xe6, 0x75, 0x63, 0xe2, 0xc5, 0xeb, 0xc6, 0xc4, + 0xef, 0xaf, 0x1b, 0x13, 0x9f, 0xdf, 0x29, 0xae, 0xe1, 0xd2, 0xd4, 0x96, 0xf8, 0xe6, 0x6c, 0x07, + 0xc4, 0xee, 0xfb, 0xd8, 0x7e, 0x92, 0xb8, 0xe0, 0xbb, 0x79, 0x77, 0x86, 0xff, 0x6b, 0xe2, 0xed, + 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xec, 0xf5, 0x0a, 0x6c, 0x2b, 0x11, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1426,6 +1548,7 @@ type MsgClient interface { ConfirmLogicCall(ctx context.Context, in *MsgConfirmLogicCall, opts ...grpc.CallOption) (*MsgConfirmLogicCallResponse, error) DepositClaim(ctx context.Context, in *MsgDepositClaim, opts ...grpc.CallOption) (*MsgDepositClaimResponse, error) WithdrawClaim(ctx context.Context, in *MsgWithdrawClaim, opts ...grpc.CallOption) (*MsgWithdrawClaimResponse, error) + ValsetUpdateClaim(ctx context.Context, in *MsgValsetUpdatedClaim, opts ...grpc.CallOption) (*MsgValsetUpdatedClaimResponse, error) ERC20DeployedClaim(ctx context.Context, in *MsgERC20DeployedClaim, opts ...grpc.CallOption) (*MsgERC20DeployedClaimResponse, error) LogicCallExecutedClaim(ctx context.Context, in *MsgLogicCallExecutedClaim, opts ...grpc.CallOption) (*MsgLogicCallExecutedClaimResponse, error) SetOrchestratorAddress(ctx context.Context, in *MsgSetOrchestratorAddress, opts ...grpc.CallOption) (*MsgSetOrchestratorAddressResponse, error) @@ -1503,6 +1626,15 @@ func (c *msgClient) WithdrawClaim(ctx context.Context, in *MsgWithdrawClaim, opt return out, nil } +func (c *msgClient) ValsetUpdateClaim(ctx context.Context, in *MsgValsetUpdatedClaim, opts ...grpc.CallOption) (*MsgValsetUpdatedClaimResponse, error) { + out := new(MsgValsetUpdatedClaimResponse) + err := c.cc.Invoke(ctx, "/gravity.v1.Msg/ValsetUpdateClaim", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) ERC20DeployedClaim(ctx context.Context, in *MsgERC20DeployedClaim, opts ...grpc.CallOption) (*MsgERC20DeployedClaimResponse, error) { out := new(MsgERC20DeployedClaimResponse) err := c.cc.Invoke(ctx, "/gravity.v1.Msg/ERC20DeployedClaim", in, out, opts...) @@ -1548,6 +1680,7 @@ type MsgServer interface { ConfirmLogicCall(context.Context, *MsgConfirmLogicCall) (*MsgConfirmLogicCallResponse, error) DepositClaim(context.Context, *MsgDepositClaim) (*MsgDepositClaimResponse, error) WithdrawClaim(context.Context, *MsgWithdrawClaim) (*MsgWithdrawClaimResponse, error) + ValsetUpdateClaim(context.Context, *MsgValsetUpdatedClaim) (*MsgValsetUpdatedClaimResponse, error) ERC20DeployedClaim(context.Context, *MsgERC20DeployedClaim) (*MsgERC20DeployedClaimResponse, error) LogicCallExecutedClaim(context.Context, *MsgLogicCallExecutedClaim) (*MsgLogicCallExecutedClaimResponse, error) SetOrchestratorAddress(context.Context, *MsgSetOrchestratorAddress) (*MsgSetOrchestratorAddressResponse, error) @@ -1579,6 +1712,9 @@ func (*UnimplementedMsgServer) DepositClaim(ctx context.Context, req *MsgDeposit func (*UnimplementedMsgServer) WithdrawClaim(ctx context.Context, req *MsgWithdrawClaim) (*MsgWithdrawClaimResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method WithdrawClaim not implemented") } +func (*UnimplementedMsgServer) ValsetUpdateClaim(ctx context.Context, req *MsgValsetUpdatedClaim) (*MsgValsetUpdatedClaimResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ValsetUpdateClaim not implemented") +} func (*UnimplementedMsgServer) ERC20DeployedClaim(ctx context.Context, req *MsgERC20DeployedClaim) (*MsgERC20DeployedClaimResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ERC20DeployedClaim not implemented") } @@ -1722,6 +1858,24 @@ func _Msg_WithdrawClaim_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } +func _Msg_ValsetUpdateClaim_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgValsetUpdatedClaim) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ValsetUpdateClaim(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gravity.v1.Msg/ValsetUpdateClaim", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ValsetUpdateClaim(ctx, req.(*MsgValsetUpdatedClaim)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_ERC20DeployedClaim_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgERC20DeployedClaim) if err := dec(in); err != nil { @@ -1826,6 +1980,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "WithdrawClaim", Handler: _Msg_WithdrawClaim_Handler, }, + { + MethodName: "ValsetUpdateClaim", + Handler: _Msg_ValsetUpdateClaim_Handler, + }, { MethodName: "ERC20DeployedClaim", Handler: _Msg_ERC20DeployedClaim_Handler, @@ -2624,6 +2782,88 @@ func (m *MsgLogicCallExecutedClaimResponse) MarshalToSizedBuffer(dAtA []byte) (i return len(dAtA) - i, nil } +func (m *MsgValsetUpdatedClaim) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgValsetUpdatedClaim) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgValsetUpdatedClaim) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Orchestrator) > 0 { + i -= len(m.Orchestrator) + copy(dAtA[i:], m.Orchestrator) + i = encodeVarintMsgs(dAtA, i, uint64(len(m.Orchestrator))) + i-- + dAtA[i] = 0x32 + } + if len(m.Members) > 0 { + for iNdEx := len(m.Members) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Members[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMsgs(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if m.BlockHeight != 0 { + i = encodeVarintMsgs(dAtA, i, uint64(m.BlockHeight)) + i-- + dAtA[i] = 0x18 + } + if m.ValsetNonce != 0 { + i = encodeVarintMsgs(dAtA, i, uint64(m.ValsetNonce)) + i-- + dAtA[i] = 0x10 + } + if m.EventNonce != 0 { + i = encodeVarintMsgs(dAtA, i, uint64(m.EventNonce)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgValsetUpdatedClaimResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgValsetUpdatedClaimResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgValsetUpdatedClaimResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func (m *MsgCancelSendToEth) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -3045,6 +3285,43 @@ func (m *MsgLogicCallExecutedClaimResponse) Size() (n int) { return n } +func (m *MsgValsetUpdatedClaim) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.EventNonce != 0 { + n += 1 + sovMsgs(uint64(m.EventNonce)) + } + if m.ValsetNonce != 0 { + n += 1 + sovMsgs(uint64(m.ValsetNonce)) + } + if m.BlockHeight != 0 { + n += 1 + sovMsgs(uint64(m.BlockHeight)) + } + if len(m.Members) > 0 { + for _, e := range m.Members { + l = e.Size() + n += 1 + l + sovMsgs(uint64(l)) + } + } + l = len(m.Orchestrator) + if l > 0 { + n += 1 + l + sovMsgs(uint64(l)) + } + return n +} + +func (m *MsgValsetUpdatedClaimResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func (m *MsgCancelSendToEth) Size() (n int) { if m == nil { return 0 @@ -5496,6 +5773,235 @@ func (m *MsgLogicCallExecutedClaimResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgValsetUpdatedClaim) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgValsetUpdatedClaim: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgValsetUpdatedClaim: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EventNonce", wireType) + } + m.EventNonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EventNonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ValsetNonce", wireType) + } + m.ValsetNonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ValsetNonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHeight", wireType) + } + m.BlockHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlockHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Members", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMsgs + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Members = append(m.Members, &BridgeValidator{}) + if err := m.Members[len(m.Members)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Orchestrator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Orchestrator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMsgs(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthMsgs + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthMsgs + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgValsetUpdatedClaimResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgValsetUpdatedClaimResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgValsetUpdatedClaimResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipMsgs(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthMsgs + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthMsgs + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MsgCancelSendToEth) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 From fcf01c48d8055f3bde01ea9691d73c5951c739f4 Mon Sep 17 00:00:00 2001 From: Justin Kilpatrick Date: Tue, 13 Apr 2021 11:23:03 -0400 Subject: [PATCH 5/7] Update Orchestrator oracle to relay validator sets --- orchestrator/cosmos_gravity/src/send.rs | 38 ++++++++++----- .../gravity_proto/src/prost/gravity.v1.rs | 21 +++++++- .../src/types/ethereum_events.rs | 48 ++++++++++++++----- .../gravity_utils/src/types/valsets.rs | 13 +++++ .../src/ethereum_event_watcher.rs | 8 ++++ .../orchestrator/src/oracle_resync.rs | 17 +++++-- orchestrator/test_runner/src/happy_path.rs | 5 +- 7 files changed, 120 insertions(+), 30 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/send.rs b/orchestrator/cosmos_gravity/src/send.rs index bdffaa341..a902c3f57 100644 --- a/orchestrator/cosmos_gravity/src/send.rs +++ b/orchestrator/cosmos_gravity/src/send.rs @@ -21,6 +21,7 @@ use gravity_proto::gravity::MsgRequestBatch; use gravity_proto::gravity::MsgSendToEth; use gravity_proto::gravity::MsgSetOrchestratorAddress; use gravity_proto::gravity::MsgValsetConfirm; +use gravity_proto::gravity::MsgValsetUpdatedClaim; use gravity_proto::gravity::MsgWithdrawClaim; use gravity_utils::message_signatures::{ encode_logic_call_confirm, encode_tx_batch_confirm, encode_valset_confirm, @@ -267,6 +268,7 @@ pub async fn send_logic_call_confirm( .await } +#[allow(clippy::clippy::too_many_arguments)] pub async fn send_ethereum_claims( contact: &Contact, private_key: PrivateKey, @@ -274,6 +276,7 @@ pub async fn send_ethereum_claims( withdraws: Vec, erc20_deploys: Vec, logic_calls: Vec, + valsets: Vec, fee: Coin, ) -> Result { let our_address = private_key.to_address(&contact.get_prefix()).unwrap(); @@ -289,7 +292,7 @@ pub async fn send_ethereum_claims( let mut unordered_msgs = HashMap::new(); for deposit in deposits { let claim = MsgDepositClaim { - event_nonce: downcast_uint256(deposit.event_nonce.clone()).unwrap(), + event_nonce: deposit.event_nonce, block_height: downcast_uint256(deposit.block_height).unwrap(), token_contract: deposit.erc20.to_string(), amount: deposit.amount.to_string(), @@ -298,22 +301,22 @@ pub async fn send_ethereum_claims( orchestrator: our_address.to_string(), }; let msg = Msg::new("/gravity.v1.MsgDepositClaim", claim); - unordered_msgs.insert(deposit.event_nonce.clone(), msg); + unordered_msgs.insert(deposit.event_nonce, msg); } for withdraw in withdraws { let claim = MsgWithdrawClaim { - event_nonce: downcast_uint256(withdraw.event_nonce.clone()).unwrap(), + event_nonce: withdraw.event_nonce, block_height: downcast_uint256(withdraw.block_height).unwrap(), token_contract: withdraw.erc20.to_string(), - batch_nonce: downcast_uint256(withdraw.batch_nonce).unwrap(), + batch_nonce: withdraw.batch_nonce, orchestrator: our_address.to_string(), }; let msg = Msg::new("/gravity.v1.MsgWithdrawClaim", claim); - unordered_msgs.insert(withdraw.event_nonce.clone(), msg); + unordered_msgs.insert(withdraw.event_nonce, msg); } for deploy in erc20_deploys { let claim = MsgErc20DeployedClaim { - event_nonce: downcast_uint256(deploy.event_nonce.clone()).unwrap(), + event_nonce: deploy.event_nonce, block_height: downcast_uint256(deploy.block_height).unwrap(), cosmos_denom: deploy.cosmos_denom, token_contract: deploy.erc20_address.to_string(), @@ -323,24 +326,35 @@ pub async fn send_ethereum_claims( orchestrator: our_address.to_string(), }; let msg = Msg::new("/gravity.v1.MsgERC20DeployedClaim", claim); - unordered_msgs.insert(deploy.event_nonce.clone(), msg); + unordered_msgs.insert(deploy.event_nonce, msg); } for call in logic_calls { let claim = MsgLogicCallExecutedClaim { - event_nonce: downcast_uint256(call.event_nonce.clone()).unwrap(), + event_nonce: call.event_nonce, block_height: downcast_uint256(call.block_height).unwrap(), invalidation_id: call.invalidation_id, - invalidation_nonce: downcast_uint256(call.invalidation_nonce).unwrap(), + invalidation_nonce: call.invalidation_nonce, orchestrator: our_address.to_string(), }; let msg = Msg::new("/gravity.v1.MsgLogicCallExecutedClaim", claim); - unordered_msgs.insert(call.event_nonce.clone(), msg); + unordered_msgs.insert(call.event_nonce, msg); + } + for valset in valsets { + let claim = MsgValsetUpdatedClaim { + event_nonce: valset.event_nonce, + valset_nonce: valset.valset_nonce, + block_height: downcast_uint256(valset.block_height).unwrap(), + members: valset.members.iter().map(|v| v.into()).collect(), + orchestrator: our_address.to_string(), + }; + let msg = Msg::new("/gravity.v1.MsgValsetUpdatedClaim", claim); + unordered_msgs.insert(valset.event_nonce, msg); } let mut keys = Vec::new(); for (key, _) in unordered_msgs.iter() { - keys.push(key.clone()); + keys.push(*key); } - keys.sort(); + keys.sort_unstable(); let mut msgs = Vec::new(); for i in keys { diff --git a/orchestrator/gravity_proto/src/prost/gravity.v1.rs b/orchestrator/gravity_proto/src/prost/gravity.v1.rs index 7a7a4c2fb..e8bd2df3d 100644 --- a/orchestrator/gravity_proto/src/prost/gravity.v1.rs +++ b/orchestrator/gravity_proto/src/prost/gravity.v1.rs @@ -46,6 +46,7 @@ pub enum ClaimType { Withdraw = 2, Erc20Deployed = 3, LogicCallExecuted = 4, + ValsetUpdated = 5, } /// IDSet represents a set of IDs #[derive(Clone, PartialEq, ::prost::Message)] @@ -388,6 +389,24 @@ pub struct MsgLogicCallExecutedClaim { #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgLogicCallExecutedClaimResponse { } +/// This informs the Cosmos module that a validator +/// set has been updated. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgValsetUpdatedClaim { + #[prost(uint64, tag="1")] + pub event_nonce: u64, + #[prost(uint64, tag="2")] + pub valset_nonce: u64, + #[prost(uint64, tag="3")] + pub block_height: u64, + #[prost(message, repeated, tag="4")] + pub members: ::prost::alloc::vec::Vec, + #[prost(string, tag="6")] + pub orchestrator: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgValsetUpdatedClaimResponse { +} /// This call allows the sender (and only the sender) /// to cancel a given MsgSendToEth and recieve a refund /// of the tokens @@ -401,7 +420,7 @@ pub struct MsgCancelSendToEth { #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgCancelSendToEthResponse { } -# [doc = r" Generated client implementations."] pub mod msg_client { # ! [allow (unused_variables , dead_code , missing_docs)] use tonic :: codegen :: * ; # [doc = " Msg defines the state transitions possible within gravity"] pub struct MsgClient < T > { inner : tonic :: client :: Grpc < T > , } impl MsgClient < tonic :: transport :: Channel > { # [doc = r" Attempt to create a new client by connecting to a given endpoint."] pub async fn connect < D > (dst : D) -> Result < Self , tonic :: transport :: Error > where D : std :: convert :: TryInto < tonic :: transport :: Endpoint > , D :: Error : Into < StdError > , { let conn = tonic :: transport :: Endpoint :: new (dst) ? . connect () . await ? ; Ok (Self :: new (conn)) } } impl < T > MsgClient < T > where T : tonic :: client :: GrpcService < tonic :: body :: BoxBody > , T :: ResponseBody : Body + HttpBody + Send + 'static , T :: Error : Into < StdError > , < T :: ResponseBody as HttpBody > :: Error : Into < StdError > + Send , { pub fn new (inner : T) -> Self { let inner = tonic :: client :: Grpc :: new (inner) ; Self { inner } } pub fn with_interceptor (inner : T , interceptor : impl Into < tonic :: Interceptor >) -> Self { let inner = tonic :: client :: Grpc :: with_interceptor (inner , interceptor) ; Self { inner } } pub async fn valset_confirm (& mut self , request : impl tonic :: IntoRequest < super :: MsgValsetConfirm > ,) -> Result < tonic :: Response < super :: MsgValsetConfirmResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/ValsetConfirm") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn send_to_eth (& mut self , request : impl tonic :: IntoRequest < super :: MsgSendToEth > ,) -> Result < tonic :: Response < super :: MsgSendToEthResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/SendToEth") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn request_batch (& mut self , request : impl tonic :: IntoRequest < super :: MsgRequestBatch > ,) -> Result < tonic :: Response < super :: MsgRequestBatchResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/RequestBatch") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn confirm_batch (& mut self , request : impl tonic :: IntoRequest < super :: MsgConfirmBatch > ,) -> Result < tonic :: Response < super :: MsgConfirmBatchResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/ConfirmBatch") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn confirm_logic_call (& mut self , request : impl tonic :: IntoRequest < super :: MsgConfirmLogicCall > ,) -> Result < tonic :: Response < super :: MsgConfirmLogicCallResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/ConfirmLogicCall") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn deposit_claim (& mut self , request : impl tonic :: IntoRequest < super :: MsgDepositClaim > ,) -> Result < tonic :: Response < super :: MsgDepositClaimResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/DepositClaim") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn withdraw_claim (& mut self , request : impl tonic :: IntoRequest < super :: MsgWithdrawClaim > ,) -> Result < tonic :: Response < super :: MsgWithdrawClaimResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/WithdrawClaim") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn erc20_deployed_claim (& mut self , request : impl tonic :: IntoRequest < super :: MsgErc20DeployedClaim > ,) -> Result < tonic :: Response < super :: MsgErc20DeployedClaimResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/ERC20DeployedClaim") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn logic_call_executed_claim (& mut self , request : impl tonic :: IntoRequest < super :: MsgLogicCallExecutedClaim > ,) -> Result < tonic :: Response < super :: MsgLogicCallExecutedClaimResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/LogicCallExecutedClaim") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn set_orchestrator_address (& mut self , request : impl tonic :: IntoRequest < super :: MsgSetOrchestratorAddress > ,) -> Result < tonic :: Response < super :: MsgSetOrchestratorAddressResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/SetOrchestratorAddress") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn cancel_send_to_eth (& mut self , request : impl tonic :: IntoRequest < super :: MsgCancelSendToEth > ,) -> Result < tonic :: Response < super :: MsgCancelSendToEthResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/CancelSendToEth") ; self . inner . unary (request . into_request () , path , codec) . await } } impl < T : Clone > Clone for MsgClient < T > { fn clone (& self) -> Self { Self { inner : self . inner . clone () , } } } impl < T > std :: fmt :: Debug for MsgClient < T > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "MsgClient {{ ... }}") } } }/// Params represent the Gravity genesis and store parameters +# [doc = r" Generated client implementations."] pub mod msg_client { # ! [allow (unused_variables , dead_code , missing_docs)] use tonic :: codegen :: * ; # [doc = " Msg defines the state transitions possible within gravity"] pub struct MsgClient < T > { inner : tonic :: client :: Grpc < T > , } impl MsgClient < tonic :: transport :: Channel > { # [doc = r" Attempt to create a new client by connecting to a given endpoint."] pub async fn connect < D > (dst : D) -> Result < Self , tonic :: transport :: Error > where D : std :: convert :: TryInto < tonic :: transport :: Endpoint > , D :: Error : Into < StdError > , { let conn = tonic :: transport :: Endpoint :: new (dst) ? . connect () . await ? ; Ok (Self :: new (conn)) } } impl < T > MsgClient < T > where T : tonic :: client :: GrpcService < tonic :: body :: BoxBody > , T :: ResponseBody : Body + HttpBody + Send + 'static , T :: Error : Into < StdError > , < T :: ResponseBody as HttpBody > :: Error : Into < StdError > + Send , { pub fn new (inner : T) -> Self { let inner = tonic :: client :: Grpc :: new (inner) ; Self { inner } } pub fn with_interceptor (inner : T , interceptor : impl Into < tonic :: Interceptor >) -> Self { let inner = tonic :: client :: Grpc :: with_interceptor (inner , interceptor) ; Self { inner } } pub async fn valset_confirm (& mut self , request : impl tonic :: IntoRequest < super :: MsgValsetConfirm > ,) -> Result < tonic :: Response < super :: MsgValsetConfirmResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/ValsetConfirm") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn send_to_eth (& mut self , request : impl tonic :: IntoRequest < super :: MsgSendToEth > ,) -> Result < tonic :: Response < super :: MsgSendToEthResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/SendToEth") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn request_batch (& mut self , request : impl tonic :: IntoRequest < super :: MsgRequestBatch > ,) -> Result < tonic :: Response < super :: MsgRequestBatchResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/RequestBatch") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn confirm_batch (& mut self , request : impl tonic :: IntoRequest < super :: MsgConfirmBatch > ,) -> Result < tonic :: Response < super :: MsgConfirmBatchResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/ConfirmBatch") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn confirm_logic_call (& mut self , request : impl tonic :: IntoRequest < super :: MsgConfirmLogicCall > ,) -> Result < tonic :: Response < super :: MsgConfirmLogicCallResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/ConfirmLogicCall") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn deposit_claim (& mut self , request : impl tonic :: IntoRequest < super :: MsgDepositClaim > ,) -> Result < tonic :: Response < super :: MsgDepositClaimResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/DepositClaim") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn withdraw_claim (& mut self , request : impl tonic :: IntoRequest < super :: MsgWithdrawClaim > ,) -> Result < tonic :: Response < super :: MsgWithdrawClaimResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/WithdrawClaim") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn valset_update_claim (& mut self , request : impl tonic :: IntoRequest < super :: MsgValsetUpdatedClaim > ,) -> Result < tonic :: Response < super :: MsgValsetUpdatedClaimResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/ValsetUpdateClaim") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn erc20_deployed_claim (& mut self , request : impl tonic :: IntoRequest < super :: MsgErc20DeployedClaim > ,) -> Result < tonic :: Response < super :: MsgErc20DeployedClaimResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/ERC20DeployedClaim") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn logic_call_executed_claim (& mut self , request : impl tonic :: IntoRequest < super :: MsgLogicCallExecutedClaim > ,) -> Result < tonic :: Response < super :: MsgLogicCallExecutedClaimResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/LogicCallExecutedClaim") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn set_orchestrator_address (& mut self , request : impl tonic :: IntoRequest < super :: MsgSetOrchestratorAddress > ,) -> Result < tonic :: Response < super :: MsgSetOrchestratorAddressResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/SetOrchestratorAddress") ; self . inner . unary (request . into_request () , path , codec) . await } pub async fn cancel_send_to_eth (& mut self , request : impl tonic :: IntoRequest < super :: MsgCancelSendToEth > ,) -> Result < tonic :: Response < super :: MsgCancelSendToEthResponse > , tonic :: Status > { self . inner . ready () . await . map_err (| e | { tonic :: Status :: new (tonic :: Code :: Unknown , format ! ("Service was not ready: {}" , e . into ())) }) ? ; let codec = tonic :: codec :: ProstCodec :: default () ; let path = http :: uri :: PathAndQuery :: from_static ("/gravity.v1.Msg/CancelSendToEth") ; self . inner . unary (request . into_request () , path , codec) . await } } impl < T : Clone > Clone for MsgClient < T > { fn clone (& self) -> Self { Self { inner : self . inner . clone () , } } } impl < T > std :: fmt :: Debug for MsgClient < T > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "MsgClient {{ ... }}") } } }/// Params represent the Gravity genesis and store parameters /// gravity_id: /// a random 32 byte value to prevent signature reuse, for example if the /// cosmos validators decided to use the same Ethereum keys for another chain diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 671766c84..85ccc3644 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -19,6 +19,7 @@ use web30::types::Log; pub struct ValsetUpdatedEvent { pub valset_nonce: u64, pub event_nonce: u64, + pub block_height: Uint256, pub members: Vec, } @@ -116,9 +117,19 @@ impl ValsetUpdatedEvent { ); } + let block_height = if let Some(bn) = input.block_number.clone() { + bn + } else { + return Err(GravityError::InvalidEventLogError( + "Log does not have block number, we only search logs already in blocks?" + .to_string(), + )); + }; + Ok(ValsetUpdatedEvent { valset_nonce, event_nonce, + block_height, members: validators, }) } @@ -129,6 +140,17 @@ impl ValsetUpdatedEvent { } Ok(res) } + /// returns all values in the array with event nonces greater + /// than the provided value + pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { + let mut ret = Vec::new(); + for item in input { + if item.event_nonce > event_nonce { + ret.push(item.clone()) + } + } + ret + } } /// A parsed struct representing the Ethereum event fired by the Gravity contract when @@ -137,7 +159,7 @@ impl ValsetUpdatedEvent { pub struct TransactionBatchExecutedEvent { /// the nonce attached to the transaction batch that follows /// it throughout it's lifecycle - pub batch_nonce: Uint256, + pub batch_nonce: u64, /// The block height this event occurred at pub block_height: Uint256, /// The ERC20 token contract address for the batch executed, since batches are uniform @@ -146,7 +168,7 @@ pub struct TransactionBatchExecutedEvent { /// the event nonce representing a unique ordering of events coming out /// of the Gravity solidity contract. Ensuring that these events can only be played /// back in order - pub event_nonce: Uint256, + pub event_nonce: u64, } impl TransactionBatchExecutedEvent { @@ -173,6 +195,8 @@ impl TransactionBatchExecutedEvent { "Event nonce overflow, probably incorrect parsing".to_string(), )) } else { + let batch_nonce: u64 = batch_nonce.to_string().parse().unwrap(); + let event_nonce: u64 = event_nonce.to_string().parse().unwrap(); Ok(TransactionBatchExecutedEvent { batch_nonce, block_height, @@ -198,7 +222,7 @@ impl TransactionBatchExecutedEvent { pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { let mut ret = Vec::new(); for item in input { - if item.event_nonce > event_nonce.into() { + if item.event_nonce > event_nonce { ret.push(item.clone()) } } @@ -219,7 +243,7 @@ pub struct SendToCosmosEvent { /// The amount of the erc20 token that is being sent pub amount: Uint256, /// The transaction's nonce, used to make sure there can be no accidental duplication - pub event_nonce: Uint256, + pub event_nonce: u64, /// The block height this event occurred at pub block_height: Uint256, } @@ -255,6 +279,7 @@ impl SendToCosmosEvent { "Event nonce overflow, probably incorrect parsing".to_string(), )) } else { + let event_nonce: u64 = event_nonce.to_string().parse().unwrap(); Ok(SendToCosmosEvent { erc20, sender, @@ -282,7 +307,7 @@ impl SendToCosmosEvent { pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { let mut ret = Vec::new(); for item in input { - if item.event_nonce > event_nonce.into() { + if item.event_nonce > event_nonce { ret.push(item.clone()) } } @@ -306,7 +331,7 @@ pub struct Erc20DeployedEvent { pub symbol: String, /// The number of decimals required to represent the smallest unit of this token pub decimals: u8, - pub event_nonce: Uint256, + pub event_nonce: u64, pub block_height: Uint256, } @@ -333,6 +358,7 @@ impl Erc20DeployedEvent { "Nonce overflow, probably incorrect parsing".to_string(), )); } + let event_nonce: u64 = nonce.to_string().parse().unwrap(); let index_start = 5 * 32; let index_end = index_start + 32; @@ -419,7 +445,7 @@ impl Erc20DeployedEvent { cosmos_denom: denom, name: erc20_name, decimals, - event_nonce: nonce, + event_nonce, erc20_address: erc20, symbol, block_height, @@ -442,7 +468,7 @@ impl Erc20DeployedEvent { pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { let mut ret = Vec::new(); for item in input { - if item.event_nonce > event_nonce.into() { + if item.event_nonce > event_nonce { ret.push(item.clone()) } } @@ -454,9 +480,9 @@ impl Erc20DeployedEvent { #[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Hash)] pub struct LogicCallExecutedEvent { pub invalidation_id: Vec, - pub invalidation_nonce: Uint256, + pub invalidation_nonce: u64, pub return_data: Vec, - pub event_nonce: Uint256, + pub event_nonce: u64, pub block_height: Uint256, } @@ -476,7 +502,7 @@ impl LogicCallExecutedEvent { pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { let mut ret = Vec::new(); for item in input { - if item.event_nonce > event_nonce.into() { + if item.event_nonce > event_nonce { ret.push(item.clone()) } } diff --git a/orchestrator/gravity_utils/src/types/valsets.rs b/orchestrator/gravity_utils/src/types/valsets.rs index 401ca8076..ce3228328 100644 --- a/orchestrator/gravity_utils/src/types/valsets.rs +++ b/orchestrator/gravity_utils/src/types/valsets.rs @@ -419,3 +419,16 @@ impl From<&gravity_proto::gravity::BridgeValidator> for ValsetMember { } } } + +impl From<&ValsetMember> for gravity_proto::gravity::BridgeValidator { + fn from(input: &ValsetMember) -> gravity_proto::gravity::BridgeValidator { + let ethereum_address = match input.eth_address { + Some(e) => e.to_string(), + None => String::new(), + }; + gravity_proto::gravity::BridgeValidator { + power: input.power, + ethereum_address, + } + } +} diff --git a/orchestrator/orchestrator/src/ethereum_event_watcher.rs b/orchestrator/orchestrator/src/ethereum_event_watcher.rs index 47301ec02..fa8a8a0ea 100644 --- a/orchestrator/orchestrator/src/ethereum_event_watcher.rs +++ b/orchestrator/orchestrator/src/ethereum_event_watcher.rs @@ -108,6 +108,7 @@ pub async fn check_for_events( // multi event block again. In theory we only send all events for every block and that will pass of fail // atomicly but lets not take that risk. let last_event_nonce = get_last_event_nonce(grpc_client, our_cosmos_address).await?; + let valsets = ValsetUpdatedEvent::filter_by_event_nonce(last_event_nonce, &valsets); let deposits = SendToCosmosEvent::filter_by_event_nonce(last_event_nonce, &deposits); let withdraws = TransactionBatchExecutedEvent::filter_by_event_nonce(last_event_nonce, &withdraws); @@ -116,6 +117,12 @@ pub async fn check_for_events( let logic_calls = LogicCallExecutedEvent::filter_by_event_nonce(last_event_nonce, &logic_calls); + if !valsets.is_empty() { + info!( + "Oracle observed Valset update with nonce {} and event nonce {}", + valsets[0].valset_nonce, valsets[0].event_nonce + ) + } if !deposits.is_empty() { info!( "Oracle observed deposit with sender {}, destination {}, amount {}, and event nonce {}", @@ -155,6 +162,7 @@ pub async fn check_for_events( withdraws, erc20_deploys, logic_calls, + valsets, fee, ) .await?; diff --git a/orchestrator/orchestrator/src/oracle_resync.rs b/orchestrator/orchestrator/src/oracle_resync.rs index a4ed0089f..5ea518256 100644 --- a/orchestrator/orchestrator/src/oracle_resync.rs +++ b/orchestrator/orchestrator/src/oracle_resync.rs @@ -120,7 +120,8 @@ pub async fn get_last_checked_block( for event in batch_events { match TransactionBatchExecutedEvent::from_log(&event) { Ok(batch) => { - if batch.event_nonce == last_event_nonce && event.block_number.is_some() { + if upcast(batch.event_nonce) == last_event_nonce && event.block_number.is_some() + { return event.block_number.unwrap(); } } @@ -130,7 +131,8 @@ pub async fn get_last_checked_block( for event in send_to_cosmos_events { match SendToCosmosEvent::from_log(&event) { Ok(send) => { - if send.event_nonce == last_event_nonce && event.block_number.is_some() { + if upcast(send.event_nonce) == last_event_nonce && event.block_number.is_some() + { return event.block_number.unwrap(); } } @@ -140,7 +142,9 @@ pub async fn get_last_checked_block( for event in erc20_deployed_events { match Erc20DeployedEvent::from_log(&event) { Ok(deploy) => { - if deploy.event_nonce == last_event_nonce && event.block_number.is_some() { + if upcast(deploy.event_nonce) == last_event_nonce + && event.block_number.is_some() + { return event.block_number.unwrap(); } } @@ -150,7 +154,8 @@ pub async fn get_last_checked_block( for event in logic_call_executed_events { match LogicCallExecutedEvent::from_log(&event) { Ok(call) => { - if call.event_nonce == last_event_nonce && event.block_number.is_some() { + if upcast(call.event_nonce) == last_event_nonce && event.block_number.is_some() + { return event.block_number.unwrap(); } } @@ -180,3 +185,7 @@ pub async fn get_last_checked_block( panic!("You have reached the end of block history without finding the Gravity contract deploy event! You must have the wrong contract address!"); } + +fn upcast(input: u64) -> Uint256 { + input.into() +} diff --git a/orchestrator/test_runner/src/happy_path.rs b/orchestrator/test_runner/src/happy_path.rs index c72c8fed7..ed7bbbbc9 100644 --- a/orchestrator/test_runner/src/happy_path.rs +++ b/orchestrator/test_runner/src/happy_path.rs @@ -85,7 +85,7 @@ pub async fn happy_path_test( // this test may have false positives if the timeout is not // long enough. TODO check for an error on the cosmos send response submit_duplicate_erc20_send( - 1u64.into(), + 1u64, &contact, erc20_address, 1u64.into(), @@ -425,7 +425,7 @@ async fn test_batch( // already been submitted to test the nonce functionality. #[allow(clippy::too_many_arguments)] async fn submit_duplicate_erc20_send( - nonce: Uint256, + nonce: u64, contact: &Contact, erc20_address: EthAddress, amount: Uint256, @@ -459,6 +459,7 @@ async fn submit_duplicate_erc20_send( vec![], vec![], vec![], + vec![], get_fee(), ) .await From 3548c96cfb2ded7fa3182b869df67a5a3523ed4b Mon Sep 17 00:00:00 2001 From: Justin Kilpatrick Date: Tue, 13 Apr 2021 12:00:26 -0400 Subject: [PATCH 6/7] Prune validator sets based on last observed This code provides the most efficient possible validator set pruning that we can prove is correct. By pruning the last observed validator we can keep the number of valsets in the store to a very low value during normal operation and safely extend the required storage in the case that the bridge becomes halted for some reason. --- module/x/gravity/abci.go | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/module/x/gravity/abci.go b/module/x/gravity/abci.go index 59b7e8f44..bf0b8e181 100644 --- a/module/x/gravity/abci.go +++ b/module/x/gravity/abci.go @@ -10,16 +10,20 @@ import ( // EndBlocker is called at the end of every block func EndBlocker(ctx sdk.Context, k keeper.Keeper) { + params := k.GetParams(ctx) // Question: what here can be epoched? slashing(ctx, k) attestationTally(ctx, k) cleanupTimedOutBatches(ctx, k) cleanupTimedOutLogicCalls(ctx, k) createValsets(ctx, k) + pruneValsets(ctx, k, params) + // TODO: prune claims, attestations when they pass in the handler } func createValsets(ctx sdk.Context, k keeper.Keeper) { // Auto ValsetRequest Creation. + // WARNING: do not use k.GetLastObservedValset in this function, it *will* result in losing control of the bridge // 1. If there are no valset requests, create a new one. // 2. If there is at least one validator who started unbonding in current block. (we persist last unbonded block height in hooks.go) // This will make sure the unbonding validator has to provide an attestation to a new Valset @@ -33,18 +37,36 @@ func createValsets(ctx sdk.Context, k keeper.Keeper) { } } +func pruneValsets(ctx sdk.Context, k keeper.Keeper, params types.Params) { + // Validator set pruning + // prune all validator sets with a nonce less than the + // last observed nonce, they can't be submitted any longer + // + // Only prune valsets after the signed valsets window has passed + // so that slashing can occur the block before we remove them + lastObserved := k.GetLastObservedValset(ctx) + currentBlock := uint64(ctx.BlockHeight()) + tooEarly := currentBlock < params.SignedValsetsWindow + if lastObserved != nil && !tooEarly { + earliestToPrune := currentBlock - params.SignedValsetsWindow + sets := k.GetValsets(ctx) + for _, set := range sets { + if set.Nonce < lastObserved.Nonce && set.Height < earliestToPrune { + k.DeleteValset(ctx, set.Nonce) + } + } + } +} + func slashing(ctx sdk.Context, k keeper.Keeper) { params := k.GetParams(ctx) - // Slash validator for not confirming valset requests, batch requests and not attesting claims rightfully + // Slash validator for not confirming valset requests, batch requests ValsetSlashing(ctx, k, params) BatchSlashing(ctx, k, params) - // TODO slashing for arbitrary logic is missing + // TODO slashing for arbitrary logic signatures is missing - // TODO: prune validator sets, older than 6 months, this time is chosen out of an abundance of caution - // TODO: prune outgoing tx batches while looping over them above, older than 15h and confirmed - // TODO: prune claims, attestations } // Iterate over all attestations currently being voted on in order of nonce and From c13d12e4a673bf77b58c8a495dc37431bad9cf5a Mon Sep 17 00:00:00 2001 From: Justin Kilpatrick Date: Thu, 15 Apr 2021 08:25:01 -0400 Subject: [PATCH 7/7] Modfiy Gravity.sol to reserve event nonce 1 Now that we are emitting validator set update events with an event nonce we have an event that is using event nonce zero. This is a big problem on the Cosmos side as the logic has all been developed with the assumption that event nonce 0 is a special unused value. --- orchestrator/orchestrator/src/oracle_resync.rs | 6 ++++-- solidity/contracts/Gravity.sol | 4 +++- solidity/test/deployERC20.ts | 2 +- solidity/test/sendToCosmos.ts | 8 ++++---- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/orchestrator/orchestrator/src/oracle_resync.rs b/orchestrator/orchestrator/src/oracle_resync.rs index 5ea518256..3b27b124d 100644 --- a/orchestrator/orchestrator/src/oracle_resync.rs +++ b/orchestrator/orchestrator/src/oracle_resync.rs @@ -169,11 +169,11 @@ pub async fn get_last_checked_block( // no other events can come before it, therefore either there's been a parsing error // or no events have been submitted on this chain yet. if valset.valset_nonce == 0 && last_event_nonce == 1u8.into() { - return latest_block; + return event.block_number.unwrap(); } // if we're looking for a later event nonce and we find the deployment of the contract // we must have failed to parse the event we're looking for. The oracle can not start - if valset.valset_nonce == 0 && last_event_nonce > 1u8.into() { + else if valset.valset_nonce == 0 && last_event_nonce > 1u8.into() { panic!("Could not find the last event relayed by {}, Last Event nonce is {} but no event matching that could be found!", our_cosmos_address, last_event_nonce) } } @@ -183,6 +183,8 @@ pub async fn get_last_checked_block( current_block = end_search; } + // we should exit above when we find the zero valset, if we have the wrong contract address through we could be at it a while as we go over + // the entire history to 'prove' it. panic!("You have reached the end of block history without finding the Gravity contract deploy event! You must have the wrong contract address!"); } diff --git a/solidity/contracts/Gravity.sol b/solidity/contracts/Gravity.sol index 64509c8fe..f000be684 100644 --- a/solidity/contracts/Gravity.sol +++ b/solidity/contracts/Gravity.sol @@ -35,7 +35,9 @@ contract Gravity is ReentrancyGuard { mapping(address => uint256) public state_lastBatchNonces; mapping(bytes32 => uint256) public state_invalidationMapping; uint256 public state_lastValsetNonce = 0; - uint256 public state_lastEventNonce = 0; + // event nonce zero is reserved by the Cosmos module as a special + // value indicating that no events have yet been submitted + uint256 public state_lastEventNonce = 1; // These are set once at initialization bytes32 public state_gravityId; diff --git a/solidity/test/deployERC20.ts b/solidity/test/deployERC20.ts index 75320833e..d28b0de6d 100644 --- a/solidity/test/deployERC20.ts +++ b/solidity/test/deployERC20.ts @@ -63,7 +63,7 @@ async function runTest(opts: {}) { _name: 'Atom', _symbol: 'ATOM', _decimals: 6, - _eventNonce: BigNumber.from(1) + _eventNonce: BigNumber.from(2) }) diff --git a/solidity/test/sendToCosmos.ts b/solidity/test/sendToCosmos.ts index 3ff46c880..8be707fe2 100644 --- a/solidity/test/sendToCosmos.ts +++ b/solidity/test/sendToCosmos.ts @@ -45,11 +45,11 @@ async function runTest(opts: {}) { await signers[0].getAddress(), ethers.utils.formatBytes32String("myCosmosAddress"), 1000, - 1 + 2 ); expect((await testERC20.functions.balanceOf(gravity.address))[0]).to.equal(1000); - expect((await gravity.functions.state_lastEventNonce())[0]).to.equal(1); + expect((await gravity.functions.state_lastEventNonce())[0]).to.equal(2); @@ -65,11 +65,11 @@ async function runTest(opts: {}) { await signers[0].getAddress(), ethers.utils.formatBytes32String("myCosmosAddress"), 1000, - 2 + 3 ); expect((await testERC20.functions.balanceOf(gravity.address))[0]).to.equal(2000); - expect((await gravity.functions.state_lastEventNonce())[0]).to.equal(2); + expect((await gravity.functions.state_lastEventNonce())[0]).to.equal(3); } describe("sendToCosmos tests", function () {