Skip to content

Commit

Permalink
[bridge] handle eth events in monitor (#19389)
Browse files Browse the repository at this point in the history
## Description 

1. in `bridge.move` rename `ETokenAlreadyClaimed` to
`ETokenAlreadyClaimedOrHitLimit` and update comments accordingly.
2. implements `handle_eth_events`, mostly bumping metrics for governance
action events
3. use a macro to update sui side metrics as well
4. adds `UpdateRouteLimitEvent` from Sui.


## Test plan 

How did you test the new or updated feature?

---

## Release notes

Check each box that your changes affect. If none of the boxes relate to
your changes, release notes aren't required.

For each box you select, include information after the relevant heading
that describes the impact of your changes that a user might notice and
any actions they must take to implement updates.

- [ ] Protocol: 
- [ ] Nodes (Validators and Full nodes): 
- [ ] Indexer: 
- [ ] JSON-RPC: 
- [ ] GraphQL: 
- [ ] CLI: 
- [ ] Rust SDK:
- [ ] REST API:
  • Loading branch information
longbowlu authored Sep 17, 2024
1 parent bf86ff9 commit 5563665
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 36 deletions.
6 changes: 4 additions & 2 deletions crates/sui-bridge/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ pub struct MoveBlocklistValidatorEvent {
}

// `UpdateRouteLimitEvent` emitted in limiter.move
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct MoveUpdateRouteLimitEvent {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct UpdateRouteLimitEvent {
pub sending_chain: u8,
pub receiving_chain: u8,
pub new_limit: u64,
Expand Down Expand Up @@ -360,6 +360,7 @@ crate::declare_events!(
TokenRegistrationEvent(TokenRegistrationEvent) => ("treasury::TokenRegistrationEvent", MoveTokenRegistrationEvent),
NewTokenEvent(NewTokenEvent) => ("treasury::NewTokenEvent", MoveNewTokenEvent),
UpdateTokenPriceEvent(UpdateTokenPriceEvent) => ("treasury::UpdateTokenPriceEvent", UpdateTokenPriceEvent),
UpdateRouteLimitEvent(UpdateRouteLimitEvent) => ("limiter::UpdateRouteLimitEvent", UpdateRouteLimitEvent),

// Add new event types here. Format:
// EnumVariantName(Struct) => ("{module}::{event_struct}", CorrespondingMoveStruct)
Expand Down Expand Up @@ -427,6 +428,7 @@ impl SuiBridgeEvent {
SuiBridgeEvent::TokenRegistrationEvent(_event) => None,
SuiBridgeEvent::NewTokenEvent(_event) => None,
SuiBridgeEvent::UpdateTokenPriceEvent(_event) => None,
SuiBridgeEvent::UpdateRouteLimitEvent(_event) => None,
}
}
}
Expand Down
151 changes: 124 additions & 27 deletions crates/sui-bridge/src/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
//! `BridgeMonitor` receives all `SuiBridgeEvent` and `EthBridgeEvent`
//! and handles them accordingly.

use crate::abi::EthBridgeEvent;
use crate::abi::{
EthBridgeCommitteeEvents, EthBridgeConfigEvents, EthBridgeEvent, EthBridgeLimiterEvents,
EthCommitteeUpgradeableContractEvents, EthSuiBridgeEvents,
};
use crate::client::bridge_authority_aggregator::BridgeAuthorityAggregator;
use crate::crypto::BridgeAuthorityPublicKeyBytes;
use crate::events::{BlocklistValidatorEvent, CommitteeMemberUrlUpdateEvent};
Expand Down Expand Up @@ -88,8 +91,8 @@ where
}
}
eth_event = eth_monitor_rx.recv() => {
if let Some(_eth_event) = eth_event {
// TODO
if let Some(eth_event) = eth_event {
Self::handle_eth_events(eth_event, &bridge_metrics);
} else {
panic!("BridgeMonitor eth events channel was closed unexpectedly");
}
Expand All @@ -107,6 +110,16 @@ where
bridge_metrics: &Arc<BridgeMetrics>,
latest_token_config: &mut HashMap<u8, TypeTag>,
) {
info!("Received SuiBridgeEvent: {:?}", event);
macro_rules! bump_sui_counter {
($action:expr) => {
bridge_metrics
.observed_governance_actions
.with_label_values(&[$action, "sui"])
.inc();
};
}

match event {
SuiBridgeEvent::SuiToEthTokenBridgeV1(_) => (),
SuiBridgeEvent::TokenTransferApproved(_) => (),
Expand All @@ -118,11 +131,11 @@ where
}

SuiBridgeEvent::EmergencyOpEvent(event) => {
info!("Received EmergencyOpEvent: {:?}", event);
bridge_metrics
.observed_governance_actions
.with_label_values(&["emergency_op", "sui"])
.inc();
bump_sui_counter!(if event.frozen {
"bridge_paused"
} else {
"bridge_unpaused"
});
let is_paused = get_latest_bridge_pause_status_with_emergency_event(
sui_client.clone(),
event,
Expand All @@ -134,11 +147,15 @@ where
.expect("Bridge pause status watch channel should not be closed");
}

SuiBridgeEvent::CommitteeMemberRegistration(_) => (),
SuiBridgeEvent::CommitteeUpdateEvent(_) => (),
SuiBridgeEvent::CommitteeMemberRegistration(_) => {
bump_sui_counter!("committee_member_registered");
}
SuiBridgeEvent::CommitteeUpdateEvent(_) => {
bump_sui_counter!("committee_updated");
}

SuiBridgeEvent::CommitteeMemberUrlUpdateEvent(event) => {
info!("Received CommitteeMemberUrlUpdateEvent: {:?}", event);
bump_sui_counter!("committee_member_url_updated");
let new_committee = get_latest_bridge_committee_with_url_update_event(
sui_client.clone(),
event,
Expand All @@ -152,11 +169,11 @@ where
}

SuiBridgeEvent::BlocklistValidatorEvent(event) => {
info!("Received BlocklistValidatorEvent: {:?}", event);
bridge_metrics
.observed_governance_actions
.with_label_values(&["blocklist_validator", "sui"])
.inc();
bump_sui_counter!(if event.blocklisted {
"validator_blocklisted"
} else {
"validator_unblocklisted"
});
let new_committee = get_latest_bridge_committee_with_blocklist_event(
sui_client.clone(),
event,
Expand All @@ -169,14 +186,12 @@ where
info!("Committee updated with BlocklistValidatorEvent");
}

SuiBridgeEvent::TokenRegistrationEvent(_) => (),
SuiBridgeEvent::TokenRegistrationEvent(_) => {
bump_sui_counter!("new_token_registered");
}

SuiBridgeEvent::NewTokenEvent(event) => {
info!("Received NewTokenEvent: {:?}", event);
bridge_metrics
.observed_governance_actions
.with_label_values(&["new_token", "sui"])
.inc();
bump_sui_counter!("new_token_added");
if let std::collections::hash_map::Entry::Vacant(entry) =
// We only add new tokens but not remove so it's ok to just insert
latest_token_config.entry(event.token_id)
Expand All @@ -189,13 +204,95 @@ where
}
}

SuiBridgeEvent::UpdateTokenPriceEvent(event) => {
info!("Received UpdateTokenPriceEvent: {:?}", event);
SuiBridgeEvent::UpdateTokenPriceEvent(_event) => {
bump_sui_counter!("token_price_updated");
}

SuiBridgeEvent::UpdateRouteLimitEvent(_event) => {
bump_sui_counter!("limit_updated");
}
}
}

fn handle_eth_events(event: EthBridgeEvent, bridge_metrics: &Arc<BridgeMetrics>) {
info!("Received EthBridgeEvent: {:?}", event);

macro_rules! bump_eth_counter {
($action:expr) => {
bridge_metrics
.observed_governance_actions
.with_label_values(&["update_token_price", "sui"])
.inc();
}
.with_label_values(&[$action, "eth"])
.inc()
};
}

match event {
EthBridgeEvent::EthBridgeCommitteeEvents(event) => match event {
EthBridgeCommitteeEvents::BlocklistUpdatedFilter(event) => {
bump_eth_counter!(if event.is_blocklisted {
"validator_blocklisted"
} else {
"validator_unblocklisted"
});
}
EthBridgeCommitteeEvents::InitializedFilter(_) => {
bump_eth_counter!("committee_contract_initialized");
}
EthBridgeCommitteeEvents::UpgradedFilter(_) => {
bump_eth_counter!("committee_contract_upgraded");
}
},
EthBridgeEvent::EthBridgeLimiterEvents(event) => match event {
EthBridgeLimiterEvents::InitializedFilter(_) => {
bump_eth_counter!("limiter_contract_initialized");
}
EthBridgeLimiterEvents::UpgradedFilter(_) => {
bump_eth_counter!("limiter_contract_upgraded");
}
EthBridgeLimiterEvents::OwnershipTransferredFilter(_) => {
bump_eth_counter!("limiter_contract_ownership_transferred");
}
EthBridgeLimiterEvents::LimitUpdatedFilter(_) => {
bump_eth_counter!("limit_updated");
}
// This event is deprecated but we keep it for ABI compatibility
// TODO: We can safely update abi and remove it once the testnet bridge contract is upgraded
EthBridgeLimiterEvents::HourlyTransferAmountUpdatedFilter(_) => (),
},
EthBridgeEvent::EthBridgeConfigEvents(event) => match event {
EthBridgeConfigEvents::InitializedFilter(_) => {
bump_eth_counter!("config_contract_initialized");
}
EthBridgeConfigEvents::UpgradedFilter(_) => {
bump_eth_counter!("config_contract_upgraded");
}
EthBridgeConfigEvents::TokenAddedFilter(_) => {
bump_eth_counter!("new_token_added");
}
EthBridgeConfigEvents::TokenPriceUpdatedFilter(_) => {
bump_eth_counter!("update_token_price");
}
},
EthBridgeEvent::EthCommitteeUpgradeableContractEvents(event) => match event {
EthCommitteeUpgradeableContractEvents::InitializedFilter(_) => {
bump_eth_counter!("upgradeable_contract_initialized");
}
EthCommitteeUpgradeableContractEvents::UpgradedFilter(_) => {
bump_eth_counter!("upgradeable_contract_upgraded");
}
},
EthBridgeEvent::EthSuiBridgeEvents(event) => match event {
EthSuiBridgeEvents::TokensClaimedFilter(_) => (),
EthSuiBridgeEvents::TokensDepositedFilter(_) => (),
EthSuiBridgeEvents::PausedFilter(_) => bump_eth_counter!("bridge_paused"),
EthSuiBridgeEvents::UnpausedFilter(_) => bump_eth_counter!("bridge_unpaused"),
EthSuiBridgeEvents::UpgradedFilter(_) => {
bump_eth_counter!("bridge_contract_upgraded")
}
EthSuiBridgeEvents::InitializedFilter(_) => {
bump_eth_counter!("bridge_contract_initialized")
}
},
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions crates/sui-framework/docs/bridge/bridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -548,11 +548,11 @@ title: Module `0xb::bridge`



<a name="0xb_bridge_ETokenAlreadyClaimed"></a>
<a name="0xb_bridge_ETokenAlreadyClaimedOrHitLimit"></a>



<pre><code><b>const</b> <a href="bridge.md#0xb_bridge_ETokenAlreadyClaimed">ETokenAlreadyClaimed</a>: <a href="../move-stdlib/u64.md#0x1_u64">u64</a> = 15;
<pre><code><b>const</b> <a href="bridge.md#0xb_bridge_ETokenAlreadyClaimedOrHitLimit">ETokenAlreadyClaimedOrHitLimit</a>: <a href="../move-stdlib/u64.md#0x1_u64">u64</a> = 15;
</code></pre>


Expand Down Expand Up @@ -1030,7 +1030,7 @@ title: Module `0xb::bridge`
);
// Only token owner can claim the token
<b>assert</b>!(ctx.sender() == owner, <a href="bridge.md#0xb_bridge_EUnauthorisedClaim">EUnauthorisedClaim</a>);
<b>assert</b>!(maybe_token.is_some(), <a href="bridge.md#0xb_bridge_ETokenAlreadyClaimed">ETokenAlreadyClaimed</a>);
<b>assert</b>!(maybe_token.is_some(), <a href="bridge.md#0xb_bridge_ETokenAlreadyClaimedOrHitLimit">ETokenAlreadyClaimedOrHitLimit</a>);
maybe_token.destroy_some()
}
</code></pre>
Expand Down
9 changes: 5 additions & 4 deletions crates/sui-framework/packages/bridge/sources/bridge.move
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ module bridge::bridge {
const EUnexpectedMessageVersion: u64 = 12;
const EBridgeAlreadyPaused: u64 = 13;
const EBridgeNotPaused: u64 = 14;
const ETokenAlreadyClaimed: u64 = 15;
const ETokenAlreadyClaimedOrHitLimit: u64 = 15;
const EInvalidBridgeRoute: u64 = 16;
const EMustBeTokenMessage: u64 = 17;
const EInvalidEvmAddress: u64 = 18;
Expand Down Expand Up @@ -314,7 +314,8 @@ module bridge::bridge {
}

// This function can only be called by the token recipient
// Abort if the token has already been claimed.
// Abort if the token has already been claimed or hits limiter currently,
// in which case, no event will be emitted and only abort code will be returned.
public fun claim_token<T>(
bridge: &mut Bridge,
clock: &Clock,
Expand All @@ -330,12 +331,12 @@ module bridge::bridge {
);
// Only token owner can claim the token
assert!(ctx.sender() == owner, EUnauthorisedClaim);
assert!(maybe_token.is_some(), ETokenAlreadyClaimed);
assert!(maybe_token.is_some(), ETokenAlreadyClaimedOrHitLimit);
maybe_token.destroy_some()
}

// This function can be called by anyone to claim and transfer the token to the recipient
// If the token has already been claimed, it will return instead of aborting.
// If the token has already been claimed or hits limiter currently, it will return instead of aborting.
public fun claim_and_transfer_token<T>(
bridge: &mut Bridge,
clock: &Clock,
Expand Down

0 comments on commit 5563665

Please sign in to comment.