Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Commit

Permalink
Merge pull request #4057 from ethereum/staticcall
Browse files Browse the repository at this point in the history
EIP214: STATICCALL
  • Loading branch information
chfast authored May 24, 2017
2 parents b428693 + 4e38b30 commit 49cdc48
Show file tree
Hide file tree
Showing 15 changed files with 82 additions and 22 deletions.
2 changes: 1 addition & 1 deletion libethereum/Executive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co
{
bytes const& c = m_s.code(_p.codeAddress);
h256 codeHash = m_s.codeHash(_p.codeAddress);
m_ext = make_shared<ExtVM>(m_s, m_envInfo, m_sealEngine, _p.receiveAddress, _p.senderAddress, _origin, _p.apparentValue, _gasPrice, _p.data, &c, codeHash, m_depth);
m_ext = make_shared<ExtVM>(m_s, m_envInfo, m_sealEngine, _p.receiveAddress, _p.senderAddress, _origin, _p.apparentValue, _gasPrice, _p.data, &c, codeHash, m_depth, _p.staticCall);
}
}

Expand Down
4 changes: 2 additions & 2 deletions libethereum/ExtVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class ExtVM: public ExtVMFace
{
public:
/// Full constructor.
ExtVM(State& _s, EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, h256 const& _codeHash, unsigned _depth = 0):
ExtVMFace(_envInfo, _myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _codeHash, _depth), m_s(_s), m_sealEngine(_sealEngine)
ExtVM(State& _s, EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, h256 const& _codeHash, unsigned _depth = 0, bool _staticCall = false):
ExtVMFace(_envInfo, _myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _codeHash, _depth, _staticCall), m_s(_s), m_sealEngine(_sealEngine)
{
// Contract: processing account must exist. In case of CALL, the ExtVM
// is created only if an account has code (so exist). In case of CREATE
Expand Down
5 changes: 3 additions & 2 deletions libevm/ExtVMFace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
using namespace dev;
using namespace dev::eth;

ExtVMFace::ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, unsigned _depth):
ExtVMFace::ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, unsigned _depth, bool _staticCall):
m_envInfo(_envInfo),
myAddress(_myAddress),
caller(_caller),
Expand All @@ -34,5 +34,6 @@ ExtVMFace::ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _calle
data(_data),
code(std::move(_code)),
codeHash(_codeHash),
depth(_depth)
depth(_depth),
staticCall(_staticCall)
{}
16 changes: 15 additions & 1 deletion libevm/ExtVMFace.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,13 +194,26 @@ using OnOpFunc = std::function<void(uint64_t /*steps*/, uint64_t /* PC */, Instr

struct CallParameters
{
CallParameters() = default;
CallParameters(
Address _senderAddress,
Address _codeAddress,
Address _receiveAddress,
u256 _valueTransfer,
u256 _apparentValue,
u256 _gas,
bytesConstRef _data,
OnOpFunc _onOpFunc
): senderAddress(_senderAddress), codeAddress(_codeAddress), receiveAddress(_receiveAddress),
valueTransfer(_valueTransfer), apparentValue(_apparentValue), gas(_gas), data(_data), onOp(_onOpFunc) {}
Address senderAddress;
Address codeAddress;
Address receiveAddress;
u256 valueTransfer;
u256 apparentValue;
u256 gas;
bytesConstRef data;
bool staticCall = false;
OnOpFunc onOp;
};

Expand Down Expand Up @@ -245,7 +258,7 @@ class ExtVMFace
ExtVMFace() = default;

/// Full constructor.
ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, unsigned _depth);
ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, unsigned _depth, bool _staticCall);

virtual ~ExtVMFace() = default;

Expand Down Expand Up @@ -307,6 +320,7 @@ class ExtVMFace
h256 codeHash; ///< SHA3 hash of the executing code
SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).
unsigned depth = 0; ///< Depth of the present call.
bool staticCall = false; ///< Throw on state changing.
};

}
Expand Down
36 changes: 31 additions & 5 deletions libevm/VM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,19 +214,24 @@ void VM::interpretCases()

CASE(CREATE)
{
if (m_ext->staticCall)
throwDisallowedStateChange();

m_bounce = &VM::caseCreate;
}
BREAK

CASE(DELEGATECALL)

// Pre-homestead
if (!m_schedule->haveDelegateCall)
throwBadInstruction();

CASE(STATICCALL)
CASE(CALL)
CASE(CALLCODE)
{
if (m_OP == Instruction::DELEGATECALL && !m_schedule->haveDelegateCall)
throwBadInstruction();
if (m_OP == Instruction::STATICCALL && !m_schedule->haveStaticCall)
throwBadInstruction();
if (m_OP == Instruction::CALL && m_ext->staticCall && m_SP[2] != 0)
throwDisallowedStateChange();
m_bounce = &VM::caseCall;
}
BREAK
Expand Down Expand Up @@ -265,6 +270,9 @@ void VM::interpretCases()

CASE(SUICIDE)
{
if (m_ext->staticCall)
throwDisallowedStateChange();

m_runGas = toInt63(m_schedule->suicideGas);
Address dest = asAddress(m_SP[0]);

Expand Down Expand Up @@ -340,6 +348,9 @@ void VM::interpretCases()

CASE(LOG0)
{
if (m_ext->staticCall)
throwDisallowedStateChange();

logGasMem();
ON_OP();
updateIOGas();
Expand All @@ -350,6 +361,9 @@ void VM::interpretCases()

CASE(LOG1)
{
if (m_ext->staticCall)
throwDisallowedStateChange();

logGasMem();
ON_OP();
updateIOGas();
Expand All @@ -360,6 +374,9 @@ void VM::interpretCases()

CASE(LOG2)
{
if (m_ext->staticCall)
throwDisallowedStateChange();

logGasMem();
ON_OP();
updateIOGas();
Expand All @@ -370,6 +387,9 @@ void VM::interpretCases()

CASE(LOG3)
{
if (m_ext->staticCall)
throwDisallowedStateChange();

logGasMem();
ON_OP();
updateIOGas();
Expand All @@ -380,6 +400,9 @@ void VM::interpretCases()

CASE(LOG4)
{
if (m_ext->staticCall)
throwDisallowedStateChange();

logGasMem();
ON_OP();
updateIOGas();
Expand Down Expand Up @@ -1093,6 +1116,9 @@ void VM::interpretCases()

CASE(SSTORE)
{
if (m_ext->staticCall)
throwDisallowedStateChange();

if (!m_ext->store(m_SP[0]) && m_SP[1])
m_runGas = toInt63(m_schedule->sstoreSetGas);
else if (m_ext->store(m_SP[0]) && !m_SP[1])
Expand Down
1 change: 1 addition & 0 deletions libevm/VM.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class VM: public VMFace
void throwBadJumpDestination();
void throwBadStack(unsigned _removed, unsigned _added);
void throwRevertInstruction(owning_bytes_ref&& _output);
void throwDisallowedStateChange();

void reportStackUse();

Expand Down
22 changes: 16 additions & 6 deletions libevm/VMCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ void VM::throwBadJumpDestination()
BOOST_THROW_EXCEPTION(BadJumpDestination());
}

void VM::throwDisallowedStateChange()
{
if (m_onFail)
(this->*m_onFail)();
BOOST_THROW_EXCEPTION(DisallowedStateChange());
}

void VM::throwBadStack(unsigned _removed, unsigned _added)
{
bigint size = m_stackEnd - m_SPP;
Expand Down Expand Up @@ -182,14 +189,17 @@ bool VM::caseCallSetup(CallParameters *callParams, bytesRef& o_output)
{
m_runGas = toInt63(m_schedule->callGas);

if (m_OP == Instruction::CALL && !m_ext->exists(asAddress(m_SP[1])))
callParams->staticCall = (m_OP == Instruction::STATICCALL || m_ext->staticCall);

Address destinationAddr = asAddress(m_SP[1]);
if (m_OP == Instruction::CALL && !m_ext->exists(destinationAddr))
if (m_SP[2] > 0 || m_schedule->zeroValueTransferChargesNewAccountGas())
m_runGas += toInt63(m_schedule->callNewAccountGas);

if (m_OP != Instruction::DELEGATECALL && m_SP[2] > 0)
if ((m_OP == Instruction::CALL || m_OP == Instruction::CALLCODE) && m_SP[2] > 0)
m_runGas += toInt63(m_schedule->callValueTransferGas);

size_t sizesOffset = m_OP == Instruction::DELEGATECALL ? 2 : 3;
size_t sizesOffset = (m_OP == Instruction::DELEGATECALL || m_OP == Instruction::STATICCALL) ? 2 : 3;
u256 inputOffset = m_SP[sizesOffset];
u256 inputSize = m_SP[sizesOffset + 1];
u256 outputOffset = m_SP[sizesOffset + 2];
Expand Down Expand Up @@ -221,10 +231,10 @@ bool VM::caseCallSetup(CallParameters *callParams, bytesRef& o_output)
if (m_OP != Instruction::DELEGATECALL && m_SP[2] > 0)
callParams->gas += m_schedule->callStipend;

callParams->codeAddress = asAddress(m_SP[1]);
callParams->codeAddress = destinationAddr;

unsigned inOutOffset = 0;
if (m_OP == Instruction::DELEGATECALL)
if (m_OP == Instruction::DELEGATECALL || m_OP == Instruction::STATICCALL)
{
callParams->apparentValue = m_ext->value;
callParams->valueTransfer = 0;
Expand All @@ -244,7 +254,7 @@ bool VM::caseCallSetup(CallParameters *callParams, bytesRef& o_output)
{
callParams->onOp = m_onOp;
callParams->senderAddress = m_OP == Instruction::DELEGATECALL ? m_ext->caller : m_ext->myAddress;
callParams->receiveAddress = m_OP == Instruction::CALL ? callParams->codeAddress : m_ext->myAddress;
callParams->receiveAddress = (m_OP == Instruction::CALL || m_OP == Instruction::STATICCALL) ? callParams->codeAddress : m_ext->myAddress;
callParams->data = bytesConstRef(m_mem.data() + inOff, inSize);
o_output = bytesRef(m_mem.data() + outOff, outSize);
return true;
Expand Down
1 change: 1 addition & 0 deletions libevm/VMFace.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ ETH_SIMPLE_EXCEPTION_VM(BadJumpDestination);
ETH_SIMPLE_EXCEPTION_VM(OutOfGas);
ETH_SIMPLE_EXCEPTION_VM(OutOfStack);
ETH_SIMPLE_EXCEPTION_VM(StackUnderflow);
ETH_SIMPLE_EXCEPTION_VM(DisallowedStateChange);

struct RevertInstruction: VMException
{
Expand Down
2 changes: 2 additions & 0 deletions libevmcore/EVMSchedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ struct EVMSchedule
bool eip158Mode = false;
bool haveRevert = false;
bool haveReturnData = false;
bool haveStaticCall = false;
std::array<unsigned, 8> tierStepGas;
unsigned expGas = 10;
unsigned expByteGas = 10;
Expand Down Expand Up @@ -111,6 +112,7 @@ static const EVMSchedule MetropolisSchedule = []
EVMSchedule schedule = EIP158Schedule;
schedule.haveRevert = true;
schedule.haveReturnData = true;
schedule.haveStaticCall = true;
return schedule;
}();

Expand Down
1 change: 1 addition & 0 deletions libevmcore/Instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::CALL, { "CALL", 0, 7, 1, true, Tier::Special } },
{ Instruction::CALLCODE, { "CALLCODE", 0, 7, 1, true, Tier::Special } },
{ Instruction::RETURN, { "RETURN", 0, 2, 0, true, Tier::Zero } },
{ Instruction::STATICCALL, { "STATICCALL", 0, 6, 1, true, Tier::Special } },
{ Instruction::DELEGATECALL, { "DELEGATECALL", 0, 6, 1, true, Tier::Special } },
{ Instruction::REVERT, { "REVERT", 0, 2, 0, true, Tier::Special } },
{ Instruction::INVALID, { "INVALID", 0, 0, 0, true, Tier::Zero } },
Expand Down
1 change: 1 addition & 0 deletions libevmcore/Instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ enum class Instruction: uint8_t
CALLCODE, ///< message-call with another account's code only
RETURN, ///< halt execution returning output data
DELEGATECALL, ///< like CALLCODE but keeps caller's value and sender
STATICCALL = 0xfa, ///< like CALL except state changing operation are not permitted (will throw)
REVERT = 0xfd, ///< stop execution and revert state changes, without consuming all provided gas
INVALID = 0xfe, ///< dedicated invalid instruction
SUICIDE = 0xff ///< halt execution and register account for later deletion
Expand Down
8 changes: 5 additions & 3 deletions scripts/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ if [[ "$TESTS" == "On" ]]; then
# The whole automation process is too slow for macOS, and we don't have
# enough time to build LLVM, build EVMJIT and run the tests twice within
# the 48 minute absolute maximum run time for TravisCI.
if [[ "$OSTYPE" != "darwin"* ]]; then
$BUILD_ROOT/test/testeth -t "VMTests*,StateTests*" -- --vm jit --testpath $BUILD_ROOT/../test/jsontests
fi

# Disabled until EVMJIT will catch up with Metropolis features.
# if [[ "$OSTYPE" != "darwin"* ]]; then
# $BUILD_ROOT/test/testeth -t "VMTests*,StateTests*" -- --vm jit --testpath $BUILD_ROOT/../test/jsontests
# fi

fi
2 changes: 1 addition & 1 deletion test/jsontests
Submodule jsontests updated 2387 files
1 change: 1 addition & 0 deletions test/tools/jsontests/StateTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ BOOST_AUTO_TEST_CASE(stRevertTest){}

//Metropolis Tests
BOOST_AUTO_TEST_CASE(stStackTests){}
BOOST_AUTO_TEST_CASE(stStaticCall){}

//Stress Tests
BOOST_AUTO_TEST_CASE(stAttackTest){}
Expand Down
2 changes: 1 addition & 1 deletion test/tools/jsontests/vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ using namespace dev::eth;
using namespace dev::test;

FakeExtVM::FakeExtVM(EnvInfo const& _envInfo, unsigned _depth): /// TODO: XXX: remove the default argument & fix.
ExtVMFace(_envInfo, Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _depth)
ExtVMFace(_envInfo, Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, false, _depth)
{}

std::pair<h160, eth::owning_bytes_ref> FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&)
Expand Down

0 comments on commit 49cdc48

Please sign in to comment.