Skip to content

Commit

Permalink
Customizable ink address (paritytech#10521)
Browse files Browse the repository at this point in the history
  • Loading branch information
kvinwang authored and ark0f committed Feb 27, 2023
1 parent 8528995 commit 040580c
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 16 deletions.
1 change: 1 addition & 0 deletions bin/node/runtime/src/lib.rs
Expand Up @@ -957,6 +957,7 @@ impl pallet_contracts::Config for Runtime {
type DeletionQueueDepth = DeletionQueueDepth;
type DeletionWeightLimit = DeletionWeightLimit;
type Schedule = Schedule;
type AddressGenerator = pallet_contracts::DefaultAddressGenerator;
}

impl pallet_sudo::Config for Runtime {
Expand Down
71 changes: 56 additions & 15 deletions frame/contracts/src/lib.rs
Expand Up @@ -136,6 +136,55 @@ type BalanceOf<T> =
/// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(6);

/// Provides the contract address generation method.
///
/// See [`DefaultAddressGenerator`] for the default implementation.
pub trait AddressGenerator<T: frame_system::Config> {
/// Generate the address of a contract based on the given instantiate parameters.
///
/// # Note for implementors
/// 1. Make sure that there are no collisions, different inputs never lead to the same output.
/// 2. Make sure that the same inputs lead to the same output.
/// 3. Changing the implementation through a runtime upgrade without a proper storage migration
/// would lead to catastrophic misbehavior.
fn generate_address(
deploying_address: &T::AccountId,
code_hash: &CodeHash<T>,
salt: &[u8],
) -> T::AccountId;
}

/// Default address generator.
///
/// This is the default address generator used by contract instantiation. Its result
/// is only dependend on its inputs. It can therefore be used to reliably predict the
/// address of a contract. This is akin to the formular of eth's CREATE2 opcode. There
/// is no CREATE equivalent because CREATE2 is strictly more powerful.
///
/// Formula: `hash(deploying_address ++ code_hash ++ salt)`
pub struct DefaultAddressGenerator;

impl<T> AddressGenerator<T> for DefaultAddressGenerator
where
T: frame_system::Config,
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
{
fn generate_address(
deploying_address: &T::AccountId,
code_hash: &CodeHash<T>,
salt: &[u8],
) -> T::AccountId {
let buf: Vec<_> = deploying_address
.as_ref()
.iter()
.chain(code_hash.as_ref())
.chain(salt)
.cloned()
.collect();
UncheckedFrom::unchecked_from(T::Hashing::hash(&buf))
}
}

#[frame_support::pallet]
pub mod pallet {
use super::*;
Expand Down Expand Up @@ -227,6 +276,9 @@ pub mod pallet {
/// Changing this value for an existing chain might need a storage migration.
#[pallet::constant]
type DepositPerItem: Get<BalanceOf<Self>>;

/// The address generator used to generate the addresses of contracts.
type AddressGenerator: AddressGenerator<Self>;
}

#[pallet::pallet]
Expand Down Expand Up @@ -728,27 +780,16 @@ where
Ok(maybe_value)
}

/// Determine the address of a contract,
///
/// This is the address generation function used by contract instantiation. Its result
/// is only dependend on its inputs. It can therefore be used to reliably predict the
/// address of a contract. This is akin to the formular of eth's CREATE2 opcode. There
/// is no CREATE equivalent because CREATE2 is strictly more powerful.
/// Determine the address of a contract.
///
/// Formula: `hash(deploying_address ++ code_hash ++ salt)`
/// This is the address generation function used by contract instantiation. See
/// [`DefaultAddressGenerator`] for the default implementation.
pub fn contract_address(
deploying_address: &T::AccountId,
code_hash: &CodeHash<T>,
salt: &[u8],
) -> T::AccountId {
let buf: Vec<_> = deploying_address
.as_ref()
.iter()
.chain(code_hash.as_ref())
.chain(salt)
.cloned()
.collect();
UncheckedFrom::unchecked_from(T::Hashing::hash(&buf))
T::AddressGenerator::generate_address(deploying_address, code_hash, salt)
}

/// Store code for benchmarks which does not check nor instrument the code.
Expand Down
4 changes: 3 additions & 1 deletion frame/contracts/src/tests.rs
Expand Up @@ -24,7 +24,8 @@ use crate::{
storage::Storage,
wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode},
weights::WeightInfo,
BalanceOf, Code, CodeStorage, Config, ContractInfoOf, Error, Pallet, Schedule,
BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, Error, Pallet,
Schedule,
};
use assert_matches::assert_matches;
use codec::Encode;
Expand Down Expand Up @@ -285,6 +286,7 @@ impl Config for Test {
type Schedule = MySchedule;
type DepositPerByte = DepositPerByte;
type DepositPerItem = DepositPerItem;
type AddressGenerator = DefaultAddressGenerator;
}

pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]);
Expand Down

0 comments on commit 040580c

Please sign in to comment.