Implement new with CREATE2 and function call options.

This commit is contained in:
Mathias Baumann
2020-01-23 21:20:01 +01:00
committed by chriseth
parent 679f729f2f
commit a3f23d3158
28 changed files with 528 additions and 38 deletions
+34
View File
@@ -1929,6 +1929,40 @@ BOOST_AUTO_TEST_CASE(gas_and_value_basic)
BOOST_REQUIRE(callContractFunction("checkState()") == encodeArgs(false, 20 - 5));
}
BOOST_AUTO_TEST_CASE(gas_and_value_brace_syntax)
{
char const* sourceCode = R"(
contract helper {
bool flag;
function getBalance() payable public returns (uint256 myBalance) {
return address(this).balance;
}
function setFlag() public { flag = true; }
function getFlag() public returns (bool fl) { return flag; }
}
contract test {
helper h;
constructor() public payable { h = new helper(); }
function sendAmount(uint amount) public payable returns (uint256 bal) {
return h.getBalance{value: amount}();
}
function outOfGas() public returns (bool ret) {
h.setFlag{gas: 2}(); // should fail due to OOG
return true;
}
function checkState() public returns (bool flagAfter, uint myBal) {
flagAfter = h.getFlag();
myBal = address(this).balance;
}
}
)";
compileAndRun(sourceCode, 20);
BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(5));
// call to helper should not succeed but amount should be transferred anyway
BOOST_REQUIRE(callContractFunction("outOfGas()") == bytes());
BOOST_REQUIRE(callContractFunction("checkState()") == encodeArgs(false, 20 - 5));
}
BOOST_AUTO_TEST_CASE(gasleft_decrease)
{
char const* sourceCode = R"(
@@ -0,0 +1,17 @@
contract D {}
contract C {
function foo(int a) payable external {
this.foo{gas:2, gas: 5};
this.foo{value:2, value: 5};
this.foo{gas:2, value: 5, gas:2, value:3};
new D{salt:"abc", salt:"efg"}();
}
}
// ====
// EVMVersion: >=constantinople
// ----
// TypeError: (78-101): Duplicate option "gas".
// TypeError: (111-138): Duplicate option "value".
// TypeError: (148-189): Duplicate option "gas".
// TypeError: (148-189): Duplicate option "value".
// TypeError: (199-228): Duplicate option "salt".
@@ -0,0 +1,8 @@
contract C {
function foo() pure internal {
address(10).delegatecall{value: 7, gas: 3}("");
}
}
// ----
// TypeError: (56-98): Cannot set option "value" for delegatecall.
// Warning: (56-102): Return value of low-level calls not used.
@@ -0,0 +1,8 @@
contract D {}
contract C {
function foo(int a) pure internal {
foo{gas: 5};
}
}
// ----
// TypeError: (75-86): Function call options can only be set on external function calls or contract creations.
@@ -0,0 +1,21 @@
contract D {}
contract C {
function foo(int a) payable external {
this.foo{value:2, gas: 5}{gas:2};
(this.foo{value:2, gas: 5}){gas:2};
this.foo{value:2, gas: 5}{value:6};
this.foo.value(4){value:2, gas: 5};
this.foo{gas:2, value: 5}{value:2, gas:5};
new D{salt:"abc"}{salt:"a"}();
}
}
// ====
// EVMVersion: >=constantinople
// ----
// TypeError: (78-110): Option "gas" has already been set.
// TypeError: (120-154): Option "gas" has already been set.
// TypeError: (164-198): Option "value" has already been set.
// TypeError: (208-242): Option "value" has already been set.
// TypeError: (252-293): Option "value" has already been set.
// TypeError: (252-293): Option "gas" has already been set.
// TypeError: (303-330): Option "salt" has already been set.
@@ -0,0 +1,8 @@
contract D {}
contract C {
function foo(int a) pure internal {
a{val:5};
}
}
// ----
// TypeError: (71-79): Expected callable expression before call options.
@@ -0,0 +1,8 @@
contract D {}
contract C {
function foo(int a) pure external {
this.foo{random:5+5};
}
}
// ----
// TypeError: (73-93): Unknown call option "random". Valid options are "salt", "value" and "gas".
@@ -0,0 +1,10 @@
contract D {}
contract C {
function foo(int a) external {
this.foo{slt:5, value:3, salt: 8};
}
}
// ----
// TypeError: (64-97): Unknown call option "slt". Valid options are "salt", "value" and "gas".
// TypeError: (64-97): Cannot set option "value" on a non-payable function type.
// TypeError: (64-97): Function call option "salt" can only be used with "new".
@@ -0,0 +1,7 @@
contract C {
function foo() internal {
(bool success, ) = address(10).call{value: 7, gas: 3}("");
success;
}
}
// ----
@@ -0,0 +1,12 @@
contract D { constructor() public payable {} }
contract C {
function foo() pure internal {
new D{salt:"abc", value:3};
new D{salt:"abc"};
new D{value:5+5};
new D{salt:"aabbcc"};
}
}
// ====
// EVMVersion: >=constantinople
// ----
@@ -0,0 +1,15 @@
contract D { constructor() public payable {} }
contract C {
function foo() pure internal {
new D{salt:"abc", value:3};
new D{salt:"abc"};
new D{value:5+5};
new D{salt:"aabbcc"};
}
}
// ====
// EVMVersion: <constantinople
// ----
// TypeError: (97-123): Unsupported call option "salt" (requires Constantinople-compatible VMs).
// TypeError: (127-144): Unsupported call option "salt" (requires Constantinople-compatible VMs).
// TypeError: (168-188): Unsupported call option "salt" (requires Constantinople-compatible VMs).
@@ -0,0 +1,27 @@
contract D {}
contract C {
function foo() pure internal {
new D{salt:"abc", value:3, gas: 4};
new D{slt:5, value:3};
new D{val:5};
new D{salt:"xyz", salt:"aaf"};
new D{value:3, value:4};
new D{random:5+5};
new D{what:2130+5};
new D{gas: 2};
}
}
// ====
// EVMVersion: >=constantinople
// ----
// TypeError: (64-98): Cannot set option "value" on a non-payable function type.
// TypeError: (64-98): Function call option "gas" cannot be used with "new".
// TypeError: (102-123): Unknown call option "slt". Valid options are "salt", "value" and "gas".
// TypeError: (102-123): Cannot set option "value" on a non-payable function type.
// TypeError: (127-139): Unknown call option "val". Valid options are "salt", "value" and "gas".
// TypeError: (143-172): Duplicate option "salt".
// TypeError: (176-199): Cannot set option "value" on a non-payable function type.
// TypeError: (176-199): Cannot set option "value" on a non-payable function type.
// TypeError: (203-220): Unknown call option "random". Valid options are "salt", "value" and "gas".
// TypeError: (224-242): Unknown call option "what". Valid options are "salt", "value" and "gas".
// TypeError: (246-259): Function call option "gas" cannot be used with "new".
@@ -0,0 +1,14 @@
contract C {
struct gas { uint a; }
function f() public returns (uint, uint) {
try this.f() {
gas memory x;
} catch Error(string memory) {
}
}
}
// ====
// EVMVersion: >=byzantium
// ----
// Warning: (122-134): Unused local variable.