ckb_vm_contrib/
syscalls.rs

1/// Common syscalls that can be reused in multiple places
2use ckb_vm::{
3    registers::{A0, A7},
4    Memory, Register, SupportMachine, Syscalls,
5};
6use std::time::SystemTime;
7
8/// Syscall handler for printing debugging information to host-side STDOUT.
9/// It uses a simpler design than using STDOUT in CKB-VM itself.
10pub struct DebugSyscall {}
11
12impl<Mac: SupportMachine> Syscalls<Mac> for DebugSyscall {
13    fn initialize(&mut self, _machine: &mut Mac) -> Result<(), ckb_vm::error::Error> {
14        Ok(())
15    }
16
17    fn ecall(&mut self, machine: &mut Mac) -> Result<bool, ckb_vm::error::Error> {
18        let code = &machine.registers()[A7];
19        if code.to_i32() != 2177 {
20            return Ok(false);
21        }
22
23        let mut addr = machine.registers()[A0].to_u64();
24        let mut buffer = Vec::new();
25
26        loop {
27            let byte = machine
28                .memory_mut()
29                .load8(&Mac::REG::from_u64(addr))?
30                .to_u8();
31            if byte == 0 {
32                break;
33            }
34            buffer.push(byte);
35            addr += 1;
36        }
37
38        let s = String::from_utf8(buffer).unwrap();
39        println!("{:?}", s);
40
41        Ok(true)
42    }
43}
44
45/// Syscall handler for providing time information since boot to CKB-VM.
46/// While this is not exactly the time for the outside world, it can be used
47/// to build benchmarks within CKB-VM.
48pub struct TimeSyscall {
49    boot_time: SystemTime,
50}
51
52impl TimeSyscall {
53    pub fn new() -> Self {
54        Self {
55            boot_time: SystemTime::now(),
56        }
57    }
58}
59
60impl<Mac: SupportMachine> Syscalls<Mac> for TimeSyscall {
61    fn initialize(&mut self, _machine: &mut Mac) -> Result<(), ckb_vm::error::Error> {
62        Ok(())
63    }
64
65    fn ecall(&mut self, machine: &mut Mac) -> Result<bool, ckb_vm::error::Error> {
66        let code = &machine.registers()[A7];
67        // Zlib::crc32("time") % 10000
68        if code.to_i32() != 9285 {
69            return Ok(false);
70        }
71
72        let now = SystemTime::now();
73        let d = now
74            .duration_since(self.boot_time.clone())
75            .expect("clock goes backwards");
76
77        machine.set_register(A0, Mac::REG::from_u64(d.as_nanos() as u64));
78
79        Ok(true)
80    }
81}