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

EIP214: STATICCALL #4057

Merged
merged 6 commits into from
May 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope this won't get us into trouble: We change for value transfer for callcode, although we do not consider it state changing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be the test case for this???

Copy link
Member

@pirapira pirapira May 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CALLCODE with positive value transfer... probably we already have it... but worth trying during STATICCALL.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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){}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@winsvega you forgot to update jsontests.


//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