Merge remote-tracking branch 'upstream/develop' into vm

This commit is contained in:
Paweł Bylica 2014-12-10 17:44:10 +01:00
commit 1d85b074c8
8 changed files with 276 additions and 39 deletions

View File

@ -44,6 +44,14 @@ static CryptoPP::OID s_curveOID(CryptoPP::ASN1::secp256k1());
static CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP> s_params(s_curveOID); static CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP> s_params(s_curveOID);
static CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP>::EllipticCurve s_curve(s_params.GetCurve()); static CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP>::EllipticCurve s_curve(s_params.GetCurve());
BOOST_AUTO_TEST_CASE(cryptopp_patch)
{
KeyPair k = KeyPair::create();
bytes io_text;
s_secp256k1.decrypt(k.sec(), io_text);
BOOST_REQUIRE_EQUAL(io_text.size(), 0);
}
BOOST_AUTO_TEST_CASE(verify_secert) BOOST_AUTO_TEST_CASE(verify_secert)
{ {
h256 empty; h256 empty;

View File

@ -46,16 +46,23 @@ namespace
bytes compileContract(const string& _sourceCode) bytes compileContract(const string& _sourceCode)
{ {
Parser parser; Parser parser;
ASTPointer<ContractDefinition> contract; ASTPointer<SourceUnit> sourceUnit;
BOOST_REQUIRE_NO_THROW(contract = parser.parse(make_shared<Scanner>(CharStream(_sourceCode)))); BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
NameAndTypeResolver resolver({}); NameAndTypeResolver resolver({});
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); resolver.registerDeclarations(*sourceUnit);
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));
Compiler compiler; Compiler compiler;
compiler.compileContract(*contract, {}); compiler.compileContract(*contract, {});
// debug // debug
//compiler.streamAssembly(cout); //compiler.streamAssembly(cout);
return compiler.getAssembledBytecode(); return compiler.getAssembledBytecode();
}
BOOST_FAIL("No contract found in source.");
return bytes();
} }
/// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation. /// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation.
@ -118,8 +125,8 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers)
byte(Instruction::JUMP), // end of f byte(Instruction::JUMP), // end of f
byte(Instruction::JUMPDEST), // beginning of g byte(Instruction::JUMPDEST), // beginning of g
byte(Instruction::PUSH1), 0x0, byte(Instruction::PUSH1), 0x0,
byte(Instruction::DUP1), // initialized e and h byte(Instruction::PUSH1), 0x0, // initialized e and h
byte(Instruction::PUSH1), byte(0x29 + shift), // ret address byte(Instruction::PUSH1), byte(0x2a + shift), // ret address
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),

View File

@ -47,9 +47,11 @@ class ExecutionFramework
public: public:
ExecutionFramework() { g_logVerbosity = 0; } ExecutionFramework() { g_logVerbosity = 0; }
bytes const& compileAndRun(string const& _sourceCode, u256 const& _value = 0) bytes const& compileAndRun(string const& _sourceCode, u256 const& _value = 0, string const& _contractName = "")
{ {
bytes code = dev::solidity::CompilerStack::staticCompile(_sourceCode); dev::solidity::CompilerStack compiler;
compiler.compile(_sourceCode);
bytes code = compiler.getBytecode(_contractName);
sendMessage(code, true, _value); sendMessage(code, true, _value);
BOOST_REQUIRE(!m_output.empty()); BOOST_REQUIRE(!m_output.empty());
return m_output; return m_output;
@ -115,6 +117,7 @@ private:
void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0)
{ {
m_state.addBalance(m_sender, _value); // just in case
eth::Executive executive(m_state); eth::Executive executive(m_state);
eth::Transaction t = _isCreation ? eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) eth::Transaction t = _isCreation ? eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec())
: eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); : eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec());
@ -127,7 +130,7 @@ private:
catch (...) {} catch (...) {}
if (_isCreation) if (_isCreation)
{ {
BOOST_REQUIRE(!executive.create(Address(), _value, m_gasPrice, m_gas, &_data, Address())); BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender));
m_contractAddress = executive.newAddress(); m_contractAddress = executive.newAddress();
BOOST_REQUIRE(m_contractAddress); BOOST_REQUIRE(m_contractAddress);
BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
@ -135,14 +138,16 @@ private:
else else
{ {
BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), _value, m_gasPrice, &_data, m_gas, Address())); BOOST_REQUIRE(!executive.call(m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender));
} }
BOOST_REQUIRE(executive.go()); BOOST_REQUIRE(executive.go());
m_state.noteSending(m_sender);
executive.finalize(); executive.finalize();
m_output = executive.out().toVector(); m_output = executive.out().toVector();
} }
protected: protected:
Address m_sender;
Address m_contractAddress; Address m_contractAddress;
eth::State m_state; eth::State m_state;
u256 const m_gasPrice = 100 * eth::szabo; u256 const m_gasPrice = 100 * eth::szabo;
@ -898,6 +903,163 @@ BOOST_AUTO_TEST_CASE(ecrecover)
BOOST_CHECK(callContractFunction(0, h, v, r, s) == toBigEndian(addr)); BOOST_CHECK(callContractFunction(0, h, v, r, s) == toBigEndian(addr));
} }
BOOST_AUTO_TEST_CASE(inter_contract_calls)
{
char const* sourceCode = R"(
contract Helper {
function multiply(uint a, uint b) returns (uint c) {
return a * b;
}
}
contract Main {
Helper h;
function callHelper(uint a, uint b) returns (uint c) {
return h.multiply(a, b);
}
function getHelper() returns (address haddress) {
return address(h);
}
function setHelper(address haddress) {
h = Helper(haddress);
}
})";
compileAndRun(sourceCode, 0, "Helper");
u160 const helperAddress = m_contractAddress;
compileAndRun(sourceCode, 0, "Main");
BOOST_REQUIRE(callContractFunction(2, helperAddress) == bytes());
BOOST_REQUIRE(callContractFunction(1, helperAddress) == toBigEndian(helperAddress));
u256 a(3456789);
u256 b("0x282837623374623234aa74");
BOOST_REQUIRE(callContractFunction(0, a, b) == toBigEndian(a * b));
}
BOOST_AUTO_TEST_CASE(inter_contract_calls_with_complex_parameters)
{
char const* sourceCode = R"(
contract Helper {
function sel(uint a, bool select, uint b) returns (uint c) {
if (select) return a; else return b;
}
}
contract Main {
Helper h;
function callHelper(uint a, bool select, uint b) returns (uint c) {
return h.sel(a, select, b) * 3;
}
function getHelper() returns (address haddress) {
return address(h);
}
function setHelper(address haddress) {
h = Helper(haddress);
}
})";
compileAndRun(sourceCode, 0, "Helper");
u160 const helperAddress = m_contractAddress;
compileAndRun(sourceCode, 0, "Main");
BOOST_REQUIRE(callContractFunction(2, helperAddress) == bytes());
BOOST_REQUIRE(callContractFunction(1, helperAddress) == toBigEndian(helperAddress));
u256 a(3456789);
u256 b("0x282837623374623234aa74");
BOOST_REQUIRE(callContractFunction(0, a, true, b) == toBigEndian(a * 3));
BOOST_REQUIRE(callContractFunction(0, a, false, b) == toBigEndian(b * 3));
}
BOOST_AUTO_TEST_CASE(inter_contract_calls_accessing_this)
{
char const* sourceCode = R"(
contract Helper {
function getAddress() returns (address addr) {
return address(this);
}
}
contract Main {
Helper h;
function callHelper() returns (address addr) {
return h.getAddress();
}
function getHelper() returns (address addr) {
return address(h);
}
function setHelper(address addr) {
h = Helper(addr);
}
})";
compileAndRun(sourceCode, 0, "Helper");
u160 const helperAddress = m_contractAddress;
compileAndRun(sourceCode, 0, "Main");
BOOST_REQUIRE(callContractFunction(2, helperAddress) == bytes());
BOOST_REQUIRE(callContractFunction(1, helperAddress) == toBigEndian(helperAddress));
BOOST_REQUIRE(callContractFunction(0) == toBigEndian(helperAddress));
}
BOOST_AUTO_TEST_CASE(calls_to_this)
{
char const* sourceCode = R"(
contract Helper {
function invoke(uint a, uint b) returns (uint c) {
return this.multiply(a, b, 10);
}
function multiply(uint a, uint b, uint8 c) returns (uint ret) {
return a * b + c;
}
}
contract Main {
Helper h;
function callHelper(uint a, uint b) returns (uint ret) {
return h.invoke(a, b);
}
function getHelper() returns (address addr) {
return address(h);
}
function setHelper(address addr) {
h = Helper(addr);
}
})";
compileAndRun(sourceCode, 0, "Helper");
u160 const helperAddress = m_contractAddress;
compileAndRun(sourceCode, 0, "Main");
BOOST_REQUIRE(callContractFunction(2, helperAddress) == bytes());
BOOST_REQUIRE(callContractFunction(1, helperAddress) == toBigEndian(helperAddress));
u256 a(3456789);
u256 b("0x282837623374623234aa74");
BOOST_REQUIRE(callContractFunction(0, a, b) == toBigEndian(a * b + 10));
}
BOOST_AUTO_TEST_CASE(inter_contract_calls_with_local_vars)
{
// note that a reference to another contract's function occupies two stack slots,
// so this tests correct stack slot allocation
char const* sourceCode = R"(
contract Helper {
function multiply(uint a, uint b) returns (uint c) {
return a * b;
}
}
contract Main {
Helper h;
function callHelper(uint a, uint b) returns (uint c) {
var fu = h.multiply;
var y = 9;
var ret = fu(a, b);
return ret + y;
}
function getHelper() returns (address haddress) {
return address(h);
}
function setHelper(address haddress) {
h = Helper(haddress);
}
})";
compileAndRun(sourceCode, 0, "Helper");
u160 const helperAddress = m_contractAddress;
compileAndRun(sourceCode, 0, "Main");
BOOST_REQUIRE(callContractFunction(2, helperAddress) == bytes());
BOOST_REQUIRE(callContractFunction(1, helperAddress) == toBigEndian(helperAddress));
u256 a(3456789);
u256 b("0x282837623374623234aa74");
BOOST_REQUIRE(callContractFunction(0, a, b) == toBigEndian(a * b + 9));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

View File

@ -86,27 +86,34 @@ bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _
vector<vector<string>> _localVariables = {}) vector<vector<string>> _localVariables = {})
{ {
Parser parser; Parser parser;
ASTPointer<ContractDefinition> contract; ASTPointer<SourceUnit> sourceUnit;
BOOST_REQUIRE_NO_THROW(contract = parser.parse(make_shared<Scanner>(CharStream(_sourceCode)))); BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
NameAndTypeResolver resolver({}); NameAndTypeResolver resolver({});
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); resolver.registerDeclarations(*sourceUnit);
FirstExpressionExtractor extractor(*contract); for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
BOOST_REQUIRE(extractor.getExpression() != nullptr); if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));
FirstExpressionExtractor extractor(*contract);
BOOST_REQUIRE(extractor.getExpression() != nullptr);
CompilerContext context; CompilerContext context;
for (vector<string> const& function: _functions) for (vector<string> const& function: _functions)
context.addFunction(dynamic_cast<FunctionDefinition const&>(resolveDeclaration(function, resolver))); context.addFunction(dynamic_cast<FunctionDefinition const&>(resolveDeclaration(function, resolver)));
for (vector<string> const& variable: _localVariables) for (vector<string> const& variable: _localVariables)
context.addVariable(dynamic_cast<VariableDeclaration const&>(resolveDeclaration(variable, resolver))); context.addVariable(dynamic_cast<VariableDeclaration const&>(resolveDeclaration(variable, resolver)));
ExpressionCompiler::compileExpression(context, *extractor.getExpression()); ExpressionCompiler::compileExpression(context, *extractor.getExpression());
for (vector<string> const& function: _functions) for (vector<string> const& function: _functions)
context << context.getFunctionEntryLabel(dynamic_cast<FunctionDefinition const&>(resolveDeclaration(function, resolver))); context << context.getFunctionEntryLabel(dynamic_cast<FunctionDefinition const&>(resolveDeclaration(function, resolver)));
bytes instructions = context.getAssembledBytecode(); bytes instructions = context.getAssembledBytecode();
// debug // debug
// cout << eth::disassemble(instructions) << endl; // cout << eth::disassemble(instructions) << endl;
return instructions; return instructions;
}
BOOST_FAIL("No contract found in source.");
return bytes();
} }
} // end anonymous namespace } // end anonymous namespace

View File

@ -50,7 +50,7 @@ public:
msg += *extra; msg += *extra;
BOOST_FAIL(msg); BOOST_FAIL(msg);
} }
std::string generatedInterfaceString = m_compilerStack.getJsonDocumentation(DocumentationType::ABI_INTERFACE); std::string generatedInterfaceString = m_compilerStack.getJsonDocumentation("", DocumentationType::ABI_INTERFACE);
Json::Value generatedInterface; Json::Value generatedInterface;
m_reader.parse(generatedInterfaceString, generatedInterface); m_reader.parse(generatedInterfaceString, generatedInterface);
Json::Value expectedInterface; Json::Value expectedInterface;

View File

@ -41,10 +41,12 @@ namespace
void parseTextAndResolveNames(std::string const& _source) void parseTextAndResolveNames(std::string const& _source)
{ {
Parser parser; Parser parser;
ASTPointer<ContractDefinition> contract = parser.parse( ASTPointer<SourceUnit> sourceUnit = parser.parse(std::make_shared<Scanner>(CharStream(_source)));
std::make_shared<Scanner>(CharStream(_source)));
NameAndTypeResolver resolver({}); NameAndTypeResolver resolver({});
resolver.resolveNamesAndTypes(*contract); resolver.registerDeclarations(*sourceUnit);
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
resolver.resolveNamesAndTypes(*contract);
} }
} }

View File

@ -55,9 +55,9 @@ public:
} }
if (_userDocumentation) if (_userDocumentation)
generatedDocumentationString = m_compilerStack.getJsonDocumentation(DocumentationType::NATSPEC_USER); generatedDocumentationString = m_compilerStack.getJsonDocumentation("", DocumentationType::NATSPEC_USER);
else else
generatedDocumentationString = m_compilerStack.getJsonDocumentation(DocumentationType::NATSPEC_DEV); generatedDocumentationString = m_compilerStack.getJsonDocumentation("", DocumentationType::NATSPEC_DEV);
Json::Value generatedDocumentation; Json::Value generatedDocumentation;
m_reader.parse(generatedDocumentationString, generatedDocumentation); m_reader.parse(generatedDocumentationString, generatedDocumentation);
Json::Value expectedDocumentation; Json::Value expectedDocumentation;

View File

@ -21,13 +21,15 @@
*/ */
#include <string> #include <string>
#include <memory>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h> #include <libsolidity/Parser.h>
#include <libsolidity/Exceptions.h> #include <libsolidity/Exceptions.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
using namespace std;
namespace dev namespace dev
{ {
namespace solidity namespace solidity
@ -40,7 +42,12 @@ namespace
ASTPointer<ContractDefinition> parseText(std::string const& _source) ASTPointer<ContractDefinition> parseText(std::string const& _source)
{ {
Parser parser; Parser parser;
return parser.parse(std::make_shared<Scanner>(CharStream(_source))); ASTPointer<SourceUnit> sourceUnit = parser.parse(std::make_shared<Scanner>(CharStream(_source)));
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ASTPointer<ContractDefinition> contract = dynamic_pointer_cast<ContractDefinition>(node))
return contract;
BOOST_FAIL("No contract found in source.");
return ASTPointer<ContractDefinition>();
} }
} }
@ -380,6 +387,50 @@ BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion)
BOOST_CHECK_NO_THROW(parseText(text)); BOOST_CHECK_NO_THROW(parseText(text));
} }
BOOST_AUTO_TEST_CASE(import_directive)
{
char const* text = "import \"abc\";\n"
"contract test {\n"
" function fun() {\n"
" uint64(2);\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(multiple_contracts)
{
char const* text = "contract test {\n"
" function fun() {\n"
" uint64(2);\n"
" }\n"
"}\n"
"contract test2 {\n"
" function fun() {\n"
" uint64(2);\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(multiple_contracts_and_imports)
{
char const* text = "import \"abc\";\n"
"contract test {\n"
" function fun() {\n"
" uint64(2);\n"
" }\n"
"}\n"
"import \"def\";\n"
"contract test2 {\n"
" function fun() {\n"
" uint64(2);\n"
" }\n"
"}\n"
"import \"ghi\";\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }