Browse Source

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

cl-refactor
arkpar 10 years ago
parent
commit
f0293bf363
  1. 2
      alethzero/MainWin.cpp
  2. 2
      eth/main.cpp
  3. 2
      libdevcrypto/Common.cpp
  4. 2
      libdevcrypto/Common.h
  5. 135
      libsolidity/AST.cpp
  6. 81
      libsolidity/AST.h
  7. 105
      libsolidity/CallGraph.cpp
  8. 69
      libsolidity/CallGraph.h
  9. 165
      libsolidity/Compiler.cpp
  10. 14
      libsolidity/Compiler.h
  11. 79
      libsolidity/CompilerContext.cpp
  12. 31
      libsolidity/CompilerContext.h
  13. 1
      libsolidity/CompilerStack.cpp
  14. 2
      libsolidity/CompilerStack.h
  15. 89
      libsolidity/ExpressionCompiler.cpp
  16. 9
      libsolidity/ExpressionCompiler.h
  17. 8
      libsolidity/GlobalContext.cpp
  18. 2
      libsolidity/GlobalContext.h
  19. 37
      libsolidity/InterfaceHandler.cpp
  20. 6
      libsolidity/Parser.cpp
  21. 2
      libsolidity/Parser.h
  22. 57
      libsolidity/Types.cpp
  23. 20
      libsolidity/Types.h
  24. 46
      libweb3jsonrpc/CorsHttpServer.cpp
  25. 35
      libweb3jsonrpc/CorsHttpServer.h
  26. 1
      mix/QBasicNodeDefinition.h
  27. 12
      mix/QContractDefinition.cpp
  28. 31
      mix/QFunctionDefinition.cpp
  29. 5
      mix/QFunctionDefinition.h
  30. 1
      mix/QVariableDeclaration.h
  31. 2
      neth/main.cpp
  32. 41
      solc/CommandLineInterface.cpp
  33. 6
      solc/CommandLineInterface.h
  34. 51
      test/SolidityCompiler.cpp
  35. 62
      test/SolidityEndToEndTest.cpp
  36. 8
      test/SolidityExpressionCompiler.cpp
  37. 98
      test/SolidityNameAndTypeResolution.cpp
  38. 37
      test/SolidityParser.cpp
  39. 11
      test/TestHelper.cpp
  40. 1
      test/TestHelper.h
  41. 2
      test/jsonrpc.cpp
  42. 4
      test/solidityExecutionFramework.h
  43. 198
      test/stTransactionTestFiller.json
  44. 1
      test/state.cpp
  45. 219
      test/transaction.cpp
  46. 17
      test/tt10mbDataFieldFiller.json
  47. 290
      test/ttTransactionTestFiller.json

2
alethzero/MainWin.cpp

@ -1674,7 +1674,7 @@ string const Main::getFunctionHashes(dev::solidity::CompilerStack const &_compil
{
ret += it.first.abridged();
ret += " :";
ret += it.second->getName() + "\n";
ret += it.second.getName() + "\n";
}
return ret;
}

2
eth/main.cpp

@ -39,7 +39,7 @@
#endif
#if ETH_JSONRPC
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <libweb3jsonrpc/CorsHttpServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#endif
#include "BuildInfo.h"
using namespace std;

2
libdevcrypto/Common.cpp

@ -35,7 +35,7 @@ using namespace dev::crypto;
static Secp256k1 s_secp256k1;
bool dev::SignatureStruct::isValid()
bool dev::SignatureStruct::isValid() const
{
if (this->v > 1 ||
this->r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||

2
libdevcrypto/Common.h

@ -51,7 +51,7 @@ struct SignatureStruct
operator Signature() const { return *(h520 const*)this; }
/// @returns true if r,s,v values are valid, otherwise false
bool isValid();
bool isValid() const;
h256 r;
h256 s;

135
libsolidity/AST.cpp

@ -68,19 +68,23 @@ void ContractDefinition::checkTypeRequirements()
set<FixedHash<4>> hashes;
for (auto const& hashAndFunction: getInterfaceFunctionList())
{
FixedHash<4> const& hash = hashAndFunction.first;
FixedHash<4> const& hash = std::get<0>(hashAndFunction);
if (hashes.count(hash))
BOOST_THROW_EXCEPTION(createTypeError("Function signature hash collision for " +
hashAndFunction.second->getCanonicalSignature()));
BOOST_THROW_EXCEPTION(createTypeError(
std::string("Function signature hash collision for ") +
std::get<1>(hashAndFunction)->getCanonicalSignature(std::get<2>(hashAndFunction)->getName())));
hashes.insert(hash);
}
}
map<FixedHash<4>, FunctionDefinition const*> ContractDefinition::getInterfaceFunctions() const
map<FixedHash<4>, FunctionDescription> ContractDefinition::getInterfaceFunctions() const
{
vector<pair<FixedHash<4>, FunctionDefinition const*>> exportedFunctionList = getInterfaceFunctionList();
map<FixedHash<4>, FunctionDefinition const*> exportedFunctions(exportedFunctionList.begin(),
exportedFunctionList.end());
auto exportedFunctionList = getInterfaceFunctionList();
map<FixedHash<4>, FunctionDescription> exportedFunctions;
for (auto const& it: exportedFunctionList)
exportedFunctions.insert(make_pair(std::get<0>(it), FunctionDescription(std::get<1>(it), std::get<2>(it))));
solAssert(exportedFunctionList.size() == exportedFunctions.size(),
"Hash collision at Function Definition Hash calculation");
@ -134,20 +138,31 @@ void ContractDefinition::checkIllegalOverrides() const
}
}
vector<pair<FixedHash<4>, FunctionDefinition const*>> const& ContractDefinition::getInterfaceFunctionList() const
vector<tuple<FixedHash<4>, std::shared_ptr<FunctionType const>, Declaration const*>> const& ContractDefinition::getInterfaceFunctionList() const
{
if (!m_interfaceFunctionList)
{
set<string> functionsSeen;
m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionDefinition const*>>());
m_interfaceFunctionList.reset(new vector<tuple<FixedHash<4>, std::shared_ptr<FunctionType const>, Declaration const*>>());
for (ContractDefinition const* contract: getLinearizedBaseContracts())
{
for (ASTPointer<FunctionDefinition> const& f: contract->getDefinedFunctions())
if (f->isPublic() && !f->isConstructor() && functionsSeen.count(f->getName()) == 0)
{
functionsSeen.insert(f->getName());
FixedHash<4> hash(dev::sha3(f->getCanonicalSignature()));
m_interfaceFunctionList->push_back(make_pair(hash, f.get()));
m_interfaceFunctionList->push_back(make_tuple(hash, make_shared<FunctionType>(*f, false), f.get()));
}
for (ASTPointer<VariableDeclaration> const& v: contract->getStateVariables())
if (v->isPublic() && functionsSeen.count(v->getName()) == 0)
{
FunctionType ftype(*v);
functionsSeen.insert(v->getName());
FixedHash<4> hash(dev::sha3(ftype.getCanonicalSignature(v->getName())));
m_interfaceFunctionList->push_back(make_tuple(hash, make_shared<FunctionType>(*v), v.get()));
}
}
}
return *m_interfaceFunctionList;
}
@ -219,7 +234,7 @@ void FunctionDefinition::checkTypeRequirements()
string FunctionDefinition::getCanonicalSignature() const
{
return getName() + FunctionType(*this).getCanonicalSignature();
return FunctionType(*this).getCanonicalSignature(getName());
}
Declaration::LValueType VariableDeclaration::getLValueType() const
@ -504,5 +519,103 @@ void Literal::checkTypeRequirements()
BOOST_THROW_EXCEPTION(createTypeError("Invalid literal value."));
}
std::string const& ParamDescription::getName() const
{
return m_description.first;
}
std::string const& ParamDescription::getType() const
{
return m_description.second;
}
ASTPointer<ASTString> FunctionDescription::getDocumentation() const
{
auto function = dynamic_cast<FunctionDefinition const*>(m_description.second);
if (function)
return function->getDocumentation();
return ASTPointer<ASTString>();
}
string FunctionDescription::getSignature() const
{
return m_description.first->getCanonicalSignature(m_description.second->getName());
}
string FunctionDescription::getName() const
{
return m_description.second->getName();
}
bool FunctionDescription::isConstant() const
{
auto function = dynamic_cast<FunctionDefinition const*>(m_description.second);
if (function)
return function->isDeclaredConst();
return true;
}
vector<ParamDescription> const FunctionDescription::getParameters() const
{
auto function = dynamic_cast<FunctionDefinition const*>(m_description.second);
if (function)
{
vector<ParamDescription> paramsDescription;
for (auto const& param: function->getParameters())
paramsDescription.push_back(ParamDescription(param->getName(), param->getType()->toString()));
return paramsDescription;
}
// else for now let's assume no parameters to accessors
// LTODO: fix this for mapping types
return {};
}
vector<ParamDescription> const FunctionDescription::getReturnParameters() const
{
auto function = dynamic_cast<FunctionDefinition const*>(m_description.second);
if (function)
{
vector<ParamDescription> paramsDescription;
for (auto const& param: function->getReturnParameters())
paramsDescription.push_back(ParamDescription(param->getName(), param->getType()->toString()));
return paramsDescription;
}
auto vardecl = dynamic_cast<VariableDeclaration const*>(m_description.second);
return {ParamDescription(vardecl->getName(), vardecl->getType()->toString())};
}
Declaration const* FunctionDescription::getDeclaration() const
{
return m_description.second;
}
VariableDeclaration const* FunctionDescription::getVariableDeclaration() const
{
return dynamic_cast<VariableDeclaration const*>(m_description.second);
}
FunctionDefinition const* FunctionDescription::getFunctionDefinition() const
{
return dynamic_cast<FunctionDefinition const*>(m_description.second);
}
shared_ptr<FunctionType const> FunctionDescription::getFunctionTypeShared() const
{
return m_description.first;
}
FunctionType const* FunctionDescription::getFunctionType() const
{
return m_description.first.get();
}
}
}

81
libsolidity/AST.h

@ -156,6 +156,68 @@ private:
Declaration const* m_scope;
};
/**
* Generic Parameter description used by @see FunctionDescription to return
* a descripton of its parameters.
*/
struct ParamDescription
{
ParamDescription(std::string const& _name, std::string const& _type):
m_description(_name, _type){}
std::string const& getName() const;
std::string const& getType() const;
std::pair<std::string, std::string> m_description;
};
/**
* Generic function description able to describe both normal functions and
* functions that should be made as accessors to state variables
*/
struct FunctionDescription
{
FunctionDescription(std::shared_ptr<FunctionType const> _type, Declaration const* _decl):
m_description(_type, _decl){}
/// constructor for a constructor's function definition. Used only inside mix.
FunctionDescription(Declaration const* _def):
m_description(nullptr, _def){}
FunctionDescription():
m_description(nullptr, nullptr){}
/// @returns the natspec documentation of the function if existing. Accessor (for now) don't have natspec doc
ASTPointer<ASTString> getDocumentation() const;
/// @returns the canonical signature of the function
std::string getSignature() const;
/// @returns the name of the function, basically that of the declaration
std::string getName() const;
/// @returns whether the function is constant. IF it's an accessor this is always true
bool isConstant() const;
/// @returns the argument parameters of the function
std::vector<ParamDescription> const getParameters() const;
/// @returns the return parameters of the function
std::vector<ParamDescription> const getReturnParameters() const;
/// @returns a generic Declaration AST Node pointer which can be either a FunctionDefinition or a VariableDeclaration
Declaration const* getDeclaration() const;
/// @returns the VariableDeclaration AST Node pointer or nullptr if it's not a VariableDeclaration
VariableDeclaration const* getVariableDeclaration() const;
/// @returns the FunctionDefinition AST Node pointer or nullptr if it's not a FunctionDefinition
FunctionDefinition const* getFunctionDefinition() const;
/// @returns a created shared pointer with the type of the function
std::shared_ptr<FunctionType> makeFunctionType() const;
/// @returns a pointer to the function type
FunctionType const* getFunctionType() const;
/// @returns a shared pointer to the function type
std::shared_ptr<FunctionType const> getFunctionTypeShared() const;
std::pair<std::shared_ptr<FunctionType const>, Declaration const*> m_description;
};
/**
* Definition of a contract. This is the only AST nodes where child nodes are not visited in
* document order. It first visits all struct declarations, then all variable declarations and
@ -202,7 +264,7 @@ public:
/// @returns a map of canonical function signatures to FunctionDefinitions
/// as intended for use by the ABI.
std::map<FixedHash<4>, FunctionDefinition const*> getInterfaceFunctions() const;
std::map<FixedHash<4>, FunctionDescription> getInterfaceFunctions() const;
/// List of all (direct and indirect) base contracts in order from derived to base, including
/// the contract itself. Available after name resolution
@ -215,7 +277,7 @@ public:
private:
void checkIllegalOverrides() const;
std::vector<std::pair<FixedHash<4>, FunctionDefinition const*>> const& getInterfaceFunctionList() const;
std::vector<std::tuple<FixedHash<4>, std::shared_ptr<FunctionType const>, Declaration const*>> const& getInterfaceFunctionList() const;
std::vector<ASTPointer<InheritanceSpecifier>> m_baseContracts;
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
@ -225,7 +287,7 @@ private:
ASTPointer<ASTString> m_documentation;
std::vector<ContractDefinition const*> m_linearizedBaseContracts;
mutable std::unique_ptr<std::vector<std::pair<FixedHash<4>, FunctionDefinition const*>>> m_interfaceFunctionList;
mutable std::unique_ptr<std::vector<std::tuple<FixedHash<4>, std::shared_ptr<FunctionType const>, Declaration const*>>> m_interfaceFunctionList;
};
class InheritanceSpecifier: public ASTNode
@ -372,8 +434,8 @@ class VariableDeclaration: public Declaration
{
public:
VariableDeclaration(Location const& _location, ASTPointer<TypeName> const& _type,
ASTPointer<ASTString> const& _name):
Declaration(_location, _name), m_typeName(_type) {}
ASTPointer<ASTString> const& _name, bool _isPublic, bool _isStateVar = false):
Declaration(_location, _name), m_typeName(_type), m_isPublic(_isPublic), m_isStateVariable(_isStateVar) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
@ -385,9 +447,15 @@ public:
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
virtual LValueType getLValueType() const override;
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); }
bool isPublic() const { return m_isPublic; }
bool isStateVariable() const { return m_isStateVariable; }
private:
ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
bool m_isPublic; ///< Whether there is an accessor for it or not
bool m_isStateVariable; ///< Whether or not this is a contract state variable
std::shared_ptr<Type const> m_type; ///< derived type, initially empty
};
@ -1076,5 +1144,6 @@ private:
/// @}
}
}

105
libsolidity/CallGraph.cpp

@ -1,105 +0,0 @@
/*
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 2014
* Callgraph of functions inside a contract.
*/
#include <libsolidity/AST.h>
#include <libsolidity/CallGraph.h>
using namespace std;
namespace dev
{
namespace solidity
{
void CallGraph::addNode(ASTNode const& _node)
{
if (!m_nodesSeen.count(&_node))
{
m_workQueue.push(&_node);
m_nodesSeen.insert(&_node);
}
}
set<FunctionDefinition const*> const& CallGraph::getCalls()
{
computeCallGraph();
return m_functionsSeen;
}
void CallGraph::computeCallGraph()
{
while (!m_workQueue.empty())
{
m_workQueue.front()->accept(*this);
m_workQueue.pop();
}
}
bool CallGraph::visit(Identifier const& _identifier)
{
if (auto fun = dynamic_cast<FunctionDefinition const*>(_identifier.getReferencedDeclaration()))
{
if (m_functionOverrideResolver)
fun = (*m_functionOverrideResolver)(fun->getName());
solAssert(fun, "Error finding override for function " + fun->getName());
addNode(*fun);
}
if (auto modifier = dynamic_cast<ModifierDefinition const*>(_identifier.getReferencedDeclaration()))
{
if (m_modifierOverrideResolver)
modifier = (*m_modifierOverrideResolver)(modifier->getName());
solAssert(modifier, "Error finding override for modifier " + modifier->getName());
addNode(*modifier);
}
return true;
}
bool CallGraph::visit(FunctionDefinition const& _function)
{
m_functionsSeen.insert(&_function);
return true;
}
bool CallGraph::visit(MemberAccess const& _memberAccess)
{
// used for "BaseContract.baseContractFunction"
if (_memberAccess.getExpression().getType()->getCategory() == Type::Category::TYPE)
{
TypeType const& type = dynamic_cast<TypeType const&>(*_memberAccess.getExpression().getType());
if (type.getMembers().getMemberType(_memberAccess.getMemberName()))
{
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*type.getActualType())
.getContractDefinition();
for (ASTPointer<FunctionDefinition> const& function: contract.getDefinedFunctions())
if (function->getName() == _memberAccess.getMemberName())
{
addNode(*function);
return true;
}
}
}
return true;
}
}
}

69
libsolidity/CallGraph.h

@ -1,69 +0,0 @@
/*
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 2014
* Callgraph of functions inside a contract.
*/
#include <set>
#include <queue>
#include <functional>
#include <boost/range/iterator_range.hpp>
#include <libsolidity/ASTVisitor.h>
namespace dev
{
namespace solidity
{
/**
* Can be used to compute the graph of calls (or rather references) between functions of the same
* contract. Current functionality is limited to computing all functions that are directly
* or indirectly called by some functions.
*/
class CallGraph: private ASTConstVisitor
{
public:
using FunctionOverrideResolver = std::function<FunctionDefinition const*(std::string const&)>;
using ModifierOverrideResolver = std::function<ModifierDefinition const*(std::string const&)>;
CallGraph(FunctionOverrideResolver const& _functionOverrideResolver,
ModifierOverrideResolver const& _modifierOverrideResolver):
m_functionOverrideResolver(&_functionOverrideResolver),
m_modifierOverrideResolver(&_modifierOverrideResolver) {}
void addNode(ASTNode const& _node);
std::set<FunctionDefinition const*> const& getCalls();
private:
virtual bool visit(FunctionDefinition const& _function) override;
virtual bool visit(Identifier const& _identifier) override;
virtual bool visit(MemberAccess const& _memberAccess) override;
void computeCallGraph();
FunctionOverrideResolver const* m_functionOverrideResolver;
ModifierOverrideResolver const* m_modifierOverrideResolver;
std::set<ASTNode const*> m_nodesSeen;
std::set<FunctionDefinition const*> m_functionsSeen;
std::queue<ASTNode const*> m_workQueue;
};
}
}

165
libsolidity/Compiler.cpp

@ -28,7 +28,6 @@
#include <libsolidity/Compiler.h>
#include <libsolidity/ExpressionCompiler.h>
#include <libsolidity/CompilerUtils.h>
#include <libsolidity/CallGraph.h>
using namespace std;
@ -40,22 +39,15 @@ void Compiler::compileContract(ContractDefinition const& _contract,
{
m_context = CompilerContext(); // clear it just in case
initializeContext(_contract, _contracts);
for (ContractDefinition const* contract: _contract.getLinearizedBaseContracts())
appendFunctionSelector(_contract);
set<Declaration const*> functions = m_context.getFunctionsWithoutCode();
while (!functions.empty())
{
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
if (!function->isConstructor())
m_context.addFunction(*function);
for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
m_context.addModifier(*modifier);
for (Declaration const* function: functions)
function->accept(*this);
functions = m_context.getFunctionsWithoutCode();
}
appendFunctionSelector(_contract);
for (ContractDefinition const* contract: _contract.getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
if (!function->isConstructor())
function->accept(*this);
// Swap the runtime context with the creation-time context
swap(m_context, m_runtimeContext);
initializeContext(_contract, _contracts);
@ -66,72 +58,26 @@ void Compiler::initializeContext(ContractDefinition const& _contract,
map<ContractDefinition const*, bytes const*> const& _contracts)
{
m_context.setCompiledContracts(_contracts);
m_context.setInheritanceHierarchy(_contract.getLinearizedBaseContracts());
registerStateVariables(_contract);
}
void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext)
{
std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts();
// Make all modifiers known to the context.
for (ContractDefinition const* contract: bases)
for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
m_context.addModifier(*modifier);
// arguments for base constructors, filled in derived-to-base order
map<ContractDefinition const*, vector<ASTPointer<Expression>> const*> baseArguments;
set<FunctionDefinition const*> neededFunctions;
set<ASTNode const*> nodesUsedInConstructors;
// Determine the arguments that are used for the base constructors and also which functions
// are needed at compile time.
// Determine the arguments that are used for the base constructors.
std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts();
for (ContractDefinition const* contract: bases)
{
if (FunctionDefinition const* constructor = contract->getConstructor())
nodesUsedInConstructors.insert(constructor);
for (ASTPointer<InheritanceSpecifier> const& base: contract->getBaseContracts())
{
ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
base->getName()->getReferencedDeclaration());
solAssert(baseContract, "");
if (baseArguments.count(baseContract) == 0)
{
baseArguments[baseContract] = &base->getArguments();
for (ASTPointer<Expression> const& arg: base->getArguments())
nodesUsedInConstructors.insert(arg.get());
}
}
}
auto functionOverrideResolver = [&](string const& _name) -> FunctionDefinition const*
{
for (ContractDefinition const* contract: bases)
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
if (!function->isConstructor() && function->getName() == _name)
return function.get();
return nullptr;
};
auto modifierOverrideResolver = [&](string const& _name) -> ModifierDefinition const*
{
return &m_context.getFunctionModifier(_name);
};
neededFunctions = getFunctionsCalled(nodesUsedInConstructors, functionOverrideResolver,
modifierOverrideResolver);
// First add all overrides (or the functions themselves if there is no override)
for (FunctionDefinition const* fun: neededFunctions)
{
FunctionDefinition const* override = nullptr;
if (!fun->isConstructor())
override = functionOverrideResolver(fun->getName());
if (!!override && neededFunctions.count(override))
m_context.addFunction(*override);
}
// now add the rest
for (FunctionDefinition const* fun: neededFunctions)
if (fun->isConstructor() || functionOverrideResolver(fun->getName()) != fun)
m_context.addFunction(*fun);
// Call constructors in base-to-derived order.
// The Constructor for the most derived contract is called later.
@ -153,10 +99,14 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
m_context << eth::Instruction::DUP1 << sub << u256(0) << eth::Instruction::CODECOPY;
m_context << u256(0) << eth::Instruction::RETURN;
// note that we have to explicitly include all used functions because of absolute jump
// labels
for (FunctionDefinition const* fun: neededFunctions)
fun->accept(*this);
// note that we have to include the functions again because of absolute jump labels
set<Declaration const*> functions = m_context.getFunctionsWithoutCode();
while (!functions.empty())
{
for (Declaration const* function: functions)
function->accept(*this);
functions = m_context.getFunctionsWithoutCode();
}
}
void Compiler::appendBaseConstructorCall(FunctionDefinition const& _constructor,
@ -177,31 +127,22 @@ void Compiler::appendConstructorCall(FunctionDefinition const& _constructor)
unsigned argumentSize = 0;
for (ASTPointer<VariableDeclaration> const& var: _constructor.getParameters())
argumentSize += CompilerUtils::getPaddedSize(var->getType()->getCalldataEncodedSize());
if (argumentSize > 0)
{
m_context << u256(argumentSize);
m_context.appendProgramSize();
m_context << u256(CompilerUtils::dataStartOffset); // copy it to byte four as expected for ABI calls
m_context << eth::Instruction::CODECOPY;
appendCalldataUnpacker(_constructor, true);
appendCalldataUnpacker(FunctionType(_constructor).getParameterTypes(), true);
}
m_context.appendJumpTo(m_context.getFunctionEntryLabel(_constructor));
m_context << returnTag;
}
set<FunctionDefinition const*> Compiler::getFunctionsCalled(set<ASTNode const*> const& _nodes,
function<FunctionDefinition const*(string const&)> const& _resolveFunctionOverrides,
function<ModifierDefinition const*(string const&)> const& _resolveModifierOverrides)
{
CallGraph callgraph(_resolveFunctionOverrides, _resolveModifierOverrides);
for (ASTNode const* node: _nodes)
callgraph.addNode(*node);
return callgraph.getCalls();
}
void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
{
map<FixedHash<4>, FunctionDefinition const*> interfaceFunctions = _contract.getInterfaceFunctions();
map<FixedHash<4>, FunctionDescription> interfaceFunctions = _contract.getInterfaceFunctions();
map<FixedHash<4>, const eth::AssemblyItem> callDataUnpackerEntryPoints;
// retrieve the function signature hash from the calldata
@ -209,7 +150,6 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
CompilerUtils(m_context).loadFromMemory(0, 4, false, true);
// stack now is: 1 0 <funhash>
// for (auto it = interfaceFunctions.cbegin(); it != interfaceFunctions.cend(); ++it)
for (auto const& it: interfaceFunctions)
{
callDataUnpackerEntryPoints.insert(std::make_pair(it.first, m_context.newTag()));
@ -220,29 +160,28 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
for (auto const& it: interfaceFunctions)
{
FunctionDefinition const& function = *it.second;
FunctionType const* functionType = it.second.getFunctionType();
m_context << callDataUnpackerEntryPoints.at(it.first);
eth::AssemblyItem returnTag = m_context.pushNewTag();
appendCalldataUnpacker(function);
m_context.appendJumpTo(m_context.getFunctionEntryLabel(function));
appendCalldataUnpacker(functionType->getParameterTypes());
m_context.appendJumpTo(m_context.getFunctionEntryLabel(*it.second.getDeclaration()));
m_context << returnTag;
appendReturnValuePacker(function);
appendReturnValuePacker(functionType->getReturnParameterTypes());
}
}
unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, bool _fromMemory)
unsigned Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory)
{
// We do not check the calldata size, everything is zero-padded.
unsigned dataOffset = CompilerUtils::dataStartOffset; // the 4 bytes of the function hash signature
//@todo this can be done more efficiently, saving some CALLDATALOAD calls
for (ASTPointer<VariableDeclaration> const& var: _function.getParameters())
for (TypePointer const& type: _typeParameters)
{
unsigned const c_numBytes = var->getType()->getCalldataEncodedSize();
unsigned const c_numBytes = type->getCalldataEncodedSize();
if (c_numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(var->getLocation())
<< errinfo_comment("Type " + var->getType()->toString() + " not yet supported."));
bool const c_leftAligned = var->getType()->getCategory() == Type::Category::STRING;
<< errinfo_comment("Type " + type->toString() + " not yet supported."));
bool const c_leftAligned = type->getCategory() == Type::Category::STRING;
bool const c_padToWords = true;
dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, c_numBytes, c_leftAligned,
!_fromMemory, c_padToWords);
@ -250,26 +189,26 @@ unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, b
return dataOffset;
}
void Compiler::appendReturnValuePacker(FunctionDefinition const& _function)
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)
{
//@todo this can be also done more efficiently
unsigned dataOffset = 0;
vector<ASTPointer<VariableDeclaration>> const& parameters = _function.getReturnParameters();
unsigned stackDepth = CompilerUtils(m_context).getSizeOnStack(parameters);
for (unsigned i = 0; i < parameters.size(); ++i)
unsigned stackDepth = 0;
for (TypePointer const& type: _typeParameters)
stackDepth += type->getSizeOnStack();
for (TypePointer const& type: _typeParameters)
{
Type const& paramType = *parameters[i]->getType();
unsigned numBytes = paramType.getCalldataEncodedSize();
unsigned numBytes = type->getCalldataEncodedSize();
if (numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(parameters[i]->getLocation())
<< errinfo_comment("Type " + paramType.toString() + " not yet supported."));
CompilerUtils(m_context).copyToStackTop(stackDepth, paramType);
ExpressionCompiler::appendTypeConversion(m_context, paramType, paramType, true);
bool const c_leftAligned = paramType.getCategory() == Type::Category::STRING;
<< errinfo_comment("Type " + type->toString() + " not yet supported."));
CompilerUtils(m_context).copyToStackTop(stackDepth, *type);
ExpressionCompiler::appendTypeConversion(m_context, *type, *type, true);
bool const c_leftAligned = type->getCategory() == Type::Category::STRING;
bool const c_padToWords = true;
dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, c_leftAligned, c_padToWords);
stackDepth -= paramType.getSizeOnStack();
stackDepth -= type->getSizeOnStack();
}
// note that the stack is not cleaned up here
m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN;
@ -282,13 +221,31 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract)
m_context.addStateVariable(*variable);
}
bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
{
solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration.");
m_context.startFunction(_variableDeclaration);
m_breakTags.clear();
m_continueTags.clear();
m_context << m_context.getFunctionEntryLabel(_variableDeclaration);
ExpressionCompiler::appendStateVariableAccessor(m_context, _variableDeclaration);
unsigned sizeOnStack = _variableDeclaration.getType()->getSizeOnStack();
solAssert(sizeOnStack <= 15, "Stack too deep.");
m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP;
return false;
}
bool Compiler::visit(FunctionDefinition const& _function)
{
//@todo to simplify this, the calling convention could by changed such that
// caller puts: [retarg0] ... [retargm] [return address] [arg0] ... [argn]
// although note that this reduces the size of the visible stack
m_context.startNewFunction();
m_context.startFunction(_function);
m_returnTag = m_context.newTag();
m_breakTags.clear();
m_continueTags.clear();
@ -296,8 +253,6 @@ bool Compiler::visit(FunctionDefinition const& _function)
m_currentFunction = &_function;
m_modifierDepth = 0;
m_context << m_context.getFunctionEntryLabel(_function);
// stack upon entry: [return address] [arg0] [arg1] ... [argn]
// reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp]

14
libsolidity/Compiler.h

@ -50,19 +50,15 @@ private:
void appendBaseConstructorCall(FunctionDefinition const& _constructor,
std::vector<ASTPointer<Expression>> const& _arguments);
void appendConstructorCall(FunctionDefinition const& _constructor);
/// Recursively searches the call graph and returns all functions referenced inside _nodes.
/// _resolveOverride is called to resolve virtual function overrides.
std::set<FunctionDefinition const*> getFunctionsCalled(std::set<ASTNode const*> const& _nodes,
std::function<FunctionDefinition const*(std::string const&)> const& _resolveFunctionOverride,
std::function<ModifierDefinition const*(std::string const&)> const& _resolveModifierOverride);
void appendFunctionSelector(ContractDefinition const& _contract);
/// Creates code that unpacks the arguments for the given function, from memory if
/// @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes.
unsigned appendCalldataUnpacker(FunctionDefinition const& _function, bool _fromMemory = false);
void appendReturnValuePacker(FunctionDefinition const& _function);
/// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers.
/// From memory if @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes.
unsigned appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false);
void appendReturnValuePacker(TypePointers const& _typeParameters);
void registerStateVariables(ContractDefinition const& _contract);
virtual bool visit(VariableDeclaration const& _variableDeclaration) override;
virtual bool visit(FunctionDefinition const& _function) override;
virtual bool visit(IfStatement const& _ifStatement) override;
virtual bool visit(WhileStatement const& _whileStatement) override;

79
libsolidity/CompilerContext.cpp

@ -43,6 +43,14 @@ void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
m_stateVariablesSize += _declaration.getType()->getStorageSize();
}
void CompilerContext::startFunction(Declaration const& _function)
{
m_functionsWithCode.insert(&_function);
m_localVariables.clear();
m_asm.setDeposit(0);
*this << getFunctionEntryLabel(_function);
}
void CompilerContext::addVariable(VariableDeclaration const& _declaration,
unsigned _offsetToCurrent)
{
@ -59,18 +67,6 @@ void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _decla
*this << u256(0);
}
void CompilerContext::addFunction(FunctionDefinition const& _function)
{
eth::AssemblyItem tag(m_asm.newTag());
m_functionEntryLabels.insert(make_pair(&_function, tag));
m_virtualFunctionEntryLabels.insert(make_pair(_function.getName(), tag));
}
void CompilerContext::addModifier(ModifierDefinition const& _modifier)
{
m_functionModifiers.insert(make_pair(_modifier.getName(), &_modifier));
}
bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _contract) const
{
auto ret = m_compiledContracts.find(&_contract);
@ -83,25 +79,62 @@ bool CompilerContext::isLocalVariable(Declaration const* _declaration) const
return m_localVariables.count(_declaration);
}
eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const
eth::AssemblyItem CompilerContext::getFunctionEntryLabel(Declaration const& _declaration)
{
auto res = m_functionEntryLabels.find(&_declaration);
if (res == m_functionEntryLabels.end())
{
eth::AssemblyItem tag(m_asm.newTag());
m_functionEntryLabels.insert(make_pair(&_declaration, tag));
return tag.tag();
}
else
return res->second.tag();
}
eth::AssemblyItem CompilerContext::getVirtualFunctionEntryLabel(FunctionDefinition const& _function)
{
solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
for (ContractDefinition const* contract: m_inheritanceHierarchy)
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
if (!function->isConstructor() && function->getName() == _function.getName())
return getFunctionEntryLabel(*function);
solAssert(false, "Virtual function " + _function.getName() + " not found.");
return m_asm.newTag(); // not reached
}
eth::AssemblyItem CompilerContext::getSuperFunctionEntryLabel(string const& _name, ContractDefinition const& _base)
{
auto res = m_functionEntryLabels.find(&_function);
solAssert(res != m_functionEntryLabels.end(), "Function entry label not found.");
return res->second.tag();
// search for first contract after _base
solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
auto it = find(m_inheritanceHierarchy.begin(), m_inheritanceHierarchy.end(), &_base);
solAssert(it != m_inheritanceHierarchy.end(), "Base not found in inheritance hierarchy.");
for (++it; it != m_inheritanceHierarchy.end(); ++it)
for (ASTPointer<FunctionDefinition> const& function: (*it)->getDefinedFunctions())
if (!function->isConstructor() && function->getName() == _name)
return getFunctionEntryLabel(*function);
solAssert(false, "Super function " + _name + " not found.");
return m_asm.newTag(); // not reached
}
eth::AssemblyItem CompilerContext::getVirtualFunctionEntryLabel(FunctionDefinition const& _function) const
set<Declaration const*> CompilerContext::getFunctionsWithoutCode()
{
auto res = m_virtualFunctionEntryLabels.find(_function.getName());
solAssert(res != m_virtualFunctionEntryLabels.end(), "Function entry label not found.");
return res->second.tag();
set<Declaration const*> functions;
for (auto const& it: m_functionEntryLabels)
if (m_functionsWithCode.count(it.first) == 0)
functions.insert(it.first);
return move(functions);
}
ModifierDefinition const& CompilerContext::getFunctionModifier(string const& _name) const
{
auto res = m_functionModifiers.find(_name);
solAssert(res != m_functionModifiers.end(), "Function modifier override not found.");
return *res->second;
solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
for (ContractDefinition const* contract: m_inheritanceHierarchy)
for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
if (modifier->getName() == _name)
return *modifier.get();
BOOST_THROW_EXCEPTION(InternalCompilerError()
<< errinfo_comment("Function modifier " + _name + " not found."));
}
unsigned CompilerContext::getBaseStackOffsetOfVariable(Declaration const& _declaration) const

31
libsolidity/CompilerContext.h

@ -41,12 +41,8 @@ class CompilerContext
public:
void addMagicGlobal(MagicVariableDeclaration const& _declaration);
void addStateVariable(VariableDeclaration const& _declaration);
void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); }
void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0);
void addAndInitializeVariable(VariableDeclaration const& _declaration);
void addFunction(FunctionDefinition const& _function);
/// Adds the given modifier to the list by name if the name is not present already.
void addModifier(ModifierDefinition const& _modifier);
void setCompiledContracts(std::map<ContractDefinition const*, bytes const*> const& _contracts) { m_compiledContracts = _contracts; }
bytes const& getCompiledContract(ContractDefinition const& _contract) const;
@ -54,13 +50,22 @@ public:
void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); }
bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration) != 0; }
bool isFunctionDefinition(Declaration const* _declaration) const { return m_functionEntryLabels.count(_declaration) != 0; }
bool isLocalVariable(Declaration const* _declaration) const;
bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration) != 0; }
eth::AssemblyItem getFunctionEntryLabel(FunctionDefinition const& _function) const;
eth::AssemblyItem getFunctionEntryLabel(Declaration const& _declaration);
void setInheritanceHierarchy(std::vector<ContractDefinition const*> const& _hierarchy) { m_inheritanceHierarchy = _hierarchy; }
/// @returns the entry label of the given function and takes overrides into account.
eth::AssemblyItem getVirtualFunctionEntryLabel(FunctionDefinition const& _function) const;
eth::AssemblyItem getVirtualFunctionEntryLabel(FunctionDefinition const& _function);
/// @returns the entry label of function with the given name from the most derived class just
/// above _base in the current inheritance hierarchy.
eth::AssemblyItem getSuperFunctionEntryLabel(std::string const& _name, ContractDefinition const& _base);
/// @returns the set of functions for which we still need to generate code
std::set<Declaration const*> getFunctionsWithoutCode();
/// Resets function specific members, inserts the function entry label and marks the function
/// as "having code".
void startFunction(Declaration const& _function);
ModifierDefinition const& getFunctionModifier(std::string const& _name) const;
/// Returns the distance of the given local variable from the bottom of the stack (of the current function).
unsigned getBaseStackOffsetOfVariable(Declaration const& _declaration) const;
@ -115,14 +120,14 @@ private:
u256 m_stateVariablesSize = 0;
/// Storage offsets of state variables
std::map<Declaration const*, u256> m_stateVariables;
/// Positions of local variables on the stack.
/// Offsets of local variables on the stack (relative to stack base).
std::map<Declaration const*, unsigned> m_localVariables;
/// Labels pointing to the entry points of funcitons.
/// Labels pointing to the entry points of functions.
std::map<Declaration const*, eth::AssemblyItem> m_functionEntryLabels;
/// Labels pointing to the entry points of function overrides.
std::map<std::string, eth::AssemblyItem> m_virtualFunctionEntryLabels;
/// Mapping to obtain function modifiers by name. Should be filled from derived to base.
std::map<std::string, ModifierDefinition const*> m_functionModifiers;
/// Set of functions for which we did not yet generate code.
std::set<Declaration const*> m_functionsWithCode;
/// List of current inheritance hierarchy from derived to base.
std::vector<ContractDefinition const*> m_inheritanceHierarchy;
};
}

1
libsolidity/CompilerStack.cpp

@ -94,6 +94,7 @@ void CompilerStack::parse()
{
m_globalContext->setCurrentContract(*contract);
resolver.updateDeclaration(*m_globalContext->getCurrentThis());
resolver.updateDeclaration(*m_globalContext->getCurrentSuper());
resolver.resolveNamesAndTypes(*contract);
m_contracts[contract->getName()].contract = contract;
}

2
libsolidity/CompilerStack.h

@ -60,7 +60,7 @@ class CompilerStack: boost::noncopyable
{
public:
/// Creates a new compiler stack. Adds standard sources if @a _addStandardSources.
explicit CompilerStack(bool _addStandardSources = true);
explicit CompilerStack(bool _addStandardSources = false);
/// Adds a source object (e.g. file) to the parser. After this, parse has to be called again.
/// @returns true if a source object by the name already existed and was replaced.

89
libsolidity/ExpressionCompiler.cpp

@ -48,6 +48,12 @@ void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, Type co
compiler.appendTypeConversion(_typeOnStack, _targetType, _cleanupNeeded);
}
void ExpressionCompiler::appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize)
{
ExpressionCompiler compiler(_context, _optimize);
compiler.appendStateVariableAccessor(_varDecl);
}
bool ExpressionCompiler::visit(Assignment const& _assignment)
{
_assignment.getRightHandSide().accept(*this);
@ -359,15 +365,25 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
{
case Type::Category::CONTRACT:
{
bool alsoSearchInteger = false;
ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.getExpression().getType());
u256 identifier = type.getFunctionIdentifier(member);
if (identifier != Invalid256)
if (type.isSuper())
m_context << m_context.getSuperFunctionEntryLabel(member, type.getContractDefinition()).pushTag();
else
{
appendTypeConversion(type, IntegerType(0, IntegerType::Modifier::ADDRESS), true);
m_context << identifier;
break;
// ordinary contract type
u256 identifier = type.getFunctionIdentifier(member);
if (identifier != Invalid256)
{
appendTypeConversion(type, IntegerType(0, IntegerType::Modifier::ADDRESS), true);
m_context << identifier;
}
else
// not found in contract, search in members inherited from address
alsoSearchInteger = true;
}
// fall-through to "integer" otherwise (address)
if (!alsoSearchInteger)
break;
}
case Type::Category::INTEGER:
if (member == "balance")
@ -463,8 +479,10 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
Declaration const* declaration = _identifier.getReferencedDeclaration();
if (MagicVariableDeclaration const* magicVar = dynamic_cast<MagicVariableDeclaration const*>(declaration))
{
if (magicVar->getType()->getCategory() == Type::Category::CONTRACT) // must be "this"
m_context << eth::Instruction::ADDRESS;
if (magicVar->getType()->getCategory() == Type::Category::CONTRACT)
// "this" or "super"
if (!dynamic_cast<ContractType const&>(*magicVar->getType()).isSuper())
m_context << eth::Instruction::ADDRESS;
}
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag();
@ -789,6 +807,13 @@ unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _typ
return length;
}
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
{
m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType());
solAssert(m_currentLValue.isInStorage(), "");
m_currentLValue.retrieveValueFromStorage(_varDecl.getType(), true);
}
ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType,
unsigned _baseStackOffset):
m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset)
@ -816,21 +841,7 @@ void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bo
break;
}
case STORAGE:
if (!_expression.getType()->isValueType())
break; // no distinction between value and reference for non-value types
if (!_remove)
*m_context << eth::Instruction::DUP1;
if (m_size == 1)
*m_context << eth::Instruction::SLOAD;
else
for (unsigned i = 0; i < m_size; ++i)
{
*m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1;
if (i + 1 < m_size)
*m_context << u256(1) << eth::Instruction::ADD;
else
*m_context << eth::Instruction::POP;
}
retrieveValueFromStorage(_expression.getType(), _remove);
break;
case MEMORY:
if (!_expression.getType()->isValueType())
@ -845,6 +856,25 @@ void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bo
}
}
void ExpressionCompiler::LValue::retrieveValueFromStorage(TypePointer const& _type, bool _remove) const
{
if (!_type->isValueType())
return; // no distinction between value and reference for non-value types
if (!_remove)
*m_context << eth::Instruction::DUP1;
if (m_size == 1)
*m_context << eth::Instruction::SLOAD;
else
for (unsigned i = 0; i < m_size; ++i)
{
*m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1;
if (i + 1 < m_size)
*m_context << u256(1) << eth::Instruction::ADD;
else
*m_context << eth::Instruction::POP;
}
}
void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool _move) const
{
switch (m_type)
@ -951,6 +981,14 @@ void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression co
}
}
void ExpressionCompiler::LValue::fromStateVariable(Declaration const& _varDecl, TypePointer const& _type)
{
m_type = STORAGE;
solAssert(_type->getStorageSize() <= numeric_limits<unsigned>::max(), "The storage size of " + _type->toString() + " should fit in an unsigned");
*m_context << m_context->getStorageLocationOfVariable(_varDecl);
m_size = unsigned(_type->getStorageSize());
}
void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration)
{
if (m_context->isLocalVariable(&_declaration))
@ -961,10 +999,7 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D
}
else if (m_context->isStateVariable(&_declaration))
{
m_type = STORAGE;
solAssert(_identifier.getType()->getStorageSize() <= numeric_limits<unsigned>::max(), "The storage size of " + _identifier.getType()->toString() + " should fit in unsigned");
m_size = unsigned(_identifier.getType()->getStorageSize());
*m_context << m_context->getStorageLocationOfVariable(_declaration);
fromStateVariable(_declaration, _identifier.getType());
}
else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation())

9
libsolidity/ExpressionCompiler.h

@ -53,6 +53,8 @@ public:
/// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type.
static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack,
Type const& _targetType, bool _cleanupNeeded = false);
/// Appends code for a State Variable accessor function
static void appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false);
private:
explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false):
@ -95,6 +97,9 @@ private:
unsigned appendArgumentCopyToMemory(TypePointers const& _functionType, std::vector<ASTPointer<Expression const>> const& _arguments,
unsigned _memoryOffset = 0);
/// Appends code for a State Variable accessor function
void appendStateVariableAccessor(VariableDeclaration const& _varDecl);
/**
* Helper class to store and retrieve lvalues to and from various locations.
* All types except STACK store a reference in a slot on the stack, STACK just
@ -111,6 +116,8 @@ private:
/// Set type according to the declaration and retrieve the reference.
/// @a _expression is the current expression
void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration);
/// Convenience function to set type for a state variable and retrieve the reference
void fromStateVariable(Declaration const& _varDecl, TypePointer const& _type);
void reset() { m_type = NONE; m_baseStackOffset = 0; m_size = 0; }
bool isValid() const { return m_type != NONE; }
@ -125,6 +132,8 @@ private:
/// also removes the reference from the stack (note that is does not reset the type to @a NONE).
/// @a _expression is the current expression, used for error reporting.
void retrieveValue(Expression const& _expression, bool _remove = false) const;
/// Convenience function to retrieve Value from Storage. Specific version of @ref retrieveValue
void retrieveValueFromStorage(TypePointer const& _type, bool _remove = false) const;
/// Stores a value (from the stack directly beneath the reference, which is assumed to
/// be on the top of the stack, if any) in the lvalue and removes the reference.
/// Also removes the stored value from the stack if @a _move is

8
libsolidity/GlobalContext.cpp

@ -83,5 +83,13 @@ MagicVariableDeclaration const* GlobalContext::getCurrentThis() const
}
MagicVariableDeclaration const* GlobalContext::getCurrentSuper() const
{
if (!m_superPointer[m_currentContract])
m_superPointer[m_currentContract] = make_shared<MagicVariableDeclaration>(
"super", make_shared<ContractType>(*m_currentContract, true));
return m_superPointer[m_currentContract].get();
}
}
}

2
libsolidity/GlobalContext.h

@ -48,6 +48,7 @@ public:
GlobalContext();
void setCurrentContract(ContractDefinition const& _contract);
MagicVariableDeclaration const* getCurrentThis() const;
MagicVariableDeclaration const* getCurrentSuper() const;
/// @returns a vector of all implicit global declarations excluding "this".
std::vector<Declaration const*> getDeclarations() const;
@ -56,6 +57,7 @@ private:
std::vector<std::shared_ptr<MagicVariableDeclaration const>> m_magicVariables;
ContractDefinition const* m_currentContract = nullptr;
std::map<ContractDefinition const*, std::shared_ptr<MagicVariableDeclaration const>> mutable m_thisPointer;
std::map<ContractDefinition const*, std::shared_ptr<MagicVariableDeclaration const>> mutable m_superPointer;
};
}

37
libsolidity/InterfaceHandler.cpp

@ -45,23 +45,23 @@ std::unique_ptr<std::string> InterfaceHandler::getABIInterface(ContractDefinitio
Json::Value inputs(Json::arrayValue);
Json::Value outputs(Json::arrayValue);
auto populateParameters = [](std::vector<ASTPointer<VariableDeclaration>> const& _vars)
auto populateParameters = [](vector<ParamDescription> const& _params)
{
Json::Value params(Json::arrayValue);
for (ASTPointer<VariableDeclaration> const& var: _vars)
for (auto const& param: _params)
{
Json::Value input;
input["name"] = var->getName();
input["type"] = var->getType()->toString();
input["name"] = param.getName();
input["type"] = param.getType();
params.append(input);
}
return params;
};
method["name"] = it.second->getName();
method["constant"] = it.second->isDeclaredConst();
method["inputs"] = populateParameters(it.second->getParameters());
method["outputs"] = populateParameters(it.second->getReturnParameters());
method["name"] = it.second.getName();
method["constant"] = it.second.isConstant();
method["inputs"] = populateParameters(it.second.getParameters());
method["outputs"] = populateParameters(it.second.getReturnParameters());
methods.append(method);
}
return std::unique_ptr<std::string>(new std::string(m_writer.write(methods)));
@ -72,17 +72,16 @@ unique_ptr<string> InterfaceHandler::getABISolidityInterface(ContractDefinition
string ret = "contract " + _contractDef.getName() + "{";
for (auto const& it: _contractDef.getInterfaceFunctions())
{
FunctionDefinition const* f = it.second;
auto populateParameters = [](vector<ASTPointer<VariableDeclaration>> const& _vars)
auto populateParameters = [](vector<ParamDescription> const& _params)
{
string r = "";
for (ASTPointer<VariableDeclaration> const& var: _vars)
r += (r.size() ? "," : "(") + var->getType()->toString() + " " + var->getName();
for (auto const& param: _params)
r += (r.size() ? "," : "(") + param.getType() + " " + param.getName();
return r.size() ? r + ")" : "()";
};
ret += "function " + f->getName() + populateParameters(f->getParameters()) + (f->isDeclaredConst() ? "constant " : "");
if (f->getReturnParameters().size())
ret += "returns" + populateParameters(f->getReturnParameters());
ret += "function " + it.second.getName() + populateParameters(it.second.getParameters()) + (it.second.isConstant() ? "constant " : "");
if (it.second.getReturnParameters().size())
ret += "returns" + populateParameters(it.second.getReturnParameters());
else if (ret.back() == ' ')
ret.pop_back();
ret += "{}";
@ -98,7 +97,7 @@ std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefi
for (auto const& it: _contractDef.getInterfaceFunctions())
{
Json::Value user;
auto strPtr = it.second->getDocumentation();
auto strPtr = it.second.getDocumentation();
if (strPtr)
{
resetUser();
@ -106,7 +105,7 @@ std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefi
if (!m_notice.empty())
{// since @notice is the only user tag if missing function should not appear
user["notice"] = Json::Value(m_notice);
methods[it.second->getCanonicalSignature()] = user;
methods[it.second.getSignature()] = user;
}
}
}
@ -139,7 +138,7 @@ std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefin
for (auto const& it: _contractDef.getInterfaceFunctions())
{
Json::Value method;
auto strPtr = it.second->getDocumentation();
auto strPtr = it.second.getDocumentation();
if (strPtr)
{
resetDev();
@ -162,7 +161,7 @@ std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefin
method["return"] = m_return;
if (!method.empty()) // add the function, only if we have any documentation to add
methods[it.second->getCanonicalSignature()] = method;
methods[it.second.getSignature()] = method;
}
}
doc["methods"] = methods;

6
libsolidity/Parser.cpp

@ -150,7 +150,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
Token::isElementaryTypeName(currentToken))
{
bool const allowVar = false;
stateVariables.push_back(parseVariableDeclaration(allowVar));
stateVariables.push_back(parseVariableDeclaration(allowVar, visibilityIsPublic, true));
expectToken(Token::SEMICOLON);
}
else if (currentToken == Token::MODIFIER)
@ -245,12 +245,12 @@ ASTPointer<StructDefinition> Parser::parseStructDefinition()
return nodeFactory.createNode<StructDefinition>(name, members);
}
ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(bool _allowVar)
ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(bool _allowVar, bool _isPublic, bool _isStateVariable)
{
ASTNodeFactory nodeFactory(*this);
ASTPointer<TypeName> type = parseTypeName(_allowVar);
nodeFactory.markEndPosition();
return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken());
return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken(), _isPublic, _isStateVariable);
}
ASTPointer<ModifierDefinition> Parser::parseModifierDefinition()

2
libsolidity/Parser.h

@ -52,7 +52,7 @@ private:
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
ASTPointer<FunctionDefinition> parseFunctionDefinition(bool _isPublic, ASTString const* _contractName);
ASTPointer<StructDefinition> parseStructDefinition();
ASTPointer<VariableDeclaration> parseVariableDeclaration(bool _allowVar);
ASTPointer<VariableDeclaration> parseVariableDeclaration(bool _allowVar, bool _isPublic = false, bool _isStateVar = false);
ASTPointer<ModifierDefinition> parseModifierDefinition();
ASTPointer<ModifierInvocation> parseModifierInvocation();
ASTPointer<Identifier> parseIdentifier();

57
libsolidity/Types.cpp

@ -450,7 +450,9 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
if (_convertTo.getCategory() == Category::CONTRACT)
{
auto const& bases = getContractDefinition().getLinearizedBaseContracts();
return find(bases.begin(), bases.end(),
if (m_super && bases.size() <= 1)
return false;
return find(m_super ? ++bases.begin() : bases.begin(), bases.end(),
&dynamic_cast<ContractType const&>(_convertTo).getContractDefinition()) != bases.end();
}
return false;
@ -472,12 +474,12 @@ bool ContractType::operator==(Type const& _other) const
if (_other.getCategory() != getCategory())
return false;
ContractType const& other = dynamic_cast<ContractType const&>(_other);
return other.m_contract == m_contract;
return other.m_contract == m_contract && other.m_super == m_super;
}
string ContractType::toString() const
{
return "contract " + m_contract.getName();
return "contract " + string(m_super ? "super " : "") + m_contract.getName();
}
MemberList const& ContractType::getMembers() const
@ -488,8 +490,16 @@ MemberList const& ContractType::getMembers() const
// All address members and all interface functions
map<string, shared_ptr<Type const>> members(IntegerType::AddressMemberList.begin(),
IntegerType::AddressMemberList.end());
for (auto const& it: m_contract.getInterfaceFunctions())
members[it.second->getName()] = make_shared<FunctionType>(*it.second, false);
if (m_super)
{
for (ContractDefinition const* base: m_contract.getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& function: base->getDefinedFunctions())
if (!function->isConstructor())
members.insert(make_pair(function->getName(), make_shared<FunctionType>(*function, true)));
}
else
for (auto const& it: m_contract.getInterfaceFunctions())
members[it.second.getName()] = it.second.getFunctionTypeShared();
m_members.reset(new MemberList(members));
}
return *m_members;
@ -511,9 +521,9 @@ shared_ptr<FunctionType const> const& ContractType::getConstructorType() const
u256 ContractType::getFunctionIdentifier(string const& _functionName) const
{
auto interfaceFunctions = m_contract.getInterfaceFunctions();
for (auto it = interfaceFunctions.cbegin(); it != interfaceFunctions.cend(); ++it)
if (it->second->getName() == _functionName)
return FixedHash<4>::Arith(it->first);
for (auto const& it: m_contract.getInterfaceFunctions())
if (it.second.getName() == _functionName)
return FixedHash<4>::Arith(it.first);
return Invalid256;
}
@ -582,15 +592,42 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal
m_location(_isInternal ? Location::INTERNAL : Location::EXTERNAL)
{
TypePointers params;
vector<string> paramNames;
TypePointers retParams;
vector<string> retParamNames;
params.reserve(_function.getParameters().size());
paramNames.reserve(_function.getParameters().size());
for (ASTPointer<VariableDeclaration> const& var: _function.getParameters())
{
paramNames.push_back(var->getName());
params.push_back(var->getType());
}
retParams.reserve(_function.getReturnParameters().size());
retParamNames.reserve(_function.getReturnParameters().size());
for (ASTPointer<VariableDeclaration> const& var: _function.getReturnParameters())
{
retParamNames.push_back(var->getName());
retParams.push_back(var->getType());
}
swap(params, m_parameterTypes);
swap(paramNames, m_parameterNames);
swap(retParams, m_returnParameterTypes);
swap(retParamNames, m_returnParameterNames);
}
FunctionType::FunctionType(VariableDeclaration const& _varDecl):
m_location(Location::EXTERNAL)
{
TypePointers params({});
vector<string> paramNames({});
TypePointers retParams({_varDecl.getType()});
vector<string> retParamNames({ _varDecl.getName()});
// for now, no input parameters LTODO: change for some things like mapping
swap(params, m_parameterTypes);
swap(paramNames, m_parameterNames);
swap(retParams, m_returnParameterTypes);
swap(retParamNames, m_returnParameterNames);
}
bool FunctionType::operator==(Type const& _other) const
@ -672,9 +709,9 @@ MemberList const& FunctionType::getMembers() const
}
}
string FunctionType::getCanonicalSignature() const
string FunctionType::getCanonicalSignature(std::string const& _name) const
{
string ret = "(";
string ret = _name + "(";
for (auto it = m_parameterTypes.cbegin(); it != m_parameterTypes.cend(); ++it)
ret += (*it)->toString() + (it + 1 == m_parameterTypes.cend() ? "" : ",");

20
libsolidity/Types.h

@ -277,7 +277,8 @@ class ContractType: public Type
{
public:
virtual Category getCategory() const override { return Category::CONTRACT; }
ContractType(ContractDefinition const& _contract): m_contract(_contract) {}
explicit ContractType(ContractDefinition const& _contract, bool _super = false):
m_contract(_contract), m_super(_super) {}
/// Contracts can be implicitly converted to super classes and to addresses.
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
/// Contracts can be converted to themselves and to integers.
@ -289,6 +290,7 @@ public:
virtual MemberList const& getMembers() const override;
bool isSuper() const { return m_super; }
ContractDefinition const& getContractDefinition() const { return m_contract; }
/// Returns the function type of the constructor. Note that the location part of the function type
@ -301,6 +303,9 @@ public:
private:
ContractDefinition const& m_contract;
/// If true, it is the "super" type of the current contract, i.e. it contains only inherited
/// members.
bool m_super;
/// Type of the constructor, @see getConstructorType. Lazily initialized.
mutable std::shared_ptr<FunctionType const> m_constructorType;
/// List of member types, will be lazy-initialized because of recursive references.
@ -314,7 +319,7 @@ class StructType: public Type
{
public:
virtual Category getCategory() const override { return Category::STRUCT; }
StructType(StructDefinition const& _struct): m_struct(_struct) {}
explicit StructType(StructDefinition const& _struct): m_struct(_struct) {}
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(Type const& _other) const override;
virtual u256 getStorageSize() const override;
@ -353,6 +358,7 @@ public:
virtual Category getCategory() const override { return Category::FUNCTION; }
explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true);
explicit FunctionType(VariableDeclaration const& _varDecl);
FunctionType(strings const& _parameterTypes, strings const& _returnParameterTypes,
Location _location = Location::INTERNAL):
FunctionType(parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes),
@ -364,7 +370,9 @@ public:
m_location(_location), m_gasSet(_gasSet), m_valueSet(_valueSet) {}
TypePointers const& getParameterTypes() const { return m_parameterTypes; }
std::vector<std::string> const& getParameterNames() const { return m_parameterNames; }
TypePointers const& getReturnParameterTypes() const { return m_returnParameterTypes; }
std::vector<std::string> const& getReturnParameterNames() const { return m_returnParameterNames; }
virtual bool operator==(Type const& _other) const override;
virtual std::string toString() const override;
@ -375,7 +383,7 @@ public:
virtual MemberList const& getMembers() const override;
Location const& getLocation() const { return m_location; }
std::string getCanonicalSignature() const;
std::string getCanonicalSignature(std::string const& _name) const;
bool gasSet() const { return m_gasSet; }
bool valueSet() const { return m_valueSet; }
@ -389,6 +397,8 @@ private:
TypePointers m_parameterTypes;
TypePointers m_returnParameterTypes;
std::vector<std::string> m_parameterNames;
std::vector<std::string> m_returnParameterNames;
Location const m_location;
bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack
bool const m_valueSet = false; ///< true iff the value to be sent is on the stack
@ -443,7 +453,7 @@ class TypeType: public Type
{
public:
virtual Category getCategory() const override { return Category::TYPE; }
TypeType(TypePointer const& _actualType, ContractDefinition const* _currentContract = nullptr):
explicit TypeType(TypePointer const& _actualType, ContractDefinition const* _currentContract = nullptr):
m_actualType(_actualType), m_currentContract(_currentContract) {}
TypePointer const& getActualType() const { return m_actualType; }
@ -497,7 +507,7 @@ public:
enum class Kind { BLOCK, MSG, TX };
virtual Category getCategory() const override { return Category::MAGIC; }
MagicType(Kind _kind);
explicit MagicType(Kind _kind);
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override
{

46
libweb3jsonrpc/CorsHttpServer.cpp

@ -1,46 +0,0 @@
/*
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 CorsHttpServer.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
#include "CorsHttpServer.h"
namespace jsonrpc
{
int HttpServer::callback(struct mg_connection*)
{
return 0;
}
bool CorsHttpServer::SendResponse(std::string const& _response, void* _addInfo)
{
struct mg_connection* conn = (struct mg_connection*) _addInfo;
if (mg_printf(conn, "HTTP/1.1 200 OK\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %d\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Access-Control-Allow-Headers: Content-Type\r\n"
"\r\n"
"%s",(int)_response.length(), _response.c_str()) > 0)
return true;
return false;
}
}

35
libweb3jsonrpc/CorsHttpServer.h

@ -1,35 +0,0 @@
/*
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 CorsHttpServer.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
#include <jsonrpccpp/server/connectors/httpserver.h>
namespace jsonrpc
{
class CorsHttpServer: public HttpServer
{
public:
using HttpServer::HttpServer;
bool virtual SendResponse(std::string const& _response, void* _addInfo = NULL);
};
}

1
mix/QBasicNodeDefinition.h

@ -38,6 +38,7 @@ public:
QBasicNodeDefinition(): QObject() {}
~QBasicNodeDefinition() {}
QBasicNodeDefinition(solidity::Declaration const* _d): QObject(), m_name(QString::fromStdString(_d->getName())) {}
QBasicNodeDefinition(std::string const& _name): QObject(), m_name(QString::fromStdString(_name)) {}
/// Get the name of the node.
QString name() const { return m_name; }

12
mix/QContractDefinition.cpp

@ -34,15 +34,15 @@ using namespace dev::mix;
QContractDefinition::QContractDefinition(dev::solidity::ContractDefinition const* _contract): QBasicNodeDefinition(_contract)
{
if (_contract->getConstructor() != nullptr)
m_constructor = new QFunctionDefinition(_contract->getConstructor(), -1);
{
FunctionDescription desc(_contract->getConstructor());
m_constructor = new QFunctionDefinition(desc);
}
else
m_constructor = new QFunctionDefinition();
auto interfaceFunctions = _contract->getInterfaceFunctions();
unsigned i = 0;
for (auto it = interfaceFunctions.cbegin(); it != interfaceFunctions.cend(); ++it, ++i)
m_functions.append(new QFunctionDefinition(it->second, i));
}
for (auto const& it: _contract->getInterfaceFunctions())
m_functions.append(new QFunctionDefinition(it.second));}
QFunctionDefinition* QContractDefinition::getFunction(dev::FixedHash<4> _hash)

31
mix/QFunctionDefinition.cpp

@ -21,19 +21,36 @@
#include <libsolidity/AST.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/Exceptions.h>
#include "QVariableDeclaration.h"
#include "QFunctionDefinition.h"
using namespace dev::solidity;
using namespace dev::mix;
QFunctionDefinition::QFunctionDefinition(dev::solidity::FunctionDefinition const* _f, int _index): QBasicNodeDefinition(_f), m_index(_index), m_hash(dev::sha3(_f->getCanonicalSignature()))
QFunctionDefinition::QFunctionDefinition(dev::solidity::FunctionDescription const& _f): QBasicNodeDefinition(_f.getDeclaration()), m_hash(dev::sha3(_f.getSignature()))
{
std::vector<std::shared_ptr<VariableDeclaration>> parameters = _f->getParameterList().getParameters();
for (unsigned i = 0; i < parameters.size(); i++)
m_parameters.append(new QVariableDeclaration(parameters.at(i).get()));
FunctionDefinition const* funcDef;
VariableDeclaration const* varDecl;
if ((funcDef = _f.getFunctionDefinition()))
{
std::vector<std::shared_ptr<VariableDeclaration>> parameters = funcDef->getParameterList().getParameters();
for (unsigned i = 0; i < parameters.size(); i++)
m_parameters.append(new QVariableDeclaration(parameters.at(i).get()));
std::vector<std::shared_ptr<VariableDeclaration>> returnParameters = _f->getReturnParameters();
for (unsigned i = 0; i < returnParameters.size(); i++)
m_returnParameters.append(new QVariableDeclaration(returnParameters.at(i).get()));
std::vector<std::shared_ptr<VariableDeclaration>> returnParameters = funcDef->getReturnParameters();
for (unsigned i = 0; i < returnParameters.size(); i++)
m_returnParameters.append(new QVariableDeclaration(returnParameters.at(i).get()));
}
else
{
if (!(varDecl = _f.getVariableDeclaration()))
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Malformed FunctionDescription. Should never happen."));
// only the return parameter for now.
// TODO: change this for other state variables like mapping and maybe abstract this inside solidity and not here
auto returnParams = _f.getReturnParameters();
m_returnParameters.append(new QVariableDeclaration(returnParams[0]));
}
}

5
mix/QFunctionDefinition.h

@ -36,19 +36,16 @@ class QFunctionDefinition: public QBasicNodeDefinition
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<dev::mix::QVariableDeclaration> parameters READ parameters)
Q_PROPERTY(int index READ index)
public:
QFunctionDefinition() {}
QFunctionDefinition(solidity::FunctionDefinition const* _f, int _index);
QFunctionDefinition(solidity::FunctionDescription const& _f);
/// Get all input parameters of this function.
QList<QVariableDeclaration*> const& parametersList() const { return m_parameters; }
/// Get all input parameters of this function as QML property.
QQmlListProperty<QVariableDeclaration> parameters() const { return QQmlListProperty<QVariableDeclaration>(const_cast<QFunctionDefinition*>(this), const_cast<QFunctionDefinition*>(this)->m_parameters); }
/// Get all return parameters of this function.
QList<QVariableDeclaration*> returnParameters() const { return m_returnParameters; }
/// Get the index of this function on the contract ABI.
int index() const { return m_index; }
/// Get the hash of this function declaration on the contract ABI.
FixedHash<4> hash() const { return m_hash; }

1
mix/QVariableDeclaration.h

@ -37,6 +37,7 @@ class QVariableDeclaration: public QBasicNodeDefinition
public:
QVariableDeclaration() {}
QVariableDeclaration(solidity::VariableDeclaration const* _v): QBasicNodeDefinition(_v), m_type(QString::fromStdString(_v->getType()->toString())) {}
QVariableDeclaration(solidity::ParamDescription const& _v): QBasicNodeDefinition(_v.getName()), m_type(QString::fromStdString(_v.getType())) {}
QString type() const { return m_type; }
private:
QString m_type;

2
neth/main.cpp

@ -32,7 +32,7 @@
#include <libethereum/All.h>
#if ETH_JSONRPC
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <libweb3jsonrpc/CorsHttpServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#endif
#include <libwebthree/WebThree.h>
#include "BuildInfo.h"

41
solc/CommandLineInterface.cpp

@ -61,6 +61,7 @@ static string const g_argBinaryStr = "binary";
static string const g_argOpcodesStr = "opcodes";
static string const g_argNatspecDevStr = "natspec-dev";
static string const g_argNatspecUserStr = "natspec-user";
static string const g_argAddStandard = "add-std";
static void version()
{
@ -116,13 +117,13 @@ void CommandLineInterface::handleBinary(string const& _contract)
if (outputToStdout(choice))
{
cout << "Binary: " << endl;
cout << toHex(m_compiler.getBytecode(_contract)) << endl;
cout << toHex(m_compiler->getBytecode(_contract)) << endl;
}
if (outputToFile(choice))
{
ofstream outFile(_contract + ".binary");
outFile << toHex(m_compiler.getBytecode(_contract));
outFile << toHex(m_compiler->getBytecode(_contract));
outFile.close();
}
}
@ -133,14 +134,14 @@ void CommandLineInterface::handleOpcode(string const& _contract)
if (outputToStdout(choice))
{
cout << "Opcodes: " << endl;
cout << eth::disassemble(m_compiler.getBytecode(_contract));
cout << eth::disassemble(m_compiler->getBytecode(_contract));
cout << endl;
}
if (outputToFile(choice))
{
ofstream outFile(_contract + ".opcode");
outFile << eth::disassemble(m_compiler.getBytecode(_contract));
outFile << eth::disassemble(m_compiler->getBytecode(_contract));
outFile.close();
}
}
@ -191,13 +192,13 @@ void CommandLineInterface::handleMeta(DocumentationType _type, string const& _co
if (outputToStdout(choice))
{
cout << title << endl;
cout << m_compiler.getMetadata(_contract, _type) << endl;
cout << m_compiler->getMetadata(_contract, _type) << endl;
}
if (outputToFile(choice))
{
ofstream outFile(_contract + suffix);
outFile << m_compiler.getMetadata(_contract, _type);
outFile << m_compiler->getMetadata(_contract, _type);
outFile.close();
}
}
@ -211,6 +212,7 @@ bool CommandLineInterface::parseArguments(int argc, char** argv)
("help", "Show help message and exit")
("version", "Show version and exit")
("optimize", po::value<bool>()->default_value(false), "Optimize bytecode for size")
("add-std", po::value<bool>()->default_value(false), "Add standard contracts")
("input-file", po::value<vector<string>>(), "input file")
(g_argAstStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the AST of the contract.")
@ -292,31 +294,32 @@ bool CommandLineInterface::processInput()
m_sourceCodes[infile] = asString(dev::contents(infile));
}
m_compiler.reset(new CompilerStack(m_args["add-std"].as<bool>()));
try
{
for (auto const& sourceCode: m_sourceCodes)
m_compiler.addSource(sourceCode.first, sourceCode.second);
m_compiler->addSource(sourceCode.first, sourceCode.second);
// TODO: Perhaps we should not compile unless requested
m_compiler.compile(m_args["optimize"].as<bool>());
m_compiler->compile(m_args["optimize"].as<bool>());
}
catch (ParserError const& _exception)
{
SourceReferenceFormatter::printExceptionInformation(cerr, _exception, "Parser error", m_compiler);
SourceReferenceFormatter::printExceptionInformation(cerr, _exception, "Parser error", *m_compiler);
return false;
}
catch (DeclarationError const& _exception)
{
SourceReferenceFormatter::printExceptionInformation(cerr, _exception, "Declaration error", m_compiler);
SourceReferenceFormatter::printExceptionInformation(cerr, _exception, "Declaration error", *m_compiler);
return false;
}
catch (TypeError const& _exception)
{
SourceReferenceFormatter::printExceptionInformation(cerr, _exception, "Type error", m_compiler);
SourceReferenceFormatter::printExceptionInformation(cerr, _exception, "Type error", *m_compiler);
return false;
}
catch (CompilerError const& _exception)
{
SourceReferenceFormatter::printExceptionInformation(cerr, _exception, "Compiler error", m_compiler);
SourceReferenceFormatter::printExceptionInformation(cerr, _exception, "Compiler error", *m_compiler);
return false;
}
catch (InternalCompilerError const& _exception)
@ -369,12 +372,12 @@ void CommandLineInterface::handleAst(string const& _argStr)
cout << endl << "======= " << sourceCode.first << " =======" << endl;
if (_argStr == g_argAstStr)
{
ASTPrinter printer(m_compiler.getAST(sourceCode.first), sourceCode.second);
ASTPrinter printer(m_compiler->getAST(sourceCode.first), sourceCode.second);
printer.print(cout);
}
else
{
ASTJsonConverter converter(m_compiler.getAST(sourceCode.first));
ASTJsonConverter converter(m_compiler->getAST(sourceCode.first));
converter.print(cout);
}
}
@ -388,12 +391,12 @@ void CommandLineInterface::handleAst(string const& _argStr)
ofstream outFile(p.stem().string() + ".ast");
if (_argStr == g_argAstStr)
{
ASTPrinter printer(m_compiler.getAST(sourceCode.first), sourceCode.second);
ASTPrinter printer(m_compiler->getAST(sourceCode.first), sourceCode.second);
printer.print(outFile);
}
else
{
ASTJsonConverter converter(m_compiler.getAST(sourceCode.first));
ASTJsonConverter converter(m_compiler->getAST(sourceCode.first));
converter.print(outFile);
}
outFile.close();
@ -408,7 +411,7 @@ void CommandLineInterface::actOnInput()
handleAst(g_argAstStr);
handleAst(g_argAstJson);
vector<string> contracts = m_compiler.getContractNames();
vector<string> contracts = m_compiler->getContractNames();
for (string const& contract: contracts)
{
if (needStdout(m_args))
@ -421,13 +424,13 @@ void CommandLineInterface::actOnInput()
if (outputToStdout(choice))
{
cout << "EVM assembly:" << endl;
m_compiler.streamAssembly(cout, contract);
m_compiler->streamAssembly(cout, contract);
}
if (outputToFile(choice))
{
ofstream outFile(contract + ".evm");
m_compiler.streamAssembly(outFile, contract);
m_compiler->streamAssembly(outFile, contract);
outFile.close();
}
}

6
solc/CommandLineInterface.h

@ -21,9 +21,9 @@
*/
#pragma once
#include <boost/program_options.hpp>
#include <libsolidity/CompilerStack.h>
#include <memory>
#include <boost/program_options.hpp>
namespace dev
{
@ -65,7 +65,7 @@ private:
/// map of input files to source code strings
std::map<std::string, std::string> m_sourceCodes;
/// Solidity compiler stack
dev::solidity::CompilerStack m_compiler;
std::unique_ptr<dev::solidity::CompilerStack> m_compiler;
};
}

51
test/SolidityCompiler.cpp

@ -108,57 +108,6 @@ 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"

62
test/SolidityEndToEndTest.cpp

@ -882,6 +882,43 @@ BOOST_AUTO_TEST_CASE(constructor)
testSolidityAgainstCpp("get(uint256)", get, u256(7));
}
BOOST_AUTO_TEST_CASE(simple_accessor)
{
char const* sourceCode = "contract test {\n"
" uint256 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 data;\n"
" string6 name;\n"
" hash a_hash;\n"
" address 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"
" private:"
" 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()") == encodeArgs(42)));
}
BOOST_AUTO_TEST_CASE(balance)
{
char const* sourceCode = "contract test {\n"
@ -1868,6 +1905,7 @@ BOOST_AUTO_TEST_CASE(use_std_lib)
import "mortal";
contract Icarus is mortal { }
)";
m_addStandardSources = true;
u256 amount(130);
u160 address(23);
compileAndRun(sourceCode, amount, "Icarus");
@ -1893,6 +1931,30 @@ BOOST_AUTO_TEST_CASE(crazy_elementary_typenames_on_stack)
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_SUITE_END()
}

8
test/SolidityExpressionCompiler.cpp

@ -86,7 +86,8 @@ Declaration const& resolveDeclaration(vector<string> const& _namespacedName,
}
bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _functions = {},
vector<vector<string>> _localVariables = {}, vector<shared_ptr<MagicVariableDeclaration const>> _globalDeclarations = {})
vector<vector<string>> _localVariables = {},
vector<shared_ptr<MagicVariableDeclaration const>> _globalDeclarations = {})
{
Parser parser;
ASTPointer<SourceUnit> sourceUnit;
@ -99,10 +100,12 @@ bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _
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()))
@ -116,8 +119,7 @@ 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)

98
test/SolidityNameAndTypeResolution.cpp

@ -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 FunctionDescription 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)
@ -584,6 +630,56 @@ BOOST_AUTO_TEST_CASE(modifier_returns_value)
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 foo;\n"
"}\n";
ASTPointer<SourceUnit> source;
ContractDefinition const* contract;
BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text));
BOOST_REQUIRE((contract = retrieveContract(source, 0)) != nullptr);
FunctionDescription function = retrieveFunctionBySignature(contract, "foo()");
BOOST_CHECK_MESSAGE(function.getDeclaration() != nullptr, "Could not find the accessor function");
auto returnParams = function.getReturnParameters();
BOOST_CHECK_EQUAL(returnParams.at(0).getType(), "uint256");
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"
"private:\n"
"uint256 foo;\n"
"}\n";
ASTPointer<SourceUnit> source;
ContractDefinition const* contract;
BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text));
BOOST_CHECK((contract = retrieveContract(source, 0)) != nullptr);
FunctionDescription function = retrieveFunctionBySignature(contract, "foo()");
BOOST_CHECK_MESSAGE(function.getDeclaration() == nullptr, "Accessor function of a private variable should not exist");
}
BOOST_AUTO_TEST_SUITE_END()
}

37
test/SolidityParser.cpp

@ -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);
}
}
@ -121,14 +129,16 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation)
ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n"
" uint256 stateVar;\n"
" private:\n"
" uint256 stateVar;\n"
" public:\n"
" /// This is a test function\n"
" function functionName(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
BOOST_CHECK_EQUAL(*function->getDocumentation(), "This is a test function");
checkFunctionNatspec(function, "This is a test function");
}
BOOST_AUTO_TEST_CASE(function_normal_comments)
@ -144,7 +154,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)
@ -152,7 +162,9 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n"
" private:\n"
" uint256 stateVar;\n"
" public:\n"
" /// This is test function 1\n"
" function functionName1(hash hashin) returns (hash hashout) {}\n"
" /// This is test function 2\n"
@ -166,17 +178,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 +205,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 +222,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 +230,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)

11
test/TestHelper.cpp

@ -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;
}

1
test/TestHelper.h

@ -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);

2
test/jsonrpc.cpp

@ -31,8 +31,6 @@
#include <libdevcore/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>

4
test/solidityExecutionFramework.h

@ -45,8 +45,7 @@ public:
bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "")
{
// add standard sources only if contract name is given
dev::solidity::CompilerStack compiler(!_contractName.empty());
dev::solidity::CompilerStack compiler(m_addStandardSources);
try
{
compiler.addSource("", _sourceCode);
@ -175,6 +174,7 @@ private:
protected:
bool m_optimize = false;
bool m_addStandardSources = false;
Address m_sender;
Address m_contractAddress;
eth::State m_state;

198
test/stTransactionTestFiller.json

@ -289,7 +289,7 @@
}
},
"TransactionTooManyRlpElements" : {
"InternlCallStoreClearsOOG" : {
"env" : {
"currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty" : "45678256",
@ -301,26 +301,210 @@
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000",
"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" : "600",
"gasLimit" : "1600",
"gasLimit" : "700",
"gasPrice" : "1",
"gasPrice" : "12",
"nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d9",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "d2571607e241ecf590ed94b12d87c94babe36db6",
"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",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "1000",
"gasPrice" : "1",
"nonce" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"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"
}
},
}

1
test/state.cpp

@ -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 {

219
test/transaction.cpp

@ -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
test/tt10mbDataFieldFiller.json

File diff suppressed because one or more lines are too long

290
test/ttTransactionTestFiller.json

@ -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"
}
}
}
Loading…
Cancel
Save