Browse Source

Sending ether.

cl-refactor
Christian 10 years ago
parent
commit
898f989aa1
  1. 2
      libsolidity/Compiler.cpp
  2. 47
      libsolidity/ExpressionCompiler.cpp
  3. 4
      libsolidity/ExpressionCompiler.h
  4. 16
      libsolidity/Types.cpp
  5. 19
      libsolidity/Types.h
  6. 15
      test/solidityEndToEndTest.cpp

2
libsolidity/Compiler.cpp

@ -325,7 +325,7 @@ bool Compiler::visit(ExpressionStatement& _expressionStatement)
Expression& expression = _expressionStatement.getExpression(); Expression& expression = _expressionStatement.getExpression();
ExpressionCompiler::compileExpression(m_context, expression); ExpressionCompiler::compileExpression(m_context, expression);
Type::Category category = expression.getType()->getCategory(); Type::Category category = expression.getType()->getCategory();
if (category != Type::Category::VOID && category != Type::Category::MAGIC) for (unsigned i = 0; i < expression.getType()->getSizeOnStack(); ++i)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
return false; return false;
} }

47
libsolidity/ExpressionCompiler.cpp

@ -179,16 +179,17 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
} }
else else
{ {
//@todo: check for "external call" (to be stored in type) FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType());
std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments();
if (asserts(arguments.size() == function.getParameterTypes().size()))
BOOST_THROW_EXCEPTION(InternalCompilerError());
if (function.getLocation() == FunctionType::Location::INTERNAL)
{
// Calling convention: Caller pushes return address and arguments // Calling convention: Caller pushes return address and arguments
// Callee removes them and pushes return values // Callee removes them and pushes return values
FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType());
eth::AssemblyItem returnLabel = m_context.pushNewTag(); eth::AssemblyItem returnLabel = m_context.pushNewTag();
std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments();
if (asserts(arguments.size() == function.getParameterTypes().size()))
BOOST_THROW_EXCEPTION(InternalCompilerError());
for (unsigned i = 0; i < arguments.size(); ++i) for (unsigned i = 0; i < arguments.size(); ++i)
{ {
arguments[i]->accept(*this); arguments[i]->accept(*this);
@ -207,6 +208,34 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i) for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
} }
else if (function.getLocation() == FunctionType::Location::EXTERNAL)
{
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("External function calls not implemented yet."));
}
else
{
switch (function.getLocation())
{
case FunctionType::Location::SEND:
m_context << u256(0) << u256(0) << u256(0) << u256(0);
arguments.front()->accept(*this);
//@todo might not be necessary
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front());
_functionCall.getExpression().accept(*this);
m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB
<< eth::Instruction::CALL
<< eth::Instruction::POP;
break;
case FunctionType::Location::SUICIDE:
arguments.front()->accept(*this);
//@todo might not be necessary
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front());
m_context << eth::Instruction::SUICIDE;
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Function not yet implemented."));
}
}
}
return false; return false;
} }
@ -216,9 +245,13 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess)
switch (_memberAccess.getExpression().getType()->getCategory()) switch (_memberAccess.getExpression().getType()->getCategory())
{ {
case Type::Category::INTEGER: case Type::Category::INTEGER:
if (asserts(member == "balance")) if (member == "balance")
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer."));
m_context << eth::Instruction::BALANCE; m_context << eth::Instruction::BALANCE;
else if (member == "send")
{ // no modification
}
else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer."));
break; break;
case Type::Category::CONTRACT: case Type::Category::CONTRACT:
// call function // call function

4
libsolidity/ExpressionCompiler.h

@ -132,6 +132,10 @@ private:
CompilerContext& m_context; CompilerContext& m_context;
LValue m_currentLValue; LValue m_currentLValue;
/// If a "virtual" function (i.e. a bulit-in function without jump tag) is encountered, the
/// actual function is stored here. @todo prevent assignment or store it with assignment
enum class SpecialFunction { NONE, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160 };
SpecialFunction m_currentSpecialFunction;
}; };

16
libsolidity/Types.cpp

@ -192,7 +192,7 @@ u256 IntegerType::literalValue(Literal const& _literal) const
const MemberList IntegerType::AddressMemberList = const MemberList IntegerType::AddressMemberList =
MemberList({{"balance", make_shared<IntegerType const>(256)}, MemberList({{"balance", make_shared<IntegerType const>(256)},
{"send", make_shared<FunctionType const>(TypePointers({make_shared<IntegerType const>(256)}), {"send", make_shared<FunctionType const>(TypePointers({make_shared<IntegerType const>(256)}),
TypePointers())}}); TypePointers(), FunctionType::Location::SEND)}});
bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{ {
@ -314,6 +314,7 @@ FunctionType::FunctionType(FunctionDefinition const& _function)
retParams.push_back(var->getType()); retParams.push_back(var->getType());
swap(params, m_parameterTypes); swap(params, m_parameterTypes);
swap(retParams, m_returnParameterTypes); swap(retParams, m_returnParameterTypes);
m_location = Location::INTERNAL;
} }
bool FunctionType::operator==(Type const& _other) const bool FunctionType::operator==(Type const& _other) const
@ -347,6 +348,19 @@ string FunctionType::toString() const
return name + ")"; return name + ")";
} }
unsigned FunctionType::getSizeOnStack() const
{
switch (m_location)
{
case Location::INTERNAL:
return 1;
case Location::EXTERNAL:
return 2;
default:
return 0;
}
}
bool MappingType::operator==(Type const& _other) const bool MappingType::operator==(Type const& _other) const
{ {
if (_other.getCategory() != getCategory()) if (_other.getCategory() != getCategory())

19
libsolidity/Types.h

@ -115,6 +115,7 @@ public:
/// Returns true if the type can be stored as a value (as opposed to a reference) on the stack, /// Returns true if the type can be stored as a value (as opposed to a reference) on the stack,
/// i.e. it behaves differently in lvalue context and in value context. /// i.e. it behaves differently in lvalue context and in value context.
virtual bool isValueType() const { return false; } virtual bool isValueType() const { return false; }
virtual unsigned getSizeOnStack() const { return 1; }
/// Returns the list of all members of this type. Default implementation: no members. /// Returns the list of all members of this type. Default implementation: no members.
virtual MemberList const& getMembers() const { return EmptyMemberList; } virtual MemberList const& getMembers() const { return EmptyMemberList; }
@ -235,6 +236,7 @@ public:
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual u256 getStorageSize() const override; virtual u256 getStorageSize() const override;
virtual bool canLiveOutsideStorage() const override; virtual bool canLiveOutsideStorage() const override;
virtual unsigned getSizeOnStack() const override { return 1; /*@todo*/ }
virtual std::string toString() const override; virtual std::string toString() const override;
virtual MemberList const& getMembers() const override; virtual MemberList const& getMembers() const override;
@ -255,10 +257,17 @@ private:
class FunctionType: public Type class FunctionType: public Type
{ {
public: public:
/// The meaning of the value(s) on the stack referencing the function:
/// INTERNAL: jump tag, EXTERNAL: contract address + function index,
/// OTHERS: special virtual function, nothing on the stack
enum class Location { INTERNAL, EXTERNAL, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160 };
virtual Category getCategory() const override { return Category::FUNCTION; } virtual Category getCategory() const override { return Category::FUNCTION; }
explicit FunctionType(FunctionDefinition const& _function); explicit FunctionType(FunctionDefinition const& _function);
FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes): FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes,
m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes) {} Location _location = Location::INTERNAL):
m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes),
m_location(_location) {}
TypePointers const& getParameterTypes() const { return m_parameterTypes; } TypePointers const& getParameterTypes() const { return m_parameterTypes; }
TypePointers const& getReturnParameterTypes() const { return m_returnParameterTypes; } TypePointers const& getReturnParameterTypes() const { return m_returnParameterTypes; }
@ -268,10 +277,14 @@ public:
virtual bool canBeStored() const override { return false; } virtual bool canBeStored() const override { return false; }
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); } virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); }
virtual bool canLiveOutsideStorage() const override { return false; } virtual bool canLiveOutsideStorage() const override { return false; }
virtual unsigned getSizeOnStack() const override;
Location getLocation() const { return m_location; }
private: private:
TypePointers m_parameterTypes; TypePointers m_parameterTypes;
TypePointers m_returnParameterTypes; TypePointers m_returnParameterTypes;
Location m_location;
}; };
/** /**
@ -310,6 +323,7 @@ public:
virtual bool canBeStored() const override { return false; } virtual bool canBeStored() const override { return false; }
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); } virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); }
virtual bool canLiveOutsideStorage() const override { return false; } virtual bool canLiveOutsideStorage() const override { return false; }
virtual unsigned getSizeOnStack() const override { return 0; }
}; };
/** /**
@ -349,6 +363,7 @@ public:
virtual bool operator==(Type const& _other) const; virtual bool operator==(Type const& _other) const;
virtual bool canBeStored() const override { return false; } virtual bool canBeStored() const override { return false; }
virtual bool canLiveOutsideStorage() const override { return true; } virtual bool canLiveOutsideStorage() const override { return true; }
virtual unsigned getSizeOnStack() const override { return 0; }
virtual MemberList const& getMembers() const override { return m_members; } virtual MemberList const& getMembers() const override { return m_members; }
virtual std::string toString() const override; virtual std::string toString() const override;

15
test/solidityEndToEndTest.cpp

@ -794,6 +794,21 @@ BOOST_AUTO_TEST_CASE(function_types)
BOOST_CHECK(callContractFunction(0, bytes{1}) == toBigEndian(u256(12))); BOOST_CHECK(callContractFunction(0, bytes{1}) == toBigEndian(u256(12)));
} }
BOOST_AUTO_TEST_CASE(send_ether)
{
char const* sourceCode = "contract test {\n"
" function a(address addr, uint amount) returns (uint ret) {\n"
" addr.send(amount);\n"
" return address(this).balance;\n"
" }\n"
"}\n";
u256 amount(130);
compileAndRun(sourceCode, amount + 1);
u160 address(23);
BOOST_CHECK(callContractFunction(0, address, amount) == toBigEndian(u256(1)));
BOOST_CHECK_EQUAL(m_state.balance(address), amount);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

Loading…
Cancel
Save