-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
EVM runtime: implement LOG{0..4} opcodes by emitting actor events (FI…
…P-0049) (#839)
- Loading branch information
Showing
26 changed files
with
262 additions
and
51 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,57 @@ | ||
use crate::interpreter::instructions::memory::get_memory_region; | ||
use fvm_ipld_encoding::{to_vec, BytesSer, RawBytes}; | ||
use fvm_shared::event::{Entry, Flags}; | ||
use { | ||
crate::interpreter::{ExecutionState, StatusCode, System}, | ||
fil_actors_runtime::runtime::Runtime, | ||
}; | ||
|
||
#[cfg(debug_assertions)] | ||
pub fn log( | ||
_state: &mut ExecutionState, | ||
_system: &System<impl Runtime>, | ||
_num_topics: usize, | ||
) -> Result<(), StatusCode> { | ||
todo!("unimplemented"); | ||
} | ||
/// The event key for the Ethereum log data. | ||
const EVENT_DATA_KEY: &str = "data"; | ||
|
||
/// The event keys for the Ethereum log topics. | ||
const EVENT_TOPIC_KEYS: &[&str] = &["topic1", "topic2", "topic3", "topic4"]; | ||
|
||
#[cfg(not(debug_assertions))] | ||
#[inline] | ||
pub fn log( | ||
state: &mut ExecutionState, | ||
_system: &System<impl Runtime>, | ||
system: &System<impl Runtime>, | ||
num_topics: usize, | ||
) -> Result<(), StatusCode> { | ||
// TODO: Right now, we just drop everything. But we implement this in production anyways so | ||
// things work. | ||
for _ in 0..num_topics { | ||
state.stack.pop(); | ||
// Handle the data. | ||
// Passing in a zero-sized memory region omits the data key entirely. | ||
// LOG0 + a zero-sized memory region emits an event with no entries whatsoever. In this case, | ||
// the FVM will record a hollow event carrying only the emitter actor ID. | ||
let mem_index = state.stack.pop(); | ||
let size = state.stack.pop(); | ||
let region = get_memory_region(&mut state.memory, mem_index, size) | ||
.map_err(|_| StatusCode::InvalidMemoryAccess)?; | ||
|
||
// Extract the topics. Prefer to allocate an extra item than to incur in the cost of a | ||
// decision based on the size of the data. | ||
let mut entries: Vec<Entry> = Vec::with_capacity(num_topics + 1); | ||
for key in EVENT_TOPIC_KEYS.iter().take(num_topics) { | ||
let topic = state.stack.pop(); | ||
let entry = Entry { | ||
flags: Flags::FLAG_INDEXED_VALUE, | ||
key: (*key).to_owned(), | ||
value: to_vec(&topic)?.into(), // U256 serializes as a byte string. | ||
}; | ||
entries.push(entry); | ||
} | ||
|
||
// Skip adding the data if it's zero-sized. | ||
if let Some(r) = region { | ||
let data = state.memory[r.offset..r.offset + r.size.get()].to_vec(); | ||
let entry = Entry { | ||
flags: Flags::FLAG_INDEXED_VALUE, | ||
key: EVENT_DATA_KEY.to_owned(), | ||
value: RawBytes::serialize(BytesSer(&data))?, | ||
}; | ||
entries.push(entry); | ||
} | ||
|
||
system.rt.emit_event(&entries.into())?; | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
mod asm; | ||
|
||
use fvm_ipld_encoding::{to_vec, RawBytes}; | ||
use fvm_shared::event::{ActorEvent, Entry, Flags}; | ||
|
||
mod util; | ||
|
||
#[allow(dead_code)] | ||
pub fn events_contract() -> Vec<u8> { | ||
let init = r#" | ||
"#; | ||
let body = r#" | ||
# method dispatch: | ||
# - 0x00000000 -> log_zero_data | ||
# - 0x00000001 -> log_zero_nodata | ||
# - 0x00000002 -> log_four_data | ||
%dispatch_begin() | ||
%dispatch(0x00, log_zero_data) | ||
%dispatch(0x01, log_zero_nodata) | ||
%dispatch(0x02, log_four_data) | ||
%dispatch_end() | ||
#### log a zero topic event with data | ||
log_zero_data: | ||
jumpdest | ||
push8 0x1122334455667788 | ||
push1 0x00 | ||
mstore | ||
push1 0x08 | ||
push1 0x18 ## index 24 into memory as mstore writes a full word | ||
log0 | ||
push1 0x00 | ||
push1 0x00 | ||
return | ||
#### log a zero topic event with no data | ||
log_zero_nodata: | ||
jumpdest | ||
push1 0x00 | ||
push1 0x00 | ||
log0 | ||
push1 0x00 | ||
push1 0x00 | ||
return | ||
#### log a four topic event with data | ||
log_four_data: | ||
jumpdest | ||
push8 0x1122334455667788 | ||
push1 0x00 | ||
mstore | ||
push4 0x4444 | ||
push3 0x3333 | ||
push2 0x2222 | ||
push2 0x1111 | ||
push1 0x08 | ||
push1 0x18 ## index 24 into memory as mstore writes a full word | ||
log4 | ||
push1 0x00 | ||
push1 0x00 | ||
return | ||
"#; | ||
|
||
asm::new_contract("events", init, body).unwrap() | ||
} | ||
|
||
#[test] | ||
fn test_events() { | ||
let contract = events_contract(); | ||
|
||
let mut rt = util::construct_and_verify(contract); | ||
|
||
// log zero with data | ||
let mut contract_params = vec![0u8; 32]; | ||
rt.expect_emitted_event(ActorEvent { | ||
entries: vec![Entry { | ||
flags: Flags::FLAG_INDEXED_VALUE, | ||
key: "data".to_string(), | ||
value: to_vec(&RawBytes::from( | ||
[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88].to_vec(), | ||
)) | ||
.unwrap() | ||
.into(), | ||
}], | ||
}); | ||
util::invoke_contract(&mut rt, &contract_params); | ||
|
||
// log zero without data | ||
contract_params[3] = 0x01; | ||
rt.expect_emitted_event(ActorEvent { entries: vec![] }); | ||
util::invoke_contract(&mut rt, &contract_params); | ||
|
||
// log four with data | ||
contract_params[3] = 0x02; | ||
rt.expect_emitted_event(ActorEvent { | ||
entries: vec![ | ||
Entry { | ||
flags: Flags::FLAG_INDEXED_VALUE, | ||
key: "topic1".to_string(), | ||
value: to_vec(&RawBytes::from([0x11, 0x11].to_vec())).unwrap().into(), | ||
}, | ||
Entry { | ||
flags: Flags::FLAG_INDEXED_VALUE, | ||
key: "topic2".to_string(), | ||
value: to_vec(&RawBytes::from([0x22, 0x22].to_vec())).unwrap().into(), | ||
}, | ||
Entry { | ||
flags: Flags::FLAG_INDEXED_VALUE, | ||
key: "topic3".to_string(), | ||
value: to_vec(&RawBytes::from([0x33, 0x33].to_vec())).unwrap().into(), | ||
}, | ||
Entry { | ||
flags: Flags::FLAG_INDEXED_VALUE, | ||
key: "topic4".to_string(), | ||
value: to_vec(&RawBytes::from([0x44, 0x44].to_vec())).unwrap().into(), | ||
}, | ||
Entry { | ||
flags: Flags::FLAG_INDEXED_VALUE, | ||
key: "data".to_string(), | ||
value: to_vec(&RawBytes::from( | ||
[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88].to_vec(), | ||
)) | ||
.unwrap() | ||
.into(), | ||
}, | ||
], | ||
}); | ||
util::invoke_contract(&mut rt, &contract_params); | ||
|
||
rt.verify(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.