1use std::fmt;
7
8use async_graphql::InputObject;
9use linera_base::data_types::{Amount, ArithmeticError, Resources};
10use serde::{Deserialize, Serialize};
11
12#[derive(Eq, PartialEq, Hash, Clone, Debug, Serialize, Deserialize, InputObject)]
14pub struct ResourceControlPolicy {
15 pub block: Amount,
17 pub fuel_unit: Amount,
19 pub read_operation: Amount,
21 pub write_operation: Amount,
23 pub byte_read: Amount,
25 pub byte_written: Amount,
27 pub byte_stored: Amount,
30 pub operation: Amount,
32 pub operation_byte: Amount,
34 pub message: Amount,
36 pub message_byte: Amount,
38
39 pub maximum_fuel_per_block: u64,
43 pub maximum_executed_block_size: u64,
46 pub maximum_bytes_read_per_block: u64,
48 pub maximum_bytes_written_per_block: u64,
50}
51
52impl fmt::Display for ResourceControlPolicy {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 let ResourceControlPolicy {
55 block,
56 fuel_unit,
57 read_operation,
58 write_operation,
59 byte_read,
60 byte_written,
61 byte_stored,
62 operation,
63 operation_byte,
64 message,
65 message_byte,
66 maximum_fuel_per_block,
67 maximum_executed_block_size,
68 maximum_bytes_read_per_block,
69 maximum_bytes_written_per_block,
70 } = self;
71 write!(
72 f,
73 "Resource control policy:\n\
74 {block:.2} base cost per block\n\
75 {fuel_unit:.2} cost per fuel unit\n\
76 {read_operation:.2} cost per read operation\n\
77 {write_operation:.2} cost per write operation\n\
78 {byte_read:.2} cost per byte read\n\
79 {byte_written:.2} cost per byte written\n\
80 {byte_stored:.2} cost per byte stored\n\
81 {operation:.2} per operation\n\
82 {operation_byte:.2} per byte in the argument of an operation\n\
83 {message:.2} per outgoing messages\n\
84 {message_byte:.2} per byte in the argument of an outgoing messages\n\
85 {maximum_fuel_per_block} maximum fuel per block\n\
86 {maximum_executed_block_size} maximum size of an executed block\n\
87 {maximum_bytes_read_per_block} maximum number bytes read per block\n\
88 {maximum_bytes_written_per_block} maximum number bytes written per block",
89 )
90 }
91}
92
93impl Default for ResourceControlPolicy {
94 fn default() -> Self {
95 Self {
96 block: Amount::default(),
97 fuel_unit: Amount::default(),
98 read_operation: Amount::default(),
99 write_operation: Amount::default(),
100 byte_read: Amount::default(),
101 byte_written: Amount::default(),
102 byte_stored: Amount::default(),
103 operation: Amount::default(),
104 operation_byte: Amount::default(),
105 message: Amount::default(),
106 message_byte: Amount::default(),
107 maximum_fuel_per_block: u64::MAX,
108 maximum_executed_block_size: u64::MAX,
109 maximum_bytes_read_per_block: u64::MAX,
110 maximum_bytes_written_per_block: u64::MAX,
111 }
112 }
113}
114
115impl ResourceControlPolicy {
116 pub fn block_price(&self) -> Amount {
117 self.block
118 }
119
120 pub fn total_price(&self, resources: &Resources) -> Result<Amount, ArithmeticError> {
121 let mut amount = Amount::ZERO;
122 amount.try_add_assign(self.fuel_price(resources.fuel)?)?;
123 amount.try_add_assign(self.read_operations_price(resources.read_operations)?)?;
124 amount.try_add_assign(self.write_operations_price(resources.write_operations)?)?;
125 amount.try_add_assign(self.bytes_read_price(resources.bytes_to_read as u64)?)?;
126 amount.try_add_assign(self.bytes_written_price(resources.bytes_to_write as u64)?)?;
127 amount.try_add_assign(self.message.try_mul(resources.messages as u128)?)?;
128 amount.try_add_assign(self.message_bytes_price(resources.message_size as u64)?)?;
129 amount.try_add_assign(self.bytes_stored_price(resources.storage_size_delta as u64)?)?;
130 Ok(amount)
131 }
132
133 pub(crate) fn operation_bytes_price(&self, size: u64) -> Result<Amount, ArithmeticError> {
134 self.operation_byte.try_mul(size as u128)
135 }
136
137 pub(crate) fn message_bytes_price(&self, size: u64) -> Result<Amount, ArithmeticError> {
138 self.message_byte.try_mul(size as u128)
139 }
140
141 pub(crate) fn read_operations_price(&self, count: u32) -> Result<Amount, ArithmeticError> {
142 self.read_operation.try_mul(count as u128)
143 }
144
145 pub(crate) fn write_operations_price(&self, count: u32) -> Result<Amount, ArithmeticError> {
146 self.write_operation.try_mul(count as u128)
147 }
148
149 pub(crate) fn bytes_read_price(&self, count: u64) -> Result<Amount, ArithmeticError> {
150 self.byte_read.try_mul(count as u128)
151 }
152
153 pub(crate) fn bytes_written_price(&self, count: u64) -> Result<Amount, ArithmeticError> {
154 self.byte_written.try_mul(count as u128)
155 }
156
157 #[allow(dead_code)]
159 pub(crate) fn bytes_stored_price(&self, count: u64) -> Result<Amount, ArithmeticError> {
160 self.byte_stored.try_mul(count as u128)
161 }
162
163 pub(crate) fn fuel_price(&self, fuel: u64) -> Result<Amount, ArithmeticError> {
164 self.fuel_unit.try_mul(u128::from(fuel))
165 }
166
167 pub(crate) fn remaining_fuel(&self, balance: Amount) -> u64 {
169 u64::try_from(balance.saturating_div(self.fuel_unit)).unwrap_or(u64::MAX)
170 }
171}
172
173impl ResourceControlPolicy {
174 pub fn only_fuel() -> Self {
179 Self {
180 fuel_unit: Amount::from_micros(1),
181 ..Self::default()
182 }
183 }
184
185 pub fn fuel_and_block() -> Self {
190 Self {
191 block: Amount::from_millis(1),
192 fuel_unit: Amount::from_micros(1),
193 ..Self::default()
194 }
195 }
196
197 pub fn all_categories() -> Self {
199 Self {
200 block: Amount::from_millis(1),
201 fuel_unit: Amount::from_nanos(1),
202 byte_read: Amount::from_attos(100),
203 byte_written: Amount::from_attos(1_000),
204 operation: Amount::from_attos(10),
205 operation_byte: Amount::from_attos(1),
206 message: Amount::from_attos(10),
207 message_byte: Amount::from_attos(1),
208 ..Self::default()
209 }
210 }
211
212 pub fn devnet() -> Self {
214 Self {
215 block: Amount::from_millis(1),
216 fuel_unit: Amount::from_nanos(10),
217 byte_read: Amount::from_nanos(10),
218 byte_written: Amount::from_nanos(100),
219 read_operation: Amount::from_micros(10),
220 write_operation: Amount::from_micros(20),
221 byte_stored: Amount::from_nanos(10),
222 message_byte: Amount::from_nanos(100),
223 operation_byte: Amount::from_nanos(10),
224 operation: Amount::from_micros(10),
225 message: Amount::from_micros(10),
226 maximum_fuel_per_block: 100_000_000,
227 maximum_executed_block_size: 1_000_000,
228 maximum_bytes_read_per_block: 100_000_000,
229 maximum_bytes_written_per_block: 10_000_000,
230 }
231 }
232}