mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #2096 from chriseth/sol_constantFallback
Fallback takes constant amount of gas, and send no gas with send.
This commit is contained in:
commit
b51ef4a357
16
Compiler.cpp
16
Compiler.cpp
@ -178,6 +178,16 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
|
|||||||
map<FixedHash<4>, FunctionTypePointer> interfaceFunctions = _contract.getInterfaceFunctions();
|
map<FixedHash<4>, FunctionTypePointer> interfaceFunctions = _contract.getInterfaceFunctions();
|
||||||
map<FixedHash<4>, const eth::AssemblyItem> callDataUnpackerEntryPoints;
|
map<FixedHash<4>, const eth::AssemblyItem> callDataUnpackerEntryPoints;
|
||||||
|
|
||||||
|
FunctionDefinition const* fallback = _contract.getFallbackFunction();
|
||||||
|
eth::AssemblyItem notFound = m_context.newTag();
|
||||||
|
// shortcut messages without data if we have many functions in order to be able to receive
|
||||||
|
// ether with constant gas
|
||||||
|
if (interfaceFunctions.size() > 5 || fallback)
|
||||||
|
{
|
||||||
|
m_context << eth::Instruction::CALLDATASIZE << eth::Instruction::ISZERO;
|
||||||
|
m_context.appendConditionalJumpTo(notFound);
|
||||||
|
}
|
||||||
|
|
||||||
// retrieve the function signature hash from the calldata
|
// retrieve the function signature hash from the calldata
|
||||||
if (!interfaceFunctions.empty())
|
if (!interfaceFunctions.empty())
|
||||||
CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true);
|
CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true);
|
||||||
@ -189,7 +199,10 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
|
|||||||
m_context << eth::dupInstruction(1) << u256(FixedHash<4>::Arith(it.first)) << eth::Instruction::EQ;
|
m_context << eth::dupInstruction(1) << u256(FixedHash<4>::Arith(it.first)) << eth::Instruction::EQ;
|
||||||
m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.at(it.first));
|
m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.at(it.first));
|
||||||
}
|
}
|
||||||
if (FunctionDefinition const* fallback = _contract.getFallbackFunction())
|
m_context.appendJumpTo(notFound);
|
||||||
|
|
||||||
|
m_context << notFound;
|
||||||
|
if (fallback)
|
||||||
{
|
{
|
||||||
eth::AssemblyItem returnTag = m_context.pushNewTag();
|
eth::AssemblyItem returnTag = m_context.pushNewTag();
|
||||||
fallback->accept(*this);
|
fallback->accept(*this);
|
||||||
@ -198,6 +211,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_context << eth::Instruction::STOP; // function not found
|
m_context << eth::Instruction::STOP; // function not found
|
||||||
|
|
||||||
for (auto const& it: interfaceFunctions)
|
for (auto const& it: interfaceFunctions)
|
||||||
{
|
{
|
||||||
FunctionTypePointer const& functionType = it.second;
|
FunctionTypePointer const& functionType = it.second;
|
||||||
|
@ -521,6 +521,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
break;
|
break;
|
||||||
case Location::Send:
|
case Location::Send:
|
||||||
_functionCall.getExpression().accept(*this);
|
_functionCall.getExpression().accept(*this);
|
||||||
|
m_context << u256(0); // do not send gas (there still is the stipend)
|
||||||
arguments.front()->accept(*this);
|
arguments.front()->accept(*this);
|
||||||
appendTypeConversion(*arguments.front()->getType(),
|
appendTypeConversion(*arguments.front()->getType(),
|
||||||
*function.getParameterTypes().front(), true);
|
*function.getParameterTypes().front(), true);
|
||||||
@ -532,7 +533,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
strings(),
|
strings(),
|
||||||
Location::Bare,
|
Location::Bare,
|
||||||
false,
|
false,
|
||||||
false,
|
true,
|
||||||
true
|
true
|
||||||
),
|
),
|
||||||
{}
|
{}
|
||||||
@ -1057,10 +1058,15 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize);
|
unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize);
|
||||||
unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
|
unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
|
||||||
|
|
||||||
|
bool returnSuccessCondition =
|
||||||
|
_functionType.getLocation() == FunctionType::Location::Bare ||
|
||||||
|
_functionType.getLocation() == FunctionType::Location::BareCallCode;
|
||||||
//@todo only return the first return value for now
|
//@todo only return the first return value for now
|
||||||
Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr :
|
Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr :
|
||||||
_functionType.getReturnParameterTypes().front().get();
|
_functionType.getReturnParameterTypes().front().get();
|
||||||
unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0;
|
unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0;
|
||||||
|
if (returnSuccessCondition)
|
||||||
|
retSize = 0; // return value actually is success condition
|
||||||
m_context << u256(retSize) << u256(0);
|
m_context << u256(retSize) << u256(0);
|
||||||
|
|
||||||
if (_functionType.isBareCall())
|
if (_functionType.isBareCall())
|
||||||
@ -1111,19 +1117,28 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
else
|
else
|
||||||
m_context << eth::Instruction::CALL;
|
m_context << eth::Instruction::CALL;
|
||||||
|
|
||||||
|
unsigned remainsSize =
|
||||||
|
1 + // contract address
|
||||||
|
_functionType.valueSet() +
|
||||||
|
_functionType.gasSet() +
|
||||||
|
!_functionType.isBareCall();
|
||||||
|
|
||||||
|
if (returnSuccessCondition)
|
||||||
|
m_context << eth::swapInstruction(remainsSize);
|
||||||
|
else
|
||||||
|
{
|
||||||
//Propagate error condition (if CALL pushes 0 on stack).
|
//Propagate error condition (if CALL pushes 0 on stack).
|
||||||
m_context << eth::Instruction::ISZERO;
|
m_context << eth::Instruction::ISZERO;
|
||||||
m_context.appendConditionalJumpTo(m_context.errorTag());
|
m_context.appendConditionalJumpTo(m_context.errorTag());
|
||||||
|
}
|
||||||
|
|
||||||
if (_functionType.valueSet())
|
CompilerUtils(m_context).popStackSlots(remainsSize);
|
||||||
m_context << eth::Instruction::POP;
|
|
||||||
if (_functionType.gasSet())
|
|
||||||
m_context << eth::Instruction::POP;
|
|
||||||
if (!_functionType.isBareCall())
|
|
||||||
m_context << eth::Instruction::POP;
|
|
||||||
m_context << eth::Instruction::POP; // pop contract address
|
|
||||||
|
|
||||||
if (_functionType.getLocation() == FunctionType::Location::RIPEMD160)
|
if (returnSuccessCondition)
|
||||||
|
{
|
||||||
|
// already there
|
||||||
|
}
|
||||||
|
else if (_functionType.getLocation() == FunctionType::Location::RIPEMD160)
|
||||||
{
|
{
|
||||||
// fix: built-in contract returns right-aligned data
|
// fix: built-in contract returns right-aligned data
|
||||||
CompilerUtils(m_context).loadFromMemory(0, IntegerType(160), false, true);
|
CompilerUtils(m_context).loadFromMemory(0, IntegerType(160), false, true);
|
||||||
|
@ -317,9 +317,9 @@ 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{"bool"}, FunctionType::Location::Bare, true)},
|
||||||
{"callcode", make_shared<FunctionType>(strings(), strings(), FunctionType::Location::BareCallCode, true)},
|
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareCallCode, true)},
|
||||||
{"send", make_shared<FunctionType>(strings{"uint"}, strings{}, FunctionType::Location::Send)}
|
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)}
|
||||||
});
|
});
|
||||||
|
|
||||||
IntegerConstantType::IntegerConstantType(Literal const& _literal)
|
IntegerConstantType::IntegerConstantType(Literal const& _literal)
|
||||||
|
Loading…
Reference in New Issue
Block a user