rust-ethereum / evm Goto Github PK
View Code? Open in Web Editor NEWPure Rust implementation of Ethereum Virtual Machine
License: Apache License 2.0
Pure Rust implementation of Ethereum Virtual Machine
License: Apache License 2.0
Currently no format is applied to code.
But it is a common practice for rust developers, to keep format-on-save in their editors.
What do you think about adding it to pipeline?
Currently, if core
finds an opcode it cannot handle, it will Trap
first, and then Runtime
will attempt to eval it. This is rather inefficient.
Instead, core
should expose the eval table (which is just 256-item fn pointers), to allow Runtime
to customize it. Machine
would now take a generic parameter stateS
(with default ()
), and then pass it as the final parameter to eval fns. Runtime
then should fully build with that, and only trap for CALL
/CREATE
. Gasometer
should be the only thing that wraps a Machine
.
This should make it more predictable when reasoning about performance, while not losing much abstractions.
New user to repo today, and just need some clarity.
const TEMP_CODE: &str = "608060405234801561000f575f80fd5b506101438061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80632e64cec1146100385780636057361d14610056575b5f80fd5b610040610072565b60405161004d919061009b565b60405180910390f35b610070600480360381019061006b91906100e2565b61007a565b005b5f8054905090565b805f8190555050565b5f819050919050565b61009581610083565b82525050565b5f6020820190506100ae5f83018461008c565b92915050565b5f80fd5b6100c181610083565b81146100cb575f80fd5b50565b5f813590506100dc816100b8565b92915050565b5f602082840312156100f7576100f66100b4565b5b5f610104848285016100ce565b9150509291505056fea26469706673582212207ca8a77a375aff548bc76892f6b2093ea5bec72e34f6638bcd6bc43f620679bc64736f6c63430008160033";
const ERCDATA: &str = "2e64cec1"
let code = hex::decode(TEMP_CODE).unwrap();
let data = hex::decode(ERCDATA).unwrap();
let mut handler = UnimplementedHandler;
let machine = Machine::new(
Rc::new(code),
Rc::new(data),
1024,
10000,
RuntimeState {
context: Context {
address: H160::default(),
caller: H160::default(),
apparent_value: U256::default(),
},
transaction_context: TransactionContext {
gas_price: U256::default(),
origin: H160::default(),
}
.into(),
retbuf: Vec::new(),
},
);
let mut vm = EtableInterpreter::new(machine, &RUNTIME_ETABLE);
let res = vm.run(&mut handler).exit().unwrap();
I have fed the machine the bytecode and data variables. So far it is successfully returning the bytecode from the deployment bytecode. But now I dont know where to make subsequent CALLDATA calls to the stateful machine.
If I could get clarification on this I would appreciate it.
Also, where does one extract the storage slots of the Machine after it runs?
For the current master
branch clippy with basic configurations fails:
cargo clippy --workspace -- -D warnings
Fix basic clippy issues and add basic clippy rules to CI:
cargo clippy --workspace -- -D warnings
cargo clippy --workspace --no-default-features -- -D warnings
cargo clippy --workspace --features=with-codec,with-serde -- -D warnings
There are a lot of issues when enabling:
cargo clippy --workspace -- -D warnings -D clippy::pedantic -D -D clipyy::nursery
Enabling these clippy flags 🎏 is out of the current proposal.
We should prefer bytes::Bytes
or Box<[u8]>
, as most data are immutable. This also simplifies the retbuf
.
Grepping through the code base, I found no mention of the Berlin hardfork, nor the EIPs included in that hardfork.
What are your plans in that regard? Has anyone as yet begun work on Berlin HF support, is that perhaps in a personal fork somewhere? Would contributions in that regard be welcome?
Is this EVM implementation production ready? I see the version is pre 1.0. I couldn't find a timeline or anything in the documentation. I'm looking to use this in production sometime in the next 6 months or so, and am wondering if that's too soon.
Sorry if this is not the proper place to ask.
What purpose of this line 388?
self.state.metadata_mut().gasometer.record_cost(gas_limit)
It seems this just increases the used gas by the current gas limit. It shoud exaust the remaining gas, right? And the next validation should cause OutOfGas error. But why?
Crate version: v0.41.0
While using this EVM to sync with ethereum mainnet, I've a found a sync mismatch when processing the spurious dragon hardfork at block 2675000 for this transaction:
0xad0efe76cb3983e9c2daf079af7eb6bfcd6d9b4174e66cc516378804d4e708a5
The reason is because this transaction touches the pre-compiled contract at 0x0000000000000000000000000000000000000004, which have an empty account:
An account is considered empty when it has no code and zero nonce and zero balance.
according to EIP-161 any empty account touched by the trasanction (including pre-compiled contracts) must be deleted at the end of the transaction:
d. At the end of the transaction, any account touched by the execution of that transaction which is now empty SHALL instead become non-existent (i.e. deleted).
But empty accounts should not be removed if the transaction reverts:
Addendum (2017-08-15)
On 2016-11-24, a consensus bug occurred due to two implementations having different behavior in the case of state reverts.[3] The specification was amended to clarify that empty account deletions are reverted when the state is reverted.
The vm doesn't execute Apply::Delete
for touched empty accounts when config.empty_considered_exists
is disabled.
The vm tracks touched accounts and cleanup empty account at the end of each transaction, including pre-compiled contract accounts, maybe include a new config like remove_touched_empty_accounts
.
If not, How can I be contributer?
I propose extracting the 'In Memory' functionality as a standalone module so other developer can import those data structures for their own purpose conveniently(e.g. write a simple custom simulator for EVM contracts)
After updating evm-tests to use evm 0.28 (rust-blockchain/evm-tests#4) and ethereum-tests 9.0.2 (rust-blockchain/evm-tests#5), the following failures are observed with state test cases:
GeneralStateTests/stRandom2
:
Running randomStatetest649:Istanbul:0 ... thread '<unnamed>' panicked at 'Hash not equal; calculated: 0x785db7415f4af466812dec4fd5a20f2115b6b990956d07bfed079d92d9941a8f, expect: 0x4d43f8e828620d9b54c4070f0006c3b51aa26761b06ea21b611630e646cd5259
State: {0x000000000000000000000000000000ca1100f022: MemoryAccount { nonce: 0, balance: 0, storage: {}, code: [127, 108, 117, 109, 191, 101, 114, 105, 99, 97, 110, 32, 127, 148, 57, 48, 55, 51, 55, 57, 54, 53, 51, 49, 54, 54, 49, 48, 48, 55, 52, 90, 5, 96, 0, 82, 127, 114, 101, 115, 117, 130, 103, 48, 117, 116, 32, 116, 101, 0, 65, 3, 10, 0, 0, 0, 239, 191, 113, 37, 232, 108, 117, 109, 191, 101, 114, 105, 99, 96, 32, 82, 127, 97, 110, 32, 127, 148, 57, 48, 55, 51, 55, 57, 54, 53, 51, 49, 54, 54, 49, 48, 48, 55, 52, 90, 5, 114, 101, 115, 117, 130, 103, 48, 117, 127, 116, 32, 116, 101, 0, 65, 3, 10, 0, 0, 0, 239, 191, 113, 37, 232, 108, 117, 109, 191, 101, 114, 105, 99, 97, 110, 32, 127, 148, 57, 48, 55, 127, 51, 55, 57, 54, 53, 51, 49, 54, 54, 49, 48, 48, 55, 52, 90, 5, 114, 101, 115, 117, 130, 103, 48, 117, 116, 32, 116, 101, 0, 65, 3, 10, 124, 239, 191, 113, 37, 232, 108, 117, 109, 191, 101, 114, 105, 99, 97, 110, 32, 127, 148, 57, 48, 55, 51, 55, 57, 54, 53, 51, 49, 54, 127, 54, 49, 48, 48, 55, 52, 90, 5, 114, 101, 115, 117, 130, 103, 48, 117, 116, 32, 116, 101, 0, 65, 3, 10, 0, 0, 0, 239, 191, 113, 37, 232, 96, 108, 96, 224, 83, 96, 117, 96, 225, 83, 96, 109, 96, 226, 83, 96, 191, 96, 227, 83, 96, 101, 96, 228, 83, 96, 114, 96, 229, 83, 96, 105, 96, 230, 83, 96, 99, 96, 231, 83, 96, 232, 96, 0, 96, 0, 240, 96, 0, 96, 0, 96, 0, 96, 0, 132, 90, 105, 80, 80, 127, 127, 148, 57, 48, 55, 51, 55, 57, 54, 53, 51, 49, 54, 54, 49, 48, 48, 55, 52, 90, 5, 114, 101, 115, 117, 130, 103, 48, 117, 116, 32, 116, 96, 0, 82, 96, 32, 96, 0, 243, 91, 65, 0, 97, 148, 57, 97, 32, 127, 97, 97, 110, 97, 105, 99, 97, 101, 114, 96, 5, 99, 1, 43, 155, 191, 241, 103, 0, 0, 0, 0, 0, 0, 1, 95, 86, 91, 103, 0, 0, 0, 0, 0, 0, 76, 166, 86, 97, 54, 53, 81, 97, 54, 54, 85, 97, 54, 85, 81, 97, 54, 55, 85, 97, 54, 117, 81, 97, 54, 56, 85, 97, 54, 149, 81, 97, 54, 57, 85, 97, 54, 181, 81, 97, 54, 58, 85, 97, 54, 213, 81, 97, 54, 59, 85, 97, 54, 245, 81, 97, 54, 60, 85, 97, 55, 21, 81, 97, 54, 61, 85, 97, 55, 53, 81, 97, 54, 62, 85, 97, 55, 85, 81, 97, 54, 63, 85, 97, 55, 117, 81, 97, 54, 64, 85, 97, 55, 149, 81, 97, 54, 65, 85, 97, 55, 181, 81, 97, 54, 66, 85, 97, 55, 213, 81, 97, 54, 67, 85, 97, 55, 245, 81, 97, 54, 68, 85, 97, 56, 21, 81, 97, 54, 69, 85, 97, 56, 53, 81, 97, 54, 70, 85, 97, 56, 85, 81, 97, 54, 71, 85, 97, 56, 117, 81, 97, 54, 72, 85, 97, 56, 149, 81, 97, 54, 73, 85, 97, 56, 181, 81, 97, 54, 74, 85, 97, 56, 213, 81, 97, 54, 75, 85, 97, 56, 245, 81, 97, 54, 76, 85, 97, 57, 21, 81, 97, 54, 77, 85, 97, 57, 53, 81, 97, 54, 78, 85, 97, 57, 85, 81, 97, 54, 79, 85, 97, 57, 117, 81, 97, 54, 80, 85, 97, 57, 149, 81, 97, 54, 81, 85, 97, 57, 181, 81, 97, 54, 82, 85, 97, 57, 213, 81, 97, 54, 83, 85, 97, 57, 245, 81, 97, 54, 84, 85, 97, 58, 21, 81, 97, 54, 85, 85, 97, 58, 53, 81, 97, 54, 86, 85, 97, 58, 85, 81, 97, 54, 87, 85, 97, 58, 117, 81, 97, 54, 88, 85, 97, 58, 149, 81, 97, 54, 89, 85, 97, 58, 181, 81, 97, 54, 90, 85, 97, 58, 213, 81, 97, 54, 91, 85, 97, 58, 245, 81, 97, 54, 92, 0] }, 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b: MemoryAccount { nonce: 1, balance: 4611686018425909623, storage: {}, code: [] }, 0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b: MemoryAccount { nonce: 0, balance: 1478280, storage: {}, code: [] }}', jsontests/src/utils.rs:131:9
GeneralStateTests/VMTests/vmIOandFlowOperations
:
Running jumpi:Istanbul:21 ... thread '<unnamed>' panicked at 'Hash not equal; calculated: 0xf7c921863badd0fda19afaf9642e11f4427da0fa6a2ef5292299441dbcbd0f41, expect: 0xcb4c1a36b69d9d31aa60924e43fa6bc9a76340bc1d95e905eb1a0a1c73ce0feb
State: {0x0000000000000000000000000000000000000100: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [97, 96, 13, 96, 0, 85, 96, 1, 96, 16, 96, 32, 2, 87, 91, 0] }, 0x0000000000000000000000000000000000000101: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [97, 96, 13, 96, 0, 85, 96, 1, 96, 16, 96, 32, 2, 87, 91, 0] }, 0x0000000000000000000000000000000000000102: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 1, 96, 6, 87, 0, 91, 97, 96, 13, 96, 0, 85, 0] }, 0x0000000000000000000000000000000000000103: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [97, 96, 13, 96, 0, 85, 96, 255, 99, 15, 255, 255, 255, 87, 0] }, 0x0000000000000000000000000000000000000104: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 35, 96, 1, 96, 8, 87, 96, 1, 91, 96, 2, 85] }, 0x0000000000000000000000000000000000000105: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [97, 96, 13, 96, 0, 85, 91, 96, 6, 96, 6, 87] }, 0x0000000000000000000000000000000000000106: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [97, 96, 13, 96, 1, 96, 10, 87, 96, 255, 91, 96, 0, 85] }, 0x0000000000000000000000000000000000000107: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 11, 86, 91, 97, 96, 13, 96, 0, 85, 0, 91, 96, 1, 96, 3, 87] }, 0x0000000000000000000000000000000000000108: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 1, 96, 4, 96, 5, 1, 87, 0, 91, 97, 96, 13, 96, 0, 85] }, 0x0000000000000000000000000000000000000109: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 1, 96, 7, 87, 0, 96, 91, 97, 96, 13, 96, 0, 85] }, 0x000000000000000000000000000000000000010a: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 1, 96, 7, 87, 0, 96, 1, 97, 96, 13, 96, 0, 85] }, 0x000000000000000000000000000000000000010b: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [97, 96, 13, 96, 0, 85, 96, 1, 96, 13, 87, 90, 91, 90, 96, 1, 85] }, 0x000000000000000000000000000000000000010c: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [97, 96, 13, 96, 0, 85, 96, 1, 96, 11, 87, 90, 91, 90, 96, 1, 85] }, 0x000000000000000000000000000000000000010d: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 17, 104, 1, 0, 0, 0, 0, 0, 0, 0, 13, 87, 91, 91, 97, 96, 13, 96, 0, 85] }, 0x000000000000000000000000000000000000010e: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 17, 100, 1, 0, 0, 0, 9, 87, 91, 91, 97, 96, 13, 96, 0, 85] }, 0x000000000000000000000000000000000000010f: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 0, 81, 80, 96, 1, 96, 0, 3, 80, 96, 1, 96, 0, 81, 87, 97, 96, 13, 96, 0, 85, 0] }, 0x0000000000000000000000000000000000000110: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 1, 96, 14, 87, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 97, 96, 13, 96, 0, 85] }, 0x0000000000000000000000000000000000000111: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [97, 96, 13, 96, 0, 85, 96, 16, 96, 0, 82, 91, 96, 1, 96, 0, 81, 3, 128, 96, 0, 82, 96, 11, 87] }, 0x0000000000000000000000000000000000000200: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [97, 96, 13, 96, 0, 85, 96, 0, 96, 16, 96, 32, 2, 87, 91, 0] }, 0x0000000000000000000000000000000000000201: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [97, 96, 13, 96, 0, 85, 96, 0, 96, 16, 96, 32, 2, 87, 91, 0] }, 0x0000000000000000000000000000000000000202: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 0, 96, 6, 87, 0, 91, 97, 96, 13, 96, 0, 85, 0] }, 0x0000000000000000000000000000000000000203: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [97, 96, 13, 96, 0, 85, 96, 0, 99, 15, 255, 255, 255, 87, 0] }, 0x0000000000000000000000000000000000000208: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 0, 96, 4, 96, 5, 1, 87, 0, 91, 97, 96, 13, 96, 0, 85] }, 0x000000000000000000000000000000000000020d: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 0, 104, 1, 0, 0, 0, 0, 0, 0, 0, 13, 87, 91, 91, 97, 96, 13, 96, 0, 85] }, 0x000000000000000000000000000000000000020e: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 0, 100, 1, 0, 0, 0, 9, 87, 91, 91, 97, 96, 13, 96, 0, 85] }, 0x000000000000000000000000000000000000020f: MemoryAccount { nonce: 0, balance: 838137708091124174, storage: {}, code: [96, 0, 81, 80, 96, 1, 96, 0, 3, 80, 96, 0, 96, 0, 81, 87, 97, 96, 13, 96, 0, 85, 0] }, 0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba: MemoryAccount { nonce: 0, balance: 874730, storage: {}, code: [] }, 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b: MemoryAccount { nonce: 1, balance: 17592185169685, storage: {}, code: [] }, 0xcccccccccccccccccccccccccccccccccccccccc: MemoryAccount { nonce: 0, balance: 838137708091124175, storage: {0x0000000000000000000000000000000000000000000000000000000000000000: 0x0000000000000000000000000000000000000000000000000000000000000bad}, code: [96, 0, 96, 0, 96, 0, 96, 0, 96, 4, 53, 98, 1, 0, 0, 244, 0] }}', jsontests/src/utils.rs:131:9
As far as I can tell, there's a few useful PRs that are sort of stalled, and also it seems like there's no consistent release process. I wonder if there's any specific plans around how this EVM implementation will be expanded over time, or if it's worth figuring out additional people that'd be able to review/merge PRs & publish?
The current Memory implementation has a effective_len
field (which seems unnecessary #31 ), and it will be updated unexpectedly by mload
. so msize
called before/after mload
may have different value.
Just wondering whether there is likely to be support for other EVM-compatible chains like Polygon or BSC?
Is this likely to be feasible in this project?
We introduce a new type of read-only memory region ROM
that hosts opcode 0x40-0x45, 0x46 and 0x48. Those opcode returns fixed value for a block. By doing this we can move it to core, and some of them can then use chunk gas metering.
SHA3 should also move from runtime to core, as it has no external dependencies.
Is there any documenation on how to create/execute transaction on evm? I found the doc in the version 0.11.0 documentation, but looks like it's totally removed in new version of evm.
Some of them seems to be unneeded. However, in most cases (when substate exits and fail
is called before), it should have no effect with or without. But we need to write tests for this.
Chunk gas metering refers to a one-pass compilation process where we group multiple fixed-cost opcodes, and charge gas only once at the beginning.
Command:
cd gasometer
cargo build --features tracing
Result:
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `Try`)
--> gasometer/src/lib.rs:137:14
|
16 | crate::tracing::with(|listener| listener.event($x));
| ----------------------------- this function should return `Result` or `Option` to accept `?`
...
137 | snapshot: self.snapshot()?,
| ^^^^^^^^^^^^^^^^ cannot use the `?` operator in a closure that returns `()`
|
= help: the trait `Try` is not implemented for `()`
= note: required by `from_error`
Hi,
I am trying to read the code, and have a very basic question: Is there a good place where ethereum protocol itself is well documented, and which this code adheres to? I have tried reading ethereum yellow paper, but it is not straightforward how this code maps to that.
To take a concrete example, consider this:
pub fn transact_call(
&mut self,
caller: H160,
address: H160,
value: U256,
data: Vec<u8>,
gas_limit: u64,
) -> (ExitReason, Vec<u8>) {
let transaction_cost = gasometer::call_transaction_cost(&data);
match self.state.metadata_mut().gasometer.record_transaction(transaction_cost) {
Ok(()) => (),
Err(e) => return (e.into(), Vec::new()),
The first thing transact_call
does is calculate the call transaction cost (by calculating 0 characters and non zero characters in data and multiplying by their corresponding gas cost) and records that in gasometer. (this increments used_gas
field).
My basic question is where is this behavior documented, that this has to be done in this way.
Thanks.
Current precompiles errors only contain the error kind/message. However some precompiles can have a non negligible cost, which can't be avoided only by looking at the input. For example in Frontier the "dispatch" precompile :
https://github.com/paritytech/frontier/blob/master/frame/evm/precompile/dispatch/src/lib.rs
Even if the call fails it's important to take the used weight into account, otherwise it may be possible to waste unmettered time.
I haven't looked in details in official Ethereum precompiles and if they can return errors. If they can they should return a cost of 0 to not change the current behavior (unless this is a mistake).
Design suggestion : change the return value of precompiles to Result<PrecompileOutput, PrecompileError>
, PrecompileError
having an ExitError
field and an u64
cost field. The cost could be recorded here like it's done in the success path :
https://github.com/rust-blockchain/evm/blob/master/src/executor/stack/mod.rs#L779
Additionally, an extension trait impl for ExitError
could provide a fn with_cost(self, cost: u64) -> PrecompileError
for ergonomy.
The goal is to deprecate evm-tests
repo (which contains some GPL-3 code). Rewrite when necessary so that everything can be Apache-2 and stay in one single repo.
Is there any example of how to use this library?
Reads 'Vivinity', should be fixed.
After running cargo hfuzz run evm_fuzz
I get the following error:
Compiling toml v0.5.8
Compiling fixed-hash v0.7.0
error: failed to run custom build command for `honggfuzz v0.5.54`
Caused by:
process didn't exit successfully: `/Users/laplace/Documents/repos/evm/fuzzer/hfuzz_target/release/build/honggfuzz-770ee86106a66883/build-script-build` (exit status: 101)
--- stderr
Makefile:103: *** Unsupported MAC OS X version. Stop.
thread 'main' panicked at 'assertion failed: status.success()', /Users/laplace/.cargo/registry/src/github.com-1ecc6299db9ec823/honggfuzz-0.5.54/build.rs:41:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
error: build failed```
cargo check
produces the following error:
❯ cargo check
Compiling proc-macro2 v1.0.37
Compiling unicode-xid v0.2.2
Compiling syn v1.0.91
Compiling serde_derive v1.0.136
Compiling version_check v0.9.4
Compiling serde v1.0.136
Checking cfg-if v1.0.0
Compiling libc v0.2.123
error[E0463]: can't find crate for `std`
For more information about this error, try `rustc --explain E0463`.
error: could not compile `serde_derive` due to previous error
warning: build failed, waiting for other jobs to finish...
error[E0463]: can't find crate for `core`
error: build failed
Tried cargo check --workspace --all-features
but still got the error. Any suggestions?
With #183, the code of runtime will be more consolidated, and it'll be much easier then to build to variants of the runtime handler -- sync and async. In the async case, each opcode will trap and return a future.
The speed of sync runtime matters, but not so much for async -- we can afford more abstractions.
This will be useful for light clients and other cases where state is not immediately available.
A follow-up from polkadot-evm/frontier#724 (comment).
This issue is to discuss the details of making the Handler
(https://github.com/rust-blockchain/evm/blob/master/runtime/src/handler.rs) calls fallible.
Most of them are pretty trivial, however, there are some return Capture
, which seems to wrapping the error internally already. Do we make it Result<Capture<...>, ExitFatal>
too?
The original proposal was to use the ExitFatal
, but what if we do this instead:
pub trait Handler {
...
/// The runtime error.
type RuntimeError: From<ExitFatal> + Into<ExitFatal>;
...
/// Get balance of address.
fn balance(&self, address: H160) -> Result<U256, Self::RuntimeError>;
...
The idea is to have a user-provided type that has to be able to hold the ExitFatal
(we don't require that specifically, just that we can go from and to ExitFatal
). This might give some freedom to the implementors to introduce the errors that are internal within their implementation. Not sure if this is a good idea or not, or if it is a good implementation of the idea or not, but any feedback is welcome.
CC @dmitrylavrenov, @intendednull, @Henry-bee
Description
I guess this import should fail no_std
builds.
It probably should be
funty = { version = "=1.1", default-features = false }
When running:
cargo build --no-default-features
There are compilation errors like:
Compiling evm-interpreter v1.0.0-dev (/Users/evgeny/dev/rs/sputnikvm/interpreter)
error[E0412]: cannot find type `Vec` in this scope
--> interpreter/src/call_create.rs:120:56
|
120 | pub fn code<H: RuntimeBackend>(&self, handler: &H) -> Vec<u8> {
| ^^^ not found in this scope
|
help: consider importing one of these items
|
3 + use alloc::vec::Vec;
|
3 + use crate::Vec;
|
error[E0412]: cannot find type `Vec` in this scope
--> interpreter/src/call_create.rs:131:13
|
131 | pub input: Vec<u8>,
| ^^^ not found in this scope
|
help: consider importing one of these items
|
3 + use alloc::vec::Vec;
|
3 + use crate::Vec;
|
error[E0433]: failed to resolve: use of undeclared type `Vec`
--> interpreter/src/call_create.rs:176:15
|
176 | .unwrap_or(Vec::new());
| ^^^ use of undeclared type `Vec`
|
help: consider importing one of these items
|
3 + use alloc::vec::Vec;
|
3 + use crate::Vec;
|
error[E0433]: failed to resolve: use of undeclared type `Vec`
--> interpreter/src/call_create.rs:212:27
|
212 | state.as_mut().retbuf = Vec::new();
| ^^^ use of undeclared type `Vec`
|
help: consider importing one of these items
|
3 + use alloc::vec::Vec;
|
3 + use crate::Vec;
|
error[E0412]: cannot find type `Vec` in this scope
--> interpreter/src/call_create.rs:268:11
|
268 | retbuf: Vec<u8>,
| ^^^ not found in this scope
|
help: consider importing one of these items
|
3 + use alloc::vec::Vec;
|
3 + use crate::Vec;
|
error[E0412]: cannot find type `Vec` in this scope
--> interpreter/src/call_create.rs:339:12
|
339 | pub code: Vec<u8>,
| ^^^ not found in this scope
|
help: consider importing one of these items
|
3 + use alloc::vec::Vec;
|
3 + use crate::Vec;
|
error[E0433]: failed to resolve: use of undeclared type `Vec`
--> interpreter/src/call_create.rs:363:16
|
363 | .unwrap_or(Vec::new());
| ^^^ use of undeclared type `Vec`
|
help: consider importing one of these items
|
3 + use alloc::vec::Vec;
|
3 + use crate::Vec;
|
error[E0433]: failed to resolve: use of undeclared type `Vec`
--> interpreter/src/call_create.rs:369:28
|
369 | state.as_mut().retbuf = Vec::new();
| ^^^ use of undeclared type `Vec`
|
help: consider importing one of these items
|
3 + use alloc::vec::Vec;
|
3 + use crate::Vec;
|
error[E0433]: failed to resolve: use of undeclared type `Vec`
--> interpreter/src/call_create.rs:402:16
|
402 | .unwrap_or(Vec::new());
| ^^^ use of undeclared type `Vec`
|
help: consider importing one of these items
|
3 + use alloc::vec::Vec;
|
3 + use crate::Vec;
|
error[E0433]: failed to resolve: use of undeclared type `Vec`
--> interpreter/src/call_create.rs:412:28
|
412 | state.as_mut().retbuf = Vec::new();
| ^^^ use of undeclared type `Vec`
|
help: consider importing one of these items
|
3 + use alloc::vec::Vec;
|
3 + use crate::Vec;
|
error[E0412]: cannot find type `Vec` in this scope
--> interpreter/src/call_create.rs:428:11
|
428 | retbuf: Vec<u8>,
| ^^^ not found in this scope
|
help: consider importing one of these items
|
3 + use alloc::vec::Vec;
|
3 + use crate::Vec;
|
error[E0412]: cannot find type `Vec` in this scope
--> interpreter/src/runtime.rs:13:14
|
13 | pub retbuf: Vec<u8>,
| ^^^ not found in this scope
|
help: consider importing one of these items
|
1 + use alloc::vec::Vec;
|
1 + use crate::Vec;
|
error[E0412]: cannot find type `Vec` in this scope
--> interpreter/src/runtime.rs:64:14
|
64 | pub topics: Vec<H256>,
| ^^^ not found in this scope
|
help: consider importing one of these items
|
1 + use alloc::vec::Vec;
|
1 + use crate::Vec;
|
error[E0412]: cannot find type `Vec` in this scope
--> interpreter/src/runtime.rs:65:12
|
65 | pub data: Vec<u8>,
| ^^^ not found in this scope
|
help: consider importing one of these items
|
1 + use alloc::vec::Vec;
|
1 + use crate::Vec;
|
error[E0412]: cannot find type `Vec` in this scope
--> interpreter/src/runtime.rs:111:35
|
111 | fn code(&self, address: H160) -> Vec<u8>;
| ^^^ not found in this scope
|
help: consider importing one of these items
|
1 + use alloc::vec::Vec;
|
1 + use crate::Vec;
|
error[E0412]: cannot find type `Vec` in this scope
--> interpreter/src/runtime.rs:146:46
|
146 | ...ddress: H160, code: Vec<u8>) -> Result<(), ExitError>;
| ^^^ not found in this scope
|
help: consider importing one of these items
|
1 + use alloc::vec::Vec;
|
1 + use crate::Vec;
I've been benchmarking gas usage and was having trouble with a contract that makes a CREATE call internally -- the gas estimation came out far higher than expected. The results I was getting were similar to here: polkadot-evm/frontier#252 (comment)
And to clarify, by l64
I mean the protocol defined here, to pass gas into subcontracts: ethereum/EIPs#150
Investigation shows the following cost occurring in the gasometer at l64
time:
2021-01-13 15:26:24.970 TRACE http.worker20 evm:Running opcode: Err(Create), Pre gas-left: 4294945964
2021-01-13 15:26:24.970 TRACE http.worker20 evm:Opcode costs: memory_gas: 36, gas_cost: 32000, total used gas: 231
2021-01-13 15:26:24.970 TRACE http.worker20 evm:Recording l64 cost: 67108030
2021-01-13 15:26:24.971 TRACE http.worker20 evm:Running opcode: Ok(Push(1)), Pre gas-left: 4227805934
I note that the l64 cost is approximately equal to the amount of gas remaining / 64. My suspicion is that, because the gasometer runs the code with a MAX_U256 starting gas, the l64
calls are being improperly estimated when compared with the amount of starting gas used in practice. Note that this starting gas comes from the following line in frontier: https://github.com/paritytech/frontier/blob/master/client/rpc/src/eth.rs#L760, but should theoretically be unneeded for the purposes of estimation.
If useful, here is the entire contract I've been using for testing, specifically the spawn()
call on the CreateContract
.
As a quick point of comparison, the gas estimate I get with EIP-150 enabled is 67227213
, but if I set call_l64_after_gas: false
in the config, I instead get 119183
-- much closer if not exactly the amount of gas used when the call is actually executed.
pragma solidity ^0.5.0;
contract SubContract {
constructor() public payable { }
function getAddress() external view returns (address ownAddress) {
return address(this);
}
function getValue() external view returns (uint) {
return address(this).balance;
}
}
contract CreateContract {
address public deployed;
constructor() public { }
function spawn() external returns (SubContract subAddress) {
SubContract result = new SubContract();
deployed = address(result);
return result;
}
function spawnWithValue() external payable returns (SubContract subAddress) {
SubContract result = (new SubContract).value(msg.value)();
deployed = address(result);
return result;
}
}
As part of Moonbeam we'd like to implement a precompile that allows to batch call, the precompile taking as parameters addresses, call data, etc; and performing multiple calls in one transaction on the behalf of the caller.
However with the current design it's not possible for a precompile to perform subcalls in the EVM. From Substrate/Frontier it's possible to call pallet_evm to spawn an inner EVM but it will act as its own transaction (transaction fees again, transaction events, etc).
Not sure how this can be implemented. PrecompileSet::execute
could be changed to take &mut self
, return either for the final result or to perform a subcall, and thus take as a parameter either the initial call parameters or the result of a subcall. However it seems a bit messy to manage. I thought using async/generators but yield
is unstable and I don't think we can use .await
to perform a subcall :/
Can't instantiate flipper contract. Receiving OutOfGas even when I provide maximum value of gas (4294967295).
This is exempt from debug log with couple of debug prints:
2020-02-12 18:47:48.003 tokio-blocking-driver DEBUG runtime Balance: 100000001000000, endowment: 10000000000000, fee: 0
2020-02-12 18:47:48.003 tokio-blocking-driver DEBUG runtime OutOfGasDebug("record_transaction/2")
2020-02-12 18:47:48.003 tokio-blocking-driver DEBUG runtime DispatchError
2020-02-12 18:47:48.003 tokio-blocking-driver DEBUG runtime 9
2020-02-12 18:47:48.003 tokio-blocking-driver DEBUG runtime 5
2020-02-12 18:47:48.003 tokio-blocking-driver DEBUG runtime ExitReasonFailed
How to reproduce:
I use this binary compiled with Remix from "flipper" contract":
608060405234801561001057600080fd5b5060008060006101000a81548160ff02191690831515021790555060d5806100396000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80636d4ce63c146037578063cde4efa9146057575b600080fd5b603d605f565b604051808215151515815260200191505060405180910390f35b605d6075565b005b60008060009054906101000a900460ff16905090565b6000809054906101000a900460ff16156000806101000a81548160ff02191690831515021790555056fea264697066735822122053f9ef1a2344b96cd5e209c0a160bde2246caa0d498d14f881690afc84b8272264736f6c63430006010033
The source code:
contract flipper {
bool private value;
constructor() public {
value = false;
}
function flip() public {
value = !value;
}
function get() public view returns (bool) {
return value;
}
}
It uses scale-info 1.0. No releases available yet.
Crate version: v0.41.0
Related: #222
While using this EVM to sync with ethereum mainnet, I've a found a sync mismatch when processing the transaction at block 165514:
https://etherscan.io/tx/0xe01fcce5f0fb0d04d253908ebadbada9308731a8bd0d1f1b37ad3af111e6a055
The BALANCE Opcode must return a different balance for the origin account (a.k.a. tx signer), instead of returning the actual balance, it must return the worst case balance for this account, which is balance - (tx.gasPrice * tx.gasLimit)
, because the transaction is being processed, and we don't know the final the balance.
Example contract:
ORIGIN # or CALLER, once they are the same here
BALANCE
PUSH1 0x00
SSTORE
STOP
before execute transaction: 0x47e512b02979c8b8
returned by BALANCE opcode: 0x47336ff3fab4c8b8 == balance - (gas_price * gas_limit)
after apply state changes: 0x47c014fbdbd794b8 == balance - (gas_price * gas_used)
before execute transaction: 0x47e512b02979c8b8
returned by BALANCE opcode: 0x47e512b02979c8b8
after apply state changes: 0x47c014fbdbd794b8
Decrement the tx sender balance before execute the tx,and increment again after apply the state changes.
Looking at the struct definition of memory here: https://github.com/rust-blockchain/evm/blob/5150c3cc100b7faea8c1976ecfaa6602e2044325/core/src/memory.rs#L11
There are essentially two fields effective_len
and len()
(which is data.len()
) for memory.
On opcode (0x59), we put effective_len
onto the stack, and during return/revert, we update effective len.
I am curious why we need effective_len parameter at all? can't we just resize the vector to the appropriate length (0 filled) and maintain only one variable. Is effective_len
basically a memory optimization to avoid doing that?
Hello,
I was going through ethereum's yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf) and it is mentioned that all transactions have a number of common fields:
nonce: A scalar value equal to the number of transactions sent by the sender
Looking at transact_call
here:
https://github.com/rust-blockchain/evm/blob/5150c3cc100b7faea8c1976ecfaa6602e2044325/src/executor/stack/mod.rs#L230
there is no nonce
specified in the call, and after checking initial gas usage, we immediately increment the nonce for that account in state:
self.state.inc_nonce(caller);
Why doesn't this function take a nonce as an argument (and check against state's nonce)? Are these functions supposed to be called by some other API which does take nonce?
The STATICCALL was introduced in the EIP-214 in the Byzantium hardfork, while is possible to disable some opcodes like DELEGATECALL, CREATE2, REVERT, etc.. is not possible to disable the STATICCALL opcode.
INVALID OPCODE
and consume all the gas.eth_call
result can diverge from a result expected from ethereum compliant client.The reason why I'm using this crate instead revm is because it's more flexible, smaller and easier to compile to webassembly, once the light-client is intended to support web browsers and substrate pallets.
Count on me to help to make this crate EVM compliant.
Crate version: v0.41.0
I was using this evm for syncing to ethereum mainnet, as sanity check I computed the state root using the VM and compared it against the expected state root, whoever I found a sync mismatch when processing this transaction at block 49018:
https://etherscan.io/tx/0x5c4fdc85bf5efdfcbf7d4991c37287a9c3d5b660b57b0082118c3cff3c69dff1
I was syncing using the correct preset Config::frontier, after a investigation I've found the cause of the issue.
The current implementation doesn't consider the pre EIP-2 contract creation behavior, I'll use this transaction as example: 0x5c4fdc85bf5efdfcbf7d4991c37287a9c3d5b660b57b0082118c3cff3c69dff1
Hardfork: frontier
Gas used: 145029 (which is the transaction gas_limit)
Result: ExitError::OutOfGas
Not contract created.
TRACE evm: Gasometer Record Create 65304 [gas_transaction_create: 21000, zero_data_len: 145, non_zero_data_len: 643, access_list_address_len: 0, access_list_storage_len: 0, initcode_cost: 50] [Gas used: 0, Gas left: 145029]
TRACE evm: Gasometer Record cost 79725 [Gas used: 65304, Gas left: 79725]
TRACE evm: Gasometer Record cost 3 [Gas used: 0, Gas left: 79725]
TRACE evm: OpCode Push [@0]: 0x0000…0060
TRACE evm: Gasometer Record cost 3 [Gas used: 3, Gas left: 79722]
TRACE evm: OpCode Push [@1]: 0x0000…0040
TRACE evm: Gasometer Record dynamic cost 3 - memory_gas 9 - gas_refund 0 [Gas used: 6, Gas left: 79719]
TRACE evm: OpCode MStore: 64, 0x0000…0060
TRACE evm: Gasometer Record cost 3 [Gas used: 18, Gas left: 79707]
TRACE evm: OpCode Push [@0]: 0x0000…0040
TRACE evm: Gasometer Record dynamic cost 3 - memory_gas 9 - gas_refund 0 [Gas used: 21, Gas left: 79704]
TRACE evm: OpCode MLoad: 64
TRACE evm: Gasometer Record cost 3 [Gas used: 24, Gas left: 79701]
TRACE evm: OpCode Push [@1]: 0x0000…02b4
TRACE evm: Gasometer Record cost 2 [Gas used: 27, Gas left: 79698]
TRACE evm: OpCode CodeSize: 788
TRACE evm: Gasometer Record cost 3 [Gas used: 29, Gas left: 79696]
TRACE evm: OpCode overflowing_sub 788, 692: 96
TRACE evm: Gasometer Record cost 3 [Gas used: 32, Gas left: 79693]
TRACE evm: OpCode Dup1 [@2]: 0x0000…0060
TRACE evm: Gasometer Record cost 3 [Gas used: 35, Gas left: 79690]
TRACE evm: OpCode Push [@3]: 0x0000…02b4
TRACE evm: Gasometer Record cost 3 [Gas used: 38, Gas left: 79687]
TRACE evm: OpCode Dup4 [@4]: 0x0000…0060
TRACE evm: Gasometer Record dynamic cost 12 - memory_gas 18 - gas_refund 0 [Gas used: 41, Gas left: 79684]
TRACE evm: OpCode CodeCopy: 96
TRACE evm: Gasometer Record cost 3 [Gas used: 62, Gas left: 79663]
TRACE evm: OpCode overflowing_add 96, 96: 192
TRACE evm: Gasometer Record cost 3 [Gas used: 65, Gas left: 79660]
TRACE evm: OpCode Push [@1]: 0x0000…0040
TRACE evm: Gasometer Record dynamic cost 3 - memory_gas 18 - gas_refund 0 [Gas used: 68, Gas left: 79657]
TRACE evm: OpCode MStore: 64, 0x0000…00c0
TRACE evm: Gasometer Record cost 3 [Gas used: 71, Gas left: 79654]
TRACE evm: OpCode Push [@0]: 0x0000…0060
TRACE evm: Gasometer Record cost 3 [Gas used: 74, Gas left: 79651]
TRACE evm: OpCode Dup1 [@1]: 0x0000…0060
TRACE evm: Gasometer Record dynamic cost 3 - memory_gas 18 - gas_refund 0 [Gas used: 77, Gas left: 79648]
TRACE evm: OpCode MLoad: 96
TRACE evm: Gasometer Record cost 3 [Gas used: 80, Gas left: 79645]
TRACE evm: OpCode Push [@2]: 0x0000…0060
TRACE evm: Gasometer Record cost 3 [Gas used: 83, Gas left: 79642]
TRACE evm: OpCode overflowing_add 96, 32: 128
TRACE evm: Gasometer Record cost 3 [Gas used: 86, Gas left: 79639]
TRACE evm: OpCode Swap [@0:@1]: 0x0000…0080, 0x0000…0060
TRACE evm: Gasometer Record cost 3 [Gas used: 89, Gas left: 79636]
TRACE evm: OpCode Push [@2]: 0x0000…0020
TRACE evm: Gasometer Record cost 3 [Gas used: 92, Gas left: 79633]
TRACE evm: OpCode overflowing_add 32, 96: 128
TRACE evm: Gasometer Record cost 2 [Gas used: 95, Gas left: 79630]
TRACE evm: OpCode Pop [@1]: 0x0000…0080
TRACE evm: Gasometer Record cost 1 [Gas used: 97, Gas left: 79628]
TRACE evm: Gasometer Record cost 1 [Gas used: 98, Gas left: 79627]
TRACE evm: Gasometer Record cost 2 [Gas used: 99, Gas left: 79626]
TRACE evm: OpCode Trap: Opcode(51)
TRACE evm: Gasometer Record cost 3 [Gas used: 101, Gas left: 79624]
TRACE evm: OpCode Push [@2]: 0x0000…0000
TRACE evm: Gasometer Record cost 3 [Gas used: 104, Gas left: 79621]
TRACE evm: OpCode Push [@3]: 0x0000…0000
TRACE evm: Gasometer Record cost 3 [Gas used: 107, Gas left: 79618]
TRACE evm: OpCode Push [@4]: 0x0000…0100
TRACE evm: Gasometer Record dynamic cost 10 - memory_gas 18 - gas_refund 0 [Gas used: 110, Gas left: 79615]
TRACE evm: OpCode self::arithmetic::exp 256, 0: 1
TRACE evm: Gasometer Record cost 3 [Gas used: 120, Gas left: 79605]
TRACE evm: OpCode Dup2 [@4]: 0x0000…0000
TRACE evm: Gasometer Record dynamic cost 50 - memory_gas 18 - gas_refund 0 [Gas used: 123, Gas left: 79602]
TRACE evm: OpCode Trap: Opcode(84)
TRACE evm: Gasometer Record cost 3 [Gas used: 173, Gas left: 79552]
TRACE evm: OpCode Dup2 [@5]: 0x0000…0001
TRACE evm: Gasometer Record cost 3 [Gas used: 176, Gas left: 79549]
TRACE evm: OpCode Push [@6]: 0x0000…ffff
TRACE evm: Gasometer Record cost 5 [Gas used: 179, Gas left: 79546]
TRACE evm: OpCode overflowing_mul 1461501637330902918203684832716283019655932542975, 1: 1461501637330902918203684832716283019655932542975
TRACE evm: Gasometer Record cost 3 [Gas used: 184, Gas left: 79541]
TRACE evm: OpCode self::bitwise::not 1461501637330902918203684832716283019655932542975: 115792089237316195423570985007226406215939081747436879206741300988257197096960
TRACE evm: Gasometer Record cost 3 [Gas used: 187, Gas left: 79538]
TRACE evm: OpCode bitand 115792089237316195423570985007226406215939081747436879206741300988257197096960, 0: 0
TRACE evm: Gasometer Record cost 3 [Gas used: 190, Gas left: 79535]
TRACE evm: OpCode Swap [@0:@1]: 0x0000…0000, 0x0000…0001
TRACE evm: Gasometer Record cost 3 [Gas used: 193, Gas left: 79532]
TRACE evm: OpCode Dup4 [@5]: 0x0000…6c2d
TRACE evm: Gasometer Record cost 5 [Gas used: 196, Gas left: 79529]
TRACE evm: OpCode overflowing_mul 348413676108971912559174908100972406029277031469, 1: 348413676108971912559174908100972406029277031469
TRACE evm: Gasometer Record cost 3 [Gas used: 201, Gas left: 79524]
TRACE evm: OpCode bitor 348413676108971912559174908100972406029277031469, 0: 348413676108971912559174908100972406029277031469
TRACE evm: Gasometer Record cost 3 [Gas used: 204, Gas left: 79521]
TRACE evm: OpCode Swap [@0:@1]: 0x0000…6c2d, 0x0000…0000
TRACE evm: Gasometer Record dynamic cost 20000 - memory_gas 18 - gas_refund 0 [Gas used: 207, Gas left: 79518]
TRACE evm: OpCode Trap: Opcode(85)
TRACE evm: Gasometer Record cost 2 [Gas used: 20207, Gas left: 59518]
TRACE evm: OpCode Pop [@1]: 0x0000…6c2d
TRACE evm: Gasometer Record cost 1 [Gas used: 20209, Gas left: 59516]
TRACE evm: Gasometer Record cost 3 [Gas used: 20210, Gas left: 59515]
TRACE evm: OpCode Dup1 [@1]: 0x0000…0080
TRACE evm: Gasometer Record cost 3 [Gas used: 20213, Gas left: 59512]
TRACE evm: OpCode Push [@2]: 0x0000…0001
TRACE evm: Gasometer Record cost 3 [Gas used: 20216, Gas left: 59509]
TRACE evm: OpCode Push [@3]: 0x0000…0000
TRACE evm: Gasometer Record cost 2 [Gas used: 20219, Gas left: 59506]
TRACE evm: OpCode Pop [@3]: 0x0000…0000
TRACE evm: Gasometer Record cost 3 [Gas used: 20221, Gas left: 59504]
TRACE evm: OpCode Swap [@0:@1]: 0x0000…0001, 0x0000…0080
TRACE evm: Gasometer Record cost 3 [Gas used: 20224, Gas left: 59501]
TRACE evm: OpCode Dup1 [@3]: 0x0000…0080
TRACE evm: Gasometer Record dynamic cost 3 - memory_gas 18 - gas_refund 0 [Gas used: 20227, Gas left: 59498]
TRACE evm: OpCode MLoad: 128
TRACE evm: Gasometer Record cost 3 [Gas used: 20230, Gas left: 59495]
TRACE evm: OpCode Swap [@0:@1]: 0x0000…000c, 0x0000…0080
TRACE evm: Gasometer Record cost 3 [Gas used: 20233, Gas left: 59492]
TRACE evm: OpCode Push [@4]: 0x0000…0020
TRACE evm: Gasometer Record cost 3 [Gas used: 20236, Gas left: 59489]
TRACE evm: OpCode overflowing_add 32, 128: 160
TRACE evm: Gasometer Record cost 3 [Gas used: 20239, Gas left: 59486]
TRACE evm: OpCode Swap [@0:@1]: 0x0000…00a0, 0x0000…000c
TRACE evm: Gasometer Record cost 3 [Gas used: 20242, Gas left: 59483]
TRACE evm: OpCode Dup3 [@4]: 0x0000…0001
TRACE evm: Gasometer Record cost 3 [Gas used: 20245, Gas left: 59480]
TRACE evm: OpCode Dup1 [@5]: 0x0000…0001
TRACE evm: Gasometer Record dynamic cost 50 - memory_gas 18 - gas_refund 0 [Gas used: 20248, Gas left: 59477]
TRACE evm: OpCode Trap: Opcode(84)
TRACE evm: Gasometer Record cost 3 [Gas used: 20298, Gas left: 59427]
TRACE evm: OpCode Dup3 [@6]: 0x0000…000c
TRACE evm: Gasometer Record cost 3 [Gas used: 20301, Gas left: 59424]
TRACE evm: OpCode Dup3 [@7]: 0x0000…0001
TRACE evm: Gasometer Record dynamic cost 20000 - memory_gas 18 - gas_refund 0 [Gas used: 20304, Gas left: 59421]
TRACE evm: OpCode Trap: Opcode(85)
TRACE evm: Gasometer Record cost 3 [Gas used: 40304, Gas left: 39421]
TRACE evm: OpCode Swap [@0:@1]: 0x0000…0000, 0x0000…0001
TRACE evm: Gasometer Record cost 3 [Gas used: 40307, Gas left: 39418]
TRACE evm: OpCode Push [@6]: 0x0000…0000
TRACE evm: Gasometer Record dynamic cost 3 - memory_gas 18 - gas_refund 0 [Gas used: 40310, Gas left: 39415]
TRACE evm: OpCode MStore: 0, 0x0000…0001
TRACE evm: Gasometer Record cost 3 [Gas used: 40313, Gas left: 39412]
TRACE evm: OpCode Push [@5]: 0x0000…0020
TRACE evm: Gasometer Record cost 3 [Gas used: 40316, Gas left: 39409]
TRACE evm: OpCode Push [@6]: 0x0000…0000
TRACE evm: Gasometer Record dynamic cost 36 - memory_gas 18 - gas_refund 0 [Gas used: 40319, Gas left: 39406]
TRACE evm: OpCode Trap: Opcode(32)
TRACE evm: Gasometer Record cost 3 [Gas used: 40355, Gas left: 39370]
TRACE evm: OpCode Swap [@0:@1]: 0xb10e…0cf6, 0x0000…0000
TRACE evm: Gasometer Record cost 3 [Gas used: 40358, Gas left: 39367]
TRACE evm: OpCode Push [@6]: 0x0000…001f
TRACE evm: Gasometer Record cost 3 [Gas used: 40361, Gas left: 39364]
TRACE evm: OpCode overflowing_add 31, 0: 31
TRACE evm: Gasometer Record cost 3 [Gas used: 40364, Gas left: 39361]
TRACE evm: OpCode Push [@6]: 0x0000…0020
TRACE evm: Gasometer Record cost 3 [Gas used: 40367, Gas left: 39358]
TRACE evm: OpCode Swap [@0:@1]: 0x0000…0020, 0x0000…001f
TRACE evm: Gasometer Record cost 5 [Gas used: 40370, Gas left: 39355]
TRACE evm: OpCode self::arithmetic::div 31, 32: 0
TRACE evm: Gasometer Record cost 3 [Gas used: 40375, Gas left: 39350]
TRACE evm: OpCode Dup2 [@6]: 0xb10e…0cf6
TRACE evm: Gasometer Record cost 3 [Gas used: 40378, Gas left: 39347]
TRACE evm: OpCode overflowing_add 80084422859880547211683076133703299733277748156566366325829078699459944778998, 0: 80084422859880547211683076133703299733277748156566366325829078699459944778998
TRACE evm: Gasometer Record cost 3 [Gas used: 40381, Gas left: 39344]
TRACE evm: OpCode Swap [@0:@3]: 0xb10e…0cf6, 0x0000…00a0
TRACE evm: Gasometer Record cost 3 [Gas used: 40384, Gas left: 39341]
TRACE evm: OpCode Dup3 [@6]: 0x0000…000c
TRACE evm: Gasometer Record cost 3 [Gas used: 40387, Gas left: 39338]
TRACE evm: OpCode self::bitwise::iszero 12: 0
TRACE evm: Gasometer Record cost 3 [Gas used: 40390, Gas left: 39335]
TRACE evm: OpCode Push [@7]: 0x0000…009e
TRACE evm: Gasometer Record cost 10 [Gas used: 40393, Gas left: 39332]
TRACE evm: OpCode JumpI: skipped
TRACE evm: Gasometer Record cost 3 [Gas used: 40403, Gas left: 39322]
TRACE evm: OpCode Swap [@0:@2]: 0x0000…00a0, 0x0000…000c
TRACE evm: Gasometer Record cost 3 [Gas used: 40406, Gas left: 39319]
TRACE evm: OpCode Dup3 [@6]: 0x0000…00a0
TRACE evm: Gasometer Record cost 3 [Gas used: 40409, Gas left: 39316]
TRACE evm: OpCode overflowing_add 160, 12: 172
TRACE evm: Gasometer Record cost 1 [Gas used: 40412, Gas left: 39313]
TRACE evm: Gasometer Record cost 3 [Gas used: 40413, Gas left: 39312]
TRACE evm: OpCode Dup3 [@6]: 0x0000…00a0
TRACE evm: Gasometer Record cost 3 [Gas used: 40416, Gas left: 39309]
TRACE evm: OpCode Dup2 [@7]: 0x0000…00ac
TRACE evm: Gasometer Record cost 3 [Gas used: 40419, Gas left: 39306]
TRACE evm: OpCode gt 172, 160: true
TRACE evm: Gasometer Record cost 3 [Gas used: 40422, Gas left: 39303]
TRACE evm: OpCode self::bitwise::iszero 1: 0
TRACE evm: Gasometer Record cost 3 [Gas used: 40425, Gas left: 39300]
TRACE evm: OpCode Push [@7]: 0x0000…009d
TRACE evm: Gasometer Record cost 10 [Gas used: 40428, Gas left: 39297]
TRACE evm: OpCode JumpI: skipped
TRACE evm: Gasometer Record cost 3 [Gas used: 40438, Gas left: 39287]
TRACE evm: OpCode Dup3 [@6]: 0x0000…00a0
TRACE evm: Gasometer Record dynamic cost 3 - memory_gas 18 - gas_refund 0 [Gas used: 40441, Gas left: 39284]
TRACE evm: OpCode MLoad: 160
TRACE evm: Gasometer Record cost 3 [Gas used: 40444, Gas left: 39281]
TRACE evm: OpCode Dup3 [@7]: 0xb10e…0cf6
TRACE evm: Gasometer Record cost 3 [Gas used: 40447, Gas left: 39278]
TRACE evm: OpCode Push [@8]: 0x0000…0000
TRACE evm: Gasometer Record cost 2 [Gas used: 40450, Gas left: 39275]
TRACE evm: OpCode Pop [@8]: 0x0000…0000
TRACE evm: Gasometer Record dynamic cost 20000 - memory_gas 18 - gas_refund 0 [Gas used: 40452, Gas left: 39273]
TRACE evm: OpCode Trap: Opcode(85)
TRACE evm: Gasometer Record cost 3 [Gas used: 60452, Gas left: 19273]
TRACE evm: OpCode Swap [@0:@2]: 0x0000…00ac, 0x0000…00a0
TRACE evm: Gasometer Record cost 3 [Gas used: 60455, Gas left: 19270]
TRACE evm: OpCode Push [@6]: 0x0000…0020
TRACE evm: Gasometer Record cost 3 [Gas used: 60458, Gas left: 19267]
TRACE evm: OpCode overflowing_add 32, 160: 192
TRACE evm: Gasometer Record cost 3 [Gas used: 60461, Gas left: 19264]
TRACE evm: OpCode Swap [@0:@2]: 0x0000…00c0, 0x0000…00ac
TRACE evm: Gasometer Record cost 3 [Gas used: 60464, Gas left: 19261]
TRACE evm: OpCode Swap [@0:@1]: 0x0000…00ac, 0xb10e…0cf6
TRACE evm: Gasometer Record cost 3 [Gas used: 60467, Gas left: 19258]
TRACE evm: OpCode Push [@6]: 0x0000…0001
TRACE evm: Gasometer Record cost 3 [Gas used: 60470, Gas left: 19255]
TRACE evm: OpCode overflowing_add 1, 80084422859880547211683076133703299733277748156566366325829078699459944778998: 80084422859880547211683076133703299733277748156566366325829078699459944778999
TRACE evm: Gasometer Record cost 3 [Gas used: 60473, Gas left: 19252]
TRACE evm: OpCode Swap [@0:@1]: 0xb10e…0cf7, 0x0000…00ac
TRACE evm: Gasometer Record cost 3 [Gas used: 60476, Gas left: 19249]
TRACE evm: OpCode Push [@6]: 0x0000…0081
TRACE evm: Gasometer Record cost 8 [Gas used: 60479, Gas left: 19246]
TRACE evm: OpCode Jump: 129
TRACE evm: Gasometer Record cost 1 [Gas used: 60487, Gas left: 19238]
TRACE evm: Gasometer Record cost 3 [Gas used: 60488, Gas left: 19237]
TRACE evm: OpCode Dup3 [@6]: 0x0000…00c0
TRACE evm: Gasometer Record cost 3 [Gas used: 60491, Gas left: 19234]
TRACE evm: OpCode Dup2 [@7]: 0x0000…00ac
TRACE evm: Gasometer Record cost 3 [Gas used: 60494, Gas left: 19231]
TRACE evm: OpCode gt 172, 192: false
TRACE evm: Gasometer Record cost 3 [Gas used: 60497, Gas left: 19228]
TRACE evm: OpCode self::bitwise::iszero 0: 1
TRACE evm: Gasometer Record cost 3 [Gas used: 60500, Gas left: 19225]
TRACE evm: OpCode Push [@7]: 0x0000…009d
TRACE evm: Gasometer Record cost 10 [Gas used: 60503, Gas left: 19222]
TRACE evm: OpCode JumpI: 157
TRACE evm: Gasometer Record cost 1 [Gas used: 60513, Gas left: 19212]
TRACE evm: Gasometer Record cost 1 [Gas used: 60514, Gas left: 19211]
TRACE evm: Gasometer Record cost 2 [Gas used: 60515, Gas left: 19210]
TRACE evm: OpCode Pop [@5]: 0x0000…00ac
TRACE evm: Gasometer Record cost 3 [Gas used: 60517, Gas left: 19208]
TRACE evm: OpCode Swap [@0:@1]: 0xb10e…0cf7, 0x0000…00c0
TRACE evm: Gasometer Record cost 2 [Gas used: 60520, Gas left: 19205]
TRACE evm: OpCode Pop [@4]: 0x0000…00c0
TRACE evm: Gasometer Record cost 3 [Gas used: 60522, Gas left: 19203]
TRACE evm: OpCode Push [@4]: 0x0000…00c5
TRACE evm: Gasometer Record cost 3 [Gas used: 60525, Gas left: 19200]
TRACE evm: OpCode Swap [@0:@2]: 0x0000…00c5, 0xb10e…0cf6
TRACE evm: Gasometer Record cost 3 [Gas used: 60528, Gas left: 19197]
TRACE evm: OpCode Swap [@0:@1]: 0xb10e…0cf6, 0xb10e…0cf7
TRACE evm: Gasometer Record cost 3 [Gas used: 60531, Gas left: 19194]
TRACE evm: OpCode Push [@5]: 0x0000…00a9
TRACE evm: Gasometer Record cost 8 [Gas used: 60534, Gas left: 19191]
TRACE evm: OpCode Jump: 169
TRACE evm: Gasometer Record cost 1 [Gas used: 60542, Gas left: 19183]
TRACE evm: Gasometer Record cost 3 [Gas used: 60543, Gas left: 19182]
TRACE evm: OpCode Dup1 [@5]: 0xb10e…0cf7
TRACE evm: Gasometer Record cost 3 [Gas used: 60546, Gas left: 19179]
TRACE evm: OpCode Dup3 [@6]: 0xb10e…0cf6
TRACE evm: Gasometer Record cost 3 [Gas used: 60549, Gas left: 19176]
TRACE evm: OpCode gt 80084422859880547211683076133703299733277748156566366325829078699459944778998, 80084422859880547211683076133703299733277748156566366325829078699459944778999: false
TRACE evm: Gasometer Record cost 3 [Gas used: 60552, Gas left: 19173]
TRACE evm: OpCode self::bitwise::iszero 0: 1
TRACE evm: Gasometer Record cost 3 [Gas used: 60555, Gas left: 19170]
TRACE evm: OpCode Push [@6]: 0x0000…00c1
TRACE evm: Gasometer Record cost 10 [Gas used: 60558, Gas left: 19167]
TRACE evm: OpCode JumpI: 193
TRACE evm: Gasometer Record cost 1 [Gas used: 60568, Gas left: 19157]
TRACE evm: Gasometer Record cost 2 [Gas used: 60569, Gas left: 19156]
TRACE evm: OpCode Pop [@4]: 0xb10e…0cf7
TRACE evm: Gasometer Record cost 3 [Gas used: 60571, Gas left: 19154]
TRACE evm: OpCode Swap [@0:@1]: 0xb10e…0cf6, 0x0000…00c5
TRACE evm: Gasometer Record cost 8 [Gas used: 60574, Gas left: 19151]
TRACE evm: OpCode Jump: 197
TRACE evm: Gasometer Record cost 1 [Gas used: 60582, Gas left: 19143]
TRACE evm: Gasometer Record cost 2 [Gas used: 60583, Gas left: 19142]
TRACE evm: OpCode Pop [@2]: 0xb10e…0cf6
TRACE evm: Gasometer Record cost 2 [Gas used: 60585, Gas left: 19140]
TRACE evm: OpCode Pop [@1]: 0x0000…0001
TRACE evm: Gasometer Record cost 1 [Gas used: 60587, Gas left: 19138]
TRACE evm: Gasometer Record cost 2 [Gas used: 60588, Gas left: 19137]
TRACE evm: OpCode Pop [@0]: 0x0000…0080
TRACE evm: Gasometer Record cost 3 [Gas used: 60590, Gas left: 19135]
TRACE evm: OpCode Push [@0]: 0x0000…01dc
TRACE evm: Gasometer Record cost 3 [Gas used: 60593, Gas left: 19132]
TRACE evm: OpCode Dup1 [@1]: 0x0000…01dc
TRACE evm: Gasometer Record cost 3 [Gas used: 60596, Gas left: 19129]
TRACE evm: OpCode Push [@2]: 0x0000…00d8
TRACE evm: Gasometer Record cost 3 [Gas used: 60599, Gas left: 19126]
TRACE evm: OpCode Push [@3]: 0x0000…0000
TRACE evm: Gasometer Record dynamic cost 48 - memory_gas 45 - gas_refund 0 [Gas used: 60602, Gas left: 19123]
TRACE evm: OpCode CodeCopy: 476
TRACE evm: Gasometer Record cost 3 [Gas used: 60677, Gas left: 19048]
TRACE evm: OpCode Push [@1]: 0x0000…0000
TRACE evm: Gasometer Record dynamic cost 0 - memory_gas 45 - gas_refund 0 [Gas used: 60680, Gas left: 19045]
TRACE evm: OpCode Return
DEBUG evm: Create execution using address 0x630e…fe7a: Succeed(Returned)
TRACE evm: Gasometer Record cost 95200 [Gas used: 60680, Gas left: 19045]
Hardfork: frontier
Gas used: 125984
Result: Succeed(Returned)
Empty Contract Created at 0x630ea66c8c5dc205d45a978573fa86df5af1fe7a
The difference in the execution is that if there's no gas for paying the bytecode deposit bytes.len() * 200
, it must deploy an Empty Contract Account, which is the same as deploying a regular contract, but without the bytecode.
{
"nonce": 0,
"balance": tx.value,
"code": [], // empty bytes
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000003d0768da09ce77d25e2d998e6a7b6ed4b9116c2d",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x000000000000000000000000000000000000000000000000000000000000000c",
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": "0x48656c6c6f20576f726c64210000000000000000000000000000000000000000"
},
}
For compute the state root I'm using this crate: https://docs.rs/trie-root/latest/trie_root/
This is more like a question than an issue.
I'm building a compiler from Move to EVM with Yul as the intermediate language. We are using Sputnik (for now) as a backend for various test scenarios, as we are developing in Rust. It works pretty well for us.
When using evm_runtime::tracing
, is there a way to get hand one the source position information of a step? Not sure whether the handling of source positions is more like an internal of Solidity/Yul. or part of the EVM semantics.
17 | #[auto_impl::auto_impl(&mut, Box)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not find `std` in the list of imported crates
|
= note: this error originates in the attribute macro `auto_impl::auto_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
I deploy the contract both in this evm and remix:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.4;
contract C {
function test() public pure returns (uint, uint, bytes32, bytes20, address) {
bytes32 kec = keccak256("abc");
// bytes32 sha = sha256("abc"); this evm not supports the sha256
bytes20 rip = ripemd160("abc");
uint add = addmod(10, 6, 9);
uint mul = mulmod(4, 4, 9);
bytes32 hash = 0x5cc4cee58087de1a2ea481fe9c65c92adc27cff464b7f00a486dc9bf6bb8efb3;
bytes32 r = 0x32573a0b258f251971a4ec35511c018a7e7bf75a5886534b48d12e47263048a2;
bytes32 s = 0xfe6e03543955255e235388b224704555fd036a954d3ee6dd030d9d1fea1830d7;
uint8 v = 0x1c;
address addr = ecrecover(hash, v, r, s);
return (add, mul, kec, rip, addr);
}
}
bytes32 sha = sha256("abc");
this line can be called in remix, but can't be called in this evm:
trapped explicitly: Revert(Reverted)
after delete this line, everything is ok
Can you share the solidity source code used in the benchmark benches/loop.rs
?
I'm considering writing a custom gasometer, and I want to get some initial feedback on my idea.
The main goal is to create an evm-compatible chain that meters gas in terms of storage and compute independently. I see that the gasometer is already somewhat configurable - it is easy to tune gas costs to your liking. But it is not generic over the gas units used; it always uses usize
(and isize
in a few places related to refunds).
My idea would be to first make the gasometer generic over the units used. I would then use a structure like this as my gas unit (or a simple tuple).
/// A unit for measuring gas. Tracks compute and storage costs individually.
pub struct ComputeAndStorageCosts {
compute: usize,
storage: usize,
}
In my very basic exploration, it seemed the place to start with the Config
struct, where I brainstormed something like:
/// Runtime configuration.
#[derive(Clone, Debug)]
pub struct Config<UnsignedUnits, SignedUnits> {
/// Gas paid for extcode.
pub gas_ext_code: UnsignedUnits,
/// Gas paid for extcodehash.
pub gas_ext_code_hash: UnsignedUnits,
/// Gas paid for sstore set.
pub gas_sstore_set: UnsignedUnits,
/// Gas paid for sstore reset.
pub gas_sstore_reset: UnsignedUnits,
/// Gas paid for sstore refund.
pub refund_sstore_clears: SignedUnits,
// --snip--
}
So some questions. Does this seem like a realistic improvement to make? Does it seem like the right direction to begin tackling it?
A change was introduced in version 0.30 that forces to provide a constant list of precompiles in
a BTreeMap. This raises an issue for projects that don't work with that assumption. For
example a Substrate like a parachain might want to dynamically register new precompiles that
was not known when creating the StackExecutor. Also, that list may be huge and allocate a lot of
memory, or even need a lot of storages access to be built.
We propose to go back to the previous trait design with a slight change :
pub trait PrecompileSet {
// Unchanged
fn execute(
address: H160,
input: &[u8],
target_gas: Option<u64>,
context: &Context,
) -> Option<Result<PrecompileOutput, ExitError>>;
// New function that tells if an address corresponds to a precompile.
fn is_precompile(address: H160) -> bool;
}
In regards to the warm addresses cache, it would not be initialized with the list of
precompiles (only the access list, from and into). Instead, in the warm cache test, it would first
check if the address is in the cache. If it is not, it would call the is_precompile
function, and
if this function returns true, the address is added to the cache (to avoid calling is_precompile
again for this specific address).
Of course it is worth noting that the is_precompile
implementation should minimize overhead (use
a static list if possible, read substrate storage only if necessary, etc).
Side note : this PrecompileSet
could be implemented for BTreeMap<H160, PrecompileFn>
to stay close
with the current BTreeMap
approach.
When the extend bytes are not enough, for example, the byte code is 0x64ffff
(which is PUSH5
followed by 0xffff), according to yellow paper, the bytes are right aligned in this case, so the value on the stack should be 0xffff000000
, however it's 0xffff
on sputnikvm.
We should remove the tracing
based debugging interface and instead wrap Machine
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.