cfx_types/contract_address.rs
1use super::{
2 Address, AddressSpaceUtil, AddressUtil, AddressWithSpace, Space, H256, U256,
3};
4use keccak_hash::keccak;
5use rlp::RlpStream;
6
7/// Specifies how an address is calculated for a new contract.
8#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
9pub enum CreateContractAddressType {
10 /// Address is calculated from sender and nonce. Ethereum
11 /// `create` scheme.
12 FromSenderNonce,
13 /// Address is calculated from sender, nonce, and code hash. Conflux
14 /// `create` scheme.
15 FromSenderNonceAndCodeHash,
16 /// Address is calculated from block_hash, sender, nonce and code_hash.
17 /// Potential new Conflux `create` scheme when kill_dust is enabled.
18 FromBlockNumberSenderNonceAndCodeHash,
19 /// Address is calculated from sender, salt and code hash. Conflux and
20 /// Ethereum `create2` scheme.
21 FromSenderSaltAndCodeHash(H256),
22}
23
24/// Calculate new contract address.
25pub fn cal_contract_address(
26 address_scheme: CreateContractAddressType, sender: &Address, nonce: &U256,
27 code: &[u8],
28) -> (Address, H256) {
29 let code_hash = keccak(code);
30 let (address, code_hash) = match address_scheme {
31 CreateContractAddressType::FromSenderNonce => {
32 let mut rlp = RlpStream::new_list(2);
33 rlp.append(sender);
34 rlp.append(nonce);
35 let h = Address::from(keccak(rlp.as_raw()));
36 (h, code_hash)
37 }
38 CreateContractAddressType::FromBlockNumberSenderNonceAndCodeHash => {
39 unreachable!("Inactive setting");
40 // let mut buffer = [0u8; 1 + 8 + 20 + 32 + 32];
41 // let (lead_bytes, rest) = buffer.split_at_mut(1);
42 // let (block_number_bytes, rest) = rest.split_at_mut(8);
43 // let (sender_bytes, rest) =
44 // rest.split_at_mut(Address::len_bytes());
45 // let (nonce_bytes, code_hash_bytes) =
46 // rest.split_at_mut(H256::len_bytes());
47 // // In Conflux, we take block_number and CodeHash into address
48 // // calculation. This is required to enable us to clean
49 // // up unused user account in future.
50 // lead_bytes[0] = 0x0;
51 // block_number.to_little_endian(block_number_bytes);
52 // sender_bytes.copy_from_slice(&sender.address[..]);
53 // nonce.to_little_endian(nonce_bytes);
54 // code_hash_bytes.copy_from_slice(&code_hash[..]);
55 // // In Conflux, we use the first four bits to indicate the type of
56 // // the address. For contract address, the bits will be
57 // // set to 0x8.
58 // let mut h = Address::from(keccak(&buffer[..]));
59 // h.set_contract_type_bits();
60 // (h, code_hash)
61 }
62 CreateContractAddressType::FromSenderNonceAndCodeHash => {
63 let mut buffer = [0u8; 1 + 20 + 32 + 32];
64 // In Conflux, we append CodeHash to determine the address as well.
65 // This is required to enable us to clean up unused user account in
66 // future.
67 buffer[0] = 0x0;
68 buffer[1..(1 + 20)].copy_from_slice(&sender[..]);
69 nonce.to_little_endian(&mut buffer[(1 + 20)..(1 + 20 + 32)]);
70 buffer[(1 + 20 + 32)..].copy_from_slice(&code_hash[..]);
71 // In Conflux, we use the first four bits to indicate the type of
72 // the address. For contract address, the bits will be
73 // set to 0x8.
74 let h = Address::from(keccak(&buffer[..]));
75 (h, code_hash)
76 }
77 CreateContractAddressType::FromSenderSaltAndCodeHash(salt) => {
78 let mut buffer = [0u8; 1 + 20 + 32 + 32];
79 buffer[0] = 0xff;
80 buffer[1..(1 + 20)].copy_from_slice(&sender[..]);
81 buffer[(1 + 20)..(1 + 20 + 32)].copy_from_slice(&salt[..]);
82 buffer[(1 + 20 + 32)..].copy_from_slice(&code_hash[..]);
83 // In Conflux, we use the first bit to indicate the type of the
84 // address. For contract address, the bits will be set to 0x8.
85 let h = Address::from(keccak(&buffer[..]));
86 (h, code_hash)
87 }
88 };
89 return (address, code_hash);
90}
91
92pub fn cal_contract_address_with_space(
93 address_scheme: CreateContractAddressType, sender: &AddressWithSpace,
94 nonce: &U256, code: &[u8],
95) -> (AddressWithSpace, H256) {
96 let (mut address, code_hash) =
97 cal_contract_address(address_scheme, &sender.address, nonce, code);
98 if sender.space == Space::Native {
99 address.set_contract_type_bits();
100 }
101 (address.with_space(sender.space), code_hash)
102}