Add custom opcodes

- `GET_STATE_ROOT` and `SET_STATE_ROOT` deal with the root of the state trie, and will be called from storage routines. Similarly `GET_RECEIPT_ROOT` and `SET_RECEIPT_ROOT` deal with the root of the receipt trie.
- `PANIC` enables an unsatisfiable constraint, so no proof can be generated.
- `GET_CONTEXT` and `SET_CONTEXT`, used when calling and returning
- `CONSUME_GAS` charges the sender gas; useful for cases where gas calculations are nontrivial and best implemented in assembly.
- `EXIT_KERNEL` simply clears the CPU flag indicating that we're in kernel mode; it would be used just before a jump to return to the (userspace) caller.
- `MLOAD_GENERAL` and `MSTORE_GENERAL` are for reading and writing memory, but they're not limited to the main memory segment of the current context; they can access any context and any segment. I added a couple macros to show how the they would typically be used.

There may be more later, but these are the ones I think we need for now.  I tried to fill in smaller invalid sections of the decoder's tree, as Jacqui suggested, while keeping related opcodes together. We can fine tune it when the opcode list is more stable.

These are all intended to be priviledged, i.e. they will be treated as invalid if used from userspace, for compatibility as well as (in some cases) security reasons.
This commit is contained in:
Daniel Lubarov 2022-07-17 15:07:29 -07:00
parent a9fe08a4a7
commit 925483ed1e
5 changed files with 81 additions and 22 deletions

View File

@ -90,6 +90,10 @@ pub struct CpuColumnsView<T> {
pub is_msize: T, pub is_msize: T,
pub is_gas: T, pub is_gas: T,
pub is_jumpdest: T, pub is_jumpdest: T,
pub is_get_state_root: T,
pub is_set_state_root: T,
pub is_get_receipt_root: T,
pub is_set_receipt_root: T,
pub is_push: T, pub is_push: T,
pub is_dup: T, pub is_dup: T,
pub is_swap: T, pub is_swap: T,
@ -98,13 +102,20 @@ pub struct CpuColumnsView<T> {
pub is_log2: T, pub is_log2: T,
pub is_log3: T, pub is_log3: T,
pub is_log4: T, pub is_log4: T,
pub is_panic: T,
pub is_create: T, pub is_create: T,
pub is_call: T, pub is_call: T,
pub is_callcode: T, pub is_callcode: T,
pub is_return: T, pub is_return: T,
pub is_delegatecall: T, pub is_delegatecall: T,
pub is_create2: T, pub is_create2: T,
pub is_get_context: T,
pub is_set_context: T,
pub is_consume_gas: T,
pub is_exit_kernel: T,
pub is_staticcall: T, pub is_staticcall: T,
pub is_mload_general: T,
pub is_mstore_general: T,
pub is_revert: T, pub is_revert: T,
pub is_selfdestruct: T, pub is_selfdestruct: T,
@ -124,12 +135,6 @@ pub struct CpuColumnsView<T> {
pub is_invalid_12: T, pub is_invalid_12: T,
pub is_invalid_13: T, pub is_invalid_13: T,
pub is_invalid_14: T, pub is_invalid_14: T,
pub is_invalid_15: T,
pub is_invalid_16: T,
pub is_invalid_17: T,
pub is_invalid_18: T,
pub is_invalid_19: T,
pub is_invalid_20: T,
/// If CPU cycle: the opcode, broken up into bits in **big-endian** order. /// If CPU cycle: the opcode, broken up into bits in **big-endian** order.
pub opcode_bits: [T; 8], pub opcode_bits: [T; 8],

View File

@ -15,7 +15,7 @@ use crate::cpu::columns::{CpuColumnsView, COL_MAP};
// - its start index is a multiple of its length (it is aligned) // - its start index is a multiple of its length (it is aligned)
// These properties permit us to check if an opcode belongs to a block of length 2^n by checking its // These properties permit us to check if an opcode belongs to a block of length 2^n by checking its
// top 8-n bits. // top 8-n bits.
const OPCODES: [(u64, usize, usize); 102] = [ const OPCODES: [(u64, usize, usize); 107] = [
// (start index of block, number of top bits to check (log2), flag column) // (start index of block, number of top bits to check (log2), flag column)
(0x00, 0, COL_MAP.is_stop), (0x00, 0, COL_MAP.is_stop),
(0x01, 0, COL_MAP.is_add), (0x01, 0, COL_MAP.is_add),
@ -90,34 +90,39 @@ const OPCODES: [(u64, usize, usize); 102] = [
(0x59, 0, COL_MAP.is_msize), (0x59, 0, COL_MAP.is_msize),
(0x5a, 0, COL_MAP.is_gas), (0x5a, 0, COL_MAP.is_gas),
(0x5b, 0, COL_MAP.is_jumpdest), (0x5b, 0, COL_MAP.is_jumpdest),
(0x5c, 2, COL_MAP.is_invalid_9), // 0x5c-0x5f (0x5c, 0, COL_MAP.is_get_state_root),
(0x60, 5, COL_MAP.is_push), // 0x60-0x7f (0x5d, 0, COL_MAP.is_set_state_root),
(0x80, 4, COL_MAP.is_dup), // 0x80-0x8f (0x5e, 0, COL_MAP.is_get_receipt_root),
(0x90, 4, COL_MAP.is_swap), // 0x90-0x9f (0x5f, 0, COL_MAP.is_set_receipt_root),
(0x60, 5, COL_MAP.is_push), // 0x60-0x7f
(0x80, 4, COL_MAP.is_dup), // 0x80-0x8f
(0x90, 4, COL_MAP.is_swap), // 0x90-0x9f
(0xa0, 0, COL_MAP.is_log0), (0xa0, 0, COL_MAP.is_log0),
(0xa1, 0, COL_MAP.is_log1), (0xa1, 0, COL_MAP.is_log1),
(0xa2, 0, COL_MAP.is_log2), (0xa2, 0, COL_MAP.is_log2),
(0xa3, 0, COL_MAP.is_log3), (0xa3, 0, COL_MAP.is_log3),
(0xa4, 0, COL_MAP.is_log4), (0xa4, 0, COL_MAP.is_log4),
(0xa5, 0, COL_MAP.is_invalid_10), (0xa5, 0, COL_MAP.is_panic),
(0xa6, 1, COL_MAP.is_invalid_11), // 0xa6-0xa7 (0xa6, 1, COL_MAP.is_invalid_9), // 0xa6-0xa7
(0xa8, 3, COL_MAP.is_invalid_12), // 0xa8-0xaf (0xa8, 3, COL_MAP.is_invalid_10), // 0xa8-0xaf
(0xb0, 4, COL_MAP.is_invalid_13), // 0xb0-0xbf (0xb0, 4, COL_MAP.is_invalid_11), // 0xb0-0xbf
(0xc0, 5, COL_MAP.is_invalid_14), // 0xc0-0xdf (0xc0, 5, COL_MAP.is_invalid_12), // 0xc0-0xdf
(0xe0, 4, COL_MAP.is_invalid_15), // 0xe0-0xef (0xe0, 4, COL_MAP.is_invalid_13), // 0xe0-0xef
(0xf0, 0, COL_MAP.is_create), (0xf0, 0, COL_MAP.is_create),
(0xf1, 0, COL_MAP.is_call), (0xf1, 0, COL_MAP.is_call),
(0xf2, 0, COL_MAP.is_callcode), (0xf2, 0, COL_MAP.is_callcode),
(0xf3, 0, COL_MAP.is_return), (0xf3, 0, COL_MAP.is_return),
(0xf4, 0, COL_MAP.is_delegatecall), (0xf4, 0, COL_MAP.is_delegatecall),
(0xf5, 0, COL_MAP.is_create2), (0xf5, 0, COL_MAP.is_create2),
(0xf6, 1, COL_MAP.is_invalid_16), // 0xf6-0xf7 (0xf6, 0, COL_MAP.is_get_context),
(0xf8, 1, COL_MAP.is_invalid_17), // 0xf8-0xf9 (0xf7, 0, COL_MAP.is_set_context),
(0xf8, 0, COL_MAP.is_consume_gas),
(0xf9, 0, COL_MAP.is_exit_kernel),
(0xfa, 0, COL_MAP.is_staticcall), (0xfa, 0, COL_MAP.is_staticcall),
(0xfb, 0, COL_MAP.is_invalid_18), (0xfb, 0, COL_MAP.is_mload_general),
(0xfc, 0, COL_MAP.is_invalid_19), (0xfc, 0, COL_MAP.is_mstore_general),
(0xfd, 0, COL_MAP.is_revert), (0xfd, 0, COL_MAP.is_revert),
(0xfe, 0, COL_MAP.is_invalid_20), (0xfe, 0, COL_MAP.is_invalid_14),
(0xff, 0, COL_MAP.is_selfdestruct), (0xff, 0, COL_MAP.is_selfdestruct),
]; ];

View File

@ -0,0 +1,27 @@
// Load a byte from the given segment of the current context's memory space.
// Note that main memory values are one byte each, but in general memory values
// can be 256 bits. This macro deals with a single address (unlike MSTORE), so
// if it is used with main memory, it will load a single byte.
%macro mload_current(segment)
// stack: offset
PUSH $segment
// stack: segment, offset
CURRENT_CONTEXT
// stack: context, segment, offset
MLOAD_GENERAL
// stack: value
%endmacro
// Store a byte to the given segment of the current context's memory space.
// Note that main memory values are one byte each, but in general memory values
// can be 256 bits. This macro deals with a single address (unlike MSTORE), so
// if it is used with main memory, it will store a single byte.
%macro mstore_current(segment)
// stack: offset, value
PUSH $segment
// stack: segment, offset, value
CURRENT_CONTEXT
// stack: context, segment, offset, value
MSTORE_GENERAL
// stack: (empty)
%endmacro

View File

@ -115,6 +115,10 @@ impl<'a> Interpreter<'a> {
0x59 => todo!(), // "MSIZE", 0x59 => todo!(), // "MSIZE",
0x5a => todo!(), // "GAS", 0x5a => todo!(), // "GAS",
0x5b => (), // "JUMPDEST", 0x5b => (), // "JUMPDEST",
0x5c => todo!(), // "GET_STATE_ROOT",
0x5d => todo!(), // "SET_STATE_ROOT",
0x5e => todo!(), // "GET_RECEIPT_ROOT",
0x5f => todo!(), // "SET_RECEIPT_ROOT",
x if (0x60..0x80).contains(&x) => self.run_push(x - 0x5f), // "PUSH" x if (0x60..0x80).contains(&x) => self.run_push(x - 0x5f), // "PUSH"
x if (0x80..0x90).contains(&x) => self.run_dup(x - 0x7f), // "DUP" x if (0x80..0x90).contains(&x) => self.run_dup(x - 0x7f), // "DUP"
x if (0x90..0xa0).contains(&x) => self.run_swap(x - 0x8f), // "SWAP" x if (0x90..0xa0).contains(&x) => self.run_swap(x - 0x8f), // "SWAP"
@ -123,13 +127,20 @@ impl<'a> Interpreter<'a> {
0xa2 => todo!(), // "LOG2", 0xa2 => todo!(), // "LOG2",
0xa3 => todo!(), // "LOG3", 0xa3 => todo!(), // "LOG3",
0xa4 => todo!(), // "LOG4", 0xa4 => todo!(), // "LOG4",
0xa5 => panic!("Executed PANIC"), // "PANIC",
0xf0 => todo!(), // "CREATE", 0xf0 => todo!(), // "CREATE",
0xf1 => todo!(), // "CALL", 0xf1 => todo!(), // "CALL",
0xf2 => todo!(), // "CALLCODE", 0xf2 => todo!(), // "CALLCODE",
0xf3 => todo!(), // "RETURN", 0xf3 => todo!(), // "RETURN",
0xf4 => todo!(), // "DELEGATECALL", 0xf4 => todo!(), // "DELEGATECALL",
0xf5 => todo!(), // "CREATE2", 0xf5 => todo!(), // "CREATE2",
0xf6 => todo!(), // "GET_CONTEXT",
0xf7 => todo!(), // "SET_CONTEXT",
0xf8 => todo!(), // "CONSUME_GAS",
0xf9 => todo!(), // "EXIT_KERNEL",
0xfa => todo!(), // "STATICCALL", 0xfa => todo!(), // "STATICCALL",
0xfb => todo!(), // "MLOAD_GENERAL",
0xfc => todo!(), // "MSTORE_GENERAL",
0xfd => todo!(), // "REVERT", 0xfd => todo!(), // "REVERT",
0xfe => todo!(), // "INVALID", 0xfe => todo!(), // "INVALID",
0xff => todo!(), // "SELFDESTRUCT", 0xff => todo!(), // "SELFDESTRUCT",

View File

@ -71,6 +71,10 @@ pub(crate) fn get_opcode(mnemonic: &str) -> u8 {
"MSIZE" => 0x59, "MSIZE" => 0x59,
"GAS" => 0x5a, "GAS" => 0x5a,
"JUMPDEST" => 0x5b, "JUMPDEST" => 0x5b,
"GET_STATE_ROOT" => 0x5c,
"SET_STATE_ROOT" => 0x5d,
"GET_RECEIPT_ROOT" => 0x5e,
"SET_RECEIPT_ROOT" => 0x5f,
"DUP1" => 0x80, "DUP1" => 0x80,
"DUP2" => 0x81, "DUP2" => 0x81,
"DUP3" => 0x82, "DUP3" => 0x82,
@ -108,13 +112,20 @@ pub(crate) fn get_opcode(mnemonic: &str) -> u8 {
"LOG2" => 0xa2, "LOG2" => 0xa2,
"LOG3" => 0xa3, "LOG3" => 0xa3,
"LOG4" => 0xa4, "LOG4" => 0xa4,
"PANIC" => 0xa5,
"CREATE" => 0xf0, "CREATE" => 0xf0,
"CALL" => 0xf1, "CALL" => 0xf1,
"CALLCODE" => 0xf2, "CALLCODE" => 0xf2,
"RETURN" => 0xf3, "RETURN" => 0xf3,
"DELEGATECALL" => 0xf4, "DELEGATECALL" => 0xf4,
"CREATE2" => 0xf5, "CREATE2" => 0xf5,
"GET_CONTEXT" => 0xf6,
"SET_CONTEXT" => 0xf7,
"CONSUME_GAS" => 0xf8,
"EXIT_KERNEL" => 0xf9,
"STATICCALL" => 0xfa, "STATICCALL" => 0xfa,
"MLOAD_GENERAL" => 0xfb,
"MSTORE_GENERAL" => 0xfc,
"REVERT" => 0xfd, "REVERT" => 0xfd,
"INVALID" => 0xfe, "INVALID" => 0xfe,
"SELFDESTRUCT" => 0xff, "SELFDESTRUCT" => 0xff,