1use crate::{config::PricingParams, error::Escape, ink::Ink};
2
3pub const STYLUS_INK_LEFT: &str = "stylus_ink_left";
5pub const STYLUS_INK_STATUS: &str = "stylus_ink_status";
6
7pub const STYLUS_STACK_LEFT: &str = "stylus_stack_left";
9
10pub const STYLUS_ENTRY_POINT: &str = "user_entrypoint";
12
13pub const HOSTIO_INK: Ink = Ink(8400);
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub enum MachineMeter {
19 Ready(Ink),
20 Exhausted,
21}
22
23impl MachineMeter {
24 pub fn ink(&self) -> Ink {
25 match self {
26 Self::Ready(ink) => *ink,
27 Self::Exhausted => Ink(0),
28 }
29 }
30
31 pub fn status(&self) -> u32 {
32 match self {
33 Self::Ready(_) => 0,
34 Self::Exhausted => 1,
35 }
36 }
37}
38
39pub trait MeteredMachine {
41 fn ink_left(&self) -> MachineMeter;
42 fn set_meter(&mut self, meter: MachineMeter);
43
44 fn ink_ready(&self) -> Result<Ink, Escape> {
45 match self.ink_left() {
46 MachineMeter::Ready(ink) => Ok(ink),
47 MachineMeter::Exhausted => Escape::out_of_ink(),
48 }
49 }
50
51 fn set_ink(&mut self, ink: Ink) {
52 self.set_meter(MachineMeter::Ready(ink));
53 }
54
55 fn buy_ink(&mut self, ink: Ink) -> Result<(), Escape> {
56 let current = self.ink_ready()?;
57 if current < ink {
58 self.set_meter(MachineMeter::Exhausted);
59 return Escape::out_of_ink();
60 }
61 self.set_meter(MachineMeter::Ready(current - ink));
62 Ok(())
63 }
64
65 fn require_ink(&mut self, ink: Ink) -> Result<(), Escape> {
66 let current = self.ink_ready()?;
67 if current < ink {
68 return Escape::out_of_ink();
69 }
70 Ok(())
71 }
72
73 fn pay_for_read(&mut self, bytes: u32) -> Result<(), Escape> {
74 self.buy_ink(crate::pricing::read_price(bytes))
75 }
76
77 fn pay_for_write(&mut self, bytes: u32) -> Result<(), Escape> {
78 self.buy_ink(crate::pricing::write_price(bytes))
79 }
80
81 fn pay_for_keccak(&mut self, bytes: u32) -> Result<(), Escape> {
82 self.buy_ink(crate::pricing::keccak_price(bytes))
83 }
84}
85
86pub trait GasMeteredMachine: MeteredMachine {
88 fn pricing(&self) -> PricingParams;
89
90 fn buy_gas(&mut self, gas: u64) -> Result<(), Escape> {
91 let ink = self.pricing().gas_to_ink(crate::ink::Gas(gas));
92 self.buy_ink(ink)
93 }
94
95 fn require_gas(&mut self, gas: u64) -> Result<(), Escape> {
96 let ink = self.pricing().gas_to_ink(crate::ink::Gas(gas));
97 self.require_ink(ink)
98 }
99
100 fn pay_for_evm_log(&mut self, topics: u32, data_len: u32) -> Result<(), Escape> {
101 use crate::pricing::evm_gas;
102 let cost = (1 + topics as u64) * evm_gas::LOG_TOPIC_GAS;
103 let cost = cost.saturating_add(data_len as u64 * evm_gas::LOG_DATA_GAS);
104 self.buy_gas(cost)
105 }
106}
107
108pub trait DepthCheckedMachine {
110 fn stack_left(&mut self) -> u32;
111 fn set_stack(&mut self, size: u32);
112}