Skip to content

Commit

Permalink
Refactor: Unify DomainAddress and account conversions (r2) (#1969)
Browse files Browse the repository at this point in the history
* runtime-common compiling

* runtimes compiling

* add IT required changes

* add id_eth

* rename id_eth to in_eth

* fix lp UTs, still pending the inbounds

* finish lp UTs

* fix IT last tests

* fix clippy and benchmarking

* fix issues after rebasing

* fix IT

* base refactor

* fix ids

* fix weird compilation issue

* fix clippy

* minor change
  • Loading branch information
lemunozm authored Aug 16, 2024
1 parent d1d823a commit eb7e14b
Show file tree
Hide file tree
Showing 41 changed files with 598 additions and 841 deletions.
135 changes: 73 additions & 62 deletions libs/types/src/domain_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,87 +10,96 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

use cfg_utils::vec_to_fixed_array;
use frame_support::pallet_prelude::RuntimeDebug;
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::traits::AccountIdConversion;
use sp_core::{crypto::AccountId32, H160};
use sp_runtime::{traits::AccountIdConversion, TypeId};

use crate::EVMChainId;

const MAX_ADDRESS_SIZE: usize = 32;

/// By just clamping the value to a smaller address
pub fn account_to_eth_address(address: AccountId32) -> H160 {
let bytes: [u8; 32] = address.into();
H160::from(
*(bytes)
.split_first_chunk::<20>()
.expect("always fit, qed")
.0,
)
}

/// By adding chain information to the new added bytes
pub fn eth_address_to_account(chain_id: u64, address: H160) -> AccountId32 {
// We use a custom encoding here rather than relying on
// `AccountIdConversion` for a couple of reasons:
// 1. We have very few bytes to spare, so choosing our own fields is nice
// 2. AccountIdConversion puts the tag first, which can unbalance the storage
// trees if users create many H160-derived accounts. We put the tag last
// here.
let tag = b"EVM";
let mut bytes = [0; 32];
bytes[0..20].copy_from_slice(&address.0);
bytes[20..28].copy_from_slice(&chain_id.to_be_bytes());
bytes[28..31].copy_from_slice(tag);
AccountId32::new(bytes)
}

/// A Domain is a chain or network we can send a message to.
#[derive(Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
#[derive(Encode, Decode, Clone, Copy, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
pub enum Domain {
/// Referring to the Centrifuge Parachain. Will be used for handling
/// incoming messages.
///
/// NOTE: messages CAN NOT be sent directly from the Centrifuge chain to the
/// Centrifuge chain itself.
/// Referring to the Centrifuge Chain.
Centrifuge,
/// An EVM domain, identified by its EVM Chain Id
EVM(EVMChainId),
Evm(EVMChainId),
}

impl TypeId for Domain {
const TYPE_ID: [u8; 4] = crate::ids::DOMAIN_ID;
}

impl Domain {
pub fn into_account<AccountId: Encode + Decode>(&self) -> AccountId {
DomainLocator {
domain: self.clone(),
}
.into_account_truncating()
self.into_account_truncating()
}
}

#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub struct DomainLocator<Domain> {
pub domain: Domain,
}

#[derive(Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
pub enum DomainAddress {
/// A Centrifuge-Chain based account address, 32-bytes long
Centrifuge([u8; 32]),
/// An EVM chain address, 20-bytes long
EVM(EVMChainId, [u8; 20]),
}

impl Default for DomainAddress {
fn default() -> Self {
DomainAddress::Centrifuge([0; 32])
}
/// A centrifuge based account
Centrifuge(AccountId32),
/// An EVM chain address
Evm(EVMChainId, H160),
}

impl DomainAddress {
pub fn evm(chain_id: EVMChainId, address: [u8; 20]) -> Self {
Self::EVM(chain_id, address)
}

pub fn centrifuge(address: [u8; 32]) -> Self {
Self::Centrifuge(address)
}
impl TypeId for DomainAddress {
const TYPE_ID: [u8; 4] = crate::ids::DOMAIN_ADDRESS_ID;
}

impl From<(EVMChainId, [u8; 20])> for DomainAddress {
fn from((chain_id, address): (EVMChainId, [u8; 20])) -> Self {
Self::evm(chain_id, address)
impl Default for DomainAddress {
fn default() -> Self {
DomainAddress::Centrifuge(AccountId32::new([0; 32]))
}
}

impl From<DomainAddress> for Domain {
fn from(x: DomainAddress) -> Self {
match x {
DomainAddress::Centrifuge(_) => Domain::Centrifuge,
DomainAddress::EVM(chain_id, _) => Domain::EVM(chain_id),
DomainAddress::Evm(chain_id, _) => Domain::Evm(chain_id),
}
}
}

impl DomainAddress {
/// Get the address in a 32-byte long representation.
/// For EVM addresses, append 12 zeros.
pub fn address(&self) -> [u8; 32] {
match self.clone() {
Self::Centrifuge(x) => x,
Self::EVM(_, x) => vec_to_fixed_array(x),
pub fn new(domain: Domain, address: [u8; MAX_ADDRESS_SIZE]) -> Self {
match domain {
Domain::Centrifuge => DomainAddress::Centrifuge(address.into()),
Domain::Evm(chain_id) => {
DomainAddress::Evm(chain_id, account_to_eth_address(address.into()))
}
}
}

Expand All @@ -99,24 +108,26 @@ impl DomainAddress {
}
}

#[cfg(test)]
mod tests {
use parity_scale_codec::{Decode, Encode};

use super::*;

#[test]
fn test_domain_encode_decode() {
test_domain_identity(Domain::Centrifuge);
test_domain_identity(Domain::EVM(1284));
test_domain_identity(Domain::EVM(1));
impl DomainAddress {
/// Returns the current address as an centrifuge address
pub fn account(&self) -> AccountId32 {
match self.clone() {
Self::Centrifuge(x) => x,
Self::Evm(chain_id, x) => eth_address_to_account(chain_id, x),
}
}

/// Test that (decode . encode) results in the original value
fn test_domain_identity(domain: Domain) {
let encoded = domain.encode();
let decoded = Domain::decode(&mut encoded.as_slice()).unwrap();
/// Returns the current address as an ethrerum address,
/// clamping the inner address if needed.
pub fn h160(&self) -> H160 {
match self.clone() {
Self::Centrifuge(x) => account_to_eth_address(x),
Self::Evm(_, x) => x,
}
}

assert_eq!(domain, decoded);
/// Returns the current address as plain bytes
pub fn bytes(&self) -> [u8; MAX_ADDRESS_SIZE] {
self.account().into()
}
}
14 changes: 3 additions & 11 deletions libs/types/src/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@
use frame_support::PalletId;
use sp_runtime::TypeId;

use crate::{
domain_address::{DomainAddress, DomainLocator},
investments::InvestmentAccount,
};
use crate::investments::InvestmentAccount;

// The TypeId impl we derive pool-accounts from
impl<InvestmentId> TypeId for InvestmentAccount<InvestmentId> {
Expand All @@ -45,10 +42,5 @@ pub const CHAIN_BRIDGE_NATIVE_TOKEN_ID: [u8; 4] = *b"xCFG";
/// The identifier of the group eligible to receive block rewards.
pub const COLLATOR_GROUP_ID: u32 = 1;

impl TypeId for DomainAddress {
const TYPE_ID: [u8; 4] = *b"dadr";
}

impl<Domain> TypeId for DomainLocator<Domain> {
const TYPE_ID: [u8; 4] = *b"domn";
}
pub const DOMAIN_ID: [u8; 4] = *b"domn";
pub const DOMAIN_ADDRESS_ID: [u8; 4] = *b"dadr";
14 changes: 7 additions & 7 deletions node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ use cfg_primitives::{
SAFE_XCM_VERSION,
};
use cfg_types::{
domain_address::DomainAddress,
fee_keys::FeeKey,
tokens::{usdc, AssetMetadata, CrossChainTransferability, CurrencyId, CustomMetadata},
};
use cfg_utils::vec_to_fixed_array;
use cumulus_primitives_core::ParaId;
use hex_literal::hex;
use runtime_common::account_conversion::AccountConverter;
use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
use sc_service::{ChainType, Properties};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -271,8 +271,8 @@ fn centrifuge_genesis(
let chain_id: u32 = id.into();

endowed_accounts.extend(endowed_evm_accounts.into_iter().map(|(addr, id)| {
let chain_id = id.unwrap_or_else(|| chain_id.into());
AccountConverter::convert_evm_address(chain_id, addr)
let chain_id = id.unwrap_or(chain_id.into());
DomainAddress::Evm(chain_id, addr.into()).account()
}));

let num_endowed_accounts = endowed_accounts.len();
Expand Down Expand Up @@ -371,8 +371,8 @@ fn altair_genesis(
let chain_id: u32 = id.into();

endowed_accounts.extend(endowed_evm_accounts.into_iter().map(|(addr, id)| {
let chain_id = id.unwrap_or_else(|| chain_id.into());
AccountConverter::convert_evm_address(chain_id, addr)
let chain_id = id.unwrap_or(chain_id.into());
DomainAddress::Evm(chain_id, addr.into()).account()
}));

let num_endowed_accounts = endowed_accounts.len();
Expand Down Expand Up @@ -472,8 +472,8 @@ fn development_genesis(
let chain_id: u32 = id.into();

endowed_accounts.extend(endowed_evm_accounts.into_iter().map(|(addr, id)| {
let chain_id = id.unwrap_or_else(|| chain_id.into());
AccountConverter::convert_evm_address(chain_id, addr)
let chain_id = id.unwrap_or(chain_id.into());
DomainAddress::Evm(chain_id, addr.into()).account()
}));

let num_endowed_accounts = endowed_accounts.len();
Expand Down
6 changes: 2 additions & 4 deletions pallets/axelar-router/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ pub mod pallet {

T::Receiver::receive(
AxelarId::Evm(chain_id).into(),
DomainAddress::EVM(chain_id, source_address_bytes),
DomainAddress::Evm(chain_id, source_address_bytes.into()),
payload.to_vec(),
)
}
Expand Down Expand Up @@ -330,8 +330,6 @@ pub mod pallet {

match config.domain {
DomainConfig::Evm(evm_config) => {
let sender_evm_address = H160::from_slice(&origin.address()[0..20]);

let message = wrap_into_axelar_msg(
message,
chain_name.into_inner(),
Expand All @@ -340,7 +338,7 @@ pub mod pallet {
.map_err(DispatchError::Other)?;

T::Transactor::call(
sender_evm_address,
origin.h160(),
evm_config.target_contract_address,
message.as_slice(),
evm_config.fee_values.value,
Expand Down
8 changes: 4 additions & 4 deletions pallets/axelar-router/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use frame_support::{assert_err, assert_noop, assert_ok};
use sp_core::U256;
use sp_core::{crypto::AccountId32, U256};

use crate::{mock::*, *};

Expand All @@ -9,7 +9,7 @@ const LP_CONTRACT_ADDRESS: H160 = H160::repeat_byte(1);
const AXELAR_CONTRACT_ADDRESS: H160 = H160::repeat_byte(2);
const SOURCE_ADDRESS: H160 = H160::repeat_byte(3);
const AXELAR_CONTRACT_HASH: H256 = H256::repeat_byte(42);
const SENDER: DomainAddress = DomainAddress::Centrifuge([0; 32]);
const SENDER: DomainAddress = DomainAddress::Centrifuge(AccountId32::new([0; 32]));
const MESSAGE: &[u8] = &[1, 2, 3];
const FEE_VALUE: U256 = U256::zero();
const GAS_LIMIT: U256 = U256::one();
Expand Down Expand Up @@ -91,7 +91,7 @@ mod send {
correct_configuration();

Transactor::mock_call(move |from, to, data, value, gas_price, gas_limit| {
assert_eq!(from, H160::from_slice(&SENDER.address()[0..20]));
assert_eq!(from, SENDER.h160());
assert_eq!(to, AXELAR_CONTRACT_ADDRESS);
assert_eq!(data, &wrap_message(MESSAGE.to_vec()));
assert_eq!(value, FEE_VALUE);
Expand Down Expand Up @@ -143,7 +143,7 @@ mod receive {

Receiver::mock_receive(|middleware, origin, message| {
assert_eq!(middleware, Middleware(AxelarId::Evm(CHAIN_ID)));
assert_eq!(origin, DomainAddress::EVM(CHAIN_ID, SOURCE_ADDRESS.0));
assert_eq!(origin, DomainAddress::Evm(CHAIN_ID, SOURCE_ADDRESS));
assert_eq!(&message, MESSAGE);
Ok(())
});
Expand Down
4 changes: 2 additions & 2 deletions pallets/liquidity-pools-gateway/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ pub mod pallet {
T::AdminOrigin::ensure_origin(origin)?;

ensure!(domain != Domain::Centrifuge, Error::<T>::DomainNotSupported);
DomainHookAddress::<T>::insert(domain.clone(), hook_address);
DomainHookAddress::<T>::insert(domain, hook_address);

Self::deposit_event(Event::DomainHookAddressSet {
domain,
Expand Down Expand Up @@ -495,7 +495,7 @@ pub mod pallet {
Error::<T>::DomainNotSupported
);

PackedMessage::<T>::mutate((&from, destination.clone()), |batch| match batch {
PackedMessage::<T>::mutate((&from, destination), |batch| match batch {
Some(batch) => batch.pack_with(message),
None => Self::queue_outbound_message(destination, message),
})
Expand Down
9 changes: 5 additions & 4 deletions pallets/liquidity-pools-gateway/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ use frame_support::{derive_impl, weights::constants::RocksDbWeight};
use frame_system::EnsureRoot;
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_core::{crypto::AccountId32, H256};
use sp_core::{crypto::AccountId32, H160};
use sp_runtime::{traits::IdentityLookup, DispatchError, DispatchResult};

use crate::{pallet as pallet_liquidity_pools_gateway, EnsureLocal, GatewayMessage};

pub const TEST_SESSION_ID: u32 = 1;
pub const TEST_EVM_CHAIN: EVMChainId = 1;
pub const TEST_DOMAIN_ADDRESS: DomainAddress = DomainAddress::EVM(TEST_EVM_CHAIN, [1; 20]);
pub const TEST_DOMAIN_ADDRESS: DomainAddress =
DomainAddress::Evm(TEST_EVM_CHAIN, H160::repeat_byte(1));

pub const ROUTER_ID_1: RouterId = RouterId(1);
pub const ROUTER_ID_2: RouterId = RouterId(2);
Expand Down Expand Up @@ -123,7 +124,7 @@ impl RouterProvider<Domain> for TestRouterProvider {
fn routers_for_domain(domain: Domain) -> Vec<Self::RouterId> {
match domain {
Domain::Centrifuge => vec![],
Domain::EVM(_) => vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3],
Domain::Evm(_) => vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3],
}
}
}
Expand Down Expand Up @@ -161,7 +162,7 @@ impl cfg_mocks::router_message::pallet::Config for Runtime {
}

frame_support::parameter_types! {
pub Sender: DomainAddress = DomainAddress::Centrifuge(AccountId32::from(H256::from_low_u64_be(123).to_fixed_bytes()).into());
pub Sender: DomainAddress = DomainAddress::Centrifuge(AccountId32::from([1; 32]));
pub const MaxIncomingMessageSize: u32 = 1024;
pub const LpAdminAccount: AccountId32 = LP_ADMIN_ACCOUNT;
pub const MaxRouterCount: u32 = 8;
Expand Down
7 changes: 1 addition & 6 deletions pallets/liquidity-pools-gateway/src/origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ use cfg_types::domain_address::DomainAddress;
use frame_support::traits::EnsureOrigin;
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
#[cfg(feature = "runtime-benchmarks")]
use sp_core::H160;
use sp_runtime::RuntimeDebug;

#[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)]
Expand All @@ -34,9 +32,6 @@ impl<O: Into<Result<GatewayOrigin, O>> + From<GatewayOrigin>> EnsureOrigin<O> fo

#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin() -> Result<O, ()> {
Ok(O::from(GatewayOrigin::Domain(DomainAddress::EVM(
1,
H160::from_low_u64_be(1).into(),
))))
unimplemented!()
}
}
Loading

0 comments on commit eb7e14b

Please sign in to comment.