mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #1931 from chriseth/sol_callcode
Bare callcode for addresses and contracts.
This commit is contained in:
commit
9c85254751
@ -458,9 +458,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Location::External:
|
case Location::External:
|
||||||
|
case Location::CallCode:
|
||||||
case Location::Bare:
|
case Location::Bare:
|
||||||
|
case Location::BareCallCode:
|
||||||
_functionCall.getExpression().accept(*this);
|
_functionCall.getExpression().accept(*this);
|
||||||
appendExternalFunctionCall(function, arguments, function.getLocation() == Location::Bare);
|
appendExternalFunctionCall(function, arguments);
|
||||||
break;
|
break;
|
||||||
case Location::Creation:
|
case Location::Creation:
|
||||||
{
|
{
|
||||||
@ -527,13 +529,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
TypePointers{},
|
TypePointers{},
|
||||||
strings(),
|
strings(),
|
||||||
strings(),
|
strings(),
|
||||||
Location::External,
|
Location::Bare,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true
|
true
|
||||||
),
|
),
|
||||||
{},
|
{}
|
||||||
true
|
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case Location::Suicide:
|
case Location::Suicide:
|
||||||
@ -622,7 +623,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
m_context << contractAddresses.find(function.getLocation())->second;
|
m_context << contractAddresses.find(function.getLocation())->second;
|
||||||
for (unsigned i = function.getSizeOnStack(); i > 0; --i)
|
for (unsigned i = function.getSizeOnStack(); i > 0; --i)
|
||||||
m_context << eth::swapInstruction(i);
|
m_context << eth::swapInstruction(i);
|
||||||
appendExternalFunctionCall(function, arguments, true);
|
appendExternalFunctionCall(function, arguments);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -685,7 +686,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
|||||||
IntegerType(0, IntegerType::Modifier::Address), true);
|
IntegerType(0, IntegerType::Modifier::Address), true);
|
||||||
m_context << eth::Instruction::BALANCE;
|
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(),
|
appendTypeConversion(*_memberAccess.getExpression().getType(),
|
||||||
IntegerType(0, IntegerType::Modifier::Address), true);
|
IntegerType(0, IntegerType::Modifier::Address), true);
|
||||||
else
|
else
|
||||||
@ -1031,9 +1032,10 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack)
|
|||||||
m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND;
|
m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functionType,
|
void ExpressionCompiler::appendExternalFunctionCall(
|
||||||
vector<ASTPointer<Expression const>> const& _arguments,
|
FunctionType const& _functionType,
|
||||||
bool bare)
|
vector<ASTPointer<Expression const>> const& _arguments
|
||||||
|
)
|
||||||
{
|
{
|
||||||
solAssert(_functionType.takesArbitraryParameters() ||
|
solAssert(_functionType.takesArbitraryParameters() ||
|
||||||
_arguments.size() == _functionType.getParameterTypes().size(), "");
|
_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 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 gasStackPos = m_context.currentToBaseStackOffset(gasValueSize);
|
||||||
unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
|
unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
|
||||||
|
|
||||||
@ -1057,7 +1059,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
|
|||||||
unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0;
|
unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0;
|
||||||
m_context << u256(retSize) << u256(0);
|
m_context << u256(retSize) << u256(0);
|
||||||
|
|
||||||
if (bare)
|
if (_functionType.isBareCall())
|
||||||
m_context << u256(0);
|
m_context << u256(0);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1074,7 +1076,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
|
|||||||
_arguments,
|
_arguments,
|
||||||
_functionType.getParameterTypes(),
|
_functionType.getParameterTypes(),
|
||||||
_functionType.padArguments(),
|
_functionType.padArguments(),
|
||||||
bare,
|
_functionType.getLocation() == FunctionType::Location::Bare ||
|
||||||
|
_functionType.getLocation() == FunctionType::Location::BareCallCode,
|
||||||
_functionType.takesArbitraryParameters()
|
_functionType.takesArbitraryParameters()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1093,14 +1096,20 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
|
|||||||
// send all gas except the amount needed to execute "SUB" and "CALL"
|
// 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.
|
// @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 << 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();
|
auto tag = m_context.appendConditionalJump();
|
||||||
m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0.
|
m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0.
|
||||||
if (_functionType.valueSet())
|
if (_functionType.valueSet())
|
||||||
m_context << eth::Instruction::POP;
|
m_context << eth::Instruction::POP;
|
||||||
if (_functionType.gasSet())
|
if (_functionType.gasSet())
|
||||||
m_context << eth::Instruction::POP;
|
m_context << eth::Instruction::POP;
|
||||||
if (!bare)
|
if (!_functionType.isBareCall())
|
||||||
m_context << eth::Instruction::POP;
|
m_context << eth::Instruction::POP;
|
||||||
m_context << eth::Instruction::POP; // pop contract address
|
m_context << eth::Instruction::POP; // pop contract address
|
||||||
|
|
||||||
|
@ -98,8 +98,10 @@ private:
|
|||||||
void appendHighBitsCleanup(IntegerType const& _typeOnStack);
|
void appendHighBitsCleanup(IntegerType const& _typeOnStack);
|
||||||
|
|
||||||
/// Appends code to call a function of the given type with the given arguments.
|
/// 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,
|
void appendExternalFunctionCall(
|
||||||
bool bare = false);
|
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
|
/// 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
|
/// 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
|
/// this call. If @a _padToWordBoundaries is set to false, all values are concatenated without
|
||||||
|
23
Types.cpp
23
Types.cpp
@ -316,6 +316,7 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
|
|||||||
const MemberList IntegerType::AddressMemberList({
|
const MemberList IntegerType::AddressMemberList({
|
||||||
{"balance", make_shared<IntegerType >(256)},
|
{"balance", make_shared<IntegerType >(256)},
|
||||||
{"call", make_shared<FunctionType>(strings(), strings(), FunctionType::Location::Bare, true)},
|
{"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)}
|
{"send", make_shared<FunctionType>(strings{"uint"}, strings{}, FunctionType::Location::Send)}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1115,9 +1116,11 @@ unsigned FunctionType::getSizeOnStack() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned size = 0;
|
unsigned size = 0;
|
||||||
if (location == Location::External)
|
if (location == Location::External || location == Location::CallCode)
|
||||||
size = 2;
|
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;
|
size = 1;
|
||||||
if (m_gasSet)
|
if (m_gasSet)
|
||||||
size++;
|
size++;
|
||||||
@ -1156,6 +1159,7 @@ MemberList const& FunctionType::getMembers() const
|
|||||||
case Location::SHA256:
|
case Location::SHA256:
|
||||||
case Location::RIPEMD160:
|
case Location::RIPEMD160:
|
||||||
case Location::Bare:
|
case Location::Bare:
|
||||||
|
case Location::BareCallCode:
|
||||||
if (!m_members)
|
if (!m_members)
|
||||||
{
|
{
|
||||||
MemberList::MemberMap 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
|
string FunctionType::externalSignature(std::string const& _name) const
|
||||||
{
|
{
|
||||||
std::string funcName = _name;
|
std::string funcName = _name;
|
||||||
|
37
Types.h
37
Types.h
@ -540,17 +540,32 @@ private:
|
|||||||
class FunctionType: public Type
|
class FunctionType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// The meaning of the value(s) on the stack referencing the function:
|
/// How this function is invoked on the EVM.
|
||||||
/// INTERNAL: jump tag, EXTERNAL: contract address + function identifier,
|
|
||||||
/// BARE: contract address (non-abi contract call)
|
|
||||||
/// OTHERS: special virtual function, nothing on the stack
|
|
||||||
/// @todo This documentation is outdated, and Location should rather be named "Type"
|
/// @todo This documentation is outdated, and Location should rather be named "Type"
|
||||||
enum class Location { Internal, External, Creation, Send,
|
enum class Location
|
||||||
SHA3, Suicide,
|
{
|
||||||
ECRecover, SHA256, RIPEMD160,
|
Internal, ///< stack-call using plain JUMP
|
||||||
Log0, Log1, Log2, Log3, Log4, Event,
|
External, ///< external call using CALL
|
||||||
SetGas, SetValue, BlockHash,
|
CallCode, ///< extercnal call using CALLCODE, i.e. not exchanging the storage
|
||||||
Bare };
|
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; }
|
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)
|
/// @returns true if the types of parameters are equal (does't check return parameter types)
|
||||||
bool hasEqualArgumentTypes(FunctionType const& _other) const;
|
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; }
|
Location const& getLocation() const { return m_location; }
|
||||||
/// @returns the external signature of this function type given the function name
|
/// @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
|
/// If @a _name is not provided (empty string) then the @c m_declaration member of the
|
||||||
|
Loading…
Reference in New Issue
Block a user