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
EVM-C: Remove factory class #131
Conversation
218d986
to
79663b4
Compare
79663b4
to
a3cce32
Compare
a3cce32
to
c7a351c
Compare
@chfast After reading through the code I decided to build the library from the readme instructions. That seemed to go fine until I got to step 5. It doesn't say what directory the build directory should go in, and searching my hard drive for CMakeLists.txt didn't find anyplace that looked right.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice!
/// FIXME: We should rethink reporting internal errors. One of the options | ||
/// it to allow using any negative value to represent internal errors. | ||
/// @todo We should rethink reporting internal errors. One of the options | ||
/// it to allow using any negative value to represent internal errors. | ||
EVM_INTERNAL_ERROR = -1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handing over all the negative numbers seems a good idea. An optional string might be good if the memory management isn't too much trouble.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I will clarify that negative values are allowed and are related to implementation-defined errors.
Yes, additional error message is possible. We actually had it in evm_result before, but it was removed. Memory management is not a problem, because evm_result have "virtual destruktor". However, I'd like to add it the moment we have any practical use case for it. What do you think @axic? Do you need it in your eWASM enabled fork of cpp-ethereum?
include/evm.h
Outdated
/// | ||
/// @return EVM instance. | ||
struct evm_factory examplevm_get_factory(void); | ||
/// @todo Specify if this function can return null pointer to indicate error. | ||
struct evm_instance* examplevm_create(void); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it has to be able to return a null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, then.
@@ -437,6 +428,15 @@ typedef void (*evm_prepare_code_fn)(struct evm_instance* instance, | |||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So CACHED code doesn't have to be on-disk, but won't become UNKNOWN? And READY code might become CACHED, or might go back to being UNKNOWN?
I probably missed it, but what are the flags? Implementation defined? They show up in few places.
It might be good to allow for implementations that support preparation to execute ready or cached code based on the code's hash.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I needed this to have the same capabilities in API for JIT as before going EVM-C. This is needed for SmartJIT strategy - it has to decide where to delegate the execution - to JIT or to interpreter.
READY means the pre-processed code is in memory and there is not overhead of starting execution in JIT.
CACHED means the pre-processed code is on-disk and the overhead of executing in JIT will be to load the code from disk.
We should think about generalizing this API more... but it is not critical at the moment, and not required to implement interpreter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, but I'm still confused. Let me try again.
- Are READY files guaranteed to be ready for subsequent calls?
- Are CACHED files guaranteed to be cached or ready for subsequent calls?
This matters for a JIT, as I understand that a JIT that does not cache its output and keep it cached can be exploited.
(Whether the cache is on disk or in memory is an implementation detail.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No and no.
In terms of JIT, READY means that the code is in memory. Memory is limited, you have to delete some codes over time.
The same for CACHED. Your disk space is limited, so you may want to remove some codes from on-disk cache.
So there are no guarantees that any code will preserve its current status.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. The first no I expected. But I do worry about code falling out of the cache. In discussions with @Arachnid he was quite clear that caches that can spill are exploitable. I'll hope he shows up and explains.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes - any cache with eviction cannot be relied on as a performance optimisation in a blockchain environment. The attacker can simply devise an attack that round-robins a larger number of entries than the cache can hold, guaranteeing every single action is a cache miss.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks to explaining this to me. Then, the CACHED code SHOULD be maintained the same way the Ethereum state is. I will add this clarification in comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And as I think we discussed, a good strategy might be to compile and cache contracts when they are first created so an interpreter isn't even needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry about build instructions. They are always out-dated.
Anyway, If you want to play with EVM-C you only need the header evm.h
.
/// FIXME: We should rethink reporting internal errors. One of the options | ||
/// it to allow using any negative value to represent internal errors. | ||
/// @todo We should rethink reporting internal errors. One of the options | ||
/// it to allow using any negative value to represent internal errors. | ||
EVM_INTERNAL_ERROR = -1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I will clarify that negative values are allowed and are related to implementation-defined errors.
Yes, additional error message is possible. We actually had it in evm_result before, but it was removed. Memory management is not a problem, because evm_result have "virtual destruktor". However, I'd like to add it the moment we have any practical use case for it. What do you think @axic? Do you need it in your eWASM enabled fork of cpp-ethereum?
@@ -437,6 +428,15 @@ typedef void (*evm_prepare_code_fn)(struct evm_instance* instance, | |||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I needed this to have the same capabilities in API for JIT as before going EVM-C. This is needed for SmartJIT strategy - it has to decide where to delegate the execution - to JIT or to interpreter.
READY means the pre-processed code is in memory and there is not overhead of starting execution in JIT.
CACHED means the pre-processed code is on-disk and the overhead of executing in JIT will be to load the code from disk.
We should think about generalizing this API more... but it is not critical at the moment, and not required to implement interpreter.
include/evm.h
Outdated
/// | ||
/// @return EVM instance. | ||
struct evm_factory examplevm_get_factory(void); | ||
/// @todo Specify if this function can return null pointer to indicate error. | ||
struct evm_instance* examplevm_create(void); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, then.
This is final change to EVM-C API +/- documentation fixes and small refactorings.
I reviewed the previous version by drawing the class diagram of it. I managed to reduce it from 4 classes: Host, Context, EVM, Factory to only 2: EVM and Context. Now it matches very simple OOP polymorphic desing, but it is hard to see in under big C overhead.
I'm not sure we should keep the
ABI_VERSION
field. It does not seem to be useful in near future.The still missing piece is tracing.