Merge branch 'develop' into discovery

This commit is contained in:
subtly 2015-05-13 11:01:28 +02:00
commit 616c953f92
5 changed files with 192 additions and 88 deletions

View File

@ -95,6 +95,12 @@ if (JSONRPC)
target_link_libraries(testeth ${JSON_RPC_CPP_CLIENT_LIBRARIES}) target_link_libraries(testeth ${JSON_RPC_CPP_CLIENT_LIBRARIES})
endif() endif()
if (UNIX) # Create symlink to old testeth location to make bildbot happy
add_custom_command(TARGET testeth POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_BINARY_DIR}/bin/testeth ${CMAKE_BINARY_DIR}/test/testeth
)
endif()
enable_testing() enable_testing()
set(CTEST_OUTPUT_ON_FAILURE TRUE) set(CTEST_OUTPUT_ON_FAILURE TRUE)
@ -110,7 +116,6 @@ eth_add_test(ClientBase
) )
eth_add_test(JsonRpc eth_add_test(JsonRpc
ARGS --eth_testfile=BlockTests/bcJS_API_Test ARGS --eth_testfile=BlockTests/bcJS_API_Test
ARGS --eth_testfile=BlockTests/bcValidBlockTest ARGS --eth_testfile=BlockTests/bcValidBlockTest
) )

View File

@ -288,7 +288,7 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta
{ {
addressOptions = _expectedStateOptions.at(a.first); addressOptions = _expectedStateOptions.at(a.first);
} }
catch(std::out_of_range) catch(std::out_of_range const&)
{ {
BOOST_ERROR("expectedStateOptions map does not match expectedState in checkExpectedState!"); BOOST_ERROR("expectedStateOptions map does not match expectedState in checkExpectedState!");
break; break;
@ -549,58 +549,53 @@ void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _e
} }
} }
void userDefinedTest(string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests) void userDefinedTest(std::function<void(json_spirit::mValue&, bool)> doTests)
{ {
Options::get(); // parse command line options, e.g. to enable JIT if (!Options::get().singleTest)
return;
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) if (Options::get().singleTestFile.empty() || Options::get().singleTestName.empty())
{ {
string arg = boost::unit_test::framework::master_test_suite().argv[i]; cnote << "Missing user test specification\nUsage: testeth --singletest <filename> <testname>\n";
if (arg == testTypeFlag) return;
{
if (boost::unit_test::framework::master_test_suite().argc <= i + 2)
{
cnote << "Missing filename\nUsage: testeth " << testTypeFlag << " <filename> <testname>\n";
return;
}
string filename = boost::unit_test::framework::master_test_suite().argv[i + 1];
string testname = boost::unit_test::framework::master_test_suite().argv[i + 2];
int currentVerbosity = g_logVerbosity;
g_logVerbosity = 12;
try
{
cnote << "Testing user defined test: " << filename;
json_spirit::mValue v;
string s = asString(contents(filename));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. ");
json_spirit::read_string(s, v);
json_spirit::mObject oSingleTest;
json_spirit::mObject::const_iterator pos = v.get_obj().find(testname);
if (pos == v.get_obj().end())
{
cnote << "Could not find test: " << testname << " in " << filename << "\n";
return;
}
else
oSingleTest[pos->first] = pos->second;
json_spirit::mValue v_singleTest(oSingleTest);
doTests(v_singleTest, false);
}
catch (Exception const& _e)
{
BOOST_ERROR("Failed Test with Exception: " << diagnostic_information(_e));
g_logVerbosity = currentVerbosity;
}
catch (std::exception const& _e)
{
BOOST_ERROR("Failed Test with Exception: " << _e.what());
g_logVerbosity = currentVerbosity;
}
g_logVerbosity = currentVerbosity;
}
} }
auto& filename = Options::get().singleTestFile;
auto& testname = Options::get().singleTestName;
int currentVerbosity = g_logVerbosity;
g_logVerbosity = 12;
try
{
cnote << "Testing user defined test: " << filename;
json_spirit::mValue v;
string s = asString(contents(filename));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. ");
json_spirit::read_string(s, v);
json_spirit::mObject oSingleTest;
json_spirit::mObject::const_iterator pos = v.get_obj().find(testname);
if (pos == v.get_obj().end())
{
cnote << "Could not find test: " << testname << " in " << filename << "\n";
return;
}
else
oSingleTest[pos->first] = pos->second;
json_spirit::mValue v_singleTest(oSingleTest);
doTests(v_singleTest, false);
}
catch (Exception const& _e)
{
BOOST_ERROR("Failed Test with Exception: " << diagnostic_information(_e));
g_logVerbosity = currentVerbosity;
}
catch (std::exception const& _e)
{
BOOST_ERROR("Failed Test with Exception: " << _e.what());
g_logVerbosity = currentVerbosity;
}
g_logVerbosity = currentVerbosity;
} }
void executeTests(const string& _name, const string& _testPathAppendix, const boost::filesystem::path _pathToFiller, std::function<void(json_spirit::mValue&, bool)> doTests) void executeTests(const string& _name, const string& _testPathAppendix, const boost::filesystem::path _pathToFiller, std::function<void(json_spirit::mValue&, bool)> doTests)
@ -707,10 +702,9 @@ Options::Options()
{ {
auto arg = std::string{argv[i]}; auto arg = std::string{argv[i]};
if (arg == "--jit") if (arg == "--jit")
{
jit = true;
eth::VMFactory::setKind(eth::VMKind::JIT); eth::VMFactory::setKind(eth::VMKind::JIT);
} else if (arg == "--vm=smart")
eth::VMFactory::setKind(eth::VMKind::Smart);
else if (arg == "--vmtrace") else if (arg == "--vmtrace")
vmtrace = true; vmtrace = true;
else if (arg == "--filltests") else if (arg == "--filltests")
@ -743,7 +737,20 @@ Options::Options()
else if (arg == "--singletest" && i + 1 < argc) else if (arg == "--singletest" && i + 1 < argc)
{ {
singleTest = true; singleTest = true;
singleTestName = argv[i + 1]; auto name1 = std::string{argv[i + 1]};
if (i + 1 < argc) // two params
{
auto name2 = std::string{argv[i + 2]};
if (name2[0] == '-') // not param, another option
singleTestName = std::move(name1);
else
{
singleTestFile = std::move(name1);
singleTestName = std::move(name2);
}
}
else
singleTestName = std::move(name1);
} }
} }
} }

View File

@ -157,7 +157,7 @@ void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs);
void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates); void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates);
void executeTests(const std::string& _name, const std::string& _testPathAppendix, const boost::filesystem::path _pathToFiller, std::function<void(json_spirit::mValue&, bool)> doTests); void executeTests(const std::string& _name, const std::string& _testPathAppendix, const boost::filesystem::path _pathToFiller, std::function<void(json_spirit::mValue&, bool)> doTests);
void userDefinedTest(std::string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests); void userDefinedTest(std::function<void(json_spirit::mValue&, bool)> doTests);
RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj); RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj);
eth::LastHashes lastHashes(u256 _currentBlockNumber); eth::LastHashes lastHashes(u256 _currentBlockNumber);
json_spirit::mObject fillJsonWithState(eth::State _state); json_spirit::mObject fillJsonWithState(eth::State _state);
@ -179,7 +179,6 @@ void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs)
class Options class Options
{ {
public: public:
bool jit = false; ///< Use JIT
bool vmtrace = false; ///< Create EVM execution tracer // TODO: Link with log verbosity? bool vmtrace = false; ///< Create EVM execution tracer // TODO: Link with log verbosity?
bool fillTests = false; ///< Create JSON test files from execution results bool fillTests = false; ///< Create JSON test files from execution results
bool stats = false; ///< Execution time stats bool stats = false; ///< Execution time stats
@ -189,6 +188,7 @@ public:
/// Test selection /// Test selection
/// @{ /// @{
bool singleTest = false; bool singleTest = false;
std::string singleTestFile;
std::string singleTestName; std::string singleTestName;
bool performance = false; bool performance = false;
bool quadratic = false; bool quadratic = false;

View File

@ -116,36 +116,35 @@ BOOST_AUTO_TEST_CASE(ifStatement)
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 60; unsigned shift = 60;
unsigned boilerplateSize = 73; unsigned boilerplateSize = 73;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({
byte(Instruction::PUSH1), 0x0, byte(Instruction::JUMPDEST),
byte(Instruction::DUP1), byte(Instruction::PUSH1), 0x0,
byte(Instruction::PUSH1), byte(0x1b + shift), // "true" target byte(Instruction::DUP1),
byte(Instruction::JUMPI), byte(Instruction::ISZERO),
// new check "else if" condition byte(Instruction::PUSH1), byte(0x0f + shift), // "false" target
byte(Instruction::DUP1), byte(Instruction::JUMPI),
byte(Instruction::ISZERO), // "if" body
byte(Instruction::PUSH1), byte(0x13 + shift), byte(Instruction::PUSH1), 0x4d,
byte(Instruction::JUMPI), byte(Instruction::POP),
// "else" body byte(Instruction::PUSH1), byte(0x21 + shift),
byte(Instruction::PUSH1), 0x4f, byte(Instruction::JUMP),
byte(Instruction::POP), // new check "else if" condition
byte(Instruction::PUSH1), byte(0x17 + shift), // exit path of second part byte(Instruction::JUMPDEST),
byte(Instruction::JUMP), byte(Instruction::DUP1),
// "else if" body byte(Instruction::ISZERO),
byte(Instruction::JUMPDEST), byte(Instruction::ISZERO),
byte(Instruction::PUSH1), 0x4e, byte(Instruction::PUSH1), byte(0x1c + shift),
byte(Instruction::POP), byte(Instruction::JUMPI),
byte(Instruction::JUMPDEST), // "else if" body
byte(Instruction::PUSH1), byte(0x1f + shift), byte(Instruction::PUSH1), 0x4e,
byte(Instruction::JUMP), byte(Instruction::POP),
// "if" body byte(Instruction::PUSH1), byte(0x20 + shift),
byte(Instruction::JUMPDEST), byte(Instruction::JUMP),
byte(Instruction::PUSH1), 0x4d, // "else" body
byte(Instruction::POP), byte(Instruction::JUMPDEST),
byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x4f,
byte(Instruction::JUMPDEST), byte(Instruction::POP),
byte(Instruction::POP), });
byte(Instruction::JUMP)});
checkCodePresentAt(code, expectation, boilerplateSize); checkCodePresentAt(code, expectation, boilerplateSize);
} }

View File

@ -29,6 +29,7 @@
#include <libevmasm/CommonSubexpressionEliminator.h> #include <libevmasm/CommonSubexpressionEliminator.h>
#include <libevmasm/ControlFlowGraph.h> #include <libevmasm/ControlFlowGraph.h>
#include <libevmasm/Assembly.h> #include <libevmasm/Assembly.h>
#include <libevmasm/BlockDeduplicator.h>
using namespace std; using namespace std;
using namespace dev::eth; using namespace dev::eth;
@ -125,7 +126,7 @@ public:
BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end()); BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end());
} }
void checkCFG(AssemblyItems const& _input, AssemblyItems const& _expectation) AssemblyItems getCFG(AssemblyItems const& _input)
{ {
AssemblyItems output = _input; AssemblyItems output = _input;
// Running it four times should be enough for these tests. // Running it four times should be enough for these tests.
@ -138,6 +139,12 @@ public:
back_inserter(optItems)); back_inserter(optItems));
output = move(optItems); output = move(optItems);
} }
return output;
}
void checkCFG(AssemblyItems const& _input, AssemblyItems const& _expectation)
{
AssemblyItems output = getCFG(_input);
BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end()); BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end());
} }
@ -251,6 +258,63 @@ BOOST_AUTO_TEST_CASE(function_calls)
compareVersions("f(uint256)", 36); compareVersions("f(uint256)", 36);
} }
BOOST_AUTO_TEST_CASE(storage_write_in_loops)
{
char const* sourceCode = R"(
contract test {
uint d;
function f(uint a) returns (uint r) {
var x = d;
for (uint i = 1; i < a * a; i++) {
r = d;
d = i;
}
}
}
)";
compileBothVersions(sourceCode);
compareVersions("f(uint256)", 0);
compareVersions("f(uint256)", 10);
compareVersions("f(uint256)", 36);
}
BOOST_AUTO_TEST_CASE(retain_information_in_branches)
{
// This tests that the optimizer knows that we already have "z == sha3(y)" inside both branches.
char const* sourceCode = R"(
contract c {
bytes32 d;
uint a;
function f(uint x, bytes32 y) returns (uint r_a, bytes32 r_d) {
bytes32 z = sha3(y);
if (x > 8) {
z = sha3(y);
a = x;
} else {
z = sha3(y);
a = x;
}
r_a = a;
r_d = d;
}
}
)";
compileBothVersions(sourceCode);
compareVersions("f(uint256,bytes32)", 0, "abc");
compareVersions("f(uint256,bytes32)", 8, "def");
compareVersions("f(uint256,bytes32)", 10, "ghi");
m_optimize = true;
bytes optimizedBytecode = compileAndRun(sourceCode, 0, "c");
size_t numSHA3s = 0;
eth::eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) {
if (_instr == eth::Instruction::SHA3)
numSHA3s++;
});
BOOST_CHECK_EQUAL(1, numSHA3s);
}
BOOST_AUTO_TEST_CASE(cse_intermediate_swap) BOOST_AUTO_TEST_CASE(cse_intermediate_swap)
{ {
eth::KnownState state; eth::KnownState state;
@ -868,6 +932,35 @@ BOOST_AUTO_TEST_CASE(control_flow_graph_do_not_remove_returned_to)
checkCFG(input, {u256(2)}); checkCFG(input, {u256(2)});
} }
BOOST_AUTO_TEST_CASE(block_deduplicator)
{
AssemblyItems input{
AssemblyItem(PushTag, 2),
AssemblyItem(PushTag, 1),
AssemblyItem(PushTag, 3),
u256(6),
eth::Instruction::SWAP3,
eth::Instruction::JUMP,
AssemblyItem(Tag, 1),
u256(6),
eth::Instruction::SWAP3,
eth::Instruction::JUMP,
AssemblyItem(Tag, 2),
u256(6),
eth::Instruction::SWAP3,
eth::Instruction::JUMP,
AssemblyItem(Tag, 3)
};
BlockDeduplicator dedup(input);
dedup.deduplicate();
set<u256> pushTags;
for (AssemblyItem const& item: input)
if (item.type() == PushTag)
pushTags.insert(item.data());
BOOST_CHECK_EQUAL(pushTags.size(), 2);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }