Skip to content

Commit

Permalink
refactor(vft-manager): Benched submit receipt (#270)
Browse files Browse the repository at this point in the history
  • Loading branch information
gshep authored Feb 11, 2025
1 parent dedb368 commit 0a9279b
Show file tree
Hide file tree
Showing 10 changed files with 455 additions and 377 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

117 changes: 46 additions & 71 deletions api/gear/vft_manager.idl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,32 @@ type Config = struct {
reply_timeout: u32,
};

/// Type of the token supply.
type TokenSupply = enum {
/// Token supply is located on Ethereum.
///
/// This means that we're working with some pre-existing `ERC20` token on Ethereum and with
/// wrapped `VFT` token on Gear.
///
/// When this type of token supply is activated corresponding tokens will be minted/burned
/// on the gear side and locked/unlocked on the Ethereum side.
///
/// For example this type of token supply can be used to work with
/// `USDT ERC20 token`/`wrappedUSDT VFT token` pair.
Ethereum,
/// Token supply is located on Gear.
///
/// This means that we're working with some pre-existing `VFT` token on Gear and with
/// wrapped `ERC20` token on Ethereum.
///
/// When this type of token supply is activated corresponding tokens will be locked/unlocked
/// on the gear side and minted/burned on the Gear side.
///
/// For example this type of token supply can be used to work with
/// `VARA VFT token`/`wrappedVARA ERC20 token` pair.
Gear,
};

/// Error types for VFT Manageer service.
type Error = enum {
/// Error sending message to the program.
Expand Down Expand Up @@ -70,42 +96,16 @@ type Error = enum {
AlreadyProcessed,
};

/// Type of the token supply.
type TokenSupply = enum {
/// Token supply is located on Ethereum.
///
/// This means that we're working with some pre-existing `ERC20` token on Ethereum and with
/// wrapped `VFT` token on Gear.
///
/// When this type of token supply is activated corresponding tokens will be minted/burned
/// on the gear side and locked/unlocked on the Ethereum side.
///
/// For example this type of token supply can be used to work with
/// `USDT ERC20 token`/`wrappedUSDT VFT token` pair.
Ethereum,
/// Token supply is located on Gear.
///
/// This means that we're working with some pre-existing `VFT` token on Gear and with
/// wrapped `ERC20` token on Ethereum.
///
/// When this type of token supply is activated corresponding tokens will be locked/unlocked
/// on the gear side and minted/burned on the Gear side.
///
/// For example this type of token supply can be used to work with
/// `VARA VFT token`/`wrappedVARA ERC20 token` pair.
Gear,
};

/// Entry for a single message in [MessageTracker].
type RequestBridgingMsgTrackerMessageInfo = struct {
type MessageInfo = struct {
/// State of the message.
status: RequestBridgingMsgTrackerMessageStatus,
status: MessageStatus,
/// Request details.
details: RequestBridgingMsgTrackerTxDetails,
details: TxDetails,
};

/// State in which message processing can be.
type RequestBridgingMsgTrackerMessageStatus = enum {
type MessageStatus = enum {
/// Message to deposit tokens is sent.
SendingMessageToDepositTokens,
/// Reply is received for a token deposit message.
Expand All @@ -121,7 +121,7 @@ type RequestBridgingMsgTrackerMessageStatus = enum {
};

/// Details about a request associated with a message stored in [MessageTracker].
type RequestBridgingMsgTrackerTxDetails = struct {
type TxDetails = struct {
/// Address of the `VFT` token which is being bridged.
vara_token_id: actor_id,
/// Original `VFT` token owner.
Expand All @@ -134,39 +134,25 @@ type RequestBridgingMsgTrackerTxDetails = struct {
token_supply: TokenSupply,
};

/// Entry for a single message in [MessageTracker].
type SubmitReceiptMsgTrackerMessageInfo = struct {
/// State of the message.
status: SubmitReceiptMsgTrackerMessageStatus,
/// Request details.
details: SubmitReceiptMsgTrackerTxDetails,
};

/// State in which message processing can be.
type SubmitReceiptMsgTrackerMessageStatus = enum {
/// Message to withdraw tokens is sent.
SendingMessageToWithdrawTokens,
/// Reply is received for a token withdraw message.
TokenWithdrawComplete: bool,
};

/// Details about a request associated with a message stored in [MessageTracker].
type SubmitReceiptMsgTrackerTxDetails = struct {
/// Address of the `VFT` token which is being bridged.
vara_token_id: actor_id,
/// Bridged tokens receiver on Gear.
receiver: actor_id,
/// Bridged tokens amount.
amount: u256,
/// [TokenSupply] type of the token being bridged.
token_supply: TokenSupply,
};

constructor {
/// The constructor is intended for test purposes and is available only when the feature
/// `gas_calculation` is enabled.
GasCalculation : (_init_config: InitConfig, _slot_first: u64);
New : (init_config: InitConfig);
};

service VftManager {
/// The method is intended for tests and is available only when the feature `gas_calculation`
/// is enabled. Sends a VFT-message to the sender to mint/unlock tokens depending
/// on the `_supply_type`.
///
/// Designed for benchmarking gas consumption by the VFT-response processing function.
CalculateGasForReply : (_slot: u64, _transaction_index: u64, _supply_type: TokenSupply) -> result (null, Error);
/// The method is intended for tests and is available only when the feature `gas_calculation`
/// is enabled. Populates the collection with processed transactions.
///
/// Returns false when the collection is populated.
FillTransactions : () -> bool;
/// Process message further if some error was encountered during the `request_bridging`.
///
/// This method should be called only to recover funds that were stuck in the middle of the bridging
Expand All @@ -176,15 +162,6 @@ service VftManager {
/// - Gas attached to a message wasn't enough to execute entire logic in `request_bridging`.
/// - Network was heavily loaded and some message was stuck so `request_bridging` failed.
HandleRequestBridgingInterruptedTransfer : (msg_id: message_id) -> result (null, Error);
/// Process message further if some error was encountered during the `submit_receipt`.
///
/// This method should be called only to recover funds that were stuck in the middle of the bridging
/// and is not a part of a normal workflow.
///
/// There can be several reasons for `submit_receipt` to fail:
/// - Gas attached to a message wasn't enough to execute entire logic in `submit_receipt`.
/// - Network was heavily loaded and some message was stuck so `submit_receipt` failed.
HandleSubmitReceiptInterruptedTransfer : (msg_id: message_id) -> result (null, Error);
/// Add a new token pair to a [State::token_map]. Can be called only by a [State::admin].
MapVaraToEthAddress : (vara_token_id: actor_id, eth_token_id: h160, supply_type: TokenSupply) -> null;
/// Remove the token pair from [State::token_map]. Can be called only by a [State::admin].
Expand Down Expand Up @@ -228,9 +205,7 @@ service VftManager {
/// Get current [State::historical_proxy_address].
query HistoricalProxyAddress : () -> actor_id;
/// Get state of a `request_bridging` message tracker.
query RequestBridingMsgTrackerState : () -> vec struct { message_id, RequestBridgingMsgTrackerMessageInfo };
/// Get state of a `submit_receipt` message tracker.
query SubmitReceiptMsgTrackerState : () -> vec struct { message_id, SubmitReceiptMsgTrackerMessageInfo };
query RequestBridingMsgTrackerState : () -> vec struct { message_id, MessageInfo };
/// Get current [token mapping](State::token_map).
query VaraToEthAddresses : () -> vec struct { actor_id, h160, TokenSupply };

Expand Down
1 change: 1 addition & 0 deletions gear-programs/vft-manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ gclient.workspace = true

[features]
wasm-binary = []
gas_calculation = ["vft-manager-app/gas_calculation"]
6 changes: 5 additions & 1 deletion gear-programs/vft-manager/app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ gear-core.workspace = true
hex.workspace = true
sails-rs = { workspace = true, features = ["gclient"] }
sp-core = { workspace = true, features = ["std"] }
sp-runtime = { workspace = true, features = ["std"] }
tokio = { workspace = true, features = ["rt", "macros"] }
vft-manager = { workspace = true, features = ["wasm-binary"] }
vft-manager = { workspace = true, features = ["wasm-binary", "gas_calculation"] }
vft-manager-client.workspace = true

[features]
gas_calculation = []
19 changes: 19 additions & 0 deletions gear-programs/vft-manager/app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,25 @@ impl Program {
Self
}

/// The constructor is intended for test purposes and is available only when the feature
/// `gas_calculation` is enabled.
pub fn gas_calculation(_init_config: InitConfig, _slot_first: u64) -> Self {
#[cfg(feature = "gas_calculation")]
{
let self_ = Self::new(_init_config);

let transactions = services::submit_receipt::transactions_mut();
for i in 0..services::SIZE_FILL_TRANSACTIONS_STEP {
transactions.insert((_slot_first, i as u64));
}

self_
}

#[cfg(not(feature = "gas_calculation"))]
panic!("Please rebuild with enabled `gas_calculation` feature")
}

pub fn vft_manager(&self) -> VftManager<GStdExecContext> {
VftManager::new(GStdExecContext::new())
}
Expand Down
87 changes: 64 additions & 23 deletions gear-programs/vft-manager/app/src/services/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ use error::Error;
use token_mapping::TokenMap;

mod request_bridging;
mod submit_receipt;
pub mod submit_receipt;

pub use submit_receipt::abi as eth_abi;

pub const SIZE_FILL_TRANSACTIONS_STEP: usize = 50_000;

/// VFT Manager service.
pub struct VftManager<ExecContext> {
exec_context: ExecContext,
Expand Down Expand Up @@ -307,35 +309,13 @@ where
request_bridging::handle_interrupted_transfer(self, msg_id).await
}

/// Process message further if some error was encountered during the `submit_receipt`.
///
/// This method should be called only to recover funds that were stuck in the middle of the bridging
/// and is not a part of a normal workflow.
///
/// There can be several reasons for `submit_receipt` to fail:
/// - Gas attached to a message wasn't enough to execute entire logic in `submit_receipt`.
/// - Network was heavily loaded and some message was stuck so `submit_receipt` failed.
pub async fn handle_submit_receipt_interrupted_transfer(
&mut self,
msg_id: MessageId,
) -> Result<(), Error> {
submit_receipt::handle_interrupted_transfer(self, msg_id).await
}

/// Get state of a `request_bridging` message tracker.
pub fn request_briding_msg_tracker_state(
&self,
) -> Vec<(MessageId, request_bridging::MsgTrackerMessageInfo)> {
request_bridging::msg_tracker_state()
}

/// Get state of a `submit_receipt` message tracker.
pub fn submit_receipt_msg_tracker_state(
&self,
) -> Vec<(MessageId, submit_receipt::MsgTrackerMessageInfo)> {
submit_receipt::msg_tracker_state()
}

/// Get current [token mapping](State::token_map).
pub fn vara_to_eth_addresses(&self) -> Vec<(ActorId, H160, TokenSupply)> {
self.state().token_map.read_state()
Expand Down Expand Up @@ -365,6 +345,67 @@ where
pub fn historical_proxy_address(&self) -> ActorId {
self.state().historical_proxy_address
}

/// The method is intended for tests and is available only when the feature `gas_calculation`
/// is enabled. Populates the collection with processed transactions.
///
/// Returns false when the collection is populated.
pub fn fill_transactions(&mut self) -> bool {
#[cfg(feature = "gas_calculation")]
{
submit_receipt::fill_transactions()
}

#[cfg(not(feature = "gas_calculation"))]
panic!("Please rebuild with enabled `gas_calculation` feature")
}

/// The method is intended for tests and is available only when the feature `gas_calculation`
/// is enabled. Sends a VFT-message to the sender to mint/unlock tokens depending
/// on the `_supply_type`.
///
/// Designed for benchmarking gas consumption by the VFT-response processing function.
pub async fn calculate_gas_for_reply(
&mut self,
_slot: u64,
_transaction_index: u64,
_supply_type: TokenSupply,
) -> Result<(), Error> {
#[cfg(feature = "gas_calculation")]
{
use submit_receipt::token_operations;

let source = self.exec_context.actor_id();
match _supply_type {
TokenSupply::Ethereum => {
token_operations::mint(
_slot,
_transaction_index,
source,
source,
100u32.into(),
self.config(),
)
.await
}

TokenSupply::Gear => {
token_operations::unlock(
_slot,
_transaction_index,
source,
source,
100u32.into(),
self.config(),
)
.await
}
}
}

#[cfg(not(feature = "gas_calculation"))]
panic!("Please rebuild with enabled `gas_calculation` feature")
}
}

impl<T> VftManager<T>
Expand Down
Loading

0 comments on commit 0a9279b

Please sign in to comment.