Browse Source

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

cl-refactor
Gav Wood 10 years ago
parent
commit
717f74f882
  1. 2
      libsolidity/AST.cpp
  2. 37
      libsolidity/ExpressionCompiler.cpp
  3. 6
      libsolidity/ExpressionCompiler.h
  4. 23
      libsolidity/Types.cpp
  5. 37
      libsolidity/Types.h
  6. 2
      test/libethereum/stateOriginal.cpp
  7. 31
      test/libsolidity/SolidityEndToEndTest.cpp

2
libsolidity/AST.cpp

@ -746,7 +746,7 @@ void FunctionCall::checkTypeRequirements(TypePointers const*)
//@todo for structs, we have to check the number of arguments to be equal to the
// number of non-mapping members
if (m_arguments.size() != 1)
BOOST_THROW_EXCEPTION(createTypeError("More than one argument for explicit type conversion."));
BOOST_THROW_EXCEPTION(createTypeError("Exactly one argument expected for explicit type conversion."));
if (!isPositionalCall)
BOOST_THROW_EXCEPTION(createTypeError("Type conversion cannot allow named arguments."));
if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type.getActualType()))

37
libsolidity/ExpressionCompiler.cpp

@ -458,9 +458,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
break;
}
case Location::External:
case Location::CallCode:
case Location::Bare:
case Location::BareCallCode:
_functionCall.getExpression().accept(*this);
appendExternalFunctionCall(function, arguments, function.getLocation() == Location::Bare);
appendExternalFunctionCall(function, arguments);
break;
case Location::Creation:
{
@ -527,13 +529,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
TypePointers{},
strings(),
strings(),
Location::External,
Location::Bare,
false,
true,
true
),
{},
true
{}
);
break;
case Location::Suicide:
@ -622,7 +623,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context << contractAddresses.find(function.getLocation())->second;
for (unsigned i = function.getSizeOnStack(); i > 0; --i)
m_context << eth::swapInstruction(i);
appendExternalFunctionCall(function, arguments, true);
appendExternalFunctionCall(function, arguments);
break;
}
default:
@ -685,7 +686,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
IntegerType(0, IntegerType::Modifier::Address), true);
m_context << eth::Instruction::BALANCE;
}
else if (member == "send" || member.substr(0, min<size_t>(member.size(), 4)) == "call")
else if ((set<string>{"send", "call", "callcode"}).count(member))
appendTypeConversion(*_memberAccess.getExpression().getType(),
IntegerType(0, IntegerType::Modifier::Address), true);
else
@ -1031,9 +1032,10 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack)
m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND;
}
void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functionType,
vector<ASTPointer<Expression const>> const& _arguments,
bool bare)
void ExpressionCompiler::appendExternalFunctionCall(
FunctionType const& _functionType,
vector<ASTPointer<Expression const>> const& _arguments
)
{
solAssert(_functionType.takesArbitraryParameters() ||
_arguments.size() == _functionType.getParameterTypes().size(), "");
@ -1047,7 +1049,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
unsigned gasValueSize = (_functionType.gasSet() ? 1 : 0) + (_functionType.valueSet() ? 1 : 0);
unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + (bare ? 0 : 1));
unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + (_functionType.isBareCall() ? 0 : 1));
unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize);
unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
@ -1057,7 +1059,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0;
m_context << u256(retSize) << u256(0);
if (bare)
if (_functionType.isBareCall())
m_context << u256(0);
else
{
@ -1074,7 +1076,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
_arguments,
_functionType.getParameterTypes(),
_functionType.padArguments(),
bare,
_functionType.getLocation() == FunctionType::Location::Bare ||
_functionType.getLocation() == FunctionType::Location::BareCallCode,
_functionType.takesArbitraryParameters()
);
@ -1093,14 +1096,20 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
// send all gas except the amount needed to execute "SUB" and "CALL"
// @todo this retains too much gas for now, needs to be fine-tuned.
m_context << u256(50 + (_functionType.valueSet() ? 9000 : 0) + 25000) << eth::Instruction::GAS << eth::Instruction::SUB;
m_context << eth::Instruction::CALL;
if (
_functionType.getLocation() == FunctionType::Location::CallCode ||
_functionType.getLocation() == FunctionType::Location::BareCallCode
)
m_context << eth::Instruction::CALLCODE;
else
m_context << eth::Instruction::CALL;
auto tag = m_context.appendConditionalJump();
m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0.
if (_functionType.valueSet())
m_context << eth::Instruction::POP;
if (_functionType.gasSet())
m_context << eth::Instruction::POP;
if (!bare)
if (!_functionType.isBareCall())
m_context << eth::Instruction::POP;
m_context << eth::Instruction::POP; // pop contract address

6
libsolidity/ExpressionCompiler.h

@ -98,8 +98,10 @@ private:
void appendHighBitsCleanup(IntegerType const& _typeOnStack);
/// Appends code to call a function of the given type with the given arguments.
void appendExternalFunctionCall(FunctionType const& _functionType, std::vector<ASTPointer<Expression const>> const& _arguments,
bool bare = false);
void appendExternalFunctionCall(
FunctionType const& _functionType,
std::vector<ASTPointer<Expression const>> const& _arguments
);
/// Appends code that evaluates the given arguments and moves the result to memory encoded as
/// specified by the ABI. The memory offset is expected to be on the stack and is updated by
/// this call. If @a _padToWordBoundaries is set to false, all values are concatenated without

23
libsolidity/Types.cpp

@ -316,6 +316,7 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
const MemberList IntegerType::AddressMemberList({
{"balance", make_shared<IntegerType >(256)},
{"call", make_shared<FunctionType>(strings(), strings(), FunctionType::Location::Bare, true)},
{"callcode", make_shared<FunctionType>(strings(), strings(), FunctionType::Location::BareCallCode, true)},
{"send", make_shared<FunctionType>(strings{"uint"}, strings{}, FunctionType::Location::Send)}
});
@ -1115,9 +1116,11 @@ unsigned FunctionType::getSizeOnStack() const
}
unsigned size = 0;
if (location == Location::External)
if (location == Location::External || location == Location::CallCode)
size = 2;
else if (location == Location::Internal || location == Location::Bare)
else if (location == Location::Bare || location == Location::BareCallCode)
size = 1;
else if (location == Location::Internal)
size = 1;
if (m_gasSet)
size++;
@ -1156,6 +1159,7 @@ MemberList const& FunctionType::getMembers() const
case Location::SHA256:
case Location::RIPEMD160:
case Location::Bare:
case Location::BareCallCode:
if (!m_members)
{
MemberList::MemberMap members{
@ -1228,6 +1232,21 @@ bool FunctionType::hasEqualArgumentTypes(FunctionType const& _other) const
);
}
bool FunctionType::isBareCall() const
{
switch (m_location)
{
case Location::Bare:
case Location::BareCallCode:
case Location::ECRecover:
case Location::SHA256:
case Location::RIPEMD160:
return true;
default:
return false;
}
}
string FunctionType::externalSignature(std::string const& _name) const
{
std::string funcName = _name;

37
libsolidity/Types.h

@ -540,17 +540,32 @@ private:
class FunctionType: public Type
{
public:
/// The meaning of the value(s) on the stack referencing the function:
/// INTERNAL: jump tag, EXTERNAL: contract address + function identifier,
/// BARE: contract address (non-abi contract call)
/// OTHERS: special virtual function, nothing on the stack
/// How this function is invoked on the EVM.
/// @todo This documentation is outdated, and Location should rather be named "Type"
enum class Location { Internal, External, Creation, Send,
SHA3, Suicide,
ECRecover, SHA256, RIPEMD160,
Log0, Log1, Log2, Log3, Log4, Event,
SetGas, SetValue, BlockHash,
Bare };
enum class Location
{
Internal, ///< stack-call using plain JUMP
External, ///< external call using CALL
CallCode, ///< extercnal call using CALLCODE, i.e. not exchanging the storage
Bare, ///< CALL without function hash
BareCallCode, ///< CALLCODE without function hash
Creation, ///< external call using CREATE
Send, ///< CALL, but without data and gas
SHA3, ///< SHA3
Suicide, ///< SUICIDE
ECRecover, ///< CALL to special contract for ecrecover
SHA256, ///< CALL to special contract for sha256
RIPEMD160, ///< CALL to special contract for ripemd160
Log0,
Log1,
Log2,
Log3,
Log4,
Event, ///< syntactic sugar for LOG*
SetGas, ///< modify the default gas value for the function call
SetValue, ///< modify the default value transfer for the function call
BlockHash ///< BLOCKHASH
};
virtual Category getCategory() const override { return Category::Function; }
@ -620,6 +635,8 @@ public:
/// @returns true if the types of parameters are equal (does't check return parameter types)
bool hasEqualArgumentTypes(FunctionType const& _other) const;
/// @returns true if the ABI is used for this call (only meaningful for external calls)
bool isBareCall() const;
Location const& getLocation() const { return m_location; }
/// @returns the external signature of this function type given the function name
/// If @a _name is not provided (empty string) then the @c m_declaration member of the

2
test/libethereum/stateOriginal.cpp

@ -25,7 +25,7 @@
#include <secp256k1/secp256k1.h>
#include <libethereum/CanonBlockChain.h>
#include <libethereum/State.h>
#include <libethereum/Farm.h>
#include <libethcore/Farm.h>
#include <libethereum/Defaults.h>
#include "../TestHelper.h"
using namespace std;

31
test/libsolidity/SolidityEndToEndTest.cpp

@ -2558,6 +2558,37 @@ BOOST_AUTO_TEST_CASE(generic_call)
BOOST_CHECK_EQUAL(m_state.balance(m_contractAddress), 50 - 2);
}
BOOST_AUTO_TEST_CASE(generic_callcode)
{
char const* sourceCode = R"**(
contract receiver {
uint public received;
function receive(uint256 x) { received = x; }
}
contract sender {
uint public received;
function doSend(address rec) returns (uint d)
{
bytes4 signature = bytes4(bytes32(sha3("receive(uint256)")));
rec.callcode.value(2)(signature, 23);
return receiver(rec).received();
}
}
)**";
compileAndRun(sourceCode, 0, "receiver");
u160 const c_receiverAddress = m_contractAddress;
compileAndRun(sourceCode, 50, "sender");
u160 const c_senderAddress = m_contractAddress;
BOOST_CHECK(callContractFunction("doSend(address)", c_receiverAddress) == encodeArgs(0));
BOOST_CHECK(callContractFunction("received()") == encodeArgs(23));
m_contractAddress = c_receiverAddress;
BOOST_CHECK(callContractFunction("received()") == encodeArgs(0));
BOOST_CHECK(m_state.storage(c_receiverAddress).empty());
BOOST_CHECK(!m_state.storage(c_senderAddress).empty());
BOOST_CHECK_EQUAL(m_state.balance(c_receiverAddress), 0);
BOOST_CHECK_EQUAL(m_state.balance(c_senderAddress), 50);
}
BOOST_AUTO_TEST_CASE(store_bytes)
{
// this test just checks that the copy loop does not mess up the stack

Loading…
Cancel
Save