Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 15 additions & 7 deletions crates/bytecode/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,27 @@ paste = { workspace = true, optional = true }
phf = { workspace = true, features = ["macros"], optional = true }

[dev-dependencies]
serde_json = { workspace = true }
anyhow.workspace = true
rand.workspace = true
serde_json.workspace = true

[features]
default = ["std", "parse"]
std = [
"serde?/std",
"serde_json/std",
"primitives/std",
"bitvec/std",
"phf?/std",
"serde?/std",
"serde_json/std",
"primitives/std",
"bitvec/std",
"phf?/std",
]
hashbrown = ["primitives/hashbrown"]
serde = ["dep:serde", "primitives/serde", "bitvec/serde", "phf?/serde"]
serde = [
"dep:serde",
"primitives/serde",
"bitvec/serde",
"phf?/serde",
"rand/serde"
]
parse = ["phf", "paste"]

# Deprecated, please use `serde` feature instead.
Expand Down
91 changes: 91 additions & 0 deletions crates/bytecode/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,94 @@ pub unsafe fn read_i16(ptr: *const u8) -> i16 {
pub unsafe fn read_u16(ptr: *const u8) -> u16 {
u16::from_be_bytes(unsafe { ptr.cast::<[u8; 2]>().read() })
}

/// Bytecode test utilities
#[cfg(test)]
pub mod test {
use crate::opcode;
use anyhow::Result;
use primitives::U256;
use rand::Rng;

/// Constructs bytecode for inserting input into memory
pub fn build_memory_input_opcodes(start_offset: U256, input: &[u8]) -> Result<Vec<u8>> {
let mut opcodes = vec![];
let mut current_offset = start_offset;

// Iterate for each 32 bytes to prepend PUSH* and append MSTORE opcodes
let offset_step = U256::from(32);
for bytes in input.chunks(32) {
// Push the input value
build_push_bytes(bytes, &mut opcodes);

// Push the memory offset
build_push_u256(current_offset, &mut opcodes);

// Call MSTORE
opcodes.push(opcode::MSTORE);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

MSTORE uses two items, where one is offset https://www.evm.codes/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in commit 35ea2a2


// Increase the memory offset
current_offset += offset_step;
}

Ok(opcodes)
}

// Constructs a PUSH* instruction for an Uint256
fn build_push_u256(value: U256, opcodes: &mut Vec<u8>) {
let bytes = value.to_be_bytes_trimmed_vec();
build_push_bytes(&bytes, opcodes);
}

// Constructs a PUSH* instruction for the value of byte size is not greater than 32
fn build_push_bytes(bytes: &[u8], opcodes: &mut Vec<u8>) {
let len = bytes.len();
assert!(len <= 32);

let push_opcode = opcode::PUSH0 + len as u8;
opcodes.push(push_opcode);

opcodes.extend_from_slice(bytes);
}

#[test]
fn test_build_memory_input_opcodes() {
let mut rng = rand::rng();

// make the memory offset as 4 bytes for test
let start_offset = rng.random_range(0x0100_0000..=(u32::MAX - 100));
let mut current_offset = start_offset;

let mut all_inputs = vec![];
let mut expected_opcodes = vec![];

// Generate 32 bytes input array
let input_arr: [[u8; 32]; 3] = rng.random();
for input in input_arr {
all_inputs.extend(input);

expected_opcodes.push(opcode::PUSH32);
expected_opcodes.extend(input);
expected_opcodes.push(opcode::PUSH4);
expected_opcodes.extend(current_offset.to_be_bytes());
expected_opcodes.push(opcode::MSTORE);

current_offset += 32;
}

let last_input: [u8; 15] = rng.random();
{
all_inputs.extend(last_input);

expected_opcodes.push(opcode::PUSH15);
expected_opcodes.extend(last_input);
expected_opcodes.push(opcode::PUSH4);
expected_opcodes.extend(current_offset.to_be_bytes());

expected_opcodes.push(opcode::MSTORE);
}

let opcodes = build_memory_input_opcodes(U256::from(start_offset), &all_inputs).unwrap();
assert_eq!(opcodes, expected_opcodes);
}
}
Loading