Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(vft-manager): Benched submit receipt #270

Merged
merged 6 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading