Skip to content

Commit

Permalink
Merge pull request #13533 from ethereum/evmhost-create
Browse files Browse the repository at this point in the history
EVMHost: Calculate address for CREATE properly
  • Loading branch information
axic authored Sep 28, 2022
2 parents 5f8b487 + 0357ced commit 2201526
Show file tree
Hide file tree
Showing 15 changed files with 114 additions and 21 deletions.
35 changes: 30 additions & 5 deletions test/EVMHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,23 +250,48 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept

if (message.kind == EVMC_CREATE)
{
// TODO this is not the right formula
// TODO is the nonce incremented on failure, too?
// NOTE: nonce for creation from contracts starts at 1
// TODO: check if sender is an EOA and do not pre-increment
sender.nonce++;

auto encodeRlpInteger = [](int value) -> bytes {
if (value == 0) {
return bytes{128};
} else if (value <= 127) {
return bytes{static_cast<uint8_t>(value)};
} else if (value <= 0xff) {
return bytes{128 + 1, static_cast<uint8_t>(value)};
} else if (value <= 0xffff) {
return bytes{128 + 55 + 2, static_cast<uint8_t>(value >> 8), static_cast<uint8_t>(value)};
} else {
assertThrow(false, Exception, "Can only encode RLP numbers <= 0xffff");
}
};

bytes encodedNonce = encodeRlpInteger(sender.nonce);

h160 createAddress(keccak256(
bytes{static_cast<uint8_t>(0xc0 + 21 + encodedNonce.size())} +
bytes{0x94} +
bytes(begin(message.sender.bytes), end(message.sender.bytes)) +
asBytes(to_string(sender.nonce++))
), h160::AlignLeft);
encodedNonce
), h160::AlignRight);

message.destination = convertToEVMC(createAddress);
assertThrow(accounts.count(message.destination) == 0, Exception, "Account cannot exist");

code = evmc::bytes(message.input_data, message.input_data + message.input_size);
}
else if (message.kind == EVMC_CREATE2)
{
h160 createAddress(keccak256(
bytes(1, 0xff) +
bytes{0xff} +
bytes(begin(message.sender.bytes), end(message.sender.bytes)) +
bytes(begin(message.create2_salt.bytes), end(message.create2_salt.bytes)) +
keccak256(bytes(message.input_data, message.input_data + message.input_size)).asBytes()
), h160::AlignLeft);
), h160::AlignRight);

message.destination = convertToEVMC(createAddress);
if (accounts.count(message.destination) && (
accounts[message.destination].nonce > 0 ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ contract C {
// gas legacy: 250376
// gas legacyOptimized: 174522
// deposit(bytes32), 18 wei: 0x1234 ->
// ~ emit Deposit(address,bytes32,uint256) from 0xf01f7809444bd9a93a854361c6fae3f23d9e23db: #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b, #0x1234, 0x00
// ~ emit Deposit(address,bytes32,uint256) from 0x137aa4dfc0911524504fcd4d98501f179bc13b4a: #0xc06afe3a8444fc0004668591e8306bfb9968e79e, #0x1234, 0x00
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ contract C {
}
// ----
// f() ->
// ~ emit Test(function): #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b26121ff00000000000000000
// ~ emit Test(function): #0xc06afe3a8444fc0004668591e8306bfb9968e79e26121ff00000000000000000
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ contract C {
}
// ----
// f1() ->
// ~ emit TestA(function): #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87bc27fc3050000000000000000
// ~ emit TestA(function): #0xc06afe3a8444fc0004668591e8306bfb9968e79ec27fc3050000000000000000
// f2(uint256): 1 ->
// ~ emit TestB(function): #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87bbf3724af0000000000000000
// ~ emit TestB(function): #0xc06afe3a8444fc0004668591e8306bfb9968e79ebf3724af0000000000000000
4 changes: 2 additions & 2 deletions test/libsolidity/semanticTests/functionCall/failed_create.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract C {
// gas irOptimized: 184005
// gas legacy: 294335
// gas legacyOptimized: 173427
// f(uint256): 20 -> 1370859564726510389319704988634906228201275401179
// f(uint256): 20 -> 0x137aa4dfc0911524504fcd4d98501f179bc13b4a
// x() -> 1
// f(uint256): 20 -> FAILURE
// x() -> 1
Expand All @@ -29,5 +29,5 @@ contract C {
// gas legacy: 483942
// gas legacyOptimized: 302349
// x() -> 1
// stack(uint256): 10 -> 693016686122178122849713379390321835634789309880
// stack(uint256): 10 -> 0x87948bd7ebbe13a00bfd930c93e4828ab18e3908
// x() -> 2
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ contract C {
// ====
// compileToEwasm: also
// ----
// f() -> 90572315268751552425567948436632610904688605307, 90572315268751552425567948436632610904688605307
// f() -> 0xc06afe3a8444fc0004668591e8306bfb9968e79e, 0xc06afe3a8444fc0004668591e8306bfb9968e79e
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ contract C {
// increment() ->
// y() -> 1
// set() ->
// x() -> 0xfdd67305928fcac8d213d1e47bfa6165cd0b87bd09de08a0000000000000000
// x() -> 0xc06afe3a8444fc0004668591e8306bfb9968e79ed09de08a0000000000000000
// increment() ->
// y() -> 2
// incrementIndirectly() ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ contract C {
}
}
// ----
// testYul() -> 0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b
// testSol() -> 0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b
// testYul() -> 0xc06afe3a8444fc0004668591e8306bfb9968e79e
// testSol() -> 0xc06afe3a8444fc0004668591e8306bfb9968e79e
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ contract ClientReceipt {
// gas irOptimized: 191881
// gas legacy: 235167
// gas legacyOptimized: 180756
// getAddress() -> 0xf01f7809444bd9a93a854361c6fae3f23d9e23db
// balance: 0xf01f7809444bd9a93a854361c6fae3f23d9e23db -> 500
// getAddress() -> 0x137aa4dfc0911524504fcd4d98501f179bc13b4a
// balance: 0x137aa4dfc0911524504fcd4d98501f179bc13b4a -> 500
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
contract D {
uint public x;
constructor(uint a) {
x = a;
}
}

contract C {
function createDSalted(bytes32 salt, uint arg) public {
address predictedAddress = address(uint160(uint(keccak256(abi.encodePacked(
bytes1(0xff),
address(this),
salt,
keccak256(abi.encodePacked(
type(D).creationCode,
arg
))
)))));

D d = new D{salt: salt}(arg);
require(address(d) == predictedAddress, "Address mismatch.");
}
}
// ====
// EVMVersion: >=constantinople
// compileViaYul: also
// ----
// createDSalted(bytes32,uint256): 42, 64 ->
// gas legacy: 104365
2 changes: 1 addition & 1 deletion test/libsolidity/semanticTests/tryCatch/create.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ contract C {
// EVMVersion: >=byzantium
// ----
// f() -> 0, 0, 96, 13, "test message."
// g() -> 0xf01f7809444bd9a93a854361c6fae3f23d9e23db, 0, 96, 7, "success"
// g() -> 0x137aa4dfc0911524504fcd4d98501f179bc13b4a, 0, 96, 7, "success"
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ contract C {
function fun() public pure {}
}
// ----
// f() -> 0x1, 0xfdd67305928fcac8d213d1e47bfa6165cd0b87b946644cd0000000000000000, 9
// f() -> 0x1, 0xc06afe3a8444fc0004668591e8306bfb9968e79e946644cd0000000000000000, 9
39 changes: 39 additions & 0 deletions test/libsolidity/semanticTests/various/create_random.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
contract C {
function addr() external returns (address) {
return address(this);
}

function testRunner() external returns (address a1, address a2) {
assembly {
// This is `return(0, 1)`. We are using a simplified/fixed initcode to avoid
// instability due to metadata changes.
let initcode := hex"60016000f3"
mstore(0, initcode)

a1 := create(0, 0, 5)
a2 := create2(0, 0, 5, address())
}
}

function testCalc() external returns (address a1, address a2) {
a1 = calculateCreate(address(this), 1);
a2 = calculateCreate2(address(this), keccak256(hex"60016000f3"), bytes32(uint256(uint160(address(this)))));
}

function calculateCreate(address from, uint256 nonce) private pure returns (address) {
assert(nonce <= 127);
bytes memory data =
bytes.concat(hex"d694", bytes20(uint160(from)), nonce == 0 ? bytes1(hex"80") : bytes1(uint8(nonce)));
return address(uint160(uint256(keccak256(data)))); // Take the lower 160-bits
}

function calculateCreate2(address creator, bytes32 codehash, bytes32 salt) private pure returns (address) {
return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), creator, salt, codehash)))));
}
}
// ====
// EVMVersion: >=constantinople
// ----
// addr() -> 0xc06afe3a8444fc0004668591e8306bfb9968e79e
// testRunner() -> 0x137aa4dfc0911524504fcd4d98501f179bc13b4a, 0x2c1c30623ddd93e0b765a6caaca0c859eeb0644d
// testCalc() -> 0x137aa4dfc0911524504fcd4d98501f179bc13b4a, 0x2c1c30623ddd93e0b765a6caaca0c859eeb0644d
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ contract C {
// ----
// f(uint256): 2 -> 4
// h(uint256): 2 -> 5
// t() -> 0xFDD67305928FCAC8D213D1E47BFA6165CD0B87BB3DE648B0000000000000000, 0xFDD67305928FCAC8D213D1E47BFA6165CD0B87BB3DE648B0000000000000000
// t() -> 0xc06afe3a8444fc0004668591e8306bfb9968e79eb3de648b0000000000000000, 0xc06afe3a8444fc0004668591e8306bfb9968e79eb3de648b0000000000000000
2 changes: 1 addition & 1 deletion test/libsolidity/semanticTests/viaYul/function_address.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ contract C {
// ====
// compileToEwasm: also
// ----
// f() -> 0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b
// f() -> 0xc06afe3a8444fc0004668591e8306bfb9968e79e
// g() -> true
// h(function): left(0x1122334400112233445566778899AABBCCDDEEFF42424242) -> 0x1122334400112233445566778899AABBCCDDEEFF

0 comments on commit 2201526

Please sign in to comment.