Skip to content

Commit

Permalink
jsonrpc: introduce bcsEncoding tag to ease migration to base64
Browse files Browse the repository at this point in the history
Inorder to ease the transition of SuiEvent.bcs and
DynamicFieldInfo.bcsName to being encoded with base64, introduce a tag
("bcsEncoding") to indicate the encoding and gracefully default to
base58 when the tag isn't present.
  • Loading branch information
bmwill committed Dec 13, 2024
1 parent 769f145 commit 8a992f0
Show file tree
Hide file tree
Showing 19 changed files with 398 additions and 88 deletions.
6 changes: 3 additions & 3 deletions crates/sui-bridge-indexer/src/sui_transaction_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub fn into_token_transfers(
"TokenDepositedEvent" => {
info!("Observed Sui Deposit {:?}", ev);
metrics.total_sui_token_deposited.inc();
let move_event: MoveTokenDepositedEvent = bcs::from_bytes(&ev.bcs)?;
let move_event: MoveTokenDepositedEvent = bcs::from_bytes(ev.bcs.bytes())?;
transfers.push(ProcessedTxnData::TokenTransfer(TokenTransfer {
chain_id: move_event.source_chain,
nonce: move_event.seq_num,
Expand All @@ -119,7 +119,7 @@ pub fn into_token_transfers(
"TokenTransferApproved" => {
info!("Observed Sui Approval {:?}", ev);
metrics.total_sui_token_transfer_approved.inc();
let event: MoveTokenTransferApproved = bcs::from_bytes(&ev.bcs)?;
let event: MoveTokenTransferApproved = bcs::from_bytes(ev.bcs.bytes())?;
transfers.push(ProcessedTxnData::TokenTransfer(TokenTransfer {
chain_id: event.message_key.source_chain,
nonce: event.message_key.bridge_seq_num,
Expand All @@ -137,7 +137,7 @@ pub fn into_token_transfers(
"TokenTransferClaimed" => {
info!("Observed Sui Claim {:?}", ev);
metrics.total_sui_token_transfer_claimed.inc();
let event: MoveTokenTransferClaimed = bcs::from_bytes(&ev.bcs)?;
let event: MoveTokenTransferClaimed = bcs::from_bytes(ev.bcs.bytes())?;
transfers.push(ProcessedTxnData::TokenTransfer(TokenTransfer {
chain_id: event.message_key.source_chain,
nonce: event.message_key.bridge_seq_num,
Expand Down
5 changes: 3 additions & 2 deletions crates/sui-bridge/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ macro_rules! declare_events {
// Unwrap safe: we inited above
$(
if &event.type_ == $variant.get().unwrap() {
let event_struct: $event_struct = bcs::from_bytes(&event.bcs).map_err(|e| BridgeError::InternalError(format!("Failed to deserialize event to {}: {:?}", stringify!($event_struct), e)))?;
let event_struct: $event_struct = bcs::from_bytes(event.bcs.bytes()).map_err(|e| BridgeError::InternalError(format!("Failed to deserialize event to {}: {:?}", stringify!($event_struct), e)))?;
return Ok(Some(SuiBridgeEvent::$variant(event_struct.try_into()?)));
}
)*
Expand Down Expand Up @@ -443,6 +443,7 @@ pub mod tests {
use crate::types::BridgeAction;
use crate::types::SuiToEthBridgeAction;
use ethers::types::Address as EthAddress;
use sui_json_rpc_types::BcsEvent;
use sui_json_rpc_types::SuiEvent;
use sui_types::base_types::ObjectID;
use sui_types::base_types::SuiAddress;
Expand Down Expand Up @@ -484,7 +485,7 @@ pub mod tests {
});
let event = SuiEvent {
type_: SuiToEthTokenBridgeV1.get().unwrap().clone(),
bcs: bcs::to_bytes(&emitted_event).unwrap(),
bcs: BcsEvent::new(bcs::to_bytes(&emitted_event).unwrap()),
id: EventID {
tx_digest,
event_seq: event_idx as u64,
Expand Down
6 changes: 3 additions & 3 deletions crates/sui-bridge/src/server/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ mod tests {
types::{EmergencyAction, EmergencyActionType, LimitUpdateAction},
};
use ethers::types::{Address as EthAddress, TransactionReceipt};
use sui_json_rpc_types::SuiEvent;
use sui_json_rpc_types::{BcsEvent, SuiEvent};
use sui_types::bridge::{BridgeChainId, TOKEN_ID_USDC};
use sui_types::{base_types::SuiAddress, crypto::get_key_pair};

Expand Down Expand Up @@ -456,12 +456,12 @@ mod tests {

let mut sui_event_1 = SuiEvent::random_for_testing();
sui_event_1.type_ = SuiToEthTokenBridgeV1.get().unwrap().clone();
sui_event_1.bcs = bcs::to_bytes(&emitted_event_1).unwrap();
sui_event_1.bcs = BcsEvent::new(bcs::to_bytes(&emitted_event_1).unwrap());
let sui_tx_digest = sui_event_1.id.tx_digest;

let mut sui_event_2 = SuiEvent::random_for_testing();
sui_event_2.type_ = SuiToEthTokenBridgeV1.get().unwrap().clone();
sui_event_2.bcs = bcs::to_bytes(&emitted_event_1).unwrap();
sui_event_2.bcs = BcsEvent::new(bcs::to_bytes(&emitted_event_1).unwrap());
let sui_event_idx_2 = 1;
sui_client_mock.add_events_by_tx_digest(sui_tx_digest, vec![sui_event_2.clone()]);

Expand Down
5 changes: 3 additions & 2 deletions crates/sui-bridge/src/sui_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,7 @@ mod tests {
use move_core_types::account_address::AccountAddress;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use sui_json_rpc_types::BcsEvent;
use sui_types::bridge::{BridgeChainId, TOKEN_ID_SUI, TOKEN_ID_USDC};
use sui_types::crypto::get_key_pair;

Expand Down Expand Up @@ -698,7 +699,7 @@ mod tests {

let mut sui_event_1 = SuiEvent::random_for_testing();
sui_event_1.type_ = SuiToEthTokenBridgeV1.get().unwrap().clone();
sui_event_1.bcs = bcs::to_bytes(&emitted_event_1).unwrap();
sui_event_1.bcs = BcsEvent::new(bcs::to_bytes(&emitted_event_1).unwrap());

#[derive(Serialize, Deserialize)]
struct RandomStruct {}
Expand All @@ -708,7 +709,7 @@ mod tests {
let mut sui_event_2 = SuiEvent::random_for_testing();
sui_event_2.type_ = SuiToEthTokenBridgeV1.get().unwrap().clone();
sui_event_2.type_.module = Identifier::from_str("unrecognized_module").unwrap();
sui_event_2.bcs = bcs::to_bytes(&event_2).unwrap();
sui_event_2.bcs = BcsEvent::new(bcs::to_bytes(&event_2).unwrap());

// Event 3 is defined in non-bridge package
let mut sui_event_3 = sui_event_1.clone();
Expand Down
2 changes: 1 addition & 1 deletion crates/sui-graphql-rpc/src/mutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ impl Mutation {
transaction_module: e.transaction_module,
sender: e.sender,
type_: e.type_,
contents: e.bcs,
contents: e.bcs.into_bytes(),
})
.collect();

Expand Down
2 changes: 1 addition & 1 deletion crates/sui-indexer/src/apis/indexer_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ impl IndexerApiServer for IndexerApi {
results.truncate(limit);
let next_cursor = results.last().map(|o| o.object_id);
Ok(Page {
data: results,
data: results.into_iter().map(Into::into).collect(),
next_cursor,
has_next_page,
})
Expand Down
4 changes: 2 additions & 2 deletions crates/sui-indexer/src/models/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::sync::Arc;
use diesel::prelude::*;
use move_core_types::identifier::Identifier;

use sui_json_rpc_types::{type_and_fields_from_move_event_data, SuiEvent};
use sui_json_rpc_types::{type_and_fields_from_move_event_data, BcsEvent, SuiEvent};
use sui_package_resolver::{PackageStore, Resolver};
use sui_types::base_types::{ObjectID, SuiAddress};
use sui_types::digests::TransactionDigest;
Expand Down Expand Up @@ -115,7 +115,7 @@ impl StoredEvent {
transaction_module: Identifier::from_str(&self.module)?,
sender,
type_,
bcs: self.bcs,
bcs: BcsEvent::new(self.bcs),
parsed_json,
timestamp_ms: Some(self.timestamp_ms as u64),
})
Expand Down
160 changes: 159 additions & 1 deletion crates/sui-json-rpc-types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use fastcrypto::encoding::{Base58, Base64};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

pub use balance_changes::*;
pub use object_changes::*;
use serde_with::serde_as;
pub use sui_checkpoint::*;
pub use sui_coin::*;
pub use sui_event::*;
Expand All @@ -16,7 +18,6 @@ pub use sui_object::*;
pub use sui_protocol::*;
pub use sui_transaction::*;
use sui_types::base_types::ObjectID;
use sui_types::dynamic_field::DynamicFieldInfo;

#[cfg(test)]
#[path = "unit_tests/rpc_types_tests.rs"]
Expand Down Expand Up @@ -56,3 +57,160 @@ impl<T, C> Page<T, C> {
}
}
}

#[serde_with::serde_as]
#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DynamicFieldInfo {
pub name: sui_types::dynamic_field::DynamicFieldName,
#[serde(flatten)]
pub bcs_name: BcsName,
pub type_: sui_types::dynamic_field::DynamicFieldType,
pub object_type: String,
pub object_id: ObjectID,
pub version: sui_types::base_types::SequenceNumber,
pub digest: sui_types::digests::ObjectDigest,
}

impl From<sui_types::dynamic_field::DynamicFieldInfo> for DynamicFieldInfo {
fn from(
sui_types::dynamic_field::DynamicFieldInfo {
name,
bcs_name,
type_,
object_type,
object_id,
version,
digest,
}: sui_types::dynamic_field::DynamicFieldInfo,
) -> Self {
Self {
name,
bcs_name: BcsName::new(bcs_name),
type_,
object_type,
object_id,
version,
digest,
}
}
}

#[serde_as]
#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", tag = "bcsEncoding")]
#[serde(from = "MaybeTaggedBcsName")]
pub enum BcsName {
Base64 {
#[serde_as(as = "Base64")]
#[schemars(with = "Base64")]
bcs_name: Vec<u8>,
},
Base58 {
#[serde_as(as = "Base58")]
#[schemars(with = "Base58")]
bcs_name: Vec<u8>,
},
}

impl BcsName {
pub fn new(bytes: Vec<u8>) -> Self {
Self::Base64 { bcs_name: bytes }
}

pub fn bytes(&self) -> &[u8] {
match self {
BcsName::Base64 { bcs_name } => bcs_name.as_ref(),
BcsName::Base58 { bcs_name } => bcs_name.as_ref(),
}
}

pub fn into_bytes(self) -> Vec<u8> {
match self {
BcsName::Base64 { bcs_name } => bcs_name,
BcsName::Base58 { bcs_name } => bcs_name,
}
}
}

#[allow(unused)]
#[serde_as]
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase", untagged)]
enum MaybeTaggedBcsName {
Tagged(TaggedBcsName),
Base58 {
#[serde_as(as = "Base58")]
#[serde(rename = "bcsName")]
bcs_name: Vec<u8>,
},
}

#[serde_as]
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "bcsEncoding")]
enum TaggedBcsName {
Base64 {
#[serde_as(as = "Base64")]
#[serde(rename = "bcsName")]
bcs_name: Vec<u8>,
},
Base58 {
#[serde_as(as = "Base58")]
#[serde(rename = "bcsName")]
bcs_name: Vec<u8>,
},
}

impl From<MaybeTaggedBcsName> for BcsName {
fn from(name: MaybeTaggedBcsName) -> BcsName {
let bcs_name = match name {
MaybeTaggedBcsName::Tagged(TaggedBcsName::Base58 { bcs_name })
| MaybeTaggedBcsName::Base58 { bcs_name } => bcs_name,
MaybeTaggedBcsName::Tagged(TaggedBcsName::Base64 { bcs_name }) => bcs_name,
};

// Bytes are already decoded, force into Base64 variant to avoid serializing to base58
Self::Base64 { bcs_name }
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn bcs_name_test() {
let bytes = vec![0, 1, 2, 3, 4];
let untagged_base58 = r#"{"bcsName":"12VfUX"}"#;
let tagged_base58 = r#"{"bcsEncoding":"base58","bcsName":"12VfUX"}"#;
let tagged_base64 = r#"{"bcsEncoding":"base64","bcsName":"AAECAwQ="}"#;

println!(
"{}",
serde_json::to_string(&TaggedBcsName::Base64 {
bcs_name: bytes.clone()
})
.unwrap()
);

assert_eq!(
bytes,
serde_json::from_str::<BcsName>(untagged_base58)
.unwrap()
.into_bytes()
);
assert_eq!(
bytes,
serde_json::from_str::<BcsName>(tagged_base58)
.unwrap()
.into_bytes()
);
assert_eq!(
bytes,
serde_json::from_str::<BcsName>(tagged_base64)
.unwrap()
.into_bytes()
);
}
}
Loading

0 comments on commit 8a992f0

Please sign in to comment.