use crate::{ constants::{ DEFAULT_MUTATION_ROUNDS, HASH_OPCODE_INSTRUCTION_COST, MAX_GENE_SIZE, MAX_MUTATION_INSTRUCTION_BUDGET, MAX_MUTATION_PROGRAM_BYTES, SOFT_CAP_DURATION_MS, }, gene::{ add_env_quantity, get_env_quantity, sub_env_quantity, validate_state, GeneError, GeneState, }, }; use rand::Rng; use serde::{Deserialize, Serialize}; use std::time::Instant; // Stack-machine mutation opcodes (v0.6.0). // // NOTE: stack effect notation: // +1 => pushes one u32 // -1 => pops one u32 // 0 => net-zero (or no stack interaction) // // Security/performance notes: // - All index operands are normalized with modulo to avoid panics. // - Program size is bounded by MAX_MUTATION_PROGRAM_BYTES. // - Environment arithmetic is saturating and deterministic. // - Hashing uses fixed BLAKE3 commitment and fixed transcription algorithm. pub const OP_GENE_LOAD: u8 = 0x23; // +1 pub const OP_GENE_STORE: u8 = 0x24; // -1 pub const OP_MUTATE_POINT: u8 = 0x25; // 0 pub const OP_INSERT: u8 = 0x26; // -1 pub const OP_DELETE: u8 = 0x27; // +1 pub const OP_TRANSCRIBE: u8 = 0x28; // +1 pub const OP_APPLY_MUTAGEN: u8 = 0x29; // -1 pub const OP_FINALIZE_GENE_HASH: u8 = 0x2A; // +1 pub const OP_CONSUME: u8 = 0x2B; // 0 (pop amount, push remaining) pub const OP_PRODUCE: u8 = 0x2C; // 0 (pop amount, push resulting quantity) #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct MutationOrder { pub step: u64, pub program: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ExecutionTrace { pub final_ip: usize, pub final_stack: Vec, pub final_gene_commitment_hex: String, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum MutationError { ProgramTooLong { len: usize }, TruncatedInstruction { opcode: u8, ip: usize }, UnknownOpcode(u8), EmptyGene, StackUnderflow { opcode: u8, ip: usize }, GeneFull { current_len: usize }, Base64(base64::DecodeError), Gene(GeneError), } impl std::fmt::Display for MutationError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::ProgramTooLong { len } => write!(f, "mutation program too long: {len} bytes"), Self::TruncatedInstruction { opcode, ip } => { write!(f, "truncated instruction {opcode:#04x} at ip={ip}") } Self::UnknownOpcode(opcode) => write!(f, "unknown mutation opcode: {opcode:#04x}"), Self::EmptyGene => write!(f, "cannot mutate an empty gene"), Self::StackUnderflow { opcode, ip } => { write!(f, "stack underflow in opcode {opcode:#04x} at ip={ip}") } Self::GeneFull { current_len } => { write!(f, "cannot insert; gene already at max size ({current_len})") } Self::Base64(err) => write!(f, "invalid base64 mutation order: {err}"), Self::Gene(err) => write!(f, "{err}"), } } } impl std::error::Error for MutationError {} impl From for MutationError { fn from(value: GeneError) -> Self { Self::Gene(value) } } /// Encodes a `MutationOrder` into standard Base64 representation of its bytecode. pub fn encode_order_b64(order: &MutationOrder) -> String { base64::Engine::encode(&base64::engine::general_purpose::STANDARD, &order.program) } /// Decodes a `MutationOrder` from its Base64 representation. /// /// Validates that the decoded program size does not exceed the allowed maximum budget size. /// /// # Arguments /// * `step` - The step index associated with this mutation order. /// * `b64` - The Base64 string containing the raw bytecode. pub fn decode_order_b64(step: u64, b64: &str) -> Result { let program = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, b64) .map_err(MutationError::Base64)?; if program.len() > MAX_MUTATION_PROGRAM_BYTES { return Err(MutationError::ProgramTooLong { len: program.len() }); } Ok(MutationOrder { step, program }) } /// Generates a randomized `MutationOrder` program for a given step and gene size. /// /// Uses thread-local random number generator. /// /// # Arguments /// * `step` - The step index. /// * `gene_size` - The length of the gene byte buffer. pub fn generate_order(step: u64, gene_size: usize) -> MutationOrder { let mut rng = rand::thread_rng(); generate_order_with_rng(&mut rng, step, gene_size) } /// Generates a randomized `MutationOrder` program using a specific custom RNG. /// /// Builds a program containing between 20 and 36 mutation instructions (e.g. loads, point changes, /// insertions, deletions, env modifications) and ensures a minimum number of finalize hash steps are included. /// /// # Arguments /// * `rng` - The random number generator. /// * `step` - The step index. /// * `gene_size` - The length of the gene byte buffer. pub fn generate_order_with_rng( rng: &mut R, step: u64, gene_size: usize, ) -> MutationOrder { let mut program = Vec::with_capacity(128); let mut stack_depth: i32 = 0; let mut estimated_gene_len = gene_size.clamp(1, MAX_GENE_SIZE); let ops = rng.gen_range(20usize..=36usize); let mut hash_ops_needed = rng.gen_range(2..=3); for idx in 0..ops { let remaining = ops - idx; let op = if hash_ops_needed > 0 && remaining <= hash_ops_needed { OP_FINALIZE_GENE_HASH } else if stack_depth <= 0 { rng.gen_range(0u8..3u8) } else { match rng.gen_range(0u8..12u8) { 0..=1 => OP_GENE_LOAD, 2..=3 => OP_TRANSCRIBE, 4 => OP_FINALIZE_GENE_HASH, 5 => OP_GENE_STORE, 6 => OP_MUTATE_POINT, 7 => OP_INSERT, 8 => OP_DELETE, 9 => OP_APPLY_MUTAGEN, 10 => OP_CONSUME, _ => OP_PRODUCE, } }; match op { OP_GENE_LOAD => { program.push(OP_GENE_LOAD); push_u16(&mut program, rng.r#gen::()); stack_depth += 1; } OP_TRANSCRIBE => { program.push(OP_TRANSCRIBE); push_u16(&mut program, rng.r#gen::()); program.push(rng.gen_range(1u8..=16u8)); stack_depth += 1; } OP_FINALIZE_GENE_HASH => { program.push(OP_FINALIZE_GENE_HASH); stack_depth += 1; hash_ops_needed = hash_ops_needed.saturating_sub(1); } OP_GENE_STORE => { if stack_depth > 0 { program.push(OP_GENE_STORE); push_u16(&mut program, rng.r#gen::()); stack_depth -= 1; } } OP_MUTATE_POINT => { program.push(OP_MUTATE_POINT); push_u16(&mut program, rng.r#gen::()); program.push(rng.r#gen::()); } OP_INSERT => { if stack_depth > 0 && estimated_gene_len < MAX_GENE_SIZE { program.push(OP_INSERT); push_u16(&mut program, rng.r#gen::()); stack_depth -= 1; estimated_gene_len += 1; } } OP_DELETE => { program.push(OP_DELETE); push_u16(&mut program, rng.r#gen::()); stack_depth += 1; if estimated_gene_len > 1 { estimated_gene_len -= 1; } } OP_APPLY_MUTAGEN => { if stack_depth > 0 { program.push(OP_APPLY_MUTAGEN); push_u16(&mut program, rng.r#gen::()); push_u16(&mut program, rng.r#gen::()); stack_depth -= 1; } } OP_CONSUME => { if stack_depth > 0 { program.push(OP_CONSUME); push_u16(&mut program, rng.r#gen::()); } } OP_PRODUCE if stack_depth > 0 => { program.push(OP_PRODUCE); push_u16(&mut program, rng.r#gen::()); } _ => {} } } while hash_ops_needed > 0 && program.len() < MAX_MUTATION_PROGRAM_BYTES { program.push(OP_FINALIZE_GENE_HASH); hash_ops_needed -= 1; } MutationOrder { step, program } } /// Clones the `GeneState` and executes the mutation program for `DEFAULT_MUTATION_ROUNDS`. pub fn apply_program_clone(state: &GeneState, program: &[u8]) -> Result { apply_program_clone_with_rounds(state, program, DEFAULT_MUTATION_ROUNDS) } /// Clones the `GeneState` and executes the mutation program for a specific number of rounds. pub fn apply_program_clone_with_rounds( state: &GeneState, program: &[u8], rounds: u8, ) -> Result { let mut next = state.clone(); execute_program_with_rounds(&mut next, program, rounds)?; Ok(next) } /// Executes the mutation program on the mutable `GeneState` reference for a specific number of rounds. pub fn apply_program_with_rounds( state: &mut GeneState, program: &[u8], rounds: u8, ) -> Result<(), MutationError> { let _ = execute_program_with_rounds(state, program, rounds)?; Ok(()) } /// Executes the mutation program on the mutable `GeneState` reference for `DEFAULT_MUTATION_ROUNDS`. pub fn apply_program(state: &mut GeneState, program: &[u8]) -> Result<(), MutationError> { let _ = execute_program_with_rounds(state, program, DEFAULT_MUTATION_ROUNDS)?; Ok(()) } /// Executes the mutation program on the mutable `GeneState` reference for multiple rounds. /// /// Implements a soft instruction cost-budget cap check to prevent hostile/inefficient /// programs from lagging the host server thread or client runtime. /// /// # Arguments /// * `state` - The mutable gene state buffer. /// * `program` - The raw bytecode sequence. /// * `rounds` - The requested number of execution rounds. pub fn execute_program_with_rounds( state: &mut GeneState, program: &[u8], rounds: u8, ) -> Result { if state.gene.is_empty() { return Err(MutationError::EmptyGene); } validate_state(state)?; if program.len() > MAX_MUTATION_PROGRAM_BYTES { return Err(MutationError::ProgramTooLong { len: program.len() }); } let program_cost = estimate_program_cost(program); let max_rounds = std::cmp::max(1, MAX_MUTATION_INSTRUCTION_BUDGET / program_cost); let actual_rounds = std::cmp::min(rounds as usize, max_rounds) as u8; let start = Instant::now(); let mut trace = None; for _round in 0..actual_rounds { trace = Some(execute_program(state, program)?); } let elapsed = start.elapsed(); tracing::debug!( rounds = actual_rounds, requested_rounds = rounds, elapsed_ms = elapsed.as_millis(), program_len = program.len(), "mutation execution" ); if actual_rounds < rounds { tracing::debug!( requested_rounds = rounds, executed_rounds = actual_rounds, "mutation soft cap reduced mutation rounds to preserve host responsiveness" ); } if elapsed.as_millis() > SOFT_CAP_DURATION_MS { tracing::debug!( elapsed_ms = elapsed.as_millis(), "mutation execution exceeded soft cap duration" ); } Ok(trace.unwrap_or_else(|| ExecutionTrace { final_ip: 0, final_stack: Vec::new(), final_gene_commitment_hex: crate::gene::commitment_hex(state), })) } fn estimate_program_cost(program: &[u8]) -> usize { let mut ip = 0; let mut cost = 0; while ip < program.len() { let opcode = program[ip]; ip += 1; cost += if opcode == OP_FINALIZE_GENE_HASH { HASH_OPCODE_INSTRUCTION_COST } else { 1 }; ip += match opcode { OP_GENE_LOAD | OP_GENE_STORE | OP_INSERT | OP_DELETE | OP_CONSUME | OP_PRODUCE => 2, OP_MUTATE_POINT | OP_TRANSCRIBE => 3, OP_APPLY_MUTAGEN => 4, OP_FINALIZE_GENE_HASH => 0, _ => 0, } } cost.max(1) } /// Executes the VM mutation program on the mutable `GeneState` reference. /// /// This interprets VM mutation opcodes to modify the gene byte array and environment records. /// /// # Arguments /// * `state` - The mutable gene state to mutate. /// * `program` - The raw instruction bytecode slice. pub fn execute_program( state: &mut GeneState, program: &[u8], ) -> Result { if state.gene.is_empty() { return Err(MutationError::EmptyGene); } validate_state(state)?; if program.len() > MAX_MUTATION_PROGRAM_BYTES { return Err(MutationError::ProgramTooLong { len: program.len() }); } let mut ip = 0usize; let mut stack: Vec = Vec::with_capacity(16); while ip < program.len() { let opcode_ip = ip; let opcode = take_u8(program, &mut ip, 0x00)?; match opcode { OP_GENE_LOAD => { let idx = take_u16(program, &mut ip, opcode)?; let normalized = normalize_index(idx as usize, state.gene.len()); stack.push(state.gene[normalized] as u32); } OP_GENE_STORE => { let idx = take_u16(program, &mut ip, opcode)?; let value = pop_stack(&mut stack, opcode, opcode_ip)? as u8; let normalized = normalize_index(idx as usize, state.gene.len()); state.gene[normalized] = value; } OP_MUTATE_POINT => { let idx = take_u16(program, &mut ip, opcode)?; let delta = take_u8(program, &mut ip, opcode)? as i8; let normalized = normalize_index(idx as usize, state.gene.len()); state.gene[normalized] = state.gene[normalized].wrapping_add(delta as u8); } OP_INSERT => { let idx = take_u16(program, &mut ip, opcode)?; let value = pop_stack(&mut stack, opcode, opcode_ip)? as u8; if state.gene.len() >= MAX_GENE_SIZE { return Err(MutationError::GeneFull { current_len: state.gene.len(), }); } let insert_at = (idx as usize).min(state.gene.len()); state.gene.insert(insert_at, value); } OP_DELETE => { let idx = take_u16(program, &mut ip, opcode)?; let normalized = normalize_index(idx as usize, state.gene.len()); let removed = if state.gene.len() > 1 { state.gene.remove(normalized) } else { let prev = state.gene[0]; state.gene[0] = 0; prev }; stack.push(removed as u32); } OP_TRANSCRIBE => { let start = take_u16(program, &mut ip, opcode)?; let span = take_u8(program, &mut ip, opcode)?; let transcription = transcribe_window(&state.gene, start as usize, span); stack.push(transcription); } OP_APPLY_MUTAGEN => { let symbol = take_u16(program, &mut ip, opcode)?; let idx = take_u16(program, &mut ip, opcode)?; let stack_mask = pop_stack(&mut stack, opcode, opcode_ip)? as u8; let quantity = get_env_quantity(state, symbol); let mix = ((quantity as u8) ^ ((quantity >> 8) as u8) ^ ((quantity >> 16) as u8) ^ ((quantity >> 24) as u8)) ^ ((symbol & 0x00ff) as u8) ^ ((symbol >> 8) as u8) ^ stack_mask; let normalized = normalize_index(idx as usize, state.gene.len()); state.gene[normalized] ^= mix; } OP_FINALIZE_GENE_HASH => { let commit = crate::gene::commitment(state); let hash32 = u32::from_le_bytes([commit[0], commit[1], commit[2], commit[3]]); stack.push(hash32); } OP_CONSUME => { let symbol = take_u16(program, &mut ip, opcode)?; let amount = pop_stack(&mut stack, opcode, opcode_ip)?; let left = sub_env_quantity(state, symbol, amount)?; stack.push(left); } OP_PRODUCE => { let symbol = take_u16(program, &mut ip, opcode)?; let amount = pop_stack(&mut stack, opcode, opcode_ip)?; let next = add_env_quantity(state, symbol, amount)?; stack.push(next); } _ => return Err(MutationError::UnknownOpcode(opcode)), } } Ok(ExecutionTrace { final_ip: ip, final_stack: stack, final_gene_commitment_hex: crate::gene::commitment_hex(state), }) } fn transcribe_window(gene: &[u8], start: usize, span: u8) -> u32 { let count = usize::from(span.max(1)); let mut acc = 2_166_136_261u32; // FNV offset basis for i in 0..count { let idx = (start + i) % gene.len(); acc ^= gene[idx] as u32; acc = acc.wrapping_mul(16_777_619); // FNV prime } acc } fn push_u16(buf: &mut Vec, value: u16) { buf.extend_from_slice(&value.to_le_bytes()); } fn take_u8(bytes: &[u8], ip: &mut usize, opcode: u8) -> Result { if *ip >= bytes.len() { return Err(MutationError::TruncatedInstruction { opcode, ip: *ip }); } let value = bytes[*ip]; *ip += 1; Ok(value) } fn take_u16(bytes: &[u8], ip: &mut usize, opcode: u8) -> Result { if *ip + 2 > bytes.len() { return Err(MutationError::TruncatedInstruction { opcode, ip: *ip }); } let value = u16::from_le_bytes([bytes[*ip], bytes[*ip + 1]]); *ip += 2; Ok(value) } fn pop_stack(stack: &mut Vec, opcode: u8, ip: usize) -> Result { stack .pop() .ok_or(MutationError::StackUnderflow { opcode, ip }) } fn normalize_index(idx: usize, len: usize) -> usize { idx % len } #[cfg(test)] mod tests { use super::*; use crate::gene::{commitment, new_state, set_env_quantity}; use rand::{Rng, SeedableRng}; use std::time::Instant; fn u16_bytes(v: u16) -> [u8; 2] { v.to_le_bytes() } #[test] fn test_opcode_gene_load() { let mut state = new_state(4).unwrap(); state.gene = vec![10, 20, 30, 40]; let trace = execute_program(&mut state, &[OP_GENE_LOAD, 1, 0]).unwrap(); assert_eq!(trace.final_stack, vec![20]); } #[test] fn test_opcode_gene_store() { let mut state = new_state(4).unwrap(); state.gene = vec![1, 2, 3, 4]; let program = vec![ OP_GENE_LOAD, 0, 0, // stack: [1] OP_GENE_STORE, 2, 0, // gene[2] <- 1 ]; execute_program(&mut state, &program).unwrap(); assert_eq!(state.gene, vec![1, 2, 1, 4]); } #[test] fn test_opcode_mutate_point() { let mut state = new_state(4).unwrap(); state.gene[0] = 200; let program = vec![OP_MUTATE_POINT, 0, 0, 100u8]; execute_program(&mut state, &program).unwrap(); assert_eq!(state.gene[0], 44); } #[test] fn test_opcode_insert() { let mut state = new_state(3).unwrap(); state.gene = vec![10, 20, 30]; let program = vec![ OP_GENE_LOAD, 1, 0, // stack: [20] OP_INSERT, 0, 0, // insert 20 at position 0 ]; execute_program(&mut state, &program).unwrap(); assert_eq!(state.gene, vec![20, 10, 20, 30]); } #[test] fn test_opcode_delete() { let mut state = new_state(4).unwrap(); state.gene = vec![9, 8, 7, 6]; let trace = execute_program(&mut state, &[OP_DELETE, 2, 0]).unwrap(); assert_eq!(state.gene, vec![9, 8, 6]); assert_eq!(trace.final_stack, vec![7]); } #[test] fn test_opcode_transcribe() { let mut state = new_state(5).unwrap(); state.gene = vec![1, 2, 3, 4, 5]; let trace = execute_program(&mut state, &[OP_TRANSCRIBE, 1, 0, 3]).unwrap(); assert_eq!(trace.final_stack.len(), 1); assert_ne!(trace.final_stack[0], 0); } #[test] fn test_opcode_apply_mutagen() { let mut state = new_state(4).unwrap(); set_env_quantity(&mut state, 7, 0x1234_5678).unwrap(); state.gene[1] = 0xAA; let program = vec![ OP_GENE_LOAD, 0, 0, // stack mask source OP_APPLY_MUTAGEN, 7, 0, 1, 0, ]; execute_program(&mut state, &program).unwrap(); assert_ne!(state.gene[1], 0xAA); } #[test] fn test_opcode_finalize_gene_hash() { let mut state = new_state(4).unwrap(); let trace = execute_program(&mut state, &[OP_FINALIZE_GENE_HASH]).unwrap(); assert_eq!(trace.final_stack.len(), 1); } #[test] fn test_opcode_consume() { let mut state = new_state(4).unwrap(); set_env_quantity(&mut state, 3, 100).unwrap(); let program = vec![ OP_GENE_LOAD, 0, 0, // stack = [0] OP_MUTATE_POINT, 0, 0, 15, // gene[0]=15 OP_GENE_LOAD, 0, 0, // stack=[0,15] OP_CONSUME, 3, 0, // consume 15 ]; let trace = execute_program(&mut state, &program).unwrap(); assert_eq!(get_env_quantity(&state, 3), 85); assert_eq!(trace.final_stack.last().copied().unwrap(), 85); } #[test] fn test_opcode_produce() { let mut state = new_state(4).unwrap(); set_env_quantity(&mut state, 9, 5).unwrap(); let program = vec![ OP_GENE_LOAD, 0, 0, // stack [0] OP_MUTATE_POINT, 0, 0, 10, // gene[0]=10 OP_GENE_LOAD, 0, 0, // stack [0,10] OP_PRODUCE, 9, 0, // +10 ]; let trace = execute_program(&mut state, &program).unwrap(); assert_eq!(get_env_quantity(&state, 9), 15); assert_eq!(trace.final_stack.last().copied().unwrap(), 15); } #[test] fn test_zero_length_gene_is_rejected() { let mut state = GeneState { gene: vec![], environment: vec![], }; let err = execute_program(&mut state, &[OP_FINALIZE_GENE_HASH]).unwrap_err(); assert_eq!(err, MutationError::EmptyGene); } #[test] fn test_insert_rejects_max_size_gene() { let mut state = new_state(MAX_GENE_SIZE).unwrap(); let program = vec![ OP_GENE_LOAD, 0, 0, // push value OP_INSERT, 0, 0, ]; let err = execute_program(&mut state, &program).unwrap_err(); assert!(matches!(err, MutationError::GeneFull { .. })); } #[test] fn test_invalid_positions_wrap_deterministically() { let mut state_a = new_state(5).unwrap(); let mut state_b = new_state(5).unwrap(); let max_u16 = u16::MAX; let [a0, a1] = u16_bytes(max_u16); let program = vec![OP_MUTATE_POINT, a0, a1, 1]; execute_program(&mut state_a, &program).unwrap(); let wrapped = (max_u16 as usize % 5) as u16; let [w0, w1] = u16_bytes(wrapped); let wrapped_program = vec![OP_MUTATE_POINT, w0, w1, 1]; execute_program(&mut state_b, &wrapped_program).unwrap(); assert_eq!(state_a, state_b); } #[test] fn test_quantity_underflow_is_saturating() { let mut state = new_state(4).unwrap(); set_env_quantity(&mut state, 1, 3).unwrap(); state.gene[0] = 8; let program = vec![ OP_GENE_LOAD, 0, 0, // 8 OP_CONSUME, 1, 0, // consume 8 from qty 3 => 0 ]; let trace = execute_program(&mut state, &program).unwrap(); assert_eq!(get_env_quantity(&state, 1), 0); assert_eq!(trace.final_stack.last().copied().unwrap(), 0); } #[test] fn test_rejects_unknown_opcode() { let mut state = new_state(8).unwrap(); let err = execute_program(&mut state, &[0xFF]).unwrap_err(); assert_eq!(err, MutationError::UnknownOpcode(0xFF)); } #[test] fn test_rejects_truncated_instruction() { let mut state = new_state(8).unwrap(); let err = execute_program(&mut state, &[OP_GENE_LOAD, 1]).unwrap_err(); assert!(matches!(err, MutationError::TruncatedInstruction { .. })); } #[test] fn test_rejects_stack_underflow() { let mut state = new_state(8).unwrap(); let err = execute_program(&mut state, &[OP_GENE_STORE, 0, 0]).unwrap_err(); assert!(matches!(err, MutationError::StackUnderflow { .. })); } #[test] fn test_base64_order_roundtrip() { let order = MutationOrder { step: 17, program: vec![OP_GENE_LOAD, 1, 0, OP_GENE_STORE, 2, 0], }; let b64 = encode_order_b64(&order); let decoded = decode_order_b64(order.step, &b64).unwrap(); assert_eq!(decoded, order); } #[test] fn test_generate_order_is_deterministic_for_seeded_rng() { let mut rng_a = rand::rngs::StdRng::seed_from_u64(99); let mut rng_b = rand::rngs::StdRng::seed_from_u64(99); let order_a = generate_order_with_rng(&mut rng_a, 5, 64); let order_b = generate_order_with_rng(&mut rng_b, 5, 64); assert_eq!(order_a, order_b); } #[test] fn test_mutation_chain() { let mut server_state = new_state(32).unwrap(); let mut client_state = new_state(32).unwrap(); let program = vec![ OP_GENE_LOAD, 0, 0, OP_PRODUCE, 2, 0, // env[2]+=gene[0] OP_GENE_LOAD, 1, 0, OP_APPLY_MUTAGEN, 2, 0, 1, 0, // mutagen at idx1 OP_TRANSCRIBE, 0, 0, 8, // hash window OP_GENE_STORE, 2, 0, // gene[2]=transcription_low_byte OP_DELETE, 0, 0, // stack pushes removed OP_INSERT, 3, 0, // insert removed at position 3 OP_FINALIZE_GENE_HASH, ]; let server_trace = execute_program(&mut server_state, &program).unwrap(); let client_trace = execute_program(&mut client_state, &program).unwrap(); assert_eq!(server_state, client_state); assert_eq!(server_trace.final_stack, client_trace.final_stack); assert_eq!( server_trace.final_gene_commitment_hex, client_trace.final_gene_commitment_hex ); } #[test] fn test_server_client_parity_across_random_orders() { let mut rng = rand::rngs::StdRng::seed_from_u64(7); for step in 0..128u64 { let order = generate_order_with_rng(&mut rng, step, 128); let mut server_state = new_state(128).unwrap(); let mut client_state = new_state(128).unwrap(); let server_result = execute_program(&mut server_state, &order.program); let client_result = execute_program(&mut client_state, &order.program); assert_eq!(server_result.is_ok(), client_result.is_ok()); match (server_result, client_result) { (Ok(server_trace), Ok(client_trace)) => { assert_eq!(server_state, client_state); assert_eq!(server_trace.final_stack, client_trace.final_stack); assert_eq!( commitment(&server_state), commitment(&client_state), "step {step}" ); } (Err(a), Err(b)) => assert_eq!(a.to_string(), b.to_string()), _ => unreachable!(), } } } #[test] fn test_fuzz_style_random_program_bytes_do_not_diverge() { let mut rng = rand::rngs::StdRng::seed_from_u64(2026); for _ in 0..256 { let len = rng.gen_range(1usize..=MAX_MUTATION_PROGRAM_BYTES); let mut program = vec![0u8; len]; for b in &mut program { *b = rng.r#gen::(); } let mut a = new_state(64).unwrap(); let mut b = new_state(64).unwrap(); let ra = execute_program(&mut a, &program); let rb = execute_program(&mut b, &program); assert_eq!(ra.is_ok(), rb.is_ok()); if ra.is_ok() { assert_eq!(a, b); } } } #[test] fn test_performance_smoke_mutation_execution() { let mut rng = rand::rngs::StdRng::seed_from_u64(11); let mut programs = Vec::new(); for step in 0..200u64 { programs.push(generate_order_with_rng(&mut rng, step + 1, 512).program); } let start = Instant::now(); let mut state = new_state(512).unwrap(); for program in &programs { let _ = execute_program(&mut state, program); } let elapsed = start.elapsed(); // Wide bound for CI variability; this is a regression guard, not a strict benchmark. assert!( elapsed.as_secs_f64() < 2.0, "mutation execution too slow: {elapsed:?}" ); } #[test] fn test_vm_instruction_budget_soft_cap() { let state = new_state(8).unwrap(); // Construct a program with 130 OP_FINALIZE_GENE_HASH instructions. // HASH has HASH_OPCODE_INSTRUCTION_COST = 16. // Total cost will be 130 * 16 = 2080, which exceeds MAX_MUTATION_INSTRUCTION_BUDGET (2048). let program = vec![OP_FINALIZE_GENE_HASH; 130]; let cost = estimate_program_cost(&program); assert!(cost >= 2080); // Assert that the max allowed rounds is calculated as 1 since cost > budget. let expected_rounds = std::cmp::max(1, MAX_MUTATION_INSTRUCTION_BUDGET / cost); assert_eq!(expected_rounds, 1); // Execute the program with a requested 10 rounds. // The runtime should execute it successfully without panic, while applying the round limitation. let mut test_state = state.clone(); let trace = execute_program_with_rounds(&mut test_state, &program, 10).unwrap(); assert_eq!(trace.final_ip, program.len()); } }