Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cancun): EIP-5656: MCOPY - Memory copying instruction #528

Merged
merged 19 commits into from
Jul 1, 2023

Conversation

0xJepsen
Copy link
Contributor

Started working on this. Still needs work.

Will Close #523

InstructionResult::InvalidOperandOOG
);
let (data_end, overflow) = dest.overflowing_add(len);
if overflow || data_end > interpreter.return_data_buffer.len() {
Copy link
Member

Choose a reason for hiding this comment

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

wait silly question but isn't mcopy just copying data from memory to memory and not from return data buffer.

You should have memory_resize somewhere here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah this is correct.

interpreter.instruction_result = InstructionResult::OutOfOffset;
return;
}
interpreter.memory.set_data(src, dest, len, &interpreter.contract.input);
Copy link
Member

Choose a reason for hiding this comment

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

And here we are coping the contract.input that is different from the thing we check above

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep this is right, i read the memory from slice to pass the right data here

Copy link
Member

@rakita rakita left a comment

Choose a reason for hiding this comment

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

left few comments

@rakita rakita changed the title first pass feat(cancun): EIP-5656: MCOPY - Memory copying instruction Jun 21, 2023
@0xJepsen
Copy link
Contributor Author

left few comments

Awesome thanks for the comments. Will work some more on this today

InstructionResult::InvalidOperandOOG
);
// Read data with length len from src
let data = interpreter.memory.clone();
Copy link
Member

Choose a reason for hiding this comment

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

Cloning memory is a no go, it is expensive.

You could probably add copy function to memory that would done copying. Just figure out how to do in in place with vec

dest,
InstructionResult::InvalidOperandOOG
);
memory_resize!(interpreter, dest, len);
Copy link
Member

Choose a reason for hiding this comment

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

I would assume that both dest and src can increment memory. So you need to find what is bigger and increment memory by a bigger value

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I made a function to check and handle this memory_copy_resize that was inspired by the geth pr's implementation in the memory_table.go

/// Copies memory inplace to a returns a [u8]
#[inline(always)]
pub fn copy(&self, offset: usize, size: usize) -> [u8; 32] {
let mut copy = [0u8; 32];
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks like copy_word because copy is only 32, it should be size

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed this with returning a vec of bytes and then passing as a slice to the data

@0xJepsen
Copy link
Contributor Author

So the thing i want to try and fix now is that the memory_copy_resize has some nasty unwraps because the peek returns a result. I thought to use the peek because its how i was reading the Back method in the go implementation. But im not sure we have a similar implementation. I could try to write a something with similar functionality. What do you think?

@0xJepsen
Copy link
Contributor Author

0xJepsen commented Jun 24, 2023

So the thing i want to try and fix now is that the memory_copy_resize has some nasty unwraps because the peek returns a result. I thought to use the peek because its how i was reading the Back method in the go implementation. But im not sure we have a similar implementation. I could try to write a something with similar functionality. What do you think?

In the geth implementation they validate the stack length in the interpreter here
https://github.com/ethereum/go-ethereum/blob/942ba4ddaa0e2591b77a42f40059babbaaa44154/core/vm/interpreter.go#L183C1-L187C4

Where as we are doing it in the peek() implementation which is why we get a result there

interpreter.memory.set_data(src, dest, len, data);
}

pub fn memory_copy_resize(interpreter: &mut Interpreter, _host: &mut dyn Host) {
Copy link
Member

@rakita rakita Jun 26, 2023

Choose a reason for hiding this comment

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

This is faulty, and you already have dest,src, len in fn mcopy so this fn is not needed. What is needed is to memory_resize


let src = as_usize_or_fail!(interpreter, src, InstructionResult::InvalidOperandOOG);
// Read data with length len from src
let binding = interpreter.memory.copy_to_vec(src, len);
Copy link
Member

Choose a reason for hiding this comment

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

It is not optimal to create temporary vec. There is a memory operation from C that does copying of overlapping data so I assume there is something similar in rust. Make memory.copy that does internal copying of data.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I found and used copy_within
https://doc.rust-lang.org/std/ptr/fn.copy.html

Copy link
Member

Choose a reason for hiding this comment

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

This works perfectly

pub fn mcopy<SPEC: Spec>(interpreter: &mut Interpreter, host: &mut dyn Host) {
check!(interpreter, SPEC::enabled(CANCUN));
pop!(interpreter, dest, src, len);
if len == U256::ZERO {
Copy link
Member

Choose a reason for hiding this comment

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

This is not correct, even if len is zero, some gas needs to be deduced.
maybe it is best to check if len == 0 after [gas_or_fail](gas::verylowcopy_cost) is added.

Comment on lines 68 to 69
}

Copy link
Member

Choose a reason for hiding this comment

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

nit: add new line here.

@rakita
Copy link
Member

rakita commented Jun 27, 2023

I think we are close!

@0xJepsen
Copy link
Contributor Author

0xJepsen commented Jun 27, 2023

I think we are close!

Awesome, thanks for all the feedback! it's been really helpful in learning all the details here. Let me know if there are any more problems you see here.

@rakita
Copy link
Member

rakita commented Jun 28, 2023

I think we are close!

Awesome, thanks for all the feedback! it's been really helpful in learning all the details here. Let me know if there are any more problems you see here.

Can you check why eth tests are failing? And can you write some tests for this

@0xJepsen 0xJepsen force-pushed the waylon/EIP5656MCOPY branch from 914a46c to 8fd3de5 Compare June 29, 2023 02:08
@0xJepsen 0xJepsen marked this pull request as ready for review June 30, 2023 00:25
@0xJepsen
Copy link
Contributor Author

Wrote some tests and got CI passing!

Copy link
Member

@rakita rakita left a comment

Choose a reason for hiding this comment

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

gj!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

EIP-5656: MCOPY - Memory copying instruction
3 participants