scale_encoding.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::codegen::cfg::{ControlFlowGraph, Instr};
  3. use crate::codegen::encoding::AbiEncoding;
  4. use crate::codegen::vartable::Vartable;
  5. use crate::codegen::{Builtin, Expression};
  6. use crate::sema::ast::StructType;
  7. use crate::sema::ast::{Namespace, Type, Type::Uint};
  8. use solang_parser::pt::Loc::Codegen;
  9. use std::collections::HashMap;
  10. use super::buffer_validator::BufferValidator;
  11. pub(super) struct ScaleEncoding {
  12. storage_cache: HashMap<usize, Expression>,
  13. packed_encoder: bool,
  14. }
  15. impl ScaleEncoding {
  16. pub fn new(packed: bool) -> Self {
  17. Self {
  18. storage_cache: HashMap::new(),
  19. packed_encoder: packed,
  20. }
  21. }
  22. }
  23. /// Decoding the compact integer at current `offset` inside `buffer`.
  24. /// Returns the variable number of the decoded integer (32bit) and the width in bytes of the encoded version.
  25. /// More information can found in the /// [SCALE documentation](https://docs.substrate.io/reference/scale-codec/).
  26. fn decode_compact(
  27. buffer: &Expression,
  28. offset: &Expression,
  29. vartab: &mut Vartable,
  30. cfg: &mut ControlFlowGraph,
  31. ) -> (usize, Expression) {
  32. let decoded_var = vartab.temp_anonymous(&Uint(32));
  33. let size_width_var = vartab.temp_anonymous(&Uint(32));
  34. vartab.new_dirty_tracker();
  35. let read_byte = Expression::Builtin(
  36. Codegen,
  37. vec![Uint(8)],
  38. Builtin::ReadFromBuffer,
  39. vec![buffer.clone(), offset.clone()],
  40. );
  41. cfg.add(
  42. vartab,
  43. Instr::Set {
  44. loc: Codegen,
  45. res: size_width_var,
  46. expr: Expression::ZeroExt(Codegen, Uint(32), read_byte.into()),
  47. },
  48. );
  49. let size_width = Expression::Variable(Codegen, Uint(32), size_width_var);
  50. let two = Expression::NumberLiteral(Codegen, Uint(32), 2.into());
  51. let three = Expression::NumberLiteral(Codegen, Uint(32), 3.into());
  52. let cond = Expression::BitwiseAnd(Codegen, Uint(32), size_width.clone().into(), three.into());
  53. let cases = &[
  54. (
  55. Expression::NumberLiteral(Codegen, Uint(32), 0.into()),
  56. cfg.new_basic_block("case_0".into()),
  57. ),
  58. (
  59. Expression::NumberLiteral(Codegen, Uint(32), 1.into()),
  60. cfg.new_basic_block("case_1".into()),
  61. ),
  62. (
  63. Expression::NumberLiteral(Codegen, Uint(32), 2.into()),
  64. cfg.new_basic_block("case_2".into()),
  65. ),
  66. ];
  67. let default = cfg.new_basic_block("case_default".into());
  68. cfg.add(
  69. vartab,
  70. Instr::Switch {
  71. cond,
  72. cases: cases.to_vec(),
  73. default,
  74. },
  75. );
  76. let done = cfg.new_basic_block("done".into());
  77. // We will land in the default block for sizes of 2**30 (1GB) or larger.
  78. // Such big sizes are invalid for smart contracts and should never occur anyways.
  79. cfg.set_basic_block(default);
  80. cfg.add(vartab, Instr::AssertFailure { encoded_args: None });
  81. cfg.set_basic_block(cases[0].1);
  82. let expr = Expression::ShiftRight(
  83. Codegen,
  84. Uint(32),
  85. size_width.clone().into(),
  86. two.clone().into(),
  87. false,
  88. );
  89. cfg.add(
  90. vartab,
  91. Instr::Set {
  92. loc: Codegen,
  93. res: decoded_var,
  94. expr,
  95. },
  96. );
  97. cfg.add(
  98. vartab,
  99. Instr::Set {
  100. loc: Codegen,
  101. res: size_width_var,
  102. expr: Expression::NumberLiteral(Codegen, Uint(32), 1.into()),
  103. },
  104. );
  105. cfg.add(vartab, Instr::Branch { block: done });
  106. cfg.set_basic_block(cases[1].1);
  107. let read_byte = Expression::Builtin(
  108. Codegen,
  109. vec![Uint(16)],
  110. Builtin::ReadFromBuffer,
  111. vec![buffer.clone(), offset.clone()],
  112. );
  113. let expr = Expression::ShiftRight(
  114. Codegen,
  115. Uint(32),
  116. Expression::ZeroExt(Codegen, Uint(32), read_byte.into()).into(),
  117. two.clone().into(),
  118. false,
  119. );
  120. cfg.add(
  121. vartab,
  122. Instr::Set {
  123. loc: Codegen,
  124. res: decoded_var,
  125. expr,
  126. },
  127. );
  128. cfg.add(
  129. vartab,
  130. Instr::Set {
  131. loc: Codegen,
  132. res: size_width_var,
  133. expr: two.clone(),
  134. },
  135. );
  136. cfg.add(vartab, Instr::Branch { block: done });
  137. cfg.set_basic_block(cases[2].1);
  138. let read_byte = Expression::Builtin(
  139. Codegen,
  140. vec![Uint(32)],
  141. Builtin::ReadFromBuffer,
  142. vec![buffer.clone(), offset.clone()],
  143. );
  144. let expr = Expression::ShiftRight(Codegen, Uint(32), read_byte.into(), two.into(), false);
  145. cfg.add(
  146. vartab,
  147. Instr::Set {
  148. loc: Codegen,
  149. res: decoded_var,
  150. expr,
  151. },
  152. );
  153. cfg.add(
  154. vartab,
  155. Instr::Set {
  156. loc: Codegen,
  157. res: size_width_var,
  158. expr: Expression::NumberLiteral(Codegen, Uint(32), 4.into()),
  159. },
  160. );
  161. cfg.add(vartab, Instr::Branch { block: done });
  162. vartab.set_dirty(decoded_var);
  163. vartab.set_dirty(size_width_var);
  164. cfg.set_basic_block(done);
  165. cfg.set_phis(done, vartab.pop_dirty_tracker());
  166. (decoded_var, size_width)
  167. }
  168. /// Encode `expr` into `buffer` as a compact integer. More information can found in the
  169. /// [SCALE documentation](https://docs.substrate.io/reference/scale-codec/).
  170. fn encode_compact(
  171. expr: &Expression,
  172. buffer: Option<&Expression>,
  173. offset: Option<&Expression>,
  174. vartab: &mut Vartable,
  175. cfg: &mut ControlFlowGraph,
  176. ) -> Expression {
  177. let small = cfg.new_basic_block("small".into());
  178. let medium = cfg.new_basic_block("medium".into());
  179. let medium_or_big = cfg.new_basic_block("medium_or_big".into());
  180. let big = cfg.new_basic_block("big".into());
  181. let done = cfg.new_basic_block("done".into());
  182. let fail = cfg.new_basic_block("fail".into());
  183. let prepare = cfg.new_basic_block("prepare".into());
  184. let cmp_val = Expression::NumberLiteral(Codegen, Uint(32), (0x40000000 - 1).into());
  185. let compare = Expression::More {
  186. loc: Codegen,
  187. signed: false,
  188. left: expr.clone().into(),
  189. right: cmp_val.into(),
  190. };
  191. cfg.add(
  192. vartab,
  193. Instr::BranchCond {
  194. cond: compare,
  195. true_block: fail,
  196. false_block: prepare,
  197. },
  198. );
  199. cfg.set_basic_block(fail);
  200. cfg.add(vartab, Instr::AssertFailure { encoded_args: None });
  201. cfg.set_basic_block(prepare);
  202. let cmp_val = Expression::NumberLiteral(Codegen, Uint(32), (0x40 - 1).into());
  203. let compare = Expression::More {
  204. loc: Codegen,
  205. signed: false,
  206. left: expr.clone().into(),
  207. right: cmp_val.into(),
  208. };
  209. cfg.add(
  210. vartab,
  211. Instr::BranchCond {
  212. cond: compare,
  213. true_block: medium_or_big,
  214. false_block: small,
  215. },
  216. );
  217. cfg.set_basic_block(medium_or_big);
  218. let cmp_val = Expression::NumberLiteral(Codegen, Uint(32), (0x4000 - 1).into());
  219. let compare = Expression::More {
  220. loc: Codegen,
  221. signed: false,
  222. left: expr.clone().into(),
  223. right: cmp_val.into(),
  224. };
  225. cfg.add(
  226. vartab,
  227. Instr::BranchCond {
  228. cond: compare,
  229. true_block: big,
  230. false_block: medium,
  231. },
  232. );
  233. let size_variable = vartab.temp_anonymous(&Uint(32));
  234. vartab.new_dirty_tracker();
  235. let four = Expression::NumberLiteral(Codegen, Uint(32), 4.into()).into();
  236. let mul = Expression::Multiply(Codegen, Uint(32), false, expr.clone().into(), four);
  237. cfg.set_basic_block(small);
  238. if let (Some(buffer), Some(offset)) = (buffer, offset) {
  239. cfg.add(
  240. vartab,
  241. Instr::WriteBuffer {
  242. buf: buffer.clone(),
  243. offset: offset.clone(),
  244. value: Expression::Cast(Codegen, Uint(8), mul.clone().into()),
  245. },
  246. );
  247. }
  248. let one = Expression::NumberLiteral(Codegen, Uint(32), 1.into());
  249. cfg.add(
  250. vartab,
  251. Instr::Set {
  252. loc: Codegen,
  253. res: size_variable,
  254. expr: one.clone(),
  255. },
  256. );
  257. cfg.add(vartab, Instr::Branch { block: done });
  258. cfg.set_basic_block(medium);
  259. if let (Some(buffer), Some(offset)) = (buffer, offset) {
  260. let mul = Expression::BitwiseOr(Codegen, Uint(32), mul.clone().into(), one.into());
  261. cfg.add(
  262. vartab,
  263. Instr::WriteBuffer {
  264. buf: buffer.clone(),
  265. offset: offset.clone(),
  266. value: Expression::Cast(Codegen, Uint(16), mul.into()),
  267. },
  268. );
  269. }
  270. let two = Expression::NumberLiteral(Codegen, Uint(32), 2.into());
  271. cfg.add(
  272. vartab,
  273. Instr::Set {
  274. loc: Codegen,
  275. res: size_variable,
  276. expr: two.clone(),
  277. },
  278. );
  279. cfg.add(vartab, Instr::Branch { block: done });
  280. cfg.set_basic_block(big);
  281. if let (Some(buffer), Some(offset)) = (buffer, offset) {
  282. cfg.add(
  283. vartab,
  284. Instr::WriteBuffer {
  285. buf: buffer.clone(),
  286. offset: offset.clone(),
  287. value: Expression::BitwiseOr(Codegen, Uint(32), mul.into(), two.into()),
  288. },
  289. );
  290. }
  291. cfg.add(
  292. vartab,
  293. Instr::Set {
  294. loc: Codegen,
  295. res: size_variable,
  296. expr: Expression::NumberLiteral(Codegen, Uint(32), 4.into()),
  297. },
  298. );
  299. cfg.add(vartab, Instr::Branch { block: done });
  300. cfg.set_basic_block(done);
  301. cfg.set_phis(done, vartab.pop_dirty_tracker());
  302. Expression::Variable(Codegen, Uint(32), size_variable)
  303. }
  304. impl AbiEncoding for ScaleEncoding {
  305. fn size_width(
  306. &self,
  307. size: &Expression,
  308. vartab: &mut Vartable,
  309. cfg: &mut ControlFlowGraph,
  310. ) -> Expression {
  311. // FIXME:
  312. // It should be possible to optimize this to estimate always 4 bytes.
  313. // `codegen::abi_encode()` also returns the actual encoded size,
  314. // so slightly overestimating it shouldn't matter.
  315. // However, the actual length of the encoded data produced by `codegen::abi_encode()`
  316. // is ignored in some places, wich results in buggy contracts if we have not an exact estimate.
  317. // Once this is fixed (the encoded size return by `codegen::abi_encode()` must never be ignored),
  318. // this can just be always 4 bytes .
  319. encode_compact(size, None, None, vartab, cfg)
  320. }
  321. fn encode_external_function(
  322. &mut self,
  323. expr: &Expression,
  324. buffer: &Expression,
  325. offset: &Expression,
  326. ns: &Namespace,
  327. vartab: &mut Vartable,
  328. cfg: &mut ControlFlowGraph,
  329. ) -> Expression {
  330. let addr_len = ns.address_length.into();
  331. let address = expr.external_function_address();
  332. let size = self.encode_directly(&address, buffer, offset, vartab, cfg, addr_len);
  333. let offset = Expression::Add(Codegen, Uint(32), false, offset.clone().into(), size.into());
  334. let selector = expr.external_function_selector();
  335. self.encode_directly(&selector, buffer, &offset, vartab, cfg, 4.into());
  336. Expression::NumberLiteral(Codegen, Uint(32), (ns.address_length + 4).into())
  337. }
  338. fn encode_size(
  339. &mut self,
  340. expr: &Expression,
  341. buffer: &Expression,
  342. offset: &Expression,
  343. _ns: &Namespace,
  344. vartab: &mut Vartable,
  345. cfg: &mut ControlFlowGraph,
  346. ) -> Expression {
  347. encode_compact(expr, Some(buffer), Some(offset), vartab, cfg)
  348. }
  349. fn decode_external_function(
  350. &self,
  351. buffer: &Expression,
  352. offset: &Expression,
  353. ty: &Type,
  354. validator: &mut BufferValidator,
  355. ns: &Namespace,
  356. vartab: &mut Vartable,
  357. cfg: &mut ControlFlowGraph,
  358. ) -> (Expression, Expression) {
  359. let size = Expression::NumberLiteral(Codegen, Uint(32), (ns.address_length + 4).into());
  360. validator.validate_offset_plus_size(offset, &size, ns, vartab, cfg);
  361. let address = Expression::Builtin(
  362. Codegen,
  363. vec![Type::Address(false)],
  364. Builtin::ReadFromBuffer,
  365. vec![buffer.clone(), offset.clone()],
  366. );
  367. let new_offset = offset.clone().add_u32(Expression::NumberLiteral(
  368. Codegen,
  369. Uint(32),
  370. ns.address_length.into(),
  371. ));
  372. let selector = Expression::Builtin(
  373. Codegen,
  374. vec![Type::FunctionSelector],
  375. Builtin::ReadFromBuffer,
  376. vec![buffer.clone(), new_offset],
  377. );
  378. let ext_func = Expression::StructLiteral(
  379. Codegen,
  380. Type::Struct(StructType::ExternalFunction),
  381. vec![selector, address],
  382. );
  383. (Expression::Cast(Codegen, ty.clone(), ext_func.into()), size)
  384. }
  385. fn retrieve_array_length(
  386. &self,
  387. buffer: &Expression,
  388. offset: &Expression,
  389. vartab: &mut Vartable,
  390. cfg: &mut ControlFlowGraph,
  391. ) -> (usize, Expression) {
  392. decode_compact(buffer, offset, vartab, cfg)
  393. }
  394. fn storage_cache_insert(&mut self, arg_no: usize, expr: Expression) {
  395. self.storage_cache.insert(arg_no, expr);
  396. }
  397. fn storage_cache_remove(&mut self, arg_no: usize) -> Option<Expression> {
  398. self.storage_cache.remove(&arg_no)
  399. }
  400. fn calculate_string_size(
  401. &self,
  402. expr: &Expression,
  403. vartab: &mut Vartable,
  404. cfg: &mut ControlFlowGraph,
  405. ) -> Expression {
  406. // When encoding a variable length array, the total size is "compact encoded array length + N elements"
  407. let length = Expression::Builtin(
  408. Codegen,
  409. vec![Uint(32)],
  410. Builtin::ArrayLength,
  411. vec![expr.clone()],
  412. );
  413. if self.is_packed() {
  414. length
  415. } else {
  416. encode_compact(&length, None, None, vartab, cfg).add_u32(length)
  417. }
  418. }
  419. fn is_packed(&self) -> bool {
  420. self.packed_encoder
  421. }
  422. }