// Copyright 2015-2017 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Parity is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Parity. If not, see . //! JSON VM output. use ethcore::trace; use std::collections::HashMap; use util::{U256, H256, ToPretty}; use display; use vm; /// JSON formatting informant. #[derive(Default)] pub struct Informant { depth: usize, pc: usize, instruction: u8, gas_cost: U256, gas_used: U256, stack: Vec, memory: Vec, storage: HashMap, } impl Informant { fn memory(&self) -> String { format!("\"0x{}\"", self.memory.to_hex()) } fn stack(&self) -> String { let items = self.stack.iter().map(display::u256_as_str).collect::>(); format!("[{}]", items.join(",")) } fn storage(&self) -> String { let vals = self.storage.iter() .map(|(k, v)| format!("\"0x{:?}\": \"0x{:?}\"", k, v)) .collect::>(); format!("{{{}}}", vals.join(",")) } } impl vm::Informant for Informant { fn finish(&mut self, result: Result) { match result { Ok(success) => println!( "{{\"output\":\"0x{output}\",\"gasUsed\":\"{gas:x}\",\"time\":\"{time}\"}}", output = success.output.to_hex(), gas = success.gas_used, time = display::format_time(&success.time), ), Err(failure) => println!( "{{\"error\":\"{error}\",\"time\":\"{time}\"}}", error = failure.error, time = display::format_time(&failure.time), ), } } } impl trace::VMTracer for Informant { fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, stack_pop: usize, gas_cost: &U256) -> bool { self.pc = pc; self.instruction = instruction; self.gas_cost = *gas_cost; let len = self.stack.len(); self.stack.truncate(len - stack_pop); true } fn trace_executed(&mut self, gas_used: U256, stack_push: &[U256], mem_diff: Option<(usize, &[u8])>, store_diff: Option<(U256, U256)>) { println!( "{{\"pc\":{pc},\"op\":{op},\"gas\":{gas},\"gasCost\":{gas_cost},\"memory\":{memory},\"stack\":{stack},\"storage\":{storage},\"depth\":{depth}}}", pc = self.pc, op = self.instruction, gas = display::u256_as_str(&(gas_used + self.gas_cost)), gas_cost = display::u256_as_str(&self.gas_cost), memory = self.memory(), stack = self.stack(), storage = self.storage(), depth = self.depth, ); self.gas_used = gas_used; self.stack.extend_from_slice(stack_push); if let Some((pos, data)) = mem_diff { self.memory[pos..pos + data.len()].copy_from_slice(data); } if let Some((pos, val)) = store_diff { self.storage.insert(pos.into(), val.into()); } } fn prepare_subtrace(&self, _code: &[u8]) -> Self where Self: Sized { let mut vm = Informant::default(); vm.depth = self.depth + 1; vm } fn done_subtrace(&mut self, mut sub: Self) where Self: Sized { if sub.depth == 1 { // print last line with final state: sub.pc += 1; sub.instruction = 0; sub.gas_cost = 0.into(); let gas_used = sub.gas_used; trace::VMTracer::trace_executed(&mut sub, gas_used, &[], None, None); } } fn drain(self) -> Option { None } }