mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'upstream/develop' into addTests
This commit is contained in:
commit
f168904410
@ -32,22 +32,20 @@ namespace solidity
|
||||
namespace test
|
||||
{
|
||||
|
||||
class InterfaceChecker
|
||||
class JSONInterfaceChecker
|
||||
{
|
||||
public:
|
||||
JSONInterfaceChecker(): m_compilerStack(false) {}
|
||||
|
||||
void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_compilerStack.parse(_code);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
catch(boost::exception const& _e)
|
||||
{
|
||||
std::string const* extra = boost::get_error_info<errinfo_comment>(e);
|
||||
std::string msg = std::string("Parsing contract failed with: ") +
|
||||
e.what() + std::string("\n");
|
||||
if (extra)
|
||||
msg += *extra;
|
||||
auto msg = std::string("Parsing contract failed with: ") + boost::diagnostic_information(_e);
|
||||
BOOST_FAIL(msg);
|
||||
}
|
||||
std::string generatedInterfaceString = m_compilerStack.getMetadata("", DocumentationType::ABI_INTERFACE);
|
||||
@ -56,8 +54,8 @@ public:
|
||||
Json::Value expectedInterface;
|
||||
m_reader.parse(_expectedInterfaceString, expectedInterface);
|
||||
BOOST_CHECK_MESSAGE(expectedInterface == generatedInterface,
|
||||
"Expected " << _expectedInterfaceString <<
|
||||
"\n but got:\n" << generatedInterfaceString);
|
||||
"Expected:\n" << expectedInterface.toStyledString() <<
|
||||
"\n but got:\n" << generatedInterface.toStyledString());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -65,7 +63,7 @@ private:
|
||||
Json::Reader m_reader;
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(SolidityABIJSON, InterfaceChecker)
|
||||
BOOST_FIXTURE_TEST_SUITE(SolidityABIJSON, JSONInterfaceChecker)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(basic_test)
|
||||
{
|
||||
@ -77,6 +75,7 @@ BOOST_AUTO_TEST_CASE(basic_test)
|
||||
{
|
||||
"name": "f",
|
||||
"constant": false,
|
||||
"type": "function",
|
||||
"inputs": [
|
||||
{
|
||||
"name": "a",
|
||||
@ -99,7 +98,6 @@ BOOST_AUTO_TEST_CASE(empty_contract)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
"}\n";
|
||||
|
||||
char const* interface = "[]";
|
||||
|
||||
checkInterface(sourceCode, interface);
|
||||
@ -116,6 +114,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods)
|
||||
{
|
||||
"name": "f",
|
||||
"constant": false,
|
||||
"type": "function",
|
||||
"inputs": [
|
||||
{
|
||||
"name": "a",
|
||||
@ -132,6 +131,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods)
|
||||
{
|
||||
"name": "g",
|
||||
"constant": false,
|
||||
"type": "function",
|
||||
"inputs": [
|
||||
{
|
||||
"name": "b",
|
||||
@ -160,6 +160,7 @@ BOOST_AUTO_TEST_CASE(multiple_params)
|
||||
{
|
||||
"name": "f",
|
||||
"constant": false,
|
||||
"type": "function",
|
||||
"inputs": [
|
||||
{
|
||||
"name": "a",
|
||||
@ -194,6 +195,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order)
|
||||
{
|
||||
"name": "c",
|
||||
"constant": false,
|
||||
"type": "function",
|
||||
"inputs": [
|
||||
{
|
||||
"name": "b",
|
||||
@ -210,6 +212,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order)
|
||||
{
|
||||
"name": "f",
|
||||
"constant": false,
|
||||
"type": "function",
|
||||
"inputs": [
|
||||
{
|
||||
"name": "a",
|
||||
@ -239,6 +242,7 @@ BOOST_AUTO_TEST_CASE(const_function)
|
||||
{
|
||||
"name": "foo",
|
||||
"constant": false,
|
||||
"type": "function",
|
||||
"inputs": [
|
||||
{
|
||||
"name": "a",
|
||||
@ -259,6 +263,7 @@ BOOST_AUTO_TEST_CASE(const_function)
|
||||
{
|
||||
"name": "boo",
|
||||
"constant": true,
|
||||
"type": "function",
|
||||
"inputs": [{
|
||||
"name": "a",
|
||||
"type": "uint32"
|
||||
@ -275,6 +280,137 @@ BOOST_AUTO_TEST_CASE(const_function)
|
||||
checkInterface(sourceCode, interface);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(exclude_fallback_function)
|
||||
{
|
||||
char const* sourceCode = "contract test { function() {} }";
|
||||
|
||||
char const* interface = "[]";
|
||||
|
||||
checkInterface(sourceCode, interface);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(events)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function f(uint a) returns(uint d) { return a * 7; }\n"
|
||||
" event e1(uint b, address indexed c); \n"
|
||||
" event e2(); \n"
|
||||
"}\n";
|
||||
char const* interface = R"([
|
||||
{
|
||||
"name": "f",
|
||||
"constant": false,
|
||||
"type": "function",
|
||||
"inputs": [
|
||||
{
|
||||
"name": "a",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "d",
|
||||
"type": "uint256"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "e1",
|
||||
"type": "event",
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "b",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "c",
|
||||
"type": "address"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "e2",
|
||||
"type": "event",
|
||||
"inputs": []
|
||||
}
|
||||
|
||||
])";
|
||||
|
||||
checkInterface(sourceCode, interface);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inherited)
|
||||
{
|
||||
char const* sourceCode =
|
||||
" contract Base { \n"
|
||||
" function baseFunction(uint p) returns (uint i) { return p; } \n"
|
||||
" event baseEvent(string32 indexed evtArgBase); \n"
|
||||
" } \n"
|
||||
" contract Derived is Base { \n"
|
||||
" function derivedFunction(string32 p) returns (string32 i) { return p; } \n"
|
||||
" event derivedEvent(uint indexed evtArgDerived); \n"
|
||||
" }";
|
||||
|
||||
char const* interface = R"([
|
||||
{
|
||||
"name": "baseFunction",
|
||||
"constant": false,
|
||||
"type": "function",
|
||||
"inputs":
|
||||
[{
|
||||
"name": "p",
|
||||
"type": "uint256"
|
||||
}],
|
||||
"outputs":
|
||||
[{
|
||||
"name": "i",
|
||||
"type": "uint256"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "derivedFunction",
|
||||
"constant": false,
|
||||
"type": "function",
|
||||
"inputs":
|
||||
[{
|
||||
"name": "p",
|
||||
"type": "string32"
|
||||
}],
|
||||
"outputs":
|
||||
[{
|
||||
"name": "i",
|
||||
"type": "string32"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "derivedEvent",
|
||||
"type": "event",
|
||||
"inputs":
|
||||
[{
|
||||
"indexed": true,
|
||||
"name": "evtArgDerived",
|
||||
"type": "uint256"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "baseEvent",
|
||||
"type": "event",
|
||||
"inputs":
|
||||
[{
|
||||
"indexed": true,
|
||||
"name": "evtArgBase",
|
||||
"type": "string32"
|
||||
}]
|
||||
}])";
|
||||
|
||||
|
||||
checkInterface(sourceCode, interface);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ bytes compileContract(const string& _sourceCode)
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
Compiler compiler;
|
||||
compiler.compileContract(*contract, {}, map<ContractDefinition const*, bytes const*>{});
|
||||
compiler.compileContract(*contract, map<ContractDefinition const*, bytes const*>{});
|
||||
|
||||
// debug
|
||||
//compiler.streamAssembly(cout);
|
||||
@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
|
||||
"}\n";
|
||||
bytes code = compileContract(sourceCode);
|
||||
|
||||
unsigned boilerplateSize = 73;
|
||||
unsigned boilerplateSize = 69;
|
||||
bytes expectation({byte(Instruction::JUMPDEST),
|
||||
byte(Instruction::PUSH1), 0x0, // initialize local variable x
|
||||
byte(Instruction::PUSH1), 0x2,
|
||||
@ -108,65 +108,14 @@ BOOST_AUTO_TEST_CASE(smoke_test)
|
||||
checkCodePresentAt(code, expectation, boilerplateSize);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(different_argument_numbers)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function f(uint a, uint b, uint c) returns(uint d) { return b; }\n"
|
||||
" function g() returns (uint e, uint h) { h = f(1, 2, 3); }\n"
|
||||
"}\n";
|
||||
bytes code = compileContract(sourceCode);
|
||||
unsigned shift = 103;
|
||||
unsigned boilerplateSize = 116;
|
||||
bytes expectation({byte(Instruction::JUMPDEST),
|
||||
byte(Instruction::PUSH1), 0x0, // initialize return variable d
|
||||
byte(Instruction::DUP3),
|
||||
byte(Instruction::SWAP1), // assign b to d
|
||||
byte(Instruction::POP),
|
||||
byte(Instruction::PUSH1), byte(0xa + shift), // jump to return
|
||||
byte(Instruction::JUMP),
|
||||
byte(Instruction::JUMPDEST),
|
||||
byte(Instruction::SWAP4), // store d and fetch return address
|
||||
byte(Instruction::SWAP3), // store return address
|
||||
byte(Instruction::POP),
|
||||
byte(Instruction::POP),
|
||||
byte(Instruction::POP),
|
||||
byte(Instruction::JUMP), // end of f
|
||||
byte(Instruction::JUMPDEST), // beginning of g
|
||||
byte(Instruction::PUSH1), 0x0,
|
||||
byte(Instruction::PUSH1), 0x0, // initialized e and h
|
||||
byte(Instruction::PUSH1), byte(0x21 + shift), // ret address
|
||||
byte(Instruction::PUSH1), 0x1,
|
||||
byte(Instruction::PUSH1), 0x2,
|
||||
byte(Instruction::PUSH1), 0x3,
|
||||
byte(Instruction::PUSH1), byte(0x1 + shift),
|
||||
// stack here: ret e h 0x20 1 2 3 0x1
|
||||
byte(Instruction::JUMP),
|
||||
byte(Instruction::JUMPDEST),
|
||||
// stack here: ret e h f(1,2,3)
|
||||
byte(Instruction::SWAP1),
|
||||
// stack here: ret e f(1,2,3) h
|
||||
byte(Instruction::POP),
|
||||
byte(Instruction::DUP1), // retrieve it again as "value of expression"
|
||||
byte(Instruction::POP), // end of assignment
|
||||
// stack here: ret e f(1,2,3)
|
||||
byte(Instruction::JUMPDEST),
|
||||
byte(Instruction::SWAP1),
|
||||
// ret e f(1,2,3)
|
||||
byte(Instruction::SWAP2),
|
||||
// f(1,2,3) e ret
|
||||
byte(Instruction::JUMP) // end of g
|
||||
});
|
||||
checkCodePresentAt(code, expectation, boilerplateSize);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ifStatement)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function f() { bool x; if (x) 77; else if (!x) 78; else 79; }"
|
||||
"}\n";
|
||||
bytes code = compileContract(sourceCode);
|
||||
unsigned shift = 60;
|
||||
unsigned boilerplateSize = 73;
|
||||
unsigned shift = 56;
|
||||
unsigned boilerplateSize = 69;
|
||||
bytes expectation({byte(Instruction::JUMPDEST),
|
||||
byte(Instruction::PUSH1), 0x0,
|
||||
byte(Instruction::DUP1),
|
||||
@ -206,8 +155,8 @@ BOOST_AUTO_TEST_CASE(loops)
|
||||
" function f() { while(true){1;break;2;continue;3;return;4;} }"
|
||||
"}\n";
|
||||
bytes code = compileContract(sourceCode);
|
||||
unsigned shift = 60;
|
||||
unsigned boilerplateSize = 73;
|
||||
unsigned shift = 56;
|
||||
unsigned boilerplateSize = 69;
|
||||
bytes expectation({byte(Instruction::JUMPDEST),
|
||||
byte(Instruction::JUMPDEST),
|
||||
byte(Instruction::PUSH1), 0x1,
|
||||
|
@ -92,6 +92,26 @@ BOOST_AUTO_TEST_CASE(multiple_functions)
|
||||
BOOST_CHECK(callContractFunction("i_am_not_there()", bytes()) == bytes());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(named_args)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function a(uint a, uint b, uint c) returns (uint r) { r = a * 100 + b * 10 + c * 1; }\n"
|
||||
" function b() returns (uint r) { r = a({a: 1, b: 2, c: 3}); }\n"
|
||||
"}\n";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("b()", bytes()) == toBigEndian(u256(123)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(disorder_named_args)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function a(uint a, uint b, uint c) returns (uint r) { r = a * 100 + b * 10 + c * 1; }\n"
|
||||
" function b() returns (uint r) { r = a({c: 3, a: 1, b: 2}); }\n"
|
||||
"}\n";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("b()", bytes()) == toBigEndian(u256(123)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(while_loop)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
@ -772,6 +792,94 @@ BOOST_AUTO_TEST_CASE(struct_reference)
|
||||
BOOST_CHECK(callContractFunction("check()") == encodeArgs(true));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(deleteStruct)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
struct topStruct {
|
||||
nestedStruct nstr;
|
||||
emptyStruct empty;
|
||||
uint topValue;
|
||||
mapping (uint => uint) topMapping;
|
||||
}
|
||||
uint toDelete;
|
||||
topStruct str;
|
||||
struct nestedStruct {
|
||||
uint nestedValue;
|
||||
mapping (uint => bool) nestedMapping;
|
||||
}
|
||||
struct emptyStruct{
|
||||
}
|
||||
function test(){
|
||||
toDelete = 5;
|
||||
str.topValue = 1;
|
||||
str.topMapping[0] = 1;
|
||||
str.topMapping[1] = 2;
|
||||
|
||||
str.nstr.nestedValue = 2;
|
||||
str.nstr.nestedMapping[0] = true;
|
||||
str.nstr.nestedMapping[1] = false;
|
||||
delete str;
|
||||
delete toDelete;
|
||||
}
|
||||
function getToDelete() returns (uint res){
|
||||
res = toDelete;
|
||||
}
|
||||
function getTopValue() returns(uint topValue){
|
||||
topValue = str.topValue;
|
||||
}
|
||||
function getNestedValue() returns(uint nestedValue){
|
||||
nestedValue = str.nstr.nestedValue;
|
||||
}
|
||||
function getTopMapping(uint index) returns(uint ret) {
|
||||
ret = str.topMapping[index];
|
||||
}
|
||||
function getNestedMapping(uint index) returns(bool ret) {
|
||||
return str.nstr.nestedMapping[index];
|
||||
}
|
||||
})";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("getToDelete()") == encodeArgs(0));
|
||||
BOOST_CHECK(callContractFunction("getTopValue()") == encodeArgs(0));
|
||||
BOOST_CHECK(callContractFunction("getNestedValue()") == encodeArgs(0));
|
||||
// mapping values should be the same
|
||||
BOOST_CHECK(callContractFunction("getTopMapping(uint256)", 0) == encodeArgs(1));
|
||||
BOOST_CHECK(callContractFunction("getTopMapping(uint256)", 1) == encodeArgs(2));
|
||||
BOOST_CHECK(callContractFunction("getNestedMapping(uint256)", 0) == encodeArgs(true));
|
||||
BOOST_CHECK(callContractFunction("getNestedMapping(uint256)", 1) == encodeArgs(false));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(deleteLocal)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
function delLocal() returns (uint res){
|
||||
uint v = 5;
|
||||
delete v;
|
||||
res = v;
|
||||
}
|
||||
})";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("delLocal()") == encodeArgs(0));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(deleteLocals)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
function delLocal() returns (uint res1, uint res2){
|
||||
uint v = 5;
|
||||
uint w = 6;
|
||||
uint x = 7;
|
||||
delete v;
|
||||
res1 = w;
|
||||
res2 = x;
|
||||
}
|
||||
})";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("delLocal()") == encodeArgs(6, 7));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(constructor)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
@ -794,6 +902,63 @@ BOOST_AUTO_TEST_CASE(constructor)
|
||||
testSolidityAgainstCpp("get(uint256)", get, u256(7));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(simple_accessor)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" uint256 public data;\n"
|
||||
" function test() {\n"
|
||||
" data = 8;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("data()") == encodeArgs(8));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multiple_elementary_accessors)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" uint256 public data;\n"
|
||||
" string6 public name;\n"
|
||||
" hash public a_hash;\n"
|
||||
" address public an_address;\n"
|
||||
" function test() {\n"
|
||||
" data = 8;\n"
|
||||
" name = \"Celina\";\n"
|
||||
" a_hash = sha3(123);\n"
|
||||
" an_address = address(0x1337);\n"
|
||||
" super_secret_data = 42;\n"
|
||||
" }\n"
|
||||
" uint256 super_secret_data;"
|
||||
"}\n";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("data()") == encodeArgs(8));
|
||||
BOOST_CHECK(callContractFunction("name()") == encodeArgs("Celina"));
|
||||
BOOST_CHECK(callContractFunction("a_hash()") == encodeArgs(dev::sha3(toBigEndian(u256(123)))));
|
||||
BOOST_CHECK(callContractFunction("an_address()") == encodeArgs(toBigEndian(u160(0x1337))));
|
||||
BOOST_CHECK(callContractFunction("super_secret_data()") == bytes());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(complex_accessors)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" mapping(uint256 => string4) public to_string_map;\n"
|
||||
" mapping(uint256 => bool) public to_bool_map;\n"
|
||||
" mapping(uint256 => uint256) public to_uint_map;\n"
|
||||
" mapping(uint256 => mapping(uint256 => uint256)) public to_multiple_map;\n"
|
||||
" function test() {\n"
|
||||
" to_string_map[42] = \"24\";\n"
|
||||
" to_bool_map[42] = false;\n"
|
||||
" to_uint_map[42] = 12;\n"
|
||||
" to_multiple_map[42][23] = 31;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("to_string_map(uint256)", 42) == encodeArgs("24"));
|
||||
BOOST_CHECK(callContractFunction("to_bool_map(uint256)", 42) == encodeArgs(false));
|
||||
BOOST_CHECK(callContractFunction("to_uint_map(uint256)", 42) == encodeArgs(12));
|
||||
BOOST_CHECK(callContractFunction("to_multiple_map(uint256,uint256)", 42, 23) == encodeArgs(31));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(balance)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
@ -852,6 +1017,97 @@ BOOST_AUTO_TEST_CASE(type_conversions_cleanup)
|
||||
0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22}));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(convert_string_to_string)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract Test {
|
||||
function pipeTrough(string3 input) returns (string3 ret) {
|
||||
return string3(input);
|
||||
}
|
||||
})";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("pipeTrough(string3)", "abc") == encodeArgs("abc"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(convert_hash_to_string_same_size)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract Test {
|
||||
function hashToString(hash h) returns (string32 s) {
|
||||
return string32(h);
|
||||
}
|
||||
})";
|
||||
compileAndRun(sourceCode);
|
||||
u256 a("0x6162630000000000000000000000000000000000000000000000000000000000");
|
||||
BOOST_CHECK(callContractFunction("hashToString(hash256)", a) == encodeArgs(a));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(convert_hash_to_string_different_size)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract Test {
|
||||
function hashToString(hash160 h) returns (string20 s) {
|
||||
return string20(h);
|
||||
}
|
||||
})";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("hashToString(hash160)", u160("0x6161626361626361626361616263616263616263")) ==
|
||||
encodeArgs(string("aabcabcabcaabcabcabc")));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(convert_string_to_hash_same_size)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract Test {
|
||||
function stringToHash(string32 s) returns (hash h) {
|
||||
return hash(s);
|
||||
}
|
||||
})";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("stringToHash(string32)", string("abc2")) ==
|
||||
encodeArgs(u256("0x6162633200000000000000000000000000000000000000000000000000000000")));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(convert_string_to_hash_different_size)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract Test {
|
||||
function stringToHash(string20 s) returns (hash160 h) {
|
||||
return hash160(s);
|
||||
}
|
||||
})";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("stringToHash(string20)", string("aabcabcabcaabcabcabc")) ==
|
||||
encodeArgs(u160("0x6161626361626361626361616263616263616263")));
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(convert_string_to_hash_different_min_size)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract Test {
|
||||
function stringToHash(string1 s) returns (hash8 h) {
|
||||
return hash8(s);
|
||||
}
|
||||
})";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("stringToHash(string1)", string("a")) ==
|
||||
encodeArgs(u256("0x61")));
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(convert_hash_to_string_different_min_size)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract Test {
|
||||
function HashToString(hash8 h) returns (string1 s) {
|
||||
return string1(h);
|
||||
}
|
||||
})";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("HashToString(hash8)", u256("0x61")) ==
|
||||
encodeArgs(string("a")));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(send_ether)
|
||||
{
|
||||
@ -1243,6 +1499,7 @@ BOOST_AUTO_TEST_CASE(constructor_arguments)
|
||||
contract Helper {
|
||||
string3 name;
|
||||
bool flag;
|
||||
|
||||
function Helper(string3 x, bool f) {
|
||||
name = x;
|
||||
flag = f;
|
||||
@ -1273,8 +1530,7 @@ BOOST_AUTO_TEST_CASE(functions_called_by_constructor)
|
||||
setName("abc");
|
||||
}
|
||||
function getName() returns (string3 ret) { return name; }
|
||||
private:
|
||||
function setName(string3 _name) { name = _name; }
|
||||
function setName(string3 _name) private { name = _name; }
|
||||
})";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_REQUIRE(callContractFunction("getName()") == encodeArgs("abc"));
|
||||
@ -1404,6 +1660,441 @@ BOOST_AUTO_TEST_CASE(value_for_constructor)
|
||||
BOOST_REQUIRE(callContractFunction("getBalances()") == encodeArgs(12, 10));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(virtual_function_calls)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract Base {
|
||||
function f() returns (uint i) { return g(); }
|
||||
function g() returns (uint i) { return 1; }
|
||||
}
|
||||
contract Derived is Base {
|
||||
function g() returns (uint i) { return 2; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "Derived");
|
||||
BOOST_CHECK(callContractFunction("g()") == encodeArgs(2));
|
||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(2));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(access_base_storage)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract Base {
|
||||
uint dataBase;
|
||||
function getViaBase() returns (uint i) { return dataBase; }
|
||||
}
|
||||
contract Derived is Base {
|
||||
uint dataDerived;
|
||||
function setData(uint base, uint derived) returns (bool r) {
|
||||
dataBase = base;
|
||||
dataDerived = derived;
|
||||
return true;
|
||||
}
|
||||
function getViaDerived() returns (uint base, uint derived) {
|
||||
base = dataBase;
|
||||
derived = dataDerived;
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "Derived");
|
||||
BOOST_CHECK(callContractFunction("setData(uint256,uint256)", 1, 2) == encodeArgs(true));
|
||||
BOOST_CHECK(callContractFunction("getViaBase()") == encodeArgs(1));
|
||||
BOOST_CHECK(callContractFunction("getViaDerived()") == encodeArgs(1, 2));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(single_copy_with_multiple_inheritance)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract Base {
|
||||
uint data;
|
||||
function setData(uint i) { data = i; }
|
||||
function getViaBase() returns (uint i) { return data; }
|
||||
}
|
||||
contract A is Base { function setViaA(uint i) { setData(i); } }
|
||||
contract B is Base { function getViaB() returns (uint i) { return getViaBase(); } }
|
||||
contract Derived is Base, B, A { }
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "Derived");
|
||||
BOOST_CHECK(callContractFunction("getViaB()") == encodeArgs(0));
|
||||
BOOST_CHECK(callContractFunction("setViaA(uint256)", 23) == encodeArgs());
|
||||
BOOST_CHECK(callContractFunction("getViaB()") == encodeArgs(23));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(explicit_base_cass)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract BaseBase { function g() returns (uint r) { return 1; } }
|
||||
contract Base is BaseBase { function g() returns (uint r) { return 2; } }
|
||||
contract Derived is Base {
|
||||
function f() returns (uint r) { return BaseBase.g(); }
|
||||
function g() returns (uint r) { return 3; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "Derived");
|
||||
BOOST_CHECK(callContractFunction("g()") == encodeArgs(3));
|
||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(1));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(base_constructor_arguments)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract BaseBase {
|
||||
uint m_a;
|
||||
function BaseBase(uint a) {
|
||||
m_a = a;
|
||||
}
|
||||
}
|
||||
contract Base is BaseBase(7) {
|
||||
function Base() {
|
||||
m_a *= m_a;
|
||||
}
|
||||
}
|
||||
contract Derived is Base() {
|
||||
function getA() returns (uint r) { return m_a; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "Derived");
|
||||
BOOST_CHECK(callContractFunction("getA()") == encodeArgs(7 * 7));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_usage_in_constructor_arguments)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract BaseBase {
|
||||
uint m_a;
|
||||
function BaseBase(uint a) {
|
||||
m_a = a;
|
||||
}
|
||||
function g() returns (uint r) { return 2; }
|
||||
}
|
||||
contract Base is BaseBase(BaseBase.g()) {
|
||||
}
|
||||
contract Derived is Base() {
|
||||
function getA() returns (uint r) { return m_a; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "Derived");
|
||||
BOOST_CHECK(callContractFunction("getA()") == encodeArgs(2));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(virtual_function_usage_in_constructor_arguments)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract BaseBase {
|
||||
uint m_a;
|
||||
function BaseBase(uint a) {
|
||||
m_a = a;
|
||||
}
|
||||
function overridden() returns (uint r) { return 1; }
|
||||
function g() returns (uint r) { return overridden(); }
|
||||
}
|
||||
contract Base is BaseBase(BaseBase.g()) {
|
||||
}
|
||||
contract Derived is Base() {
|
||||
function getA() returns (uint r) { return m_a; }
|
||||
function overridden() returns (uint r) { return 2; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "Derived");
|
||||
BOOST_CHECK(callContractFunction("getA()") == encodeArgs(2));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(constructor_argument_overriding)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract BaseBase {
|
||||
uint m_a;
|
||||
function BaseBase(uint a) {
|
||||
m_a = a;
|
||||
}
|
||||
}
|
||||
contract Base is BaseBase(2) { }
|
||||
contract Derived is BaseBase(3), Base {
|
||||
function getA() returns (uint r) { return m_a; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "Derived");
|
||||
BOOST_CHECK(callContractFunction("getA()") == encodeArgs(3));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_modifier)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
function getOne() nonFree returns (uint r) { return 1; }
|
||||
modifier nonFree { if (msg.value > 0) _ }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("getOne()") == encodeArgs(0));
|
||||
BOOST_CHECK(callContractFunctionWithValue("getOne()", 1) == encodeArgs(1));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_modifier_local_variables)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
modifier mod1 { var a = 1; var b = 2; _ }
|
||||
modifier mod2(bool a) { if (a) return; else _ }
|
||||
function f(bool a) mod1 mod2(a) returns (uint r) { return 3; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(0));
|
||||
BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(3));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_modifier_loop)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
modifier repeat(uint count) { for (var i = 0; i < count; ++i) _ }
|
||||
function f() repeat(10) returns (uint r) { r += 1; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(10));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_modifier_multi_invocation)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
modifier repeat(bool twice) { if (twice) _ _ }
|
||||
function f(bool twice) repeat(twice) returns (uint r) { r += 1; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(1));
|
||||
BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(2));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_modifier_multi_with_return)
|
||||
{
|
||||
// Here, the explicit return prevents the second execution
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
modifier repeat(bool twice) { if (twice) _ _ }
|
||||
function f(bool twice) repeat(twice) returns (uint r) { r += 1; return r; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(1));
|
||||
BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(1));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_modifier_overriding)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract A {
|
||||
function f() mod returns (bool r) { return true; }
|
||||
modifier mod { _ }
|
||||
}
|
||||
contract C is A {
|
||||
modifier mod { }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(false));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_modifier_calling_functions_in_creation_context)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract A {
|
||||
uint data;
|
||||
function A() mod1 { f1(); }
|
||||
function f1() mod2 { data |= 0x1; }
|
||||
function f2() { data |= 0x20; }
|
||||
function f3() { }
|
||||
modifier mod1 { f2(); _ }
|
||||
modifier mod2 { f3(); }
|
||||
function getData() returns (uint r) { return data; }
|
||||
}
|
||||
contract C is A {
|
||||
modifier mod1 { f4(); _ }
|
||||
function f3() { data |= 0x300; }
|
||||
function f4() { data |= 0x4000; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("getData()") == encodeArgs(0x4300));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_modifier_for_constructor)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract A {
|
||||
uint data;
|
||||
function A() mod1 { data |= 2; }
|
||||
modifier mod1 { data |= 1; _ }
|
||||
function getData() returns (uint r) { return data; }
|
||||
}
|
||||
contract C is A {
|
||||
modifier mod1 { data |= 4; _ }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("getData()") == encodeArgs(4 | 2));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(use_std_lib)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
import "mortal";
|
||||
contract Icarus is mortal { }
|
||||
)";
|
||||
m_addStandardSources = true;
|
||||
u256 amount(130);
|
||||
u160 address(23);
|
||||
compileAndRun(sourceCode, amount, "Icarus");
|
||||
u256 balanceBefore = m_state.balance(m_sender);
|
||||
BOOST_CHECK(callContractFunction("kill()") == bytes());
|
||||
BOOST_CHECK(!m_state.addressHasCode(m_contractAddress));
|
||||
BOOST_CHECK(m_state.balance(m_sender) > balanceBefore);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(crazy_elementary_typenames_on_stack)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
function f() returns (uint r) {
|
||||
uint; uint; uint; uint;
|
||||
int x = -7;
|
||||
var a = uint;
|
||||
return a(x);
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(-7)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(super)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract A { function f() returns (uint r) { return 1; } }
|
||||
contract B is A { function f() returns (uint r) { return super.f() | 2; } }
|
||||
contract C is A { function f() returns (uint r) { return super.f() | 4; } }
|
||||
contract D is B, C { function f() returns (uint r) { return super.f() | 8; } }
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "D");
|
||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(1 | 2 | 4 | 8));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(super_in_constructor)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract A { function f() returns (uint r) { return 1; } }
|
||||
contract B is A { function f() returns (uint r) { return super.f() | 2; } }
|
||||
contract C is A { function f() returns (uint r) { return super.f() | 4; } }
|
||||
contract D is B, C { uint data; function D() { data = super.f() | 8; } function f() returns (uint r) { return data; } }
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "D");
|
||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(1 | 2 | 4 | 8));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fallback_function)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract A {
|
||||
uint data;
|
||||
function() returns (uint r) { data = 1; return 2; }
|
||||
function getData() returns (uint r) { return data; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("getData()") == encodeArgs(0));
|
||||
BOOST_CHECK(callContractFunction("") == encodeArgs(2));
|
||||
BOOST_CHECK(callContractFunction("getData()") == encodeArgs(1));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inherited_fallback_function)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract A {
|
||||
uint data;
|
||||
function() returns (uint r) { data = 1; return 2; }
|
||||
function getData() returns (uint r) { return data; }
|
||||
}
|
||||
contract B is A {}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "B");
|
||||
BOOST_CHECK(callContractFunction("getData()") == encodeArgs(0));
|
||||
BOOST_CHECK(callContractFunction("") == encodeArgs(2));
|
||||
BOOST_CHECK(callContractFunction("getData()") == encodeArgs(1));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract ClientReceipt {
|
||||
event Deposit(address indexed _from, hash indexed _id, uint _value);
|
||||
function deposit(hash _id, bool _manually) {
|
||||
if (_manually) {
|
||||
hash s = 0x50cb9fe53daa9737b786ab3646f04d0150dc50ef4e75f59509d83667ad5adb20;
|
||||
log3(msg.value, s, hash32(msg.sender), _id);
|
||||
} else
|
||||
Deposit(hash32(msg.sender), _id, msg.value);
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
u256 value(18);
|
||||
u256 id(0x1234);
|
||||
for (bool manually: {true, false})
|
||||
{
|
||||
callContractFunctionWithValue("deposit(hash256,bool)", value, id, manually);
|
||||
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
|
||||
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(value)));
|
||||
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3);
|
||||
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(address,hash256,uint256)")));
|
||||
BOOST_CHECK_EQUAL(m_logs[0].topics[1], h256(m_sender));
|
||||
BOOST_CHECK_EQUAL(m_logs[0].topics[2], h256(id));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event_no_arguments)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract ClientReceipt {
|
||||
event Deposit;
|
||||
function deposit() {
|
||||
Deposit();
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("deposit()");
|
||||
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
|
||||
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
|
||||
BOOST_CHECK(m_logs[0].data.empty());
|
||||
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
|
||||
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit()")));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event_lots_of_data)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract ClientReceipt {
|
||||
event Deposit(address _from, hash _id, uint _value, bool _flag);
|
||||
function deposit(hash _id) {
|
||||
Deposit(msg.sender, hash32(_id), msg.value, true);
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
u256 value(18);
|
||||
u256 id(0x1234);
|
||||
callContractFunctionWithValue("deposit(hash256)", value, id);
|
||||
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
|
||||
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
|
||||
BOOST_CHECK(m_logs[0].data == encodeArgs(m_sender, id, value, true));
|
||||
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
|
||||
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(address,hash256,uint256,bool)")));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
@ -86,17 +86,26 @@ Declaration const& resolveDeclaration(vector<string> const& _namespacedName,
|
||||
}
|
||||
|
||||
bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _functions = {},
|
||||
vector<vector<string>> _localVariables = {})
|
||||
vector<vector<string>> _localVariables = {},
|
||||
vector<shared_ptr<MagicVariableDeclaration const>> _globalDeclarations = {})
|
||||
{
|
||||
Parser parser;
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
|
||||
NameAndTypeResolver resolver({});
|
||||
|
||||
vector<Declaration const*> declarations;
|
||||
declarations.reserve(_globalDeclarations.size() + 1);
|
||||
for (ASTPointer<Declaration const> const& variable: _globalDeclarations)
|
||||
declarations.push_back(variable.get());
|
||||
NameAndTypeResolver resolver(declarations);
|
||||
resolver.registerDeclarations(*sourceUnit);
|
||||
|
||||
vector<ContractDefinition const*> inheritanceHierarchy;
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));
|
||||
inheritanceHierarchy = vector<ContractDefinition const*>(1, contract);
|
||||
}
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
@ -110,10 +119,12 @@ bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _
|
||||
BOOST_REQUIRE(extractor.getExpression() != nullptr);
|
||||
|
||||
CompilerContext context;
|
||||
for (vector<string> const& function: _functions)
|
||||
context.addFunction(dynamic_cast<FunctionDefinition const&>(resolveDeclaration(function, resolver)));
|
||||
context.setInheritanceHierarchy(inheritanceHierarchy);
|
||||
unsigned parametersSize = _localVariables.size(); // assume they are all one slot on the stack
|
||||
context.adjustStackOffset(parametersSize);
|
||||
for (vector<string> const& variable: _localVariables)
|
||||
context.addVariable(dynamic_cast<VariableDeclaration const&>(resolveDeclaration(variable, resolver)));
|
||||
context.addVariable(dynamic_cast<VariableDeclaration const&>(resolveDeclaration(variable, resolver)),
|
||||
parametersSize--);
|
||||
|
||||
ExpressionCompiler::compileExpression(context, *extractor.getExpression());
|
||||
|
||||
@ -390,6 +401,21 @@ BOOST_AUTO_TEST_CASE(intermediately_overflowing_literals)
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(blockhash)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function f() {\n"
|
||||
" block.blockhash(3);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
bytes code = compileFirstExpression(sourceCode, {}, {},
|
||||
{make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::BLOCK))});
|
||||
|
||||
bytes expectation({byte(eth::Instruction::PUSH1), 0x03,
|
||||
byte(eth::Instruction::BLOCKHASH)});
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
173
SolidityInterface.cpp
Normal file
173
SolidityInterface.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
This file is part of cpp-ethereum.
|
||||
|
||||
cpp-ethereum is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-ethereum is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @author Christian <c@ethdev.com>
|
||||
* @date 2015
|
||||
* Unit tests for generating source interfaces for Solidity contracts.
|
||||
*/
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <libsolidity/CompilerStack.h>
|
||||
#include <libsolidity/AST.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
|
||||
class SolidityInterfaceChecker
|
||||
{
|
||||
public:
|
||||
SolidityInterfaceChecker(): m_compilerStack(false) {}
|
||||
|
||||
/// Compiles the given code, generates the interface and parses that again.
|
||||
ContractDefinition const& checkInterface(string const& _code, string const& _contractName = "")
|
||||
{
|
||||
m_code = _code;
|
||||
BOOST_REQUIRE_NO_THROW(m_compilerStack.parse(_code));
|
||||
m_interface = m_compilerStack.getMetadata("", DocumentationType::ABI_SOLIDITY_INTERFACE);
|
||||
BOOST_REQUIRE_NO_THROW(m_reCompiler.parse(m_interface));
|
||||
return m_reCompiler.getContractDefinition(_contractName);
|
||||
}
|
||||
|
||||
string getSourcePart(ASTNode const& _node) const
|
||||
{
|
||||
Location location = _node.getLocation();
|
||||
BOOST_REQUIRE(!location.isEmpty());
|
||||
return m_interface.substr(location.start, location.end - location.start);
|
||||
}
|
||||
|
||||
protected:
|
||||
string m_code;
|
||||
string m_interface;
|
||||
CompilerStack m_compilerStack;
|
||||
CompilerStack m_reCompiler;
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(SolidityInterface, SolidityInterfaceChecker)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(empty_contract)
|
||||
{
|
||||
ContractDefinition const& contract = checkInterface("contract test {}");
|
||||
BOOST_CHECK_EQUAL(getSourcePart(contract), "contract test{}");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(single_function)
|
||||
{
|
||||
ContractDefinition const& contract = checkInterface(
|
||||
"contract test {\n"
|
||||
" function f(uint a) returns(uint d) { return a * 7; }\n"
|
||||
"}\n");
|
||||
BOOST_REQUIRE_EQUAL(1, contract.getDefinedFunctions().size());
|
||||
BOOST_CHECK_EQUAL(getSourcePart(*contract.getDefinedFunctions().front()),
|
||||
"function f(uint256 a)returns(uint256 d){}");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(single_constant_function)
|
||||
{
|
||||
ContractDefinition const& contract = checkInterface(
|
||||
"contract test { function f(uint a) constant returns(hash8 x) { 1==2; } }");
|
||||
BOOST_REQUIRE_EQUAL(1, contract.getDefinedFunctions().size());
|
||||
BOOST_CHECK_EQUAL(getSourcePart(*contract.getDefinedFunctions().front()),
|
||||
"function f(uint256 a)constant returns(hash8 x){}");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multiple_functions)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function f(uint a) returns(uint d) { return a * 7; }\n"
|
||||
" function g(uint b) returns(uint e) { return b * 8; }\n"
|
||||
"}\n";
|
||||
ContractDefinition const& contract = checkInterface(sourceCode);
|
||||
set<string> expectation({"function f(uint256 a)returns(uint256 d){}",
|
||||
"function g(uint256 b)returns(uint256 e){}"});
|
||||
BOOST_REQUIRE_EQUAL(2, contract.getDefinedFunctions().size());
|
||||
BOOST_CHECK(expectation == set<string>({getSourcePart(*contract.getDefinedFunctions().at(0)),
|
||||
getSourcePart(*contract.getDefinedFunctions().at(1))}));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(exclude_fallback_function)
|
||||
{
|
||||
char const* sourceCode = "contract test { function() {} }";
|
||||
ContractDefinition const& contract = checkInterface(sourceCode);
|
||||
BOOST_CHECK_EQUAL(getSourcePart(contract), "contract test{}");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event)
|
||||
{
|
||||
ContractDefinition const& contract = checkInterface(
|
||||
"contract test { event Event; }");
|
||||
BOOST_REQUIRE_EQUAL(1, contract.getEvents().size());
|
||||
BOOST_CHECK_EQUAL(getSourcePart(*contract.getEvents().front()),
|
||||
"event Event;");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event_arguments)
|
||||
{
|
||||
ContractDefinition const& contract = checkInterface(
|
||||
"contract test { event Event(uint a, uint indexed b); }");
|
||||
BOOST_REQUIRE_EQUAL(1, contract.getEvents().size());
|
||||
BOOST_CHECK_EQUAL(getSourcePart(*contract.getEvents().front()),
|
||||
"event Event(uint256 a,uint256 indexed b);");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(events)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function f(uint a) returns(uint d) { return a * 7; }\n"
|
||||
" event e1(uint b, address indexed c); \n"
|
||||
" event e2(); \n"
|
||||
"}\n";
|
||||
ContractDefinition const& contract = checkInterface(sourceCode);
|
||||
set<string> expectation({"event e1(uint256 b,address indexed c);", "event e2;"});
|
||||
BOOST_REQUIRE_EQUAL(2, contract.getEvents().size());
|
||||
BOOST_CHECK(expectation == set<string>({getSourcePart(*contract.getEvents().at(0)),
|
||||
getSourcePart(*contract.getEvents().at(1))}));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inheritance)
|
||||
{
|
||||
char const* sourceCode =
|
||||
" contract Base { \n"
|
||||
" function baseFunction(uint p) returns (uint i) { return p; } \n"
|
||||
" event baseEvent(string32 indexed evtArgBase); \n"
|
||||
" } \n"
|
||||
" contract Derived is Base { \n"
|
||||
" function derivedFunction(string32 p) returns (string32 i) { return p; } \n"
|
||||
" event derivedEvent(uint indexed evtArgDerived); \n"
|
||||
" }";
|
||||
ContractDefinition const& contract = checkInterface(sourceCode);
|
||||
set<string> expectedEvents({"event derivedEvent(uint256 indexed evtArgDerived);",
|
||||
"event baseEvent(string32 indexed evtArgBase);"});
|
||||
set<string> expectedFunctions({"function baseFunction(uint256 p)returns(uint256 i){}",
|
||||
"function derivedFunction(string32 p)returns(string32 i){}"});
|
||||
BOOST_CHECK(expectedEvents == set<string>({getSourcePart(*contract.getEvents().at(0)),
|
||||
getSourcePart(*contract.getEvents().at(1))}));
|
||||
BOOST_REQUIRE_EQUAL(2, contract.getDefinedFunctions().size());
|
||||
BOOST_CHECK(expectedFunctions == set<string>({getSourcePart(*contract.getDefinedFunctions().at(0)),
|
||||
getSourcePart(*contract.getDefinedFunctions().at(1))}));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -23,12 +23,15 @@
|
||||
#include <string>
|
||||
|
||||
#include <libdevcore/Log.h>
|
||||
#include <libdevcrypto/SHA3.h>
|
||||
#include <libsolidity/Scanner.h>
|
||||
#include <libsolidity/Parser.h>
|
||||
#include <libsolidity/NameAndTypeResolver.h>
|
||||
#include <libsolidity/Exceptions.h>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
@ -38,6 +41,7 @@ namespace test
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
ASTPointer<SourceUnit> parseTextAndResolveNames(std::string const& _source)
|
||||
{
|
||||
Parser parser;
|
||||
@ -53,6 +57,48 @@ ASTPointer<SourceUnit> parseTextAndResolveNames(std::string const& _source)
|
||||
|
||||
return sourceUnit;
|
||||
}
|
||||
|
||||
ASTPointer<SourceUnit> parseTextAndResolveNamesWithChecks(std::string const& _source)
|
||||
{
|
||||
Parser parser;
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
try
|
||||
{
|
||||
sourceUnit = parser.parse(std::make_shared<Scanner>(CharStream(_source)));
|
||||
NameAndTypeResolver resolver({});
|
||||
resolver.registerDeclarations(*sourceUnit);
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
resolver.resolveNamesAndTypes(*contract);
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
resolver.checkTypeRequirements(*contract);
|
||||
}
|
||||
catch(boost::exception const& _e)
|
||||
{
|
||||
auto msg = std::string("Parsing text and resolving names failed with: \n") + boost::diagnostic_information(_e);
|
||||
BOOST_FAIL(msg);
|
||||
}
|
||||
return sourceUnit;
|
||||
}
|
||||
|
||||
static ContractDefinition const* retrieveContract(ASTPointer<SourceUnit> _source, unsigned index)
|
||||
{
|
||||
ContractDefinition* contract;
|
||||
unsigned counter = 0;
|
||||
for (ASTPointer<ASTNode> const& node: _source->getNodes())
|
||||
if ((contract = dynamic_cast<ContractDefinition*>(node.get())) && counter == index)
|
||||
return contract;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static FunctionTypePointer const& retrieveFunctionBySignature(ContractDefinition const* _contract,
|
||||
std::string const& _signature)
|
||||
{
|
||||
FixedHash<4> hash(dev::sha3(_signature));
|
||||
return _contract->getInterfaceFunctions()[hash];
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(SolidityNameAndTypeResolution)
|
||||
@ -63,7 +109,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
|
||||
" uint256 stateVariable1;\n"
|
||||
" function fun(uint256 arg1) { var x; uint256 y; }"
|
||||
"}\n";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(double_stateVariable_declaration)
|
||||
@ -357,7 +403,6 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(hash_collision_in_interface)
|
||||
{
|
||||
char const* text = "contract test {\n"
|
||||
@ -369,6 +414,496 @@ BOOST_AUTO_TEST_CASE(hash_collision_in_interface)
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inheritance_basic)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract base { uint baseMember; struct BaseType { uint element; } }
|
||||
contract derived is base {
|
||||
BaseType data;
|
||||
function f() { baseMember = 7; }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inheritance_diamond_basic)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract root { function rootFunction() {} }
|
||||
contract inter1 is root { function f() {} }
|
||||
contract inter2 is root { function f() {} }
|
||||
contract derived is root, inter2, inter1 {
|
||||
function g() { f(); rootFunction(); }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cyclic_inheritance)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A is B { }
|
||||
contract B is A { }
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(illegal_override_direct)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract B { function f() {} }
|
||||
contract C is B { function f(uint i) {} }
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(illegal_override_indirect)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A { function f(uint a) {} }
|
||||
contract B { function f() {} }
|
||||
contract C is A, B { }
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(illegal_override_visibility)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract B { function f() protected {} }
|
||||
contract C is B { function f() public {} }
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(illegal_override_constness)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract B { function f() constant {} }
|
||||
contract C is B { function f() {} }
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(complex_inheritance)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A { function f() { uint8 x = C(0).g(); } }
|
||||
contract B { function f() {} function g() returns (uint8 r) {} }
|
||||
contract C is A, B { }
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(constructor_visibility)
|
||||
{
|
||||
// The constructor of a base class should not be visible in the derived class
|
||||
char const* text = R"(
|
||||
contract A { function A() { } }
|
||||
contract B is A { function f() { A x = A(0); } }
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(overriding_constructor)
|
||||
{
|
||||
// It is fine to "override" constructor of a base class since it is invisible
|
||||
char const* text = R"(
|
||||
contract A { function A() { } }
|
||||
contract B is A { function A() returns (uint8 r) {} }
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(missing_base_constructor_arguments)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A { function A(uint a) { } }
|
||||
contract B is A { }
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(base_constructor_arguments_override)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A { function A(uint a) { } }
|
||||
contract B is A { }
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(implicit_derived_to_base_conversion)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A { }
|
||||
contract B is A {
|
||||
function f() { A a = B(1); }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(implicit_base_to_derived_conversion)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A { }
|
||||
contract B is A {
|
||||
function f() { B b = A(1); }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_modifier_invocation)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract B {
|
||||
function f() mod1(2, true) mod2("0123456") { }
|
||||
modifier mod1(uint a, bool b) { if (b) _ }
|
||||
modifier mod2(string7 a) { while (a == "1234567") _ }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(invalid_function_modifier_type)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract B {
|
||||
function f() mod1(true) { }
|
||||
modifier mod1(uint a) { if (a > 0) _ }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_modifier_invocation_parameters)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract B {
|
||||
function f(uint8 a) mod1(a, true) mod2(r) returns (string7 r) { }
|
||||
modifier mod1(uint a, bool b) { if (b) _ }
|
||||
modifier mod2(string7 a) { while (a == "1234567") _ }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract B {
|
||||
function f() mod(x) { uint x = 7; }
|
||||
modifier mod(uint a) { if (a > 0) _ }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(legal_modifier_override)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A { modifier mod(uint a) {} }
|
||||
contract B is A { modifier mod(uint a) {} }
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(illegal_modifier_override)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A { modifier mod(uint a) {} }
|
||||
contract B is A { modifier mod(uint8 a) {} }
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(modifier_overrides_function)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A { modifier mod(uint a) {} }
|
||||
contract B is A { function mod(uint a) {} }
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_overrides_modifier)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A { function mod(uint a) {} }
|
||||
contract B is A { modifier mod(uint a) {} }
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(modifier_returns_value)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A {
|
||||
function f(uint a) mod(2) returns (uint r) {}
|
||||
modifier mod(uint a) { return 7; }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(state_variable_accessors)
|
||||
{
|
||||
char const* text = "contract test {\n"
|
||||
" function fun() {\n"
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"uint256 public foo;\n"
|
||||
"mapping(uint=>string4) public map;\n"
|
||||
"mapping(uint=>mapping(uint=>string4)) public multiple_map;\n"
|
||||
"}\n";
|
||||
|
||||
ASTPointer<SourceUnit> source;
|
||||
ContractDefinition const* contract;
|
||||
BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text));
|
||||
BOOST_REQUIRE((contract = retrieveContract(source, 0)) != nullptr);
|
||||
FunctionTypePointer function = retrieveFunctionBySignature(contract, "foo()");
|
||||
BOOST_REQUIRE(function && function->hasDeclaration());
|
||||
auto returnParams = function->getReturnParameterTypeNames();
|
||||
BOOST_CHECK_EQUAL(returnParams.at(0), "uint256");
|
||||
BOOST_CHECK(function->isConstant());
|
||||
|
||||
function = retrieveFunctionBySignature(contract, "map(uint256)");
|
||||
BOOST_REQUIRE(function && function->hasDeclaration());
|
||||
auto params = function->getParameterTypeNames();
|
||||
BOOST_CHECK_EQUAL(params.at(0), "uint256");
|
||||
returnParams = function->getReturnParameterTypeNames();
|
||||
BOOST_CHECK_EQUAL(returnParams.at(0), "string4");
|
||||
BOOST_CHECK(function->isConstant());
|
||||
|
||||
function = retrieveFunctionBySignature(contract, "multiple_map(uint256,uint256)");
|
||||
BOOST_REQUIRE(function && function->hasDeclaration());
|
||||
params = function->getParameterTypeNames();
|
||||
BOOST_CHECK_EQUAL(params.at(0), "uint256");
|
||||
BOOST_CHECK_EQUAL(params.at(1), "uint256");
|
||||
returnParams = function->getReturnParameterTypeNames();
|
||||
BOOST_CHECK_EQUAL(returnParams.at(0), "string4");
|
||||
BOOST_CHECK(function->isConstant());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_clash_with_state_variable_accessor)
|
||||
{
|
||||
char const* text = "contract test {\n"
|
||||
" function fun() {\n"
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"uint256 foo;\n"
|
||||
" function foo() {}\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(private_state_variable)
|
||||
{
|
||||
char const* text = "contract test {\n"
|
||||
" function fun() {\n"
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"uint256 private foo;\n"
|
||||
"uint256 protected bar;\n"
|
||||
"}\n";
|
||||
|
||||
ASTPointer<SourceUnit> source;
|
||||
ContractDefinition const* contract;
|
||||
BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text));
|
||||
BOOST_CHECK((contract = retrieveContract(source, 0)) != nullptr);
|
||||
FunctionTypePointer function;
|
||||
function = retrieveFunctionBySignature(contract, "foo()");
|
||||
BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a private variable should not exist");
|
||||
function = retrieveFunctionBySignature(contract, "bar()");
|
||||
BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a protected variable should not exist");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fallback_function)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
uint x;
|
||||
function() { x = 2; }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fallback_function_with_arguments)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
uint x;
|
||||
function(uint a) { x = 2; }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fallback_function_twice)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
uint x;
|
||||
function() { x = 2; }
|
||||
function() { x = 3; }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fallback_function_inheritance)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A {
|
||||
uint x;
|
||||
function() { x = 1; }
|
||||
}
|
||||
contract C is A {
|
||||
function() { x = 2; }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
event e(uint indexed a, string3 indexed s, bool indexed b);
|
||||
function f() { e(2, "abc", true); }
|
||||
})";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event_too_many_indexed)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
event e(uint indexed a, string3 indexed b, bool indexed c, uint indexed d);
|
||||
function f() { e(2, "abc", true); }
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event_call)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
event e(uint a, string3 indexed s, bool indexed b);
|
||||
function f() { e(2, "abc", true); }
|
||||
})";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event_inheritance)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract base {
|
||||
event e(uint a, string3 indexed s, bool indexed b);
|
||||
}
|
||||
contract c is base {
|
||||
function f() { e(2, "abc", true); }
|
||||
})";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multiple_events_argument_clash)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
event e1(uint a, uint e1, uint e2);
|
||||
event e2(uint a, uint e1, uint e2);
|
||||
})";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(access_to_default_function_visibility)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
function f() {}
|
||||
}
|
||||
contract d {
|
||||
function g() { c(0).f(); }
|
||||
})";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(access_to_protected_function)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
function f() protected {}
|
||||
}
|
||||
contract d {
|
||||
function g() { c(0).f(); }
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(access_to_default_state_variable_visibility)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
uint a;
|
||||
}
|
||||
contract d {
|
||||
function g() { c(0).a(); }
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(access_to_protected_state_variable)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
uint public a;
|
||||
}
|
||||
contract d {
|
||||
function g() { c(0).a(); }
|
||||
})";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(error_count_in_named_args)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function a(uint a, uint b) returns (uint r) { r = a + b; }\n"
|
||||
" function b() returns (uint r) { r = a({a: 1}); }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(empty_in_named_args)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function a(uint a, uint b) returns (uint r) { r = a + b; }\n"
|
||||
" function b() returns (uint r) { r = a({}); }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(duplicate_parameter_names_in_named_args)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function a(uint a, uint b) returns (uint r) { r = a + b; }\n"
|
||||
" function b() returns (uint r) { r = a({a: 1, a: 2}); }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(invalid_parameter_names_in_named_args)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function a(uint a, uint b) returns (uint r) { r = a + b; }\n"
|
||||
" function b() returns (uint r) { r = a({a: 1, c: 2}); }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ namespace test
|
||||
class DocumentationChecker
|
||||
{
|
||||
public:
|
||||
DocumentationChecker(): m_compilerStack(false) {}
|
||||
|
||||
void checkNatspec(std::string const& _code,
|
||||
std::string const& _expectedDocumentationString,
|
||||
bool _userDocumentation)
|
||||
@ -45,13 +47,9 @@ public:
|
||||
{
|
||||
m_compilerStack.parse(_code);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
catch(boost::exception const& _e)
|
||||
{
|
||||
std::string const* extra = boost::get_error_info<errinfo_comment>(e);
|
||||
std::string msg = std::string("Parsing contract failed with: ") +
|
||||
e.what() + std::string("\n");
|
||||
if (extra)
|
||||
msg += *extra;
|
||||
auto msg = std::string("Parsing contract failed with: ") + boost::diagnostic_information(_e);
|
||||
BOOST_FAIL(msg);
|
||||
}
|
||||
|
||||
@ -510,17 +508,35 @@ BOOST_AUTO_TEST_CASE(dev_title_at_function_error)
|
||||
BOOST_CHECK_THROW(checkNatspec(sourceCode, natspec, false), DocstringParsingError);
|
||||
}
|
||||
|
||||
// test for bug where having no tags in docstring would cause infinite loop
|
||||
BOOST_AUTO_TEST_CASE(natspec_no_tags)
|
||||
BOOST_AUTO_TEST_CASE(natspec_notice_without_tag)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" /// I do something awesome\n"
|
||||
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
|
||||
" function mul(uint a) returns(uint d) { return a * 7; }\n"
|
||||
"}\n";
|
||||
|
||||
char const* natspec = "{\"methods\": {}}";
|
||||
char const* natspec = "{"
|
||||
"\"methods\":{"
|
||||
" \"mul(uint256)\":{ \"notice\": \"I do something awesome\"}"
|
||||
"}}";
|
||||
|
||||
checkNatspec(sourceCode, natspec, false);
|
||||
checkNatspec(sourceCode, natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(natspec_multiline_notice_without_tag)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" /// I do something awesome\n"
|
||||
" /// which requires two lines to explain\n"
|
||||
" function mul(uint a) returns(uint d) { return a * 7; }\n"
|
||||
"}\n";
|
||||
|
||||
char const* natspec = "{"
|
||||
"\"methods\":{"
|
||||
" \"mul(uint256)\":{ \"notice\": \"I do something awesome which requires two lines to explain\"}"
|
||||
"}}";
|
||||
|
||||
checkNatspec(sourceCode, natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
@ -66,6 +66,14 @@ ASTPointer<ContractDefinition> parseTextExplainError(std::string const& _source)
|
||||
}
|
||||
}
|
||||
|
||||
static void checkFunctionNatspec(ASTPointer<FunctionDefinition> _function,
|
||||
std::string const& _expectedDoc)
|
||||
{
|
||||
auto doc = _function->getDocumentation();
|
||||
BOOST_CHECK_MESSAGE(doc != nullptr, "Function does not have Natspec Doc as expected");
|
||||
BOOST_CHECK_EQUAL(*doc, _expectedDoc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -116,6 +124,24 @@ BOOST_AUTO_TEST_CASE(single_function_param)
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(missing_parameter_name_in_named_args)
|
||||
{
|
||||
char const* text = "contract test {\n"
|
||||
" function a(uint a, uint b, uint c) returns (uint r) { r = a * 100 + b * 10 + c * 1; }\n"
|
||||
" function b() returns (uint r) { r = a({: 1, : 2, : 3}); }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(missing_argument_in_named_args)
|
||||
{
|
||||
char const* text = "contract test {\n"
|
||||
" function a(uint a, uint b, uint c) returns (uint r) { r = a * 100 + b * 10 + c * 1; }\n"
|
||||
" function b() returns (uint r) { r = a({a: , b: , c: }); }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_natspec_documentation)
|
||||
{
|
||||
ASTPointer<ContractDefinition> contract;
|
||||
@ -128,7 +154,7 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation)
|
||||
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");
|
||||
checkFunctionNatspec(function, "This is a test function");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_normal_comments)
|
||||
@ -144,7 +170,7 @@ BOOST_AUTO_TEST_CASE(function_normal_comments)
|
||||
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");
|
||||
"Should not have gotten a Natspecc comment for this function");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
|
||||
@ -166,17 +192,17 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
|
||||
auto functions = contract->getDefinedFunctions();
|
||||
|
||||
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
|
||||
BOOST_CHECK_EQUAL(*function->getDocumentation(), "This is test function 1");
|
||||
checkFunctionNatspec(function, "This is test function 1");
|
||||
|
||||
BOOST_REQUIRE_NO_THROW(function = functions.at(1));
|
||||
BOOST_CHECK_EQUAL(*function->getDocumentation(), "This is test function 2");
|
||||
checkFunctionNatspec(function, "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");
|
||||
checkFunctionNatspec(function, "This is test function 4");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multiline_function_documentation)
|
||||
@ -193,9 +219,8 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation)
|
||||
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");
|
||||
checkFunctionNatspec(function, "This is a test function\n"
|
||||
" and it has 2 lines");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body)
|
||||
@ -211,7 +236,6 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body)
|
||||
" 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"
|
||||
@ -220,12 +244,11 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body)
|
||||
auto functions = contract->getDefinedFunctions();
|
||||
|
||||
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
|
||||
BOOST_CHECK_EQUAL(*function->getDocumentation(), "fun1 description");
|
||||
checkFunctionNatspec(function, "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");
|
||||
checkFunctionNatspec(function, "This is a test function\n"
|
||||
" and it has 2 lines");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature)
|
||||
@ -495,6 +518,148 @@ BOOST_AUTO_TEST_CASE(multiple_contracts_and_imports)
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(contract_inheritance)
|
||||
{
|
||||
char const* text = "contract base {\n"
|
||||
" function fun() {\n"
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"contract derived is base {\n"
|
||||
" function fun() {\n"
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(contract_multiple_inheritance)
|
||||
{
|
||||
char const* text = "contract base {\n"
|
||||
" function fun() {\n"
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"contract derived is base, nonExisting {\n"
|
||||
" function fun() {\n"
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(contract_multiple_inheritance_with_arguments)
|
||||
{
|
||||
char const* text = "contract base {\n"
|
||||
" function fun() {\n"
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"contract derived is base(2), nonExisting(\"abc\", \"def\", base.fun()) {\n"
|
||||
" function fun() {\n"
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(placeholder_in_function_context)
|
||||
{
|
||||
char const* text = "contract c {\n"
|
||||
" function fun() returns (uint r) {\n"
|
||||
" var _ = 8;\n"
|
||||
" return _ + 1;"
|
||||
" }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(modifier)
|
||||
{
|
||||
char const* text = "contract c {\n"
|
||||
" modifier mod { if (msg.sender == 0) _ }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(modifier_arguments)
|
||||
{
|
||||
char const* text = "contract c {\n"
|
||||
" modifier mod(uint a) { if (msg.sender == a) _ }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(modifier_invocation)
|
||||
{
|
||||
char const* text = "contract c {\n"
|
||||
" modifier mod1(uint a) { if (msg.sender == a) _ }\n"
|
||||
" modifier mod2 { if (msg.sender == 2) _ }\n"
|
||||
" function f() mod1(7) mod2 { }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fallback_function)
|
||||
{
|
||||
char const* text = "contract c {\n"
|
||||
" function() { }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
event e();
|
||||
})";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event_arguments)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
event e(uint a, string32 s);
|
||||
})";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event_arguments_indexed)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
event e(uint a, string32 indexed s, bool indexed b);
|
||||
})";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(visibility_specifiers)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
uint private a;
|
||||
uint protected b;
|
||||
uint public c;
|
||||
uint d;
|
||||
function f() {}
|
||||
function f_priv() private {}
|
||||
function f_public() public {}
|
||||
function f_protected() protected {}
|
||||
})";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract c {
|
||||
uint private protected a;
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state)
|
||||
if (code.size())
|
||||
{
|
||||
_state.m_cache[address] = Account(toInt(o["balance"]), Account::ContractConception);
|
||||
_state.m_cache[address].setCode(bytesConstRef(&code));
|
||||
_state.m_cache[address].setCode(code);
|
||||
}
|
||||
else
|
||||
_state.m_cache[address] = Account(toInt(o["balance"]), Account::NormalCreation);
|
||||
@ -228,18 +228,19 @@ byte toByte(json_spirit::mValue const& _v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytes importByteArray(std::string const& _str)
|
||||
{
|
||||
return fromHex(_str.substr(0, 2) == "0x" ? _str.substr(2) : _str);
|
||||
}
|
||||
|
||||
bytes importData(json_spirit::mObject& _o)
|
||||
{
|
||||
bytes data;
|
||||
if (_o["data"].type() == json_spirit::str_type)
|
||||
if (_o["data"].get_str().find_first_of("0x") == 0)
|
||||
data = fromHex(_o["data"].get_str().substr(2));
|
||||
else
|
||||
data = fromHex(_o["data"].get_str());
|
||||
data = importByteArray(_o["data"].get_str());
|
||||
else
|
||||
for (auto const& j: _o["data"].get_array())
|
||||
data.push_back(toByte(j));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,7 @@ 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);
|
||||
bytes importByteArray(std::string const& _str);
|
||||
eth::LogEntries importLog(json_spirit::mArray& _o);
|
||||
json_spirit::mArray exportLog(eth::LogEntries _logs);
|
||||
void checkOutput(bytes const& _output, json_spirit::mObject& _o);
|
||||
|
58
commonjs.cpp
Normal file
58
commonjs.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
This file is part of cpp-ethereum.
|
||||
|
||||
cpp-ethereum is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-ethereum is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file commonjs.cpp
|
||||
* @author Marek Kotewicz <marek@ethdev.com>
|
||||
* @date 2014
|
||||
*/
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <libdevcore/Log.h>
|
||||
#include <libethcore/CommonJS.h>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(commonjs)
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::eth;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(jsToPublic)
|
||||
{
|
||||
cnote << "Testing jsToPublic...";
|
||||
KeyPair kp = KeyPair::create();
|
||||
string string = toJS(kp.pub());
|
||||
Public pub = dev::jsToPublic(string);
|
||||
BOOST_CHECK_EQUAL(kp.pub(), pub);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(jsToAddress)
|
||||
{
|
||||
cnote << "Testing jsToPublic...";
|
||||
KeyPair kp = KeyPair::create();
|
||||
string string = toJS(kp.address());
|
||||
Address address = dev::eth::jsToAddress(string);
|
||||
BOOST_CHECK_EQUAL(kp.address(), address);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(jsToSecret)
|
||||
{
|
||||
cnote << "Testing jsToPublic...";
|
||||
KeyPair kp = KeyPair::create();
|
||||
string string = toJS(kp.secret());
|
||||
Secret secret = dev::jsToSecret(string);
|
||||
BOOST_CHECK_EQUAL(kp.secret(), secret);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
2
fork.cpp
2
fork.cpp
@ -23,7 +23,7 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <libethereum/Client.h>
|
||||
#include <libethereum/BlockChain.h>
|
||||
#include <libethereum/CanonBlockChain.h>
|
||||
#include <libethereum/EthereumHost.h>
|
||||
#include "TestHelper.h"
|
||||
using namespace std;
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <random>
|
||||
#include "JsonSpiritHeaders.h"
|
||||
#include <libdevcore/CommonIO.h>
|
||||
#include <libethereum/BlockChain.h>
|
||||
#include <libethereum/CanonBlockChain.h>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include "TestHelper.h"
|
||||
|
||||
@ -58,9 +58,9 @@ BOOST_AUTO_TEST_CASE(genesis_tests)
|
||||
|
||||
js::mObject o = v.get_obj();
|
||||
|
||||
BOOST_CHECK_EQUAL(BlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str()));
|
||||
BOOST_CHECK_EQUAL(toHex(BlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str())));
|
||||
BOOST_CHECK_EQUAL(BlockInfo::headerHash(BlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str()));
|
||||
BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str()));
|
||||
BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str())));
|
||||
BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str()));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
@ -28,11 +28,9 @@
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <libdevcore/Log.h>
|
||||
#include <libdevcore/CommonIO.h>
|
||||
#include <libdevcore/CommonJS.h>
|
||||
#include <libethcore/CommonJS.h>
|
||||
#include <libwebthree/WebThree.h>
|
||||
#include <libweb3jsonrpc/WebThreeStubServer.h>
|
||||
#include <libweb3jsonrpc/CorsHttpServer.h>
|
||||
//#include <json/json.h>
|
||||
#include <jsonrpccpp/server/connectors/httpserver.h>
|
||||
#include <jsonrpccpp/client/connectors/httpclient.h>
|
||||
#include <set>
|
||||
|
@ -45,8 +45,18 @@ public:
|
||||
|
||||
bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "")
|
||||
{
|
||||
dev::solidity::CompilerStack compiler;
|
||||
compiler.compile(_sourceCode, m_optimize);
|
||||
dev::solidity::CompilerStack compiler(m_addStandardSources);
|
||||
try
|
||||
{
|
||||
compiler.addSource("", _sourceCode);
|
||||
compiler.compile(m_optimize);
|
||||
}
|
||||
catch(boost::exception const& _e)
|
||||
{
|
||||
auto msg = std::string("Compiling contract failed with: ") + boost::diagnostic_information(_e);
|
||||
BOOST_FAIL(msg);
|
||||
}
|
||||
|
||||
bytes code = compiler.getBytecode(_contractName);
|
||||
sendMessage(code, true, _value);
|
||||
BOOST_REQUIRE(!m_output.empty());
|
||||
@ -57,7 +67,6 @@ public:
|
||||
bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value,
|
||||
Args const&... _arguments)
|
||||
{
|
||||
|
||||
FixedHash<4> hash(dev::sha3(_sig));
|
||||
sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value);
|
||||
return m_output;
|
||||
@ -97,6 +106,7 @@ public:
|
||||
static bytes encode(char const* _value) { return encode(std::string(_value)); }
|
||||
static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; }
|
||||
static bytes encode(u256 const& _value) { return toBigEndian(_value); }
|
||||
static bytes encode(h256 const& _value) { return _value.asBytes(); }
|
||||
static bytes encode(bytes const& _value, bool _padLeft = true)
|
||||
{
|
||||
bytes padding = bytes((32 - _value.size() % 32) % 32, 0);
|
||||
@ -163,6 +173,7 @@ private:
|
||||
|
||||
protected:
|
||||
bool m_optimize = false;
|
||||
bool m_addStandardSources = false;
|
||||
Address m_sender;
|
||||
Address m_contractAddress;
|
||||
eth::State m_state;
|
||||
|
@ -37,5 +37,36 @@
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"data" : ""
|
||||
}
|
||||
},
|
||||
|
||||
"OverflowGasMakeMoney" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "45678256",
|
||||
"currentGasLimit" : "(2**256)-1",
|
||||
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
|
||||
"currentNumber" : "0",
|
||||
"currentTimestamp" : 1,
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"pre" : {
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "1000",
|
||||
"code" : "",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639435",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "0",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"value" : "501"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -289,7 +289,7 @@
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionTooManyRlpElements" : {
|
||||
"InternlCallStoreClearsOOG" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"currentDifficulty" : "45678256",
|
||||
@ -299,6 +299,162 @@
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"pre" :
|
||||
{
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "7000",
|
||||
"code" : "",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
|
||||
"c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "10",
|
||||
"//" : "gas = 19 going OOG, gas = 20 fine",
|
||||
"code" : "{ (CALL 19 0 1 0 0 0 0) }",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
|
||||
"0000000000000000000000000000000000000000" : {
|
||||
"balance" : "0",
|
||||
"code" : "{(SSTORE 0 0)(SSTORE 1 0)(SSTORE 2 0)(SSTORE 3 0)(SSTORE 4 0)(SSTORE 5 0)(SSTORE 6 0)(SSTORE 7 0)(SSTORE 8 0)(SSTORE 9 0)}",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
"0x" : "0x0c",
|
||||
"0x01" : "0x0c",
|
||||
"0x02" : "0x0c",
|
||||
"0x03" : "0x0c",
|
||||
"0x04" : "0x0c",
|
||||
"0x05" : "0x0c",
|
||||
"0x06" : "0x0c",
|
||||
"0x07" : "0x0c",
|
||||
"0x08" : "0x0c",
|
||||
"0x09" : "0x0c"
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "700",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "c94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"value" : "10"
|
||||
}
|
||||
},
|
||||
|
||||
"StoreClearsAndInternlCallStoreClearsOOG" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"currentDifficulty" : "45678256",
|
||||
"currentGasLimit" : "10000",
|
||||
"currentNumber" : "0",
|
||||
"currentTimestamp" : 1,
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"pre" :
|
||||
{
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "7000",
|
||||
"code" : "",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
|
||||
"c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "10",
|
||||
"//" : "gas = 19 going OOG, gas = 20 fine",
|
||||
"code" : "{(SSTORE 0 0)(SSTORE 1 0)(SSTORE 2 0)(SSTORE 3 0) (CALL 19 0 1 0 0 0 0) }",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
"0x" : "0x0c",
|
||||
"0x01" : "0x0c",
|
||||
"0x02" : "0x0c",
|
||||
"0x03" : "0x0c",
|
||||
"0x04" : "0x0c"
|
||||
}
|
||||
},
|
||||
|
||||
"0000000000000000000000000000000000000000" : {
|
||||
"balance" : "0",
|
||||
"code" : "{(SSTORE 0 0)(SSTORE 1 0)(SSTORE 2 0)(SSTORE 3 0)(SSTORE 4 0)(SSTORE 5 0)(SSTORE 6 0)(SSTORE 7 0)(SSTORE 8 0)(SSTORE 9 0)}",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
"0x" : "0x0c",
|
||||
"0x01" : "0x0c",
|
||||
"0x02" : "0x0c",
|
||||
"0x03" : "0x0c",
|
||||
"0x04" : "0x0c",
|
||||
"0x05" : "0x0c",
|
||||
"0x06" : "0x0c",
|
||||
"0x07" : "0x0c",
|
||||
"0x08" : "0x0c",
|
||||
"0x09" : "0x0c"
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "700",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "c94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"value" : "10"
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionNonceCheck" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "45678256",
|
||||
"currentGasLimit" : "1000000",
|
||||
"currentNumber" : "0",
|
||||
"currentTimestamp" : 1,
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"pre" :
|
||||
{
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "100000",
|
||||
"code" : "",
|
||||
"nonce" : "10",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "1000",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "0",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"value" : "10"
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionNonceCheck2" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "45678256",
|
||||
"currentGasLimit" : "1000000",
|
||||
"currentNumber" : "0",
|
||||
"currentTimestamp" : 1,
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"pre" :
|
||||
{
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "100000",
|
||||
@ -311,16 +467,44 @@
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "600",
|
||||
"gasLimit" : "1600",
|
||||
"gasLimit" : "1000",
|
||||
"gasPrice" : "1",
|
||||
"gasPrice" : "12",
|
||||
"nonce" : "",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d9",
|
||||
"nonce" : "10",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "d2571607e241ecf590ed94b12d87c94babe36db6",
|
||||
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"value" : "10"
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionCosts555" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "45678256",
|
||||
"currentGasLimit" : "1000000",
|
||||
"currentNumber" : "0",
|
||||
"currentTimestamp" : 1,
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"pre" :
|
||||
{
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "100000",
|
||||
"code" : "",
|
||||
"nonce" : "0",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "0x00000000000000000000112233445566778f32",
|
||||
"gasLimit" : "1000",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "0",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"value" : "0"
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include "JsonSpiritHeaders.h"
|
||||
#include <libdevcore/CommonIO.h>
|
||||
#include <libethereum/BlockChain.h>
|
||||
#include <libethereum/CanonBlockChain.h>
|
||||
#include <libethereum/State.h>
|
||||
#include <libethereum/ExtVM.h>
|
||||
#include <libethereum/Defaults.h>
|
||||
@ -35,7 +35,6 @@ using namespace std;
|
||||
using namespace json_spirit;
|
||||
using namespace dev;
|
||||
using namespace dev::eth;
|
||||
using namespace dev::eth;
|
||||
|
||||
namespace dev { namespace test {
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <secp256k1/secp256k1.h>
|
||||
#include <libethereum/BlockChain.h>
|
||||
#include <libethereum/CanonBlockChain.h>
|
||||
#include <libethereum/State.h>
|
||||
#include <libethereum/Defaults.h>
|
||||
using namespace std;
|
||||
@ -40,7 +40,7 @@ int stateTest()
|
||||
Defaults::setDBPath(boost::filesystem::temp_directory_path().string());
|
||||
|
||||
OverlayDB stateDB = State::openDB();
|
||||
BlockChain bc;
|
||||
CanonBlockChain bc;
|
||||
State s(myMiner.address(), stateDB);
|
||||
|
||||
cout << bc;
|
||||
@ -75,7 +75,8 @@ int stateTest()
|
||||
|
||||
// Mine to get some ether and set in stone.
|
||||
s.commitToMine(bc);
|
||||
while (!s.mine(100).completed) {}
|
||||
s.commitToMine(bc);
|
||||
while (!s.mine(50).completed) { s.commitToMine(bc); }
|
||||
s.completeMine();
|
||||
bc.attemptImport(s.blockData(), stateDB);
|
||||
|
||||
|
219
transaction.cpp
Normal file
219
transaction.cpp
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
This file is part of cpp-ethereum.
|
||||
|
||||
cpp-ethereum is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-ethereum is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file transaction.cpp
|
||||
* @author Dmitrii Khokhlov <winsvega@mail.ru>
|
||||
* @date 2015
|
||||
* Transaaction test functions.
|
||||
*/
|
||||
|
||||
#include "TestHelper.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace json_spirit;
|
||||
using namespace dev;
|
||||
using namespace dev::eth;
|
||||
|
||||
namespace dev { namespace test {
|
||||
|
||||
Transaction createTransactionFromFields(mObject& _tObj)
|
||||
{
|
||||
BOOST_REQUIRE(_tObj.count("data") > 0);
|
||||
BOOST_REQUIRE(_tObj.count("value") > 0);
|
||||
BOOST_REQUIRE(_tObj.count("gasPrice") > 0);
|
||||
BOOST_REQUIRE(_tObj.count("gasLimit") > 0);
|
||||
BOOST_REQUIRE(_tObj.count("nonce")> 0);
|
||||
BOOST_REQUIRE(_tObj.count("to") > 0);
|
||||
|
||||
BOOST_REQUIRE(_tObj.count("v") > 0);
|
||||
BOOST_REQUIRE(_tObj.count("r") > 0);
|
||||
BOOST_REQUIRE(_tObj.count("s") > 0);
|
||||
|
||||
//Construct Rlp of the given transaction
|
||||
RLPStream rlpStream;
|
||||
rlpStream.appendList(9);
|
||||
rlpStream << bigint(_tObj["nonce"].get_str()) << bigint(_tObj["gasPrice"].get_str()) << bigint(_tObj["gasLimit"].get_str());
|
||||
if (_tObj["to"].get_str().empty())
|
||||
rlpStream << "";
|
||||
else
|
||||
rlpStream << Address(_tObj["to"].get_str());
|
||||
rlpStream << bigint(_tObj["value"].get_str()) << importData(_tObj);
|
||||
rlpStream << bigint(_tObj["v"].get_str()) << bigint(_tObj["r"].get_str()) << bigint(_tObj["s"].get_str());
|
||||
|
||||
return Transaction(rlpStream.out(), CheckSignature::Sender);
|
||||
}
|
||||
|
||||
void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
|
||||
{
|
||||
for (auto& i: _v.get_obj())
|
||||
{
|
||||
cerr << i.first << endl;
|
||||
mObject& o = i.second.get_obj();
|
||||
|
||||
if (_fillin == false)
|
||||
{
|
||||
BOOST_REQUIRE(o.count("rlp") > 0);
|
||||
bytes rlpReaded = importByteArray(o["rlp"].get_str());
|
||||
Transaction txFromRlp;
|
||||
|
||||
try
|
||||
{
|
||||
txFromRlp = Transaction(rlpReaded, CheckSignature::Sender);
|
||||
if (!txFromRlp.signature().isValid())
|
||||
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transction object should not be defined because the RLP is invalid!");
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_REQUIRE(o.count("transaction") > 0);
|
||||
|
||||
mObject tObj = o["transaction"].get_obj();
|
||||
Transaction txFromFields = createTransactionFromFields(tObj);
|
||||
|
||||
//Check the fields restored from RLP to original fields
|
||||
BOOST_CHECK_MESSAGE(txFromFields.data() == txFromRlp.data(), "Data in given RLP not matching the Transaction data!");
|
||||
BOOST_CHECK_MESSAGE(txFromFields.value() == txFromRlp.value(), "Value in given RLP not matching the Transaction value!");
|
||||
BOOST_CHECK_MESSAGE(txFromFields.gasPrice() == txFromRlp.gasPrice(), "GasPrice in given RLP not matching the Transaction gasPrice!");
|
||||
BOOST_CHECK_MESSAGE(txFromFields.gas() == txFromRlp.gas(),"Gas in given RLP not matching the Transaction gas!");
|
||||
BOOST_CHECK_MESSAGE(txFromFields.nonce() == txFromRlp.nonce(),"Nonce in given RLP not matching the Transaction nonce!");
|
||||
BOOST_CHECK_MESSAGE(txFromFields.receiveAddress() == txFromRlp.receiveAddress(), "Receive address in given RLP not matching the Transaction 'to' address!");
|
||||
BOOST_CHECK_MESSAGE(txFromFields.sender() == txFromRlp.sender(), "Transaction sender address in given RLP not matching the Transaction 'vrs' signature!");
|
||||
BOOST_CHECK_MESSAGE(txFromFields == txFromRlp, "However, txFromFields != txFromRlp!");
|
||||
BOOST_REQUIRE (o.count("sender") > 0);
|
||||
|
||||
Address addressReaded = Address(o["sender"].get_str());
|
||||
BOOST_CHECK_MESSAGE(txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded, "Signature address of sender does not match given sender address!");
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_REQUIRE(o.count("transaction") > 0);
|
||||
mObject tObj = o["transaction"].get_obj();
|
||||
|
||||
//Construct Rlp of the given transaction
|
||||
RLPStream rlpStream;
|
||||
rlpStream.appendList(tObj.size());
|
||||
|
||||
if (tObj.count("nonce") > 0)
|
||||
rlpStream << bigint(tObj["nonce"].get_str());
|
||||
|
||||
if (tObj.count("gasPrice") > 0)
|
||||
rlpStream << bigint(tObj["gasPrice"].get_str());
|
||||
|
||||
if (tObj.count("gasLimit") > 0)
|
||||
rlpStream << bigint(tObj["gasLimit"].get_str());
|
||||
|
||||
if (tObj.count("to") > 0)
|
||||
{
|
||||
if (tObj["to"].get_str().empty())
|
||||
rlpStream << "";
|
||||
else
|
||||
rlpStream << Address(tObj["to"].get_str());
|
||||
}
|
||||
|
||||
if (tObj.count("value") > 0)
|
||||
rlpStream << bigint(tObj["value"].get_str());
|
||||
|
||||
if (tObj.count("data") > 0)
|
||||
rlpStream << importData(tObj);
|
||||
|
||||
if (tObj.count("v") > 0)
|
||||
rlpStream << bigint(tObj["v"].get_str());
|
||||
|
||||
if (tObj.count("r") > 0)
|
||||
rlpStream << bigint(tObj["r"].get_str());
|
||||
|
||||
if (tObj.count("s") > 0)
|
||||
rlpStream << bigint(tObj["s"].get_str());
|
||||
|
||||
if (tObj.count("extrafield") > 0)
|
||||
rlpStream << bigint(tObj["extrafield"].get_str());
|
||||
|
||||
o["rlp"] = "0x" + toHex(rlpStream.out());
|
||||
|
||||
try
|
||||
{
|
||||
Transaction txFromFields(rlpStream.out(), CheckSignature::Sender);
|
||||
if (!txFromFields.signature().isValid())
|
||||
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );
|
||||
|
||||
o["sender"] = toString(txFromFields.sender());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
o.erase(o.find("transaction"));
|
||||
}
|
||||
}
|
||||
}//for
|
||||
}//doTransactionTests
|
||||
|
||||
} }// Namespace Close
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(TransactionTests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(TransactionTest)
|
||||
{
|
||||
dev::test::executeTests("ttTransactionTest", "/TransactionTests", dev::test::doTransactionTests);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(tt10mbDataField)
|
||||
{
|
||||
dev::test::executeTests("tt10mbDataField", "/TransactionTests", dev::test::doTransactionTests);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ttCreateTest)
|
||||
{
|
||||
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
|
||||
{
|
||||
string arg = boost::unit_test::framework::master_test_suite().argv[i];
|
||||
if (arg == "--createtest")
|
||||
{
|
||||
if (boost::unit_test::framework::master_test_suite().argc <= i + 2)
|
||||
{
|
||||
cnote << "usage: ./testeth --createtest <PathToConstructor> <PathToDestiny>\n";
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
cnote << "Populating tests...";
|
||||
json_spirit::mValue v;
|
||||
string s = asString(dev::contents(boost::unit_test::framework::master_test_suite().argv[i + 1]));
|
||||
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + (string)boost::unit_test::framework::master_test_suite().argv[i + 1] + " is empty.");
|
||||
json_spirit::read_string(s, v);
|
||||
dev::test::doTransactionTests(v, true);
|
||||
writeFile(boost::unit_test::framework::master_test_suite().argv[i + 2], asBytes(json_spirit::write_string(v, true)));
|
||||
}
|
||||
catch (Exception const& _e)
|
||||
{
|
||||
BOOST_ERROR("Failed transaction test with Exception: " << diagnostic_information(_e));
|
||||
}
|
||||
catch (std::exception const& _e)
|
||||
{
|
||||
BOOST_ERROR("Failed transaction test with Exception: " << _e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(userDefinedFileTT)
|
||||
{
|
||||
dev::test::userDefinedTest("--ttTest", dev::test::doTransactionTests);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
17
tt10mbDataFieldFiller.json
Normal file
17
tt10mbDataFieldFiller.json
Normal file
File diff suppressed because one or more lines are too long
290
ttTransactionTestFiller.json
Normal file
290
ttTransactionTestFiller.json
Normal file
@ -0,0 +1,290 @@
|
||||
{
|
||||
"RightVRSTest" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "0x5544",
|
||||
"gasLimit" : "2000",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "3",
|
||||
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"value" : "10",
|
||||
"v" : "28",
|
||||
"r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a",
|
||||
"s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
"WrongVRSTestVl27" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "2000",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "0",
|
||||
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"value" : "10",
|
||||
"v" : "26",
|
||||
"r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a",
|
||||
"s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"
|
||||
}
|
||||
},
|
||||
|
||||
"WrongVRSTestVge31" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "2000",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "0",
|
||||
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"value" : "10",
|
||||
"v" : "31",
|
||||
"r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a",
|
||||
"s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"
|
||||
}
|
||||
},
|
||||
|
||||
"SenderTest" : {
|
||||
"//" : "sender a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "850",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "0",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "10",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "secretkey 45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionWithTooManyRLPElements" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "850",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "0",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "10",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804",
|
||||
"extrafield" : "128472387293"
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionWithTooFewRLPElements" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "0",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionWithHihghValue" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "850",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "0",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"TransactionWithHihghValueOverflow" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "850",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "0",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "115792089237316195423570985008687907853269984665640564039457584007913129639936",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionWithSvalueOverflow" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "850",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "0",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "11",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionWithRvalueOverflow" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "850",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "0",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "11",
|
||||
"v" : "27",
|
||||
"r" : "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionWithNonceOverflow" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "850",
|
||||
"gasPrice" : "1",
|
||||
"nonce" : "115792089237316195423570985008687907853269984665640564039457584007913129639936",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "11",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionWithGasPriceOverflow" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "850",
|
||||
"gasPrice" : "115792089237316195423570985008687907853269984665640564039457584007913129639936",
|
||||
"nonce" : "0",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "11",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionWithGasLimitOverflow" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639936",
|
||||
"gasPrice" : "123",
|
||||
"nonce" : "0",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "11",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
"RLPElementsWithZeros" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "0x0000011222333",
|
||||
"gasLimit" : "1000",
|
||||
"gasPrice" : "00123",
|
||||
"nonce" : "0054",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "00000011",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
"RLPWrongHexElements" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "0x0000000012",
|
||||
"gasLimit" : "1000",
|
||||
"gasPrice" : "123",
|
||||
"nonce" : "54",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "11",
|
||||
"v" : "27",
|
||||
"r" : "0x0048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0x00efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
"EmptyTransaction" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "",
|
||||
"gasPrice" : "",
|
||||
"nonce" : "",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
"AddressMore20" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "",
|
||||
"gasPrice" : "",
|
||||
"nonce" : "",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d871f",
|
||||
"value" : "",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
"AddressLess20" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "",
|
||||
"gasPrice" : "",
|
||||
"nonce" : "",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d",
|
||||
"value" : "",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
},
|
||||
|
||||
"AddressMore20WithFirstZeros" : {
|
||||
"transaction" :
|
||||
{
|
||||
"data" : "",
|
||||
"gasLimit" : "",
|
||||
"gasPrice" : "",
|
||||
"nonce" : "",
|
||||
"to" : "0x00000000000000000000000095e7baea6a6c7c4c2dfeb977efac326af552d",
|
||||
"value" : "",
|
||||
"v" : "27",
|
||||
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
|
||||
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <libethereum/Client.h>
|
||||
#include <libethereum/BlockChain.h>
|
||||
#include <libethereum/CanonBlockChain.h>
|
||||
#include <libethereum/EthereumHost.h>
|
||||
#include "TestHelper.h"
|
||||
using namespace std;
|
||||
|
198
whisperTopic.cpp
198
whisperTopic.cpp
@ -46,17 +46,21 @@ BOOST_AUTO_TEST_CASE(topic)
|
||||
auto wh = ph.registerCapability(new WhisperHost());
|
||||
ph.start();
|
||||
|
||||
started = true;
|
||||
|
||||
/// Only interested in odd packets
|
||||
auto w = wh->installWatch(BuildTopicMask("odd"));
|
||||
|
||||
for (int i = 0, last = 0; i < 200 && last < 81; ++i)
|
||||
started = true;
|
||||
set<unsigned> received;
|
||||
|
||||
for (int iterout = 0, last = 0; iterout < 200 && last < 81; ++iterout)
|
||||
{
|
||||
for (auto i: wh->checkWatch(w))
|
||||
{
|
||||
Message msg = wh->envelope(i).open();
|
||||
Message msg = wh->envelope(i).open(wh->fullTopic(w));
|
||||
last = RLP(msg.payload()).toInt<unsigned>();
|
||||
if (received.count(last))
|
||||
continue;
|
||||
received.insert(last);
|
||||
cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
|
||||
result += last;
|
||||
}
|
||||
@ -68,7 +72,7 @@ BOOST_AUTO_TEST_CASE(topic)
|
||||
this_thread::sleep_for(chrono::milliseconds(50));
|
||||
|
||||
Host ph("Test", NetworkPreferences(50300, "", false, true));
|
||||
auto wh = ph.registerCapability(new WhisperHost());
|
||||
shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
ph.start();
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
@ -87,4 +91,188 @@ BOOST_AUTO_TEST_CASE(topic)
|
||||
BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(forwarding)
|
||||
{
|
||||
cnote << "Testing Whisper forwarding...";
|
||||
auto oldLogVerbosity = g_logVerbosity;
|
||||
g_logVerbosity = 0;
|
||||
|
||||
unsigned result = 0;
|
||||
bool done = false;
|
||||
|
||||
bool startedListener = false;
|
||||
std::thread listener([&]()
|
||||
{
|
||||
setThreadName("listener");
|
||||
|
||||
// Host must be configured not to share peers.
|
||||
Host ph("Listner", NetworkPreferences(50303, "", false, true));
|
||||
ph.setIdealPeerCount(0);
|
||||
auto wh = ph.registerCapability(new WhisperHost());
|
||||
ph.start();
|
||||
|
||||
startedListener = true;
|
||||
|
||||
/// Only interested in odd packets
|
||||
auto w = wh->installWatch(BuildTopicMask("test"));
|
||||
|
||||
for (int i = 0; i < 200 && !result; ++i)
|
||||
{
|
||||
for (auto i: wh->checkWatch(w))
|
||||
{
|
||||
Message msg = wh->envelope(i).open(wh->fullTopic(w));
|
||||
unsigned last = RLP(msg.payload()).toInt<unsigned>();
|
||||
cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
|
||||
result = last;
|
||||
}
|
||||
this_thread::sleep_for(chrono::milliseconds(50));
|
||||
}
|
||||
});
|
||||
|
||||
bool startedForwarder = false;
|
||||
std::thread forwarder([&]()
|
||||
{
|
||||
setThreadName("forwarder");
|
||||
|
||||
while (!startedListener)
|
||||
this_thread::sleep_for(chrono::milliseconds(50));
|
||||
|
||||
// Host must be configured not to share peers.
|
||||
Host ph("Forwarder", NetworkPreferences(50305, "", false, true));
|
||||
ph.setIdealPeerCount(0);
|
||||
auto wh = ph.registerCapability(new WhisperHost());
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
ph.start();
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
ph.connect("127.0.0.1", 50303);
|
||||
|
||||
startedForwarder = true;
|
||||
|
||||
/// Only interested in odd packets
|
||||
auto w = wh->installWatch(BuildTopicMask("test"));
|
||||
|
||||
while (!done)
|
||||
{
|
||||
for (auto i: wh->checkWatch(w))
|
||||
{
|
||||
Message msg = wh->envelope(i).open(wh->fullTopic(w));
|
||||
cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
|
||||
}
|
||||
this_thread::sleep_for(chrono::milliseconds(50));
|
||||
}
|
||||
});
|
||||
|
||||
while (!startedForwarder)
|
||||
this_thread::sleep_for(chrono::milliseconds(50));
|
||||
|
||||
Host ph("Sender", NetworkPreferences(50300, "", false, true));
|
||||
ph.setIdealPeerCount(0);
|
||||
shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
ph.start();
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
ph.connect("127.0.0.1", 50305);
|
||||
|
||||
KeyPair us = KeyPair::create();
|
||||
wh->post(us.sec(), RLPStream().append(1).out(), BuildTopic("test"));
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
|
||||
listener.join();
|
||||
done = true;
|
||||
forwarder.join();
|
||||
g_logVerbosity = oldLogVerbosity;
|
||||
|
||||
BOOST_REQUIRE_EQUAL(result, 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(asyncforwarding)
|
||||
{
|
||||
cnote << "Testing Whisper async forwarding...";
|
||||
auto oldLogVerbosity = g_logVerbosity;
|
||||
g_logVerbosity = 2;
|
||||
|
||||
unsigned result = 0;
|
||||
bool done = false;
|
||||
|
||||
bool startedForwarder = false;
|
||||
std::thread forwarder([&]()
|
||||
{
|
||||
setThreadName("forwarder");
|
||||
|
||||
// Host must be configured not to share peers.
|
||||
Host ph("Forwarder", NetworkPreferences(50305, "", false, true));
|
||||
ph.setIdealPeerCount(0);
|
||||
auto wh = ph.registerCapability(new WhisperHost());
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
ph.start();
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
ph.connect("127.0.0.1", 50303);
|
||||
|
||||
startedForwarder = true;
|
||||
|
||||
/// Only interested in odd packets
|
||||
auto w = wh->installWatch(BuildTopicMask("test"));
|
||||
|
||||
while (!done)
|
||||
{
|
||||
for (auto i: wh->checkWatch(w))
|
||||
{
|
||||
Message msg = wh->envelope(i).open(wh->fullTopic(w));
|
||||
cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
|
||||
}
|
||||
this_thread::sleep_for(chrono::milliseconds(50));
|
||||
}
|
||||
});
|
||||
|
||||
while (!startedForwarder)
|
||||
this_thread::sleep_for(chrono::milliseconds(50));
|
||||
|
||||
{
|
||||
Host ph("Sender", NetworkPreferences(50300, "", false, true));
|
||||
ph.setIdealPeerCount(0);
|
||||
shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
ph.start();
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
ph.connect("127.0.0.1", 50305);
|
||||
|
||||
KeyPair us = KeyPair::create();
|
||||
wh->post(us.sec(), RLPStream().append(1).out(), BuildTopic("test"));
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
|
||||
{
|
||||
Host ph("Listener", NetworkPreferences(50300, "", false, true));
|
||||
ph.setIdealPeerCount(0);
|
||||
shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
ph.start();
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
ph.connect("127.0.0.1", 50305);
|
||||
|
||||
/// Only interested in odd packets
|
||||
auto w = wh->installWatch(BuildTopicMask("test"));
|
||||
|
||||
for (int i = 0; i < 200 && !result; ++i)
|
||||
{
|
||||
for (auto i: wh->checkWatch(w))
|
||||
{
|
||||
Message msg = wh->envelope(i).open(wh->fullTopic(w));
|
||||
unsigned last = RLP(msg.payload()).toInt<unsigned>();
|
||||
cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
|
||||
result = last;
|
||||
}
|
||||
this_thread::sleep_for(chrono::milliseconds(50));
|
||||
}
|
||||
}
|
||||
|
||||
done = true;
|
||||
forwarder.join();
|
||||
g_logVerbosity = oldLogVerbosity;
|
||||
|
||||
BOOST_REQUIRE_EQUAL(result, 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
Loading…
Reference in New Issue
Block a user