1use std::{
3 collections::BTreeMap,
4 sync::{Arc, Mutex},
5};
6
7use rand_core::{RngCore as _, SeedableRng as _};
8use rand_xorshift::XorShiftRng;
9
10use oasis_contract_sdk_crypto as crypto;
11use oasis_runtime_sdk::crypto::signature;
12
13use crate::{
14 context::Context,
15 env::{Crypto, CryptoError, Env},
16 event::Event,
17 storage::{ConfidentialStore, PublicStore, Store},
18 types::{
19 address::Address,
20 env::{QueryRequest, QueryResponse},
21 event::Event as RawEvent,
22 message::Message,
23 token, CallFormat, ExecutionContext, InstanceId,
24 },
25};
26
27#[derive(Clone, Default)]
29pub struct MockStore {
30 inner: BTreeMap<Vec<u8>, Vec<u8>>,
31}
32
33impl MockStore {
34 pub fn new() -> Self {
36 Self {
37 inner: BTreeMap::new(),
38 }
39 }
40}
41
42impl Store for MockStore {
43 fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
44 self.inner.get(key).cloned()
45 }
46
47 fn insert(&mut self, key: &[u8], value: &[u8]) {
48 self.inner.insert(key.to_owned(), value.to_owned());
49 }
50
51 fn remove(&mut self, key: &[u8]) {
52 self.inner.remove(key);
53 }
54}
55
56impl PublicStore for MockStore {}
57impl ConfidentialStore for MockStore {}
58
59#[derive(Clone)]
61pub struct MockEnv {
62 rng: Arc<Mutex<XorShiftRng>>,
63}
64
65impl MockEnv {
66 pub fn new() -> Self {
68 Default::default()
69 }
70}
71
72impl Default for MockEnv {
73 fn default() -> Self {
74 Self {
75 rng: Arc::new(Mutex::new(XorShiftRng::seed_from_u64(0))),
76 }
77 }
78}
79
80impl Env for MockEnv {
81 fn query<Q: Into<QueryRequest>>(&self, query: Q) -> QueryResponse {
82 match query.into() {
83 QueryRequest::BlockInfo => QueryResponse::BlockInfo {
84 round: 42,
85 epoch: 2,
86 timestamp: 100_000,
87 },
88 _ => unimplemented!(),
89 }
90 }
91
92 fn address_for_instance(&self, instance_id: InstanceId) -> Address {
93 let b = [
94 "test_12345678".as_bytes(),
95 &instance_id.as_u64().to_be_bytes(),
96 ]
97 .concat();
98 Address::from_bytes(&b).unwrap()
99 }
100
101 #[cfg(feature = "debug-utils")]
102 fn debug_print(&self, msg: &str) {
103 eprintln!("{msg}");
104 }
105}
106
107impl Crypto for MockEnv {
108 fn ecdsa_recover(&self, input: &[u8]) -> [u8; 65] {
109 crypto::ecdsa::recover(input).unwrap()
110 }
111
112 fn signature_verify_ed25519(&self, key: &[u8], message: &[u8], signature: &[u8]) -> bool {
113 let key = if let Ok(key) = signature::ed25519::PublicKey::from_bytes(key) {
114 key
115 } else {
116 return false;
117 };
118 let sig: signature::Signature = signature.to_vec().into();
119 key.verify_raw(message, &sig).is_ok()
120 }
121
122 fn signature_verify_secp256k1(&self, key: &[u8], message: &[u8], signature: &[u8]) -> bool {
123 let key = if let Ok(key) = signature::secp256k1::PublicKey::from_bytes(key) {
124 key
125 } else {
126 return false;
127 };
128 let sig: signature::Signature = signature.to_vec().into();
129 key.verify_raw(message, &sig).is_ok()
130 }
131
132 fn signature_verify_sr25519(
133 &self,
134 key: &[u8],
135 context: &[u8],
136 message: &[u8],
137 signature: &[u8],
138 ) -> bool {
139 let key = if let Ok(key) = signature::sr25519::PublicKey::from_bytes(key) {
140 key
141 } else {
142 return false;
143 };
144 let sig: signature::Signature = signature.to_vec().into();
145 key.verify(context, message, &sig).is_ok()
146 }
147
148 fn x25519_derive_symmetric(&self, public_key: &[u8], private_key: &[u8]) -> [u8; 32] {
149 crypto::x25519::derive_symmetric(public_key, private_key).unwrap()
150 }
151
152 fn deoxysii_seal(
153 &self,
154 key: &[u8],
155 nonce: &[u8],
156 message: &[u8],
157 additional_data: &[u8],
158 ) -> Result<Vec<u8>, CryptoError> {
159 Ok(crypto::deoxysii::seal(key, nonce, message, additional_data).unwrap())
160 }
161
162 fn deoxysii_open(
163 &self,
164 key: &[u8],
165 nonce: &[u8],
166 message: &[u8],
167 additional_data: &[u8],
168 ) -> Result<Vec<u8>, CryptoError> {
169 crypto::deoxysii::open(key, nonce, message, additional_data).map_err(|e| match e {
170 crypto::deoxysii::Error::DecryptionFailed => CryptoError::DecryptionFailed,
171 _ => panic!("unexpected crypto error"),
172 })
173 }
174
175 fn random_bytes(&self, _pers: &[u8], dst: &mut [u8]) -> usize {
176 self.rng.lock().unwrap().fill_bytes(dst);
177 dst.len()
178 }
179}
180
181pub struct MockContext {
183 pub ec: ExecutionContext,
185
186 pub public_store: MockStore,
188 pub confidential_store: MockStore,
190 pub env: MockEnv,
192
193 pub messages: Vec<Message>,
195 pub events: Vec<RawEvent>,
197}
198
199impl From<ExecutionContext> for MockContext {
200 fn from(ec: ExecutionContext) -> Self {
201 Self {
202 ec,
203 public_store: MockStore::new(),
204 confidential_store: MockStore::new(),
205 env: MockEnv::new(),
206 messages: Vec::new(),
207 events: Vec::new(),
208 }
209 }
210}
211
212impl Context for MockContext {
213 type PublicStore = MockStore;
214 type ConfidentialStore = MockStore;
215 type Env = MockEnv;
216
217 fn instance_id(&self) -> InstanceId {
218 self.ec.instance_id
219 }
220
221 fn instance_address(&self) -> &Address {
222 &self.ec.instance_address
223 }
224
225 fn caller_address(&self) -> &Address {
226 &self.ec.caller_address
227 }
228
229 fn deposited_tokens(&self) -> &[token::BaseUnits] {
230 &self.ec.deposited_tokens
231 }
232
233 fn is_read_only(&self) -> bool {
234 self.ec.read_only
235 }
236
237 fn call_format(&self) -> CallFormat {
238 self.ec.call_format
239 }
240
241 fn emit_message(&mut self, msg: Message) {
242 self.messages.push(msg);
243 }
244
245 fn emit_event<E: Event>(&mut self, event: E) {
246 self.events.push(event.into_raw());
247 }
248
249 fn public_store(&mut self) -> &mut Self::PublicStore {
250 &mut self.public_store
251 }
252
253 fn confidential_store(&mut self) -> &mut Self::ConfidentialStore {
254 &mut self.confidential_store
255 }
256
257 fn env(&self) -> &Self::Env {
258 &self.env
259 }
260}
261
262#[macro_export]
264#[doc(hidden)]
265macro_rules! __create_contract {
266 ($name:ty) => {};
267}