inkpad_runtime/
runtime.rs1use crate::{method::InkMethod, Error, Result};
3use inkpad_executor::{Executor, Memory};
4use inkpad_sandbox::{RuntimeInterfaces, Sandbox, Transaction};
5use inkpad_std::{Rc, String, ToString, Vec};
6use inkpad_support::{
7 convert, traits,
8 types::{self, Metadata},
9};
10use core::cell::RefCell;
11
12pub struct Runtime {
14 pub sandbox: Sandbox,
15 pub metadata: Metadata,
16 pub cache: Rc<RefCell<dyn traits::Frame<Memory>>>,
17}
18
19impl Runtime {
20 pub fn contract(contract: &[u8], ri: Option<impl RuntimeInterfaces>) -> Result<Runtime> {
22 let meta = serde_json::from_str::<Metadata>(&String::from_utf8_lossy(contract))
23 .map_err(|_| Error::DecodeContractFailed)?;
24
25 Self::new(meta, types::Cache::default(), ri)
26 }
27
28 pub fn from_contract(
30 contract: &[u8],
31 cache: impl traits::Frame<Memory> + 'static,
32 ri: Option<impl RuntimeInterfaces>,
33 ) -> Result<Runtime> {
34 let meta = serde_json::from_slice::<Metadata>(contract)
35 .map_err(|_| Error::DecodeContractFailed)?;
36
37 Self::new(meta, cache, ri)
38 }
39
40 pub fn from_metadata(
42 meta: Metadata,
43 cache: impl traits::Frame<Memory> + 'static,
44 ri: Option<impl RuntimeInterfaces>,
45 ) -> Result<Runtime> {
46 Self::new(meta, cache, ri)
47 }
48
49 pub fn load(&mut self, b: &[u8]) -> Result<[u8; 32]> {
51 self.load_metadata(
52 &serde_json::from_slice::<Metadata>(b).map_err(|_| Error::DecodeContractFailed)?,
53 )
54 }
55
56 pub fn load_metadata(&mut self, meta: &Metadata) -> Result<[u8; 32]> {
58 Ok(self.sandbox.load_metadata(meta)?)
59 }
60
61 pub fn new(
63 metadata: Metadata,
64 cache: impl traits::Frame<Memory> + 'static,
65 ri: Option<impl RuntimeInterfaces>,
66 ) -> Result<Runtime> {
67 let seal_calls = inkpad_seal::pallet_contracts(ri);
69
70 let cache = Rc::new(RefCell::new(cache));
72
73 let mut sandbox = Sandbox::new(cache.clone(), seal_calls.clone());
75 let code_hash = sandbox.load_metadata(&metadata)?;
76 sandbox.prepare(code_hash)?;
77
78 Ok(Runtime {
80 sandbox,
81 metadata,
82 cache,
83 })
84 }
85
86 pub fn deploy(
88 &mut self,
89 method: &str,
90 args: Vec<Vec<u8>>,
91 tx: Option<Transaction>,
92 ) -> Result<Option<Vec<u8>>> {
93 self.invoke(InkMethod::Deploy, method, args, tx)
94 }
95
96 pub fn call(
98 &mut self,
99 method: &str,
100 args: Vec<Vec<u8>>,
101 tx: Option<Transaction>,
102 ) -> Result<Option<Vec<u8>>> {
103 self.invoke(InkMethod::Call, method, args, tx)
104 }
105
106 pub fn invoke(
108 &mut self,
109 method: InkMethod,
110 inner_method: &str,
111 args: Vec<Vec<u8>>,
112 tx: Option<Transaction>,
113 ) -> Result<Option<Vec<u8>>> {
114 if let Some(tx) = tx {
116 self.sandbox.tx = tx;
117 }
118
119 self.sandbox.input = Some(method.parse(&self.metadata, inner_method, args)?);
121
122 let hash = self
124 .cache
125 .borrow()
126 .active()
127 .ok_or(inkpad_executor::Error::CodeNotFound)?;
128 Executor::new(
129 convert::to_storage_key(&hash[..]).ok_or(inkpad_executor::Error::CodeNotFound)?,
130 &mut self.sandbox,
131 )?
132 .invoke(&method.to_string(), &[], &mut self.sandbox)
133 .map_err(|error| Error::CallContractFailed { error })?;
134
135 self.cache
137 .borrow_mut()
138 .flush()
139 .ok_or(Error::FlushDataFailed)?;
140 Ok(self.sandbox.ret.take())
141 }
142}