Skip to content

Commit

Permalink
chore: add some optimisations to the AccountId creation methods (#985)
Browse files Browse the repository at this point in the history
## Description

The PR introduces some optimisations to the creation methods of the
`AccounId` struct. Namely, it gets rid of redundant heap allocations.

## Performance / NEAR gas cost considerations

There is no changes in the performance.

## Testing

The existing tests cover the changes.
  • Loading branch information
aleksuss authored Jan 10, 2025
1 parent 0007cf7 commit c12967b
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 20 deletions.
12 changes: 8 additions & 4 deletions engine-precompiles/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ mod costs {
}

pub mod events {
use crate::prelude::{types::Address, vec, String, ToString, H160, H256, U256};
use crate::prelude::{types::Address, vec, String, ToString, H256, U256};

/// Derived from event signature (see `tests::test_exit_signatures`)
pub const EXIT_TO_NEAR_SIGNATURE: H256 = crate::make_h256(
Expand All @@ -68,7 +68,7 @@ pub mod events {
/// which ERC-20 token is being withdrawn. However, ETH is not an ERC-20 token
/// So we need to have some other address to fill this field. This constant is
/// used for this purpose.
pub const ETH_ADDRESS: Address = Address::new(H160([0; 20]));
pub const ETH_ADDRESS: Address = Address::zero();

/// `ExitToNear`(
/// Address indexed sender,
Expand Down Expand Up @@ -655,7 +655,11 @@ impl<I: IO> Precompile for ExitToEthereum<I> {

if input.len() == 20 {
// Parse ethereum address in hex
let eth_recipient = hex::encode(input);
let mut buffer = [0; 40];
hex::encode_to_slice(input, &mut buffer).unwrap();
let recipient_in_hex = str::from_utf8(&buffer).map_err(|_| {
ExitError::Other(Cow::from("ERR_INVALID_RECIPIENT_ADDRESS"))
})?;
// unwrap cannot fail since we checked the length already
let recipient_address = Address::try_from_slice(input).map_err(|_| {
ExitError::Other(crate::prelude::Cow::from("ERR_WRONG_ADDRESS"))
Expand All @@ -668,7 +672,7 @@ impl<I: IO> Precompile for ExitToEthereum<I> {
format!(
r#"{{"amount": "{}", "recipient": "{}"}}"#,
amount.as_u128(),
eth_recipient
recipient_in_hex
)
.into_bytes(),
events::ExitToEth {
Expand Down
10 changes: 8 additions & 2 deletions engine-precompiles/src/xcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use aurora_engine_types::{
borsh::{self, BorshDeserialize},
format,
parameters::{CrossContractCallArgs, PromiseCreateArgs},
str,
types::{balance::ZERO_YOCTO, Address, EthGas, NearGas},
vec, Cow, Vec, H160, H256, U256,
};
Expand Down Expand Up @@ -299,8 +300,13 @@ fn create_target_account_id(
sender: H160,
engine_account_id: &str,
) -> Result<AccountId, PrecompileFailure> {
format!("{}.{}", hex::encode(sender.as_bytes()), engine_account_id)
.parse()
let mut buffer = [0; 40];
hex::encode_to_slice(sender.as_bytes(), &mut buffer)
.map_err(|_| revert_with_message(consts::ERR_XCC_ACCOUNT_ID))?;
let sender_in_hex =
str::from_utf8(&buffer).map_err(|_| revert_with_message(consts::ERR_XCC_ACCOUNT_ID))?;

AccountId::try_from(format!("{sender_in_hex}.{engine_account_id}"))
.map_err(|_| revert_with_message(consts::ERR_XCC_ACCOUNT_ID))
}

Expand Down
2 changes: 1 addition & 1 deletion engine-standalone-storage/src/sync/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ impl TransactionKind {
)
}
Self::WithdrawWnearToRouter(args) => {
let recipient = AccountId::new(&format!(
let recipient = AccountId::try_from(format!(
"{}.{}",
args.target.encode(),
engine_account.as_ref()
Expand Down
25 changes: 15 additions & 10 deletions engine-types/src/account_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ impl BorshDeserialize for AccountId {
return Ok(Self::default());
}

Self::new(&account).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()))
Self::try_from(account)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()))
}
}

Expand All @@ -105,15 +106,18 @@ impl<'de> Deserialize<'de> for AccountId {
D::Error: serde::de::Error,
{
let account = <String as Deserialize>::deserialize(deserializer)?;
Self::new(&account).map_err(serde::de::Error::custom)
Self::try_from(account).map_err(serde::de::Error::custom)
}
}

impl TryFrom<String> for AccountId {
type Error = ParseAccountError;

fn try_from(account_id: String) -> Result<Self, Self::Error> {
Self::new(&account_id)
let account_id = account_id.into_boxed_str();
Self::validate(&account_id)?;

Ok(Self(account_id))
}
}

Expand All @@ -130,16 +134,17 @@ impl TryFrom<Vec<u8>> for AccountId {
type Error = ParseAccountError;

fn try_from(account_id: Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(&account_id[..])
String::from_utf8(account_id)
.map_err(|_| ParseAccountError::Invalid)
.and_then(Self::try_from)
}
}

impl FromStr for AccountId {
type Err = ParseAccountError;

fn from_str(account_id: &str) -> Result<Self, Self::Err> {
Self::validate(account_id)?;
Ok(Self(account_id.into()))
Self::new(account_id)
}
}

Expand All @@ -156,14 +161,14 @@ impl fmt::Display for AccountId {
}

impl From<AccountId> for Box<str> {
fn from(value: AccountId) -> Self {
value.0
fn from(account_id: AccountId) -> Self {
account_id.0
}
}

impl From<AccountId> for Vec<u8> {
fn from(account_id: AccountId) -> Self {
account_id.as_bytes().to_vec()
account_id.0.into_boxed_bytes().into_vec()
}
}

Expand Down Expand Up @@ -202,7 +207,7 @@ impl AsRef<[u8]> for ParseAccountError {

impl fmt::Display for ParseAccountError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let msg = String::from_utf8(self.as_ref().to_vec()).unwrap();
let msg = str::from_utf8(self.as_ref()).map_err(|_| fmt::Error)?;
write!(f, "{msg}")
}
}
Expand Down
2 changes: 1 addition & 1 deletion engine/src/contract_methods/xcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub fn withdraw_wnear_to_router<I: IO + Copy, E: Env, H: PromiseHandler>(
}
let args: WithdrawWnearToRouterArgs = io.read_input_borsh()?;
let current_account_id = env.current_account_id();
let recipient = AccountId::new(&format!(
let recipient = AccountId::try_from(format!(
"{}.{}",
args.target.encode(),
current_account_id.as_ref()
Expand Down
4 changes: 2 additions & 2 deletions engine/src/xcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ where
E: Env,
{
let current_account_id = env.current_account_id();
let target_account_id = AccountId::new(&format!(
let target_account_id = AccountId::try_from(format!(
"{}.{}",
args.target.encode(),
current_account_id.as_ref()
Expand All @@ -95,7 +95,7 @@ where
if let AddressVersionStatus::DeployNeeded { create_needed } = deploy_needed {
let code = get_router_code(io).0.into_owned();
// wnear_account is needed for initialization so we must assume it is set
// in the Engine or we need to accept it as input.
// in the Engine, or we need to accept it as input.
let wnear_account = if let Some(wnear_account) = args.wnear_account_id {
wnear_account
} else {
Expand Down

0 comments on commit c12967b

Please sign in to comment.