mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
test: some tests for push0
1. `push0_disallowed.yul`: checks if `push0()` is a valid builtin in strict Yul 2. `push0_disallowed.sol`: checks if `push0()` is a valid builtin in inline assembly 3. `push0.sol`: simple semantic test that returns 0 4. `evmone_support.sol`: tests if push0 works properly in evmone 5. Updated some bytecode too large tests to use `shanghai` as version 6. Updated various tests where `push1 0` was hardcoded in different forms / expectations on bytecode size (`Assembler.cpp`, `GasCosts.cpp`, `SolidityCompiler.cpp`, `SolidityExpressionCompiler.cpp`)
This commit is contained in:
parent
802f895062
commit
41ce3feb0a
@ -31,7 +31,7 @@ REPODIR="$(realpath "$(dirname "$0")"/..)"
|
|||||||
# shellcheck source=scripts/common.sh
|
# shellcheck source=scripts/common.sh
|
||||||
source "${REPODIR}/scripts/common.sh"
|
source "${REPODIR}/scripts/common.sh"
|
||||||
|
|
||||||
EVM_VALUES=(homestead byzantium constantinople petersburg istanbul berlin london paris)
|
EVM_VALUES=(homestead byzantium constantinople petersburg istanbul berlin london paris shanghai)
|
||||||
DEFAULT_EVM=paris
|
DEFAULT_EVM=paris
|
||||||
[[ " ${EVM_VALUES[*]} " =~ $DEFAULT_EVM ]]
|
[[ " ${EVM_VALUES[*]} " =~ $DEFAULT_EVM ]]
|
||||||
OPTIMIZE_VALUES=(0 1)
|
OPTIMIZE_VALUES=(0 1)
|
||||||
|
@ -105,7 +105,7 @@ EVM_VERSIONS="homestead byzantium"
|
|||||||
|
|
||||||
if [ -z "$CI" ]
|
if [ -z "$CI" ]
|
||||||
then
|
then
|
||||||
EVM_VERSIONS+=" constantinople petersburg istanbul berlin london paris"
|
EVM_VERSIONS+=" constantinople petersburg istanbul berlin london paris shanghai"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# And then run the Solidity unit-tests in the matrix combination of optimizer / no optimizer
|
# And then run the Solidity unit-tests in the matrix combination of optimizer / no optimizer
|
||||||
|
@ -124,6 +124,8 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm):
|
|||||||
m_evmRevision = EVMC_LONDON;
|
m_evmRevision = EVMC_LONDON;
|
||||||
else if (_evmVersion == langutil::EVMVersion::paris())
|
else if (_evmVersion == langutil::EVMVersion::paris())
|
||||||
m_evmRevision = EVMC_PARIS;
|
m_evmRevision = EVMC_PARIS;
|
||||||
|
else if (_evmVersion == langutil::EVMVersion::shanghai())
|
||||||
|
m_evmRevision = EVMC_SHANGHAI;
|
||||||
else
|
else
|
||||||
assertThrow(false, Exception, "Unsupported EVM version");
|
assertThrow(false, Exception, "Unsupported EVM version");
|
||||||
|
|
||||||
|
@ -330,12 +330,16 @@ BOOST_AUTO_TEST_CASE(immutable)
|
|||||||
|
|
||||||
checkCompilation(_assembly);
|
checkCompilation(_assembly);
|
||||||
|
|
||||||
|
string genericPush0 = evmVersion.hasPush0() ? "5f" : "6000";
|
||||||
|
// PUSH1 0x1b v/s PUSH1 0x19
|
||||||
|
string dataOffset = evmVersion.hasPush0() ? "6019" : "601b" ;
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(
|
BOOST_CHECK_EQUAL(
|
||||||
_assembly.assemble().toHex(),
|
_assembly.assemble().toHex(),
|
||||||
// root.asm
|
// root.asm
|
||||||
// assign "someImmutable"
|
// assign "someImmutable"
|
||||||
"602a" // PUSH1 42 - value for someImmutable
|
"602a" + // PUSH1 42 - value for someImmutable
|
||||||
"6000" // PUSH1 0 - offset of code into which to insert the immutable
|
genericPush0 + // PUSH1 0 - offset of code into which to insert the immutable
|
||||||
"8181" // DUP2 DUP2
|
"8181" // DUP2 DUP2
|
||||||
"6001" // PUSH1 1 - offset of first someImmutable in sub_0
|
"6001" // PUSH1 1 - offset of first someImmutable in sub_0
|
||||||
"01" // ADD - add offset of immutable to offset of code
|
"01" // ADD - add offset of immutable to offset of code
|
||||||
@ -344,13 +348,13 @@ BOOST_AUTO_TEST_CASE(immutable)
|
|||||||
"01" // ADD - add offset of immutable to offset of code
|
"01" // ADD - add offset of immutable to offset of code
|
||||||
"52" // MSTORE
|
"52" // MSTORE
|
||||||
// assign "someOtherImmutable"
|
// assign "someOtherImmutable"
|
||||||
"6017" // PUSH1 23 - value for someOtherImmutable
|
"6017" + // PUSH1 23 - value for someOtherImmutable
|
||||||
"6000" // PUSH1 0 - offset of code into which to insert the immutable
|
genericPush0 + // PUSH1 0 - offset of code into which to insert the immutable
|
||||||
"6022" // PUSH1 34 - offset of someOtherImmutable in sub_0
|
"6022" // PUSH1 34 - offset of someOtherImmutable in sub_0
|
||||||
"01" // ADD - add offset of immutable to offset of code
|
"01" // ADD - add offset of immutable to offset of code
|
||||||
"52" // MSTORE
|
"52" // MSTORE
|
||||||
"6063" // PUSH1 0x63 - dataSize(sub_0)
|
"6063" + // PUSH1 0x63 - dataSize(sub_0)
|
||||||
"601b" // PUSH1 0x23 - dataOffset(sub_0)
|
dataOffset + // PUSH1 0x23 - dataOffset(sub_0)
|
||||||
"fe" // INVALID
|
"fe" // INVALID
|
||||||
// end of root.asm
|
// end of root.asm
|
||||||
// sub.asm
|
// sub.asm
|
||||||
|
@ -112,15 +112,21 @@ BOOST_AUTO_TEST_CASE(string_storage)
|
|||||||
// Costs with 0 are cases which cannot be triggered in tests.
|
// Costs with 0 are cases which cannot be triggered in tests.
|
||||||
if (evmVersion < EVMVersion::istanbul())
|
if (evmVersion < EVMVersion::istanbul())
|
||||||
CHECK_DEPLOY_GAS(0, 109241, evmVersion);
|
CHECK_DEPLOY_GAS(0, 109241, evmVersion);
|
||||||
else
|
else if (evmVersion < EVMVersion::shanghai())
|
||||||
CHECK_DEPLOY_GAS(0, 97697, evmVersion);
|
CHECK_DEPLOY_GAS(0, 97697, evmVersion);
|
||||||
|
// Shanghai is cheaper due to `push0`
|
||||||
|
else
|
||||||
|
CHECK_DEPLOY_GAS(0, 97071, evmVersion);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (evmVersion < EVMVersion::istanbul())
|
if (evmVersion < EVMVersion::istanbul())
|
||||||
CHECK_DEPLOY_GAS(139013, 123969, evmVersion);
|
CHECK_DEPLOY_GAS(139013, 123969, evmVersion);
|
||||||
else
|
else if (evmVersion < EVMVersion::shanghai())
|
||||||
CHECK_DEPLOY_GAS(123361, 110969, evmVersion);
|
CHECK_DEPLOY_GAS(123361, 110969, evmVersion);
|
||||||
|
// Shanghai is cheaper due to `push0`
|
||||||
|
else
|
||||||
|
CHECK_DEPLOY_GAS(121493, 110969, evmVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (evmVersion < EVMVersion::istanbul())
|
else if (evmVersion < EVMVersion::istanbul())
|
||||||
@ -198,7 +204,11 @@ BOOST_AUTO_TEST_CASE(single_callvaluecheck)
|
|||||||
size_t bytecodeSizeNonpayable = m_compiler.object("Nonpayable").bytecode.size();
|
size_t bytecodeSizeNonpayable = m_compiler.object("Nonpayable").bytecode.size();
|
||||||
size_t bytecodeSizePayable = m_compiler.object("Payable").bytecode.size();
|
size_t bytecodeSizePayable = m_compiler.object("Payable").bytecode.size();
|
||||||
|
|
||||||
|
auto evmVersion = solidity::test::CommonOptions::get().evmVersion();
|
||||||
|
if (evmVersion < EVMVersion::shanghai())
|
||||||
BOOST_CHECK_EQUAL(bytecodeSizePayable - bytecodeSizeNonpayable, 26);
|
BOOST_CHECK_EQUAL(bytecodeSizePayable - bytecodeSizeNonpayable, 26);
|
||||||
|
else
|
||||||
|
BOOST_CHECK_EQUAL(bytecodeSizePayable - bytecodeSizeNonpayable, 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -47,7 +47,9 @@ BOOST_AUTO_TEST_CASE(does_not_include_creation_time_only_internal_functions)
|
|||||||
bytes const& runtimeBytecode = solidity::test::bytecodeSansMetadata(compiler().runtimeObject("C").bytecode);
|
bytes const& runtimeBytecode = solidity::test::bytecodeSansMetadata(compiler().runtimeObject("C").bytecode);
|
||||||
BOOST_CHECK(creationBytecode.size() >= 90);
|
BOOST_CHECK(creationBytecode.size() >= 90);
|
||||||
BOOST_CHECK(creationBytecode.size() <= 120);
|
BOOST_CHECK(creationBytecode.size() <= 120);
|
||||||
BOOST_CHECK(runtimeBytecode.size() >= 10);
|
auto evmVersion = solidity::test::CommonOptions::get().evmVersion();
|
||||||
|
unsigned threshold = evmVersion.hasPush0() ? 9 : 10;
|
||||||
|
BOOST_CHECK(runtimeBytecode.size() >= threshold);
|
||||||
BOOST_CHECK(runtimeBytecode.size() <= 30);
|
BOOST_CHECK(runtimeBytecode.size() <= 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +210,10 @@ BOOST_AUTO_TEST_CASE(literal_false)
|
|||||||
)";
|
)";
|
||||||
bytes code = compileFirstExpression(sourceCode);
|
bytes code = compileFirstExpression(sourceCode);
|
||||||
|
|
||||||
bytes expectation({uint8_t(Instruction::PUSH1), 0x0});
|
bytes expectation = solidity::test::CommonOptions::get().evmVersion().hasPush0() ?
|
||||||
|
bytes{uint8_t(Instruction::PUSH0)} :
|
||||||
|
bytes{uint8_t(Instruction::PUSH1), 0x0};
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,21 +347,27 @@ BOOST_AUTO_TEST_CASE(arithmetic)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}});
|
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}});
|
||||||
|
bool hasPush0 = solidity::test::CommonOptions::get().evmVersion().hasPush0();
|
||||||
|
bytes push0Bytes = hasPush0 ?
|
||||||
|
bytes{uint8_t(Instruction::PUSH0)} :
|
||||||
|
bytes{uint8_t(Instruction::PUSH1), 0x0};
|
||||||
|
uint8_t size = hasPush0 ? 0x65: 0x67;
|
||||||
bytes panic =
|
bytes panic =
|
||||||
bytes{
|
bytes{
|
||||||
uint8_t(Instruction::JUMPDEST),
|
uint8_t(Instruction::JUMPDEST),
|
||||||
uint8_t(Instruction::PUSH32)
|
uint8_t(Instruction::PUSH32)
|
||||||
} +
|
} +
|
||||||
util::fromHex("4E487B7100000000000000000000000000000000000000000000000000000000") +
|
util::fromHex("4E487B7100000000000000000000000000000000000000000000000000000000") +
|
||||||
|
push0Bytes +
|
||||||
bytes{
|
bytes{
|
||||||
uint8_t(Instruction::PUSH1), 0x0,
|
|
||||||
uint8_t(Instruction::MSTORE),
|
uint8_t(Instruction::MSTORE),
|
||||||
uint8_t(Instruction::PUSH1), 0x12,
|
uint8_t(Instruction::PUSH1), 0x12,
|
||||||
uint8_t(Instruction::PUSH1), 0x4,
|
uint8_t(Instruction::PUSH1), 0x4,
|
||||||
uint8_t(Instruction::MSTORE),
|
uint8_t(Instruction::MSTORE),
|
||||||
uint8_t(Instruction::PUSH1), 0x24,
|
uint8_t(Instruction::PUSH1), 0x24
|
||||||
uint8_t(Instruction::PUSH1), 0x0,
|
} +
|
||||||
|
push0Bytes +
|
||||||
|
bytes{
|
||||||
uint8_t(Instruction::REVERT),
|
uint8_t(Instruction::REVERT),
|
||||||
uint8_t(Instruction::JUMPDEST),
|
uint8_t(Instruction::JUMPDEST),
|
||||||
uint8_t(Instruction::JUMP),
|
uint8_t(Instruction::JUMP),
|
||||||
@ -405,7 +414,7 @@ BOOST_AUTO_TEST_CASE(arithmetic)
|
|||||||
uint8_t(Instruction::DIV),
|
uint8_t(Instruction::DIV),
|
||||||
uint8_t(Instruction::PUSH1), 0x1,
|
uint8_t(Instruction::PUSH1), 0x1,
|
||||||
uint8_t(Instruction::MUL),
|
uint8_t(Instruction::MUL),
|
||||||
uint8_t(Instruction::PUSH1), 0x67,
|
uint8_t(Instruction::PUSH1), size,
|
||||||
uint8_t(Instruction::JUMP)
|
uint8_t(Instruction::JUMP)
|
||||||
} + panic;
|
} + panic;
|
||||||
else
|
else
|
||||||
@ -447,7 +456,7 @@ BOOST_AUTO_TEST_CASE(arithmetic)
|
|||||||
uint8_t(Instruction::JUMPDEST),
|
uint8_t(Instruction::JUMPDEST),
|
||||||
uint8_t(Instruction::DIV),
|
uint8_t(Instruction::DIV),
|
||||||
uint8_t(Instruction::MUL),
|
uint8_t(Instruction::MUL),
|
||||||
uint8_t(Instruction::PUSH1), 0x67,
|
uint8_t(Instruction::PUSH1), size,
|
||||||
uint8_t(Instruction::JUMP)
|
uint8_t(Instruction::JUMP)
|
||||||
} + panic;
|
} + panic;
|
||||||
|
|
||||||
@ -463,11 +472,17 @@ BOOST_AUTO_TEST_CASE(unary_operators)
|
|||||||
)";
|
)";
|
||||||
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}});
|
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}});
|
||||||
|
|
||||||
|
bytes push0Bytes = solidity::test::CommonOptions::get().evmVersion().hasPush0() ?
|
||||||
|
bytes{uint8_t(Instruction::PUSH0)} :
|
||||||
|
bytes{uint8_t(Instruction::PUSH1), 0x0};
|
||||||
|
|
||||||
bytes expectation;
|
bytes expectation;
|
||||||
if (solidity::test::CommonOptions::get().optimize)
|
if (solidity::test::CommonOptions::get().optimize)
|
||||||
expectation = {
|
expectation = bytes{
|
||||||
uint8_t(Instruction::DUP1),
|
uint8_t(Instruction::DUP1),
|
||||||
uint8_t(Instruction::PUSH1), 0x0,
|
} +
|
||||||
|
push0Bytes +
|
||||||
|
bytes{
|
||||||
uint8_t(Instruction::SUB),
|
uint8_t(Instruction::SUB),
|
||||||
uint8_t(Instruction::NOT),
|
uint8_t(Instruction::NOT),
|
||||||
uint8_t(Instruction::PUSH1), 0x2,
|
uint8_t(Instruction::PUSH1), 0x2,
|
||||||
@ -475,10 +490,12 @@ BOOST_AUTO_TEST_CASE(unary_operators)
|
|||||||
uint8_t(Instruction::ISZERO)
|
uint8_t(Instruction::ISZERO)
|
||||||
};
|
};
|
||||||
else
|
else
|
||||||
expectation = {
|
expectation = bytes{
|
||||||
uint8_t(Instruction::PUSH1), 0x2,
|
uint8_t(Instruction::PUSH1), 0x2,
|
||||||
uint8_t(Instruction::DUP2),
|
uint8_t(Instruction::DUP2),
|
||||||
uint8_t(Instruction::PUSH1), 0x0,
|
} +
|
||||||
|
push0Bytes +
|
||||||
|
bytes{
|
||||||
uint8_t(Instruction::SUB),
|
uint8_t(Instruction::SUB),
|
||||||
uint8_t(Instruction::NOT),
|
uint8_t(Instruction::NOT),
|
||||||
uint8_t(Instruction::EQ),
|
uint8_t(Instruction::EQ),
|
||||||
|
31
test/libsolidity/semanticTests/shanghai/evmone_support.sol
Normal file
31
test/libsolidity/semanticTests/shanghai/evmone_support.sol
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
contract ShortReturn {
|
||||||
|
constructor() {
|
||||||
|
assembly {
|
||||||
|
// return(0, 32)
|
||||||
|
// PUSH1 0x20 PUSH0 RETURN
|
||||||
|
mstore(0, hex"60205ff3")
|
||||||
|
return(0, 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DoesItReturnZero {
|
||||||
|
function foo() external pure returns (uint256);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Test {
|
||||||
|
ShortReturn immutable shortReturn = new ShortReturn();
|
||||||
|
function bytecode() external view returns(bytes memory) {
|
||||||
|
return address(shortReturn).code;
|
||||||
|
}
|
||||||
|
function isPush0Supported() external view returns (bool) {
|
||||||
|
assert(DoesItReturnZero(address(shortReturn)).foo() == 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// EVMVersion: >=shanghai
|
||||||
|
// ----
|
||||||
|
// bytecode() -> 0x20, 4, 0x60205ff300000000000000000000000000000000000000000000000000000000
|
||||||
|
// isPush0Supported() -> true
|
11
test/libsolidity/semanticTests/shanghai/push0.sol
Normal file
11
test/libsolidity/semanticTests/shanghai/push0.sol
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
contract C {
|
||||||
|
function zero() external returns (uint) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// EVMVersion: >=shanghai
|
||||||
|
// ----
|
||||||
|
// zero() -> 0
|
@ -7,6 +7,6 @@ contract test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
// EVMVersion: >byzantium
|
// EVMVersion: >=shanghai
|
||||||
// ----
|
// ----
|
||||||
// Warning 5574: (21-27154): Contract code size is 27192 bytes and exceeds 24576 bytes (a limit introduced in Spurious Dragon). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries.
|
// Warning 5574: (21-27154): Contract code size is 27186 bytes and exceeds 24576 bytes (a limit introduced in Spurious Dragon). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries.
|
||||||
|
@ -7,6 +7,6 @@ contract test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
// EVMVersion: >byzantium
|
// EVMVersion: >=shanghai
|
||||||
// ----
|
// ----
|
||||||
// Warning 5574: (21-27154): Contract code size is 27209 bytes and exceeds 24576 bytes (a limit introduced in Spurious Dragon). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries.
|
// Warning 5574: (21-27154): Contract code size is 27205 bytes and exceeds 24576 bytes (a limit introduced in Spurious Dragon). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries.
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
// Ok
|
||||||
|
contract push0 {}
|
||||||
|
|
||||||
|
contract A {
|
||||||
|
// Ok, warning about shadowing
|
||||||
|
function push0() external {}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() external {
|
||||||
|
assembly {
|
||||||
|
// Not okay
|
||||||
|
push0()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Warning 2519: (77-105): This declaration shadows an existing declaration.
|
||||||
|
// DeclarationError 4619: (205-210): Function "push0" not found.
|
6
test/libyul/yulSyntaxTests/invalid/push0_disallowed.yul
Normal file
6
test/libyul/yulSyntaxTests/invalid/push0_disallowed.yul
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Based on ./push_disallowed.yul (which already includes push0).
|
||||||
|
{
|
||||||
|
push0()
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// DeclarationError 4619: (72-77): Function "push0" not found.
|
@ -381,6 +381,7 @@ u256 EVMInstructionInterpreter::eval(
|
|||||||
case Instruction::JUMP:
|
case Instruction::JUMP:
|
||||||
case Instruction::JUMPI:
|
case Instruction::JUMPI:
|
||||||
case Instruction::JUMPDEST:
|
case Instruction::JUMPDEST:
|
||||||
|
case Instruction::PUSH0:
|
||||||
case Instruction::PUSH1:
|
case Instruction::PUSH1:
|
||||||
case Instruction::PUSH2:
|
case Instruction::PUSH2:
|
||||||
case Instruction::PUSH3:
|
case Instruction::PUSH3:
|
||||||
|
Loading…
Reference in New Issue
Block a user