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

EIP211: RETURNDATA #4062

Merged
merged 10 commits into from
May 18, 2017
Merged

EIP211: RETURNDATA #4062

merged 10 commits into from
May 18, 2017

Conversation

chfast
Copy link
Member

@chfast chfast commented Apr 25, 2017

@chfast chfast added this to the Metropolis milestone Apr 25, 2017
@yann300 yann300 self-assigned this Apr 27, 2017
@chfast chfast self-assigned this May 5, 2017
@codecov-io
Copy link

codecov-io commented May 5, 2017

Codecov Report

Merging #4062 into develop will decrease coverage by 0.06%.
The diff coverage is 53.33%.

@@             Coverage Diff             @@
##           develop    #4062      +/-   ##
===========================================
- Coverage    65.92%   65.85%   -0.07%     
===========================================
  Files          308      308              
  Lines        22905    22913       +8     
===========================================
- Hits         15100    15090      -10     
- Misses        7805     7823      +18
Impacted Files Coverage Δ
libevmcore/Instruction.cpp 47.5% <ø> (+9.03%) ⬆️
libevm/VM.h 76.92% <ø> (ø) ⬆️
test/tools/jsontests/vm.h 100% <ø> (ø) ⬆️
libethereum/ExtVM.h 100% <ø> (ø) ⬆️
libevm/VMOpt.cpp 87.23% <ø> (ø) ⬆️
libevm/ExtVMFace.h 80.3% <ø> (+1.19%) ⬆️
libevmcore/Instruction.h 100% <ø> (ø) ⬆️
libevm/VM.cpp 91.4% <0%> (-2.91%) ⬇️
libevmcore/EVMSchedule.h 100% <100%> (ø) ⬆️
libethereum/ExtVM.cpp 95.12% <100%> (ø) ⬆️
... and 7 more

@chfast chfast assigned winsvega and unassigned chfast and yann300 May 5, 2017
@chfast
Copy link
Member Author

chfast commented May 5, 2017

@winsvega can you generate tests for this?

libevm/VM.h Outdated
@@ -104,6 +104,9 @@ class VM: public VMFace
// space for code
bytes m_code;

/// Space for return data.
Copy link
Member

Choose a reason for hiding this comment

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

Why three /s? (I was not looking for them but I saw them.)

Copy link
Member Author

Choose a reason for hiding this comment

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

/// starts a Doxygen comment.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe clarify that this is for the data returned from the subcall.
Because now we have m_output described as "return bytes" and m_returnedData described as "return data", this is confusing if you don't know what's it all about

@@ -204,6 +54,8 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::ADDMOD, { "ADDMOD", 0, 3, 1, false, Tier::Mid } },
{ Instruction::MULMOD, { "MULMOD", 0, 3, 1, false, Tier::Mid } },
{ Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1, false, Tier::Low } },
{ Instruction::RETURNDATASIZE,{"RETURNDATASIZE", 0, 0, 1, false, Tier::Low } },
{ Instruction::RETURNDATACOPY,{"RETURNDATACOPY", 0, 3, 0, false, Tier::Low } },
Copy link
Member

Choose a reason for hiding this comment

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

Why do the Tiers look different from those of CALLDATASIZE and CALLDATACOPY?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think I was so focused on setting the number of args right I forgot about the costs.

@@ -204,6 +54,8 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::ADDMOD, { "ADDMOD", 0, 3, 1, false, Tier::Mid } },
{ Instruction::MULMOD, { "MULMOD", 0, 3, 1, false, Tier::Mid } },
{ Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1, false, Tier::Low } },
{ Instruction::RETURNDATASIZE,{"RETURNDATASIZE", 0, 0, 1, false, Tier::VeryLow } },
Copy link
Member

Choose a reason for hiding this comment

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

Are the prices still not right? Tier::VeryLow is 3, but RETURNDATASIZE should be 2, which is Tier::Base, like CALLDATASIZE
And RETURNDATACOPY should be Tier::VeryLow ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Of course. I'm really sorry, I must have been distracted. BTW, "side effect" is not used, but this should be addressed in #4072.

@@ -204,6 +54,8 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::ADDMOD, { "ADDMOD", 0, 3, 1, false, Tier::Mid } },
{ Instruction::MULMOD, { "MULMOD", 0, 3, 1, false, Tier::Mid } },
{ Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1, false, Tier::Low } },
{ Instruction::RETURNDATASIZE,{"RETURNDATASIZE", 0, 0, 1, false, Tier::VeryLow } },
{ Instruction::RETURNDATACOPY,{"RETURNDATACOPY", 0, 3, 0, false, Tier::Low } },
Copy link
Member

Choose a reason for hiding this comment

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

I guess it should have true for side-effects like CALLDATACOPY

bytesRef output;
if (caseCallSetup(callParams.get(), output))
{
std::pair<bool, owning_bytes_ref> callResult = m_ext->call(*callParams);
callResult.second.copyTo(output);
m_returnData.assign(callResult.second.begin(), callResult.second.end());
Copy link
Member

Choose a reason for hiding this comment

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

Could we define m_returnData as owning_bytes_ref and then move here instead of copying?

(if not, using helpers like owning_bytes_ref::toBytes probably would make this expression simpler)

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not a big fun of helpers like toBytes, usually C++ std lib should be enough. But the question is: should we keep the full memory buffer (owning_bytes_ref) or copy only the return buffer.

Copy link
Member Author

Choose a reason for hiding this comment

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

Anyway, refactored.

bool success = false;
owning_bytes_ref outputRef;
std::tie(success, outputRef) = m_ext->call(*callParams);
outputRef.copyTo(output);
Copy link
Member

Choose a reason for hiding this comment

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

Am I mistaken that output is only written to but not read from? (This didn't change in this commit, but I started wondering now.)

Copy link
Member

Choose a reason for hiding this comment

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

Ah, it's the caller's memory!

Copy link
Member Author

Choose a reason for hiding this comment

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

Magic. The output is actually a memory reference initialized in caseCallSetup(). This is exactly CALL output buffer, might be of length 0 depending on CALL arguments. Here we copy the data there according to what the CALL requested.

@chfast
Copy link
Member Author

chfast commented May 11, 2017

Big thanks for reviewing this.
Should we wait for tests and finalization of the spec (opcode numbers are to be changes, and decision about copying out of buffer)?

@gumb0
Copy link
Member

gumb0 commented May 11, 2017

I would better merge now, then fix what changed later

ON_OP();
updateIOGas();

copyDataToMemory(&m_returnData, m_SP);
Copy link
Member

Choose a reason for hiding this comment

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

Not strictly connected to this PR, but probably it would be better to have the offset + size as explicit parameters in copyDataToMemory.

@@ -120,6 +120,9 @@ void VM::caseCreate()
uint64_t initOff = (uint64_t)m_SP[1];
uint64_t initSize = (uint64_t)m_SP[2];

// Clear the return data buffer. This will not free the memory.
m_returnData.clear();

Copy link
Member

Choose a reason for hiding this comment

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

When the contract initialization executes REVERT, m_returnData has to be set.

Copy link
Member

Choose a reason for hiding this comment

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

See the last sentence on this line: https://github.com/ethereum/EIPs/pull/211/files#diff-fd8c393953fe66162d8bb518d87bfb57R32

(That's something I learned while doing YP.)

Copy link
Member Author

Choose a reason for hiding this comment

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

Implemented.

Copy link
Member

@gumb0 gumb0 left a comment

Choose a reason for hiding this comment

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

Need to update return buffer after CREATE

owning_bytes_ref revertOutput;
std::tie(addr, revertOutput) = m_ext->create(endowment, gas, bytesConstRef(m_mem.data() + initOff, initSize), m_onOp);
m_SPP[0] = (u160)addr;
m_returnData = revertOutput.toBytes();
Copy link
Member

Choose a reason for hiding this comment

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

When the creation succeeds, does this set the deployed code in the buffer?

Copy link
Member Author

Choose a reason for hiding this comment

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

No. Executive handles this. For CREATE, the VM output is only taken in case of REVERT. https://github.com/ethereum/cpp-ethereum/blob/develop/libethereum/Executive.cpp#L411.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I see. I've opened the same file in the editor but I was not quite seeing it.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's my role to explain the changes.

libevm/JitVM.cpp Outdated
auto addr = env.create(value, gas, input, {});
h160 addr;
owning_bytes_ref revertOutput;
std::tie(addr, revertOutput) = env.create(value, gas, input, {});
Copy link
Member

Choose a reason for hiding this comment

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

revertOutput is not used after create, is this correct?

Copy link
Member Author

Choose a reason for hiding this comment

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

At the moment it is. EVM-C does not support "revert output" yet so there is not option to pass this back to EVMJIT. But EVM-C v4 changes are in progress.

Copy link
Member

Choose a reason for hiding this comment

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

I'd use std::ignore while this is the case.

@@ -47,6 +47,9 @@ enum class Instruction: uint8_t
EXP, ///< exponential operation
SIGNEXTEND, ///< extend length of signed integer

RETURNDATASIZE = 0x0d, ///< size of data returned from previous call
RETURNDATACOPY = 0x0e, ///< copy data returned from previous call to memory
Copy link
Member

Choose a reason for hiding this comment

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

The opcodes seem to have changed: ethereum/solidity#2275 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

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

Not in the EIP PR.

if (m_ext->balance(m_ext->myAddress) >= endowment && m_ext->depth < 1024)
{
*m_io_gas_p = m_io_gas;
u256 createGas = *m_io_gas_p;
if (!m_schedule->staticCallDepthLimit())
createGas -= createGas / 64;
u256 gas = createGas;
m_SPP[0] = (u160)m_ext->create(endowment, gas, bytesConstRef(m_mem.data() + initOff, initSize), m_onOp);
h160 addr;
owning_bytes_ref revertOutput;
Copy link
Member

Choose a reason for hiding this comment

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

Maybe name it just output? Because revertOutput is kind of assuming how create works internally and that only REVERT can return data. Which is the case now, but could change in the furure

@gumb0
Copy link
Member

gumb0 commented May 17, 2017

Looks good now, just a couple of minor comments.

@gumb0
Copy link
Member

gumb0 commented May 17, 2017

@yann300 take a look at changes in ExtVM::create here, you'll probably need to rebase on that if we merge this first

@chfast
Copy link
Member Author

chfast commented May 17, 2017

Ok, I will try to apply suggestions as soon as possible.

@chfast
Copy link
Member Author

chfast commented May 18, 2017

Ready to land?

@pirapira
Copy link
Member

@chriseth is changing the EIP.

@chfast
Copy link
Member Author

chfast commented May 18, 2017

@gumb0 @pirapira @chriseth I'm for merging this as is, and implement the final decision about throwing on out-of-range reads when the decision is made. If you agree, please press the Merge button.

@gumb0 gumb0 merged commit acfbe83 into develop May 18, 2017
@pirapira pirapira deleted the returndata branch May 24, 2017 13:04
This pull request was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants