Merge branch 'develop' of github.com:ethereum/cpp-ethereum into develop

Conflicts:
	test/vm.cpp
This commit is contained in:
Gav Wood 2014-12-02 20:09:00 +01:00
commit 2f5b9151d5
8 changed files with 264 additions and 14 deletions

View File

@ -72,6 +72,7 @@ ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller): m_TestObject(_o
if (!isFiller)
{
importState(_o["post"].get_obj(), m_statePost);
m_environment.sub.logs = importLog(_o["logs"].get_obj());
}
}
@ -148,6 +149,9 @@ void ImportTest::exportTest(bytes _output, State& _statePost)
// export output
m_TestObject["out"] = "0x" + toHex(_output);
// export logs
m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries());
// export post state
json_spirit::mObject postState;
@ -255,6 +259,44 @@ bytes importCode(json_spirit::mObject& _o)
return code;
}
LogEntries importLog(json_spirit::mObject& _o)
{
LogEntries logEntries;
for (auto const& l: _o)
{
json_spirit::mObject o = l.second.get_obj();
// cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest)
assert(o.count("address") > 0);
assert(o.count("topics") > 0);
assert(o.count("data") > 0);
LogEntry log;
log.address = Address(o["address"].get_str());
for (auto const& t: o["topics"].get_array())
log.topics.push_back(h256(t.get_str()));
log.data = importData(o);
logEntries.push_back(log);
}
return logEntries;
}
json_spirit::mObject exportLog(eth::LogEntries _logs)
{
json_spirit::mObject ret;
if (_logs.size() == 0) return ret;
for (LogEntry const& l: _logs)
{
json_spirit::mObject o;
o["address"] = toString(l.address);
json_spirit::mArray topics;
for (auto const& t: l.topics)
topics.push_back(toString(t));
o["topics"] = topics;
o["data"] = "0x" + toHex(l.data);
ret[toString(l.bloom())] = o;
}
return ret;
}
void checkOutput(bytes const& _output, json_spirit::mObject& _o)
{
int j = 0;

View File

@ -68,6 +68,8 @@ u256 toInt(json_spirit::mValue const& _v);
byte toByte(json_spirit::mValue const& _v);
bytes importCode(json_spirit::mObject& _o);
bytes importData(json_spirit::mObject& _o);
eth::LogEntries importLog(json_spirit::mObject& _o);
json_spirit::mObject exportLog(eth::LogEntries _logs);
void checkOutput(bytes const& _output, json_spirit::mObject& _o);
void checkStorage(std::map<u256, u256> _expectedStore, std::map<u256, u256> _resultStore, Address _expectedAddr);
void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs);

View File

@ -121,14 +121,14 @@ void doMyTests(json_spirit::mValue& v)
{
for (auto& i: v.get_obj())
{
cnote << i.first;
mObject& o = i.second.get_obj();
assert(o.count("env") > 0);
assert(o.count("pre") > 0);
assert(o.count("exec") > 0);
eth::VM vm;
test::FakeExtVM fev;
dev::test::FakeExtVM fev;
fev.importEnv(o["env"].get_obj());
fev.importState(o["pre"].get_obj());
@ -141,17 +141,20 @@ void doMyTests(json_spirit::mValue& v)
fev.code = fev.thisTxCode;
}
vm.reset(fev.gas);
bytes output;
eth::VM vm(fev.gas);
u256 gas;
bool vmExceptionOccured = false;
try
{
output = vm.go(fev).toBytes();
output = vm.go(fev, fev.simpleTrace()).toBytes();
gas = vm.gas();
}
catch (eth::VMException const& _e)
{
cnote << "VM did throw an exception: " << diagnostic_information(_e);
gas = 0;
vmExceptionOccured = true;
}
catch (Exception const& _e)
{
@ -180,9 +183,13 @@ void doMyTests(json_spirit::mValue& v)
o["env"] = mValue(fev.exportEnv());
o["exec"] = mValue(fev.exportExec());
o["post"] = mValue(fev.exportState());
o["callcreates"] = fev.exportCallCreates();
o["out"] = "0x" + toHex(output);
fev.push(o, "gas", gas);
if (!vmExceptionOccured)
{
o["post"] = mValue(fev.exportState());
o["callcreates"] = fev.exportCallCreates();
o["out"] = "0x" + toHex(output);
fev.push(o, "gas", gas);
o["logs"] = mValue(test::exportLog(fev.sub.logs));
}
}
}

View File

@ -37,13 +37,14 @@ namespace test
namespace
{
ASTPointer<ASTNode> parseText(std::string const& _source)
ASTPointer<ContractDefinition> parseText(std::string const& _source)
{
Parser parser;
return parser.parse(std::make_shared<Scanner>(CharStream(_source)));
}
}
BOOST_AUTO_TEST_SUITE(SolidityParser)
BOOST_AUTO_TEST_CASE(smoke_test)
@ -91,6 +92,164 @@ BOOST_AUTO_TEST_CASE(single_function_param)
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(function_natspec_documentation)
{
ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n"
" uint256 stateVar;\n"
" /// This is a test function\n"
" function functionName(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is a test function");
}
BOOST_AUTO_TEST_CASE(function_normal_comments)
{
ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n"
" uint256 stateVar;\n"
" // We won't see this comment\n"
" function functionName(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr,
"Should not have gotten a Natspect comment for this function");
}
BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
{
ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n"
" uint256 stateVar;\n"
" /// This is test function 1\n"
" function functionName1(hash hashin) returns (hash hashout) {}\n"
" /// This is test function 2\n"
" function functionName2(hash hashin) returns (hash hashout) {}\n"
" // nothing to see here\n"
" function functionName3(hash hashin) returns (hash hashout) {}\n"
" /// This is test function 4\n"
" function functionName4(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 1");
BOOST_REQUIRE_NO_THROW(function = functions.at(1));
BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 2");
BOOST_REQUIRE_NO_THROW(function = functions.at(2));
BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr,
"Should not have gotten natspec comment for functionName3()");
BOOST_REQUIRE_NO_THROW(function = functions.at(3));
BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 4");
}
BOOST_AUTO_TEST_CASE(multiline_function_documentation)
{
ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n"
" uint256 stateVar;\n"
" /// This is a test function\n"
" /// and it has 2 lines\n"
" function functionName1(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
BOOST_CHECK_EQUAL(*function->getDocumentation(),
" This is a test function\n"
" and it has 2 lines");
}
BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body)
{
ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n"
" /// fun1 description\n"
" function fun1(uint256 a) {\n"
" var b;\n"
" /// I should not interfere with actual natspec comments\n"
" uint256 c;\n"
" mapping(address=>hash) d;\n"
" string name = \"Solidity\";"
" }\n"
" uint256 stateVar;\n"
" /// This is a test function\n"
" /// and it has 2 lines\n"
" function fun(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
BOOST_CHECK_EQUAL(*function->getDocumentation(), " fun1 description");
BOOST_REQUIRE_NO_THROW(function = functions.at(1));
BOOST_CHECK_EQUAL(*function->getDocumentation(),
" This is a test function\n"
" and it has 2 lines");
}
BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature)
{
ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n"
" uint256 stateVar;\n"
" function ///I am in the wrong place \n"
" fun1(uint256 a) {\n"
" var b;\n"
" /// I should not interfere with actual natspec comments\n"
" uint256 c;\n"
" mapping(address=>hash) d;\n"
" string name = \"Solidity\";"
" }\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
BOOST_CHECK_MESSAGE(!function->getDocumentation(),
"Shouldn't get natspec docstring for this function");
}
BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature)
{
ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n"
" uint256 stateVar;\n"
" function fun1(uint256 a) {\n"
" /// I should have been above the function signature\n"
" var b;\n"
" /// I should not interfere with actual natspec comments\n"
" uint256 c;\n"
" mapping(address=>hash) d;\n"
" string name = \"Solidity\";"
" }\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
BOOST_CHECK_MESSAGE(!function->getDocumentation(),
"Shouldn't get natspec docstring for this function");
}
BOOST_AUTO_TEST_CASE(struct_definition)
{
char const* text = "contract test {\n"

37
stExampleFiller.json Normal file
View File

@ -0,0 +1,37 @@
{
"add11" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "256",
"currentGasLimit" : "1000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"code" : "0x6001600101600055",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "10000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000"
}
}
}

View File

@ -81,6 +81,9 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
// check output
checkOutput(output, o);
// check logs
checkLog(theState.pending().size() ? theState.log(0) : LogEntries(), importer.m_environment.sub.logs);
// check addresses
auto expectedAddrs = importer.m_statePost.addresses();
auto resultAddrs = theState.addresses();

4
vm.cpp
View File

@ -384,7 +384,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
o["callcreates"] = fev.exportCallCreates();
o["out"] = "0x" + toHex(output);
fev.push(o, "gas", gas);
o["logs"] = mValue(fev.exportLog());
o["logs"] = mValue(exportLog(fev.sub.logs));
}
}
else
@ -402,7 +402,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
dev::test::FakeExtVM test;
test.importState(o["post"].get_obj());
test.importCallCreates(o["callcreates"].get_array());
test.importLog(o["logs"].get_obj());
test.sub.logs = importLog(o["logs"].get_obj());
checkOutput(output, o);

4
vm.h
View File

@ -66,14 +66,14 @@ public:
u256 doPosts();
json_spirit::mObject exportEnv();
void importEnv(json_spirit::mObject& _o);
json_spirit::mObject exportLog();
void importLog(json_spirit::mObject& _o);
json_spirit::mObject exportState();
void importState(json_spirit::mObject& _object);
json_spirit::mObject exportExec();
void importExec(json_spirit::mObject& _o);
json_spirit::mArray exportCallCreates();
void importCallCreates(json_spirit::mArray& _callcreates);
json_spirit::mObject exportLog();
void importLog(json_spirit::mObject& _o);
eth::OnOpFunc simpleTrace();