[isoltest] Add bytecode builtin.

This commit is contained in:
Alexander Arlt 2021-05-20 19:52:56 -05:00
parent e9ee571b35
commit ba44baa0eb
4 changed files with 77 additions and 3 deletions

View File

@ -247,6 +247,13 @@ public:
return m_sender;
}
bytes returndata() const
{
return m_output;
}
bool transactionSuccessful() const { return m_transactionSuccessful; }
private:
template <class CppFunction, class... Args>
auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments)

View File

@ -30,6 +30,7 @@
#include <functional>
#include <memory>
#include <optional>
#include <regex>
#include <stdexcept>
#include <utility>
@ -175,11 +176,43 @@ map<string, Builtin> SemanticTest::makeBuiltins()
return toBigEndian(h256(ExecutionFramework::setAccount(accountNumber).asBytes(), h256::AlignRight));
}
},
{
"bytecode",
[this](FunctionCall const& _call) -> optional<bytes>
{
bool result = false;
optional<regex> regexPattern;
soltestAssert(m_deployedBytecode.has_value(), "No bytecode deployed.");
soltestAssert(_call.arguments.parameters.size() == 1, "Bytecode pattern string expected.");
string pattern = _call.arguments.parameters.at(0).rawString;
bytes bytecode = m_deployedBytecode.value();
if (pattern.length() >= 2 && boost::starts_with(pattern, "\"") && boost::ends_with(pattern, "\""))
{
pattern = pattern.substr(1, pattern.length() - 2);
try
{
regexPattern = regex(pattern);
}
catch (std::regex_error const&)
{
}
}
if (regexPattern.has_value())
result = regex_match(toHex(bytecode), regexPattern.value());
else
{
soltestAssert(isValidHex(pattern), "Must be a valid hex string or a regular expression.");
result = toHex(bytecode).find(pattern.substr(2)) != std::string::npos;
}
return toBigEndian(u256(result ? 1 : 0));
}
},
};
}
vector<SideEffectHook> SemanticTest::makeSideEffectHooks() const
vector<SideEffectHook> SemanticTest::makeSideEffectHooks()
{
return {
[](FunctionCall const& _call) -> vector<string>
@ -192,7 +225,19 @@ vector<SideEffectHook> SemanticTest::makeSideEffectHooks() const
return result;
}
return {};
}};
},
[this](FunctionCall const& _call) -> vector<string>
{
if (boost::starts_with(_call.signature, "constructor("))
{
if (ExecutionFramework::transactionSuccessful())
m_deployedBytecode = ExecutionFramework::returndata();
else
m_deployedBytecode.reset();
}
return {};
},
};
}
TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)

View File

@ -23,6 +23,7 @@
#include <libsolutil/AnsiColorized.h>
#include <iosfwd>
#include <optional>
#include <string>
#include <vector>
#include <utility>
@ -81,7 +82,7 @@ private:
TestResult runTest(std::ostream& _stream, std::string const& _linePrefix, bool _formatted, bool _isYulRun, bool _isEwasmRun);
bool checkGasCostExpectation(TestFunctionCall& io_test, bool _compileViaYul) const;
std::map<std::string, Builtin> makeBuiltins();
std::vector<SideEffectHook> makeSideEffectHooks() const;
std::vector<SideEffectHook> makeSideEffectHooks();
SourceMap m_sources;
std::size_t m_lineOffset;
std::vector<TestFunctionCall> m_tests;
@ -99,6 +100,7 @@ private:
bool m_gasCostFailure = false;
bool m_enforceGasCost = false;
u256 m_enforceGasCostMinValue;
std::optional<bytes> m_deployedBytecode{};
};
}

View File

@ -0,0 +1,20 @@
contract SmokeTest {
constructor()
{
}
}
// ====
// compileViaYul: also
// ----
// constructor()
// bytecode: 0x00112233 -> 0
// bytecode: 0x60806040526 -> 1
// bytecode: 0x806040526 -> 1
// bytecode: 0x6040526 -> 1
// bytecode: 0x5040526 -> 0
// bytecode: "(60).*" -> 1
// bytecode: ".*(40).*" -> 1
// bytecode: ".*40.*6.*" -> 1
// bytecode: ".*40.*600000.*" -> 0
// bytecode: ".*40.*600011.*" -> 0
// bytecode: ".*40.*6000.*" -> 1