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

263 add optimizations audit recommendations #392

Merged
merged 25 commits into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3046062
SYS-04 Double Iterations can be merged into a single one
gianfra-t Aug 30, 2023
3194a81
SRL-02/SRW-02 limit parameter type optimization. get_latest_transacti…
gianfra-t Aug 30, 2023
e2c99ab
RPC-01/ Closure usage could simplify the codebase
gianfra-t Aug 31, 2023
640671c
PRO-02/PRF-02 Return Type Could be an Option
gianfra-t Aug 31, 2023
d05cfbc
LIV-01 Duplicated Helper Function Call
gianfra-t Aug 31, 2023
facd26b
LIP-04/LI5-04 Potential Unnecessary Computations
gianfra-t Aug 31, 2023
4c5bee2
LIP-03/LI5-03 Redundant Condition Check
gianfra-t Aug 31, 2023
b48b127
Rollback on LIV-01, try_deposit_collateral is also used in other pall…
gianfra-t Aug 31, 2023
090c314
LII-02/LBS-01 Duplicated Condition Check
gianfra-t Aug 31, 2023
c0abe50
4FC-06/9B2-06 Loops optimizations with iterators
gianfra-t Aug 31, 2023
d794f37
refactor for RPC-01
gianfra-t Sep 1, 2023
0cc62fa
Fix weird indentation within macro
ebma Sep 1, 2023
9298605
Replace `get_old_vault_replace_requests_filter`
ebma Sep 1, 2023
0f72231
Fix mock type declaration issues
ebma Sep 1, 2023
689e48f
Change signature of `get_vault_redeem_requests()`
ebma Sep 1, 2023
3c99b7b
RPC-01 fixed mock issue by adding constrained trait object, functions…
gianfra-t Sep 1, 2023
1ba4241
Fix (potential) bug introduced before in 4FC-06/9B2-06. mut requests …
gianfra-t Sep 4, 2023
0ccf8e5
Refactor RPC-01. Remove the need for 2 into_iter() calls
gianfra-t Sep 4, 2023
215c08d
Refactor PRO-02/PRF-02. Also return None when building fails.
gianfra-t Sep 4, 2023
ba506f0
FIX issue introduced by LII-02/LBS-01. Second check is needed.
gianfra-t Sep 4, 2023
28cbeb4
Refactor on LIP-04/LI5-04.
gianfra-t Sep 4, 2023
35dc5eb
Update pallets/vault-registry/src/lib.rs
gianfra-t Sep 4, 2023
8d70c49
Update pallets/vault-registry/src/lib.rs
gianfra-t Sep 4, 2023
5a6b56b
format
gianfra-t Sep 5, 2023
afdc423
clippy changes
gianfra-t Sep 7, 2023
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
73 changes: 53 additions & 20 deletions clients/runtime/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1109,10 +1109,11 @@ pub trait RedeemPallet {
async fn get_redeem_request(&self, redeem_id: H256) -> Result<SpacewalkRedeemRequest, Error>;

/// Get all redeem requests requested of the given vault
async fn get_vault_redeem_requests(
async fn get_vault_redeem_requests<T>(
&self,
account_id: AccountId,
) -> Result<Vec<(H256, SpacewalkRedeemRequest)>, Error>;
filter: Box<dyn Fn((H256, SpacewalkRedeemRequest)) -> Option<T> + Send>,
) -> Result<Vec<T>, Error>;

async fn get_redeem_period(&self) -> Result<BlockNumber, Error>;
}
Expand Down Expand Up @@ -1165,24 +1166,38 @@ impl RedeemPallet for SpacewalkParachain {
.await
}

async fn get_vault_redeem_requests(
async fn get_vault_redeem_requests<T>(
&self,
account_id: AccountId,
) -> Result<Vec<(H256, SpacewalkRedeemRequest)>, Error> {
filter: Box<dyn Fn((H256, SpacewalkRedeemRequest)) -> Option<T> + Send>,
) -> Result<Vec<T>, Error> {
let head = self.get_finalized_block_hash().await?;
let result: Vec<H256> = self
.api
.rpc()
.request("redeem_getVaultRedeemRequests", rpc_params![account_id, head])
.await?;
join_all(
result.into_iter().map(|key| async move {
self.get_redeem_request(key).await.map(|value| (key, value))
}),
)
.await
.into_iter()
.collect()

let redeem_requests = join_all(result.into_iter().map(|key| async move {
self.get_redeem_request(key).await.map(|value| (key, value))
}))
.await;

let mut some_error: Option<Error> = None;
let filtered_results: Vec<_> = redeem_requests
.into_iter()
.filter_map(|item_maybe| match item_maybe {
Ok(item) => filter(item),
Err(e) => {
some_error.get_or_insert(e);
None
},
})
.collect();
match some_error {
Some(err) => Err(err),
None => Ok(filtered_results),
}
}

async fn get_redeem_period(&self) -> Result<BlockNumber, Error> {
Expand Down Expand Up @@ -1256,10 +1271,11 @@ pub trait ReplacePallet {
) -> Result<Vec<(H256, SpacewalkReplaceRequest)>, Error>;

/// Get all replace requests made by the given vault
async fn get_old_vault_replace_requests(
async fn get_old_vault_replace_requests<T: 'static>(
&self,
account_id: AccountId,
) -> Result<Vec<(H256, SpacewalkReplaceRequest)>, Error>;
filter: Box<dyn Fn((H256, SpacewalkReplaceRequest)) -> Option<T> + Send>,
) -> Result<Vec<T>, Error>;

/// Get the time difference in number of blocks between when a replace
/// request is created and required completion time by a vault
Expand Down Expand Up @@ -1352,22 +1368,39 @@ impl ReplacePallet for SpacewalkParachain {
}

/// Get all replace requests made by the given vault
async fn get_old_vault_replace_requests(
async fn get_old_vault_replace_requests<T>(
&self,
account_id: AccountId,
) -> Result<Vec<(H256, SpacewalkReplaceRequest)>, Error> {
filter: Box<dyn Fn((H256, SpacewalkReplaceRequest)) -> Option<T> + Send>,
) -> Result<Vec<T>, Error> {
let head = self.get_finalized_block_hash().await?;
let result: Vec<H256> = self
.api
.rpc()
.request("replace_getOldVaultReplaceRequests", rpc_params![account_id, head])
.await?;
join_all(result.into_iter().map(|key| async move {

let replace_requests = join_all(result.into_iter().map(|key| async move {
self.get_replace_request(key).await.map(|value| (key, value))
}))
.await
.into_iter()
.collect()
.await;

let mut some_error: Option<Error> = None;
let filtered_results: Vec<_> = replace_requests
.into_iter()
.filter_map(|item_maybe| match item_maybe {
Ok(item) => filter(item),
Err(e) => {
some_error.get_or_insert(e);
None
},
})
.collect();

match some_error {
Some(err) => Err(err),
None => Ok(filtered_results),
}
}

async fn get_replace_period(&self) -> Result<u32, Error> {
Expand Down
16 changes: 8 additions & 8 deletions clients/vault/src/cancellation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,16 +169,16 @@ impl<P: IssuePallet + ReplacePallet + Send + Sync> Canceller<P> for ReplaceCance
// verbose drain_filter
fn drain_expired(requests: &mut Vec<ActiveRequest>, current_height: u32) -> Vec<ActiveRequest> {
let mut expired = Vec::new();
gianfra-t marked this conversation as resolved.
Show resolved Hide resolved
let has_expired = |request: &ActiveRequest| current_height > request.parachain_deadline_height;
let mut i = 0;
while i != requests.len() {
if has_expired(&requests[i]) {
let req = requests.remove(i);
expired.push(req);

requests.retain(|req| {
if current_height > req.parachain_deadline_height {
expired.push(*req);
false
} else {
i += 1;
true
}
}
});

expired
}

Expand Down
45 changes: 27 additions & 18 deletions clients/vault/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,29 +374,38 @@ pub async fn execute_open_requests(
let parachain_rpc = &parachain_rpc;
let vault_id = parachain_rpc.get_account_id().clone();

// get all redeem and replace requests
let (redeem_requests, replace_requests) = try_join!(
parachain_rpc.get_vault_redeem_requests(vault_id.clone()),
parachain_rpc.get_old_vault_replace_requests(vault_id.clone()),
)?;

let open_redeems = redeem_requests
.into_iter()
.filter(|(_, request)| request.status == RedeemRequestStatus::Pending)
.filter_map(|(hash, request)| {
//closure to filter and transform redeem_requests
let filter_redeem_reqs = move |(hash, request): (H256, SpacewalkRedeemRequest)| {
if request.status == RedeemRequestStatus::Pending {
Request::from_redeem_request(hash, request, payment_margin).ok()
});
} else {
None
}
};

let open_replaces = replace_requests
.into_iter()
.filter(|(_, request)| request.status == ReplaceRequestStatus::Pending)
.filter_map(|(hash, request)| {
//closure to filter and transform replace_requests
let filter_replace_reqs = move |(hash, request): (H256, SpacewalkReplaceRequest)| {
if request.status == ReplaceRequestStatus::Pending {
Request::from_replace_request(hash, request, payment_margin).ok()
});
} else {
None
}
};

// get all redeem and replace requests
let (open_redeems, open_replaces) = try_join!(
parachain_rpc
.get_vault_redeem_requests::<Request>(vault_id.clone(), Box::new(filter_redeem_reqs)),
parachain_rpc.get_old_vault_replace_requests::<Request>(
vault_id.clone(),
Box::new(filter_replace_reqs)
),
)?;

// collect all requests into a hashmap, indexed by their id
let mut open_requests = open_redeems
.chain(open_replaces)
.into_iter()
.chain(open_replaces.into_iter())
.map(|x| (derive_shortened_request_id(&x.hash.0), x))
.collect::<HashMap<_, _>>();

Expand Down Expand Up @@ -461,7 +470,7 @@ pub async fn execute_open_requests(

// All requests remaining in the hashmap did not have a Stellar payment yet, so pay
// and execute all of these
for (_, request) in open_requests {
for (_, request) in open_requests.into_iter() {
// there are potentially a large number of open requests - pay and execute each
// in a separate task to ensure that awaiting confirmations does not significantly
// delay other requests
Expand Down
10 changes: 8 additions & 2 deletions clients/vault/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use runtime::{
types::currency_id::CurrencyIdExt,
AggregateUpdatedEvent, CollateralBalancesPallet, CurrencyId, Error as RuntimeError, FixedU128,
IssuePallet, IssueRequestStatus, OracleKey, RedeemPallet, RedeemRequestStatus, SecurityPallet,
SpacewalkParachain, UtilFuncs, VaultId, VaultRegistryPallet, H256,
SpacewalkParachain, SpacewalkRedeemRequest, UtilFuncs, VaultId, VaultRegistryPallet, H256,
};
use service::{
warp::{Rejection, Reply},
Expand Down Expand Up @@ -469,8 +469,14 @@ pub async fn poll_metrics<
loop {
publish_native_currency_balance(parachain_rpc).await?;
publish_issue_count(parachain_rpc, vault_id_manager).await;

let pass_all_filter = |item: (H256, SpacewalkRedeemRequest)| Some(item);

if let Ok(redeems) = parachain_rpc
.get_vault_redeem_requests(parachain_rpc.get_account_id().clone())
.get_vault_redeem_requests::<(H256, SpacewalkRedeemRequest)>(
parachain_rpc.get_account_id().clone(),
Box::new(pass_all_filter),
)
.await
{
publish_redeem_count(vault_id_manager, &redeems).await;
Expand Down
20 changes: 9 additions & 11 deletions clients/vault/src/oracle/collector/proof_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,24 +114,22 @@ impl ScpMessageCollector {
&self,
slot: Slot,
sender: &StellarMessageSender,
) -> UnlimitedVarArray<ScpEnvelope> {
let empty = UnlimitedVarArray::new_empty();

) -> Option<UnlimitedVarArray<ScpEnvelope>> {
if let Some(envelopes) = self.envelopes_map().get(&slot) {
// lacking envelopes
if envelopes.len() < get_min_externalized_messages(self.is_public()) {
tracing::debug!(
"Proof Building for slot {slot}: not enough envelopes to build proof "
);
} else {
return UnlimitedVarArray::new(envelopes.clone()).unwrap_or(empty)
return UnlimitedVarArray::new(envelopes.clone()).ok()
}
}

// forcefully retrieve envelopes
self.fetch_missing_envelopes(slot, sender).await;

empty
return None
}

/// Returns either a TransactionSet or a ProofStatus saying it failed to retrieve the set.
Expand Down Expand Up @@ -179,15 +177,15 @@ impl ScpMessageCollector {
/// * `slot` - the slot where the txset is to get.
/// * `sender` - used to send messages to Stellar Node
pub async fn build_proof(&self, slot: Slot, sender: &StellarMessageSender) -> Option<Proof> {
let envelopes = self.get_envelopes(slot, sender).await;
let envelopes_maybe = self.get_envelopes(slot, sender).await;
// return early if we don't have enough envelopes or the tx_set
if envelopes.len() == 0 {
tracing::debug!("Couldn't built proof for slot {slot} due to missing envelopes");
if let Some(envelopes) = envelopes_maybe {
let tx_set = self.get_txset(slot, sender).await?;
return Some(Proof { slot, envelopes, tx_set })
} else {
tracing::debug!("Couldn't build proof for slot {slot} due to missing envelopes");
return None
}

let tx_set = self.get_txset(slot, sender).await?;
Some(Proof { slot, envelopes, tx_set })
}

/// Insert envelopes fetched from the archive to the map
Expand Down
83 changes: 45 additions & 38 deletions clients/vault/src/replace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,47 +248,54 @@ mod tests {
}

mockall::mock! {
Provider {}

#[async_trait]
pub trait VaultRegistryPallet {
async fn get_vault(&self, vault_id: &VaultId) -> Result<SpacewalkVault, RuntimeError>;
async fn get_vaults_by_account_id(&self, account_id: &AccountId) -> Result<Vec<VaultId>, RuntimeError>;
async fn get_all_vaults(&self) -> Result<Vec<SpacewalkVault>, RuntimeError>;
async fn register_vault(&self, vault_id: &VaultId, collateral: u128) -> Result<(), RuntimeError>;
async fn deposit_collateral(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>;
async fn withdraw_collateral(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>;
async fn get_public_key(&self) -> Result<Option<StellarPublicKeyRaw>, RuntimeError>;
async fn register_public_key(&self, public_key: StellarPublicKeyRaw) -> Result<(), RuntimeError>;
async fn get_required_collateral_for_wrapped(&self, amount: u128, wrapped_currency: CurrencyId, collateral_currency: CurrencyId) -> Result<u128, RuntimeError>;
async fn get_required_collateral_for_vault(&self, vault_id: VaultId) -> Result<u128, RuntimeError>;
async fn get_vault_total_collateral(&self, vault_id: VaultId) -> Result<u128, RuntimeError>;
async fn get_collateralization_from_vault(&self, vault_id: VaultId, only_issued: bool) -> Result<u128, RuntimeError>;
}
Provider {}

#[async_trait]
pub trait VaultRegistryPallet {
async fn get_vault(&self, vault_id: &VaultId) -> Result<SpacewalkVault, RuntimeError>;
async fn get_vaults_by_account_id(&self, account_id: &AccountId) -> Result<Vec<VaultId>, RuntimeError>;
async fn get_all_vaults(&self) -> Result<Vec<SpacewalkVault>, RuntimeError>;
async fn register_vault(&self, vault_id: &VaultId, collateral: u128) -> Result<(), RuntimeError>;
async fn deposit_collateral(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>;
async fn withdraw_collateral(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>;
async fn get_public_key(&self) -> Result<Option<StellarPublicKeyRaw>, RuntimeError>;
async fn register_public_key(&self, public_key: StellarPublicKeyRaw) -> Result<(), RuntimeError>;
async fn get_required_collateral_for_wrapped(&self, amount: u128, wrapped_currency: CurrencyId, collateral_currency: CurrencyId) -> Result<u128, RuntimeError>;
async fn get_required_collateral_for_vault(&self, vault_id: VaultId) -> Result<u128, RuntimeError>;
async fn get_vault_total_collateral(&self, vault_id: VaultId) -> Result<u128, RuntimeError>;
async fn get_collateralization_from_vault(&self, vault_id: VaultId, only_issued: bool) -> Result<u128, RuntimeError>;
}

#[async_trait]
pub trait ReplacePallet {
async fn request_replace(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>;
async fn withdraw_replace(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>;
async fn accept_replace(&self, new_vault: &VaultId, old_vault: &VaultId, amount: u128, collateral: u128, stellar_address: StellarPublicKeyRaw) -> Result<(), RuntimeError>;
async fn execute_replace(&self, replace_id: H256, tx_env: &[u8], scp_envs: &[u8], tx_set: &[u8]) -> Result<(), RuntimeError>;
async fn cancel_replace(&self, replace_id: H256) -> Result<(), RuntimeError>;
async fn get_new_vault_replace_requests(&self, account_id: AccountId) -> Result<Vec<(H256, SpacewalkReplaceRequest)>, RuntimeError>;
async fn get_old_vault_replace_requests(&self, account_id: AccountId) -> Result<Vec<(H256, SpacewalkReplaceRequest)>, RuntimeError>;
async fn get_replace_period(&self) -> Result<u32, RuntimeError>;
async fn get_replace_request(&self, replace_id: H256) -> Result<SpacewalkReplaceRequest, RuntimeError>;
async fn get_replace_dust_amount(&self) -> Result<u128, RuntimeError>;
}


#[async_trait]
pub trait CollateralBalancesPallet {
async fn get_free_balance(&self, currency_id: CurrencyId) -> Result<Balance, RuntimeError>;
async fn get_native_balance_for_id(&self, id: &AccountId) -> Result<Balance, RuntimeError>;
async fn get_free_balance_for_id(&self, id: AccountId, currency_id: CurrencyId) -> Result<Balance, RuntimeError>;
async fn get_reserved_balance(&self, currency_id: CurrencyId) -> Result<Balance, RuntimeError>;
async fn get_reserved_balance_for_id(&self, id: AccountId, currency_id: CurrencyId) -> Result<Balance, RuntimeError>;
async fn transfer_to(&self, recipient: &AccountId, amount: u128, currency_id: CurrencyId) -> Result<(), RuntimeError>; }
#[async_trait]
pub trait ReplacePallet {
async fn request_replace(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>;
async fn withdraw_replace(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>;
async fn accept_replace(&self, new_vault: &VaultId, old_vault: &VaultId, amount: u128, collateral: u128, stellar_address: StellarPublicKeyRaw) -> Result<(), RuntimeError>;
async fn execute_replace(&self, replace_id: H256, tx_env: &[u8], scp_envs: &[u8], tx_set: &[u8]) -> Result<(), RuntimeError>;
async fn cancel_replace(&self, replace_id: H256) -> Result<(), RuntimeError>;
async fn get_new_vault_replace_requests(&self, account_id: AccountId) -> Result<Vec<(H256, SpacewalkReplaceRequest)>, RuntimeError>;
async fn get_old_vault_replace_requests<T: 'static>(
&self,
account_id: AccountId,
filter: Box<dyn Fn((H256, SpacewalkReplaceRequest)) -> Option<T> + Send>,
) -> Result<Vec<T>, RuntimeError>;
async fn get_replace_period(&self) -> Result<u32, RuntimeError>;
async fn get_replace_request(&self, replace_id: H256) -> Result<SpacewalkReplaceRequest, RuntimeError>;
async fn get_replace_dust_amount(&self) -> Result<u128, RuntimeError>;
}


#[async_trait]
pub trait CollateralBalancesPallet {
async fn get_free_balance(&self, currency_id: CurrencyId) -> Result<Balance, RuntimeError>;
async fn get_native_balance_for_id(&self, id: &AccountId) -> Result<Balance, RuntimeError>;
async fn get_free_balance_for_id(&self, id: AccountId, currency_id: CurrencyId) -> Result<Balance, RuntimeError>;
async fn get_reserved_balance(&self, currency_id: CurrencyId) -> Result<Balance, RuntimeError>;
async fn get_reserved_balance_for_id(&self, id: AccountId, currency_id: CurrencyId) -> Result<Balance, RuntimeError>;
async fn transfer_to(&self, recipient: &AccountId, amount: u128, currency_id: CurrencyId) -> Result<(), RuntimeError>;
}
}

impl Clone for MockProvider {
Expand Down
Loading