1use javm::{InProcessKernelAssist, Vm};
9use javm_cap::CapHash;
10use javm_cap::image::Image;
11
12use crate::apply::{Block, EventOutcome, apply_block};
13use crate::error::KernelError;
14use crate::genesis::{Genesis, genesis};
15use crate::state::{State, state_root};
16
17pub struct Kernel {
20 state: State,
21 chain_instance_hash: CapHash,
22 vm: Vm<InProcessKernelAssist>,
23}
24
25impl Kernel {
26 pub fn from_genesis(chain_image: Image) -> Self {
28 let Genesis {
29 state,
30 chain_instance_hash,
31 chain_image_hash: _,
32 root_cnode_hash: _,
33 } = genesis(chain_image).expect("genesis must succeed for a valid chain image");
34
35 Self {
36 state,
37 chain_instance_hash,
38 vm: Vm::new(InProcessKernelAssist::new()),
39 }
40 }
41
42 pub fn apply(
45 &mut self,
46 block: &Block,
47 gas_per_event: u64,
48 quota_per_event: u64,
49 ) -> Result<Vec<EventOutcome>, KernelError> {
50 apply_block(
51 &mut self.state,
52 &mut self.vm,
53 &mut self.chain_instance_hash,
54 block,
55 gas_per_event,
56 quota_per_event,
57 )
58 }
59
60 pub fn state(&self) -> &State {
62 &self.state
63 }
64
65 pub fn state_root(&self) -> CapHash {
67 state_root(&self.state)
68 }
69
70 pub fn chain_instance_hash(&self) -> CapHash {
73 self.chain_instance_hash
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use crate::abi;
81 use crate::apply::{Block, Event, EventOutcome};
82 use javm_cap::image::Image;
83 use std::collections::BTreeMap;
84
85 fn minimal_chain_image() -> Image {
86 let mut endpoints = BTreeMap::new();
88 endpoints.insert(
89 0,
90 javm_cap::image::EndpointDef {
91 entry_pc: 0,
92 arg_registers: 0,
93 arg_cnode_size: 0,
94 initial_regs: BTreeMap::new(),
95 },
96 );
97 Image {
101 code: vec![20u8, 7, 42, 0, 0, 0, 0, 0, 0, 0, 10, 0],
102 packed_bitmask: vec![0x01, 0x04],
103 jump_table: Vec::new(),
104 endpoints,
105 memory_mappings: Vec::new(),
106 gas_slots: vec![abi::BARE_GAS_SLOT],
107 quota_slots: vec![abi::BARE_QUOTA_SLOT],
108 pinned_slots: BTreeMap::new(),
109 initial_slots: BTreeMap::new(),
110 yield_marker_slot: Some(abi::BARE_YIELD_CATCHER_SLOT),
111 }
112 }
113
114 #[test]
115 fn kernel_from_genesis_yields_deterministic_state_root() {
116 let k1 = Kernel::from_genesis(minimal_chain_image());
117 let k2 = Kernel::from_genesis(minimal_chain_image());
118 assert_eq!(k1.state_root(), k2.state_root());
119 }
120
121 #[test]
122 fn kernel_apply_advances_state_root_via_payload_publish() {
123 let mut kernel = Kernel::from_genesis(minimal_chain_image());
128 let root_0 = kernel.state_root();
129
130 let block = Block {
131 events: vec![Event {
132 endpoint_idx: 0,
133 payload: b"hello".to_vec(),
134 }],
135 };
136 let outcomes = kernel.apply(&block, 10_000, 10_000).unwrap();
137 let root_1 = kernel.state_root();
138
139 assert_ne!(root_0, root_1);
140 assert_eq!(outcomes.len(), 1);
141 }
142
143 #[test]
144 fn kernel_apply_replay_is_deterministic() {
145 let mut k1 = Kernel::from_genesis(minimal_chain_image());
147 let mut k2 = Kernel::from_genesis(minimal_chain_image());
148 let block = || Block {
149 events: vec![Event {
150 endpoint_idx: 0,
151 payload: b"replay-determinism".to_vec(),
152 }],
153 };
154 let _ = k1.apply(&block(), 10_000, 10_000).unwrap();
155 let _ = k2.apply(&block(), 10_000, 10_000).unwrap();
156 assert_eq!(k1.state_root(), k2.state_root());
157 }
158
159 #[allow(dead_code)]
162 fn _enum_touch(o: EventOutcome) -> EventOutcome {
163 o
164 }
165}