1use std::{
2 borrow::{Borrow, Cow},
3 fmt::Display,
4 path::Path,
5};
6
7use blake2::{Blake2s256, Digest};
8use serde::{Deserialize, Serialize};
9use serde_with::serde_as;
10
11use crate::prelude::ContractInstanceId;
12
13const APPLICATION_HASH_SIZE: usize = 32;
14const COMPONENT_HASH_LENGTH: usize = 32;
15
16#[derive(Debug, Serialize, Deserialize, Clone)]
18#[serde_as]
19pub struct Component<'a> {
20 #[serde_as(as = "serde_with::Bytes")]
21 #[serde(borrow)]
22 code: Cow<'a, [u8]>,
23 key: ComponentKey,
24}
25
26impl PartialEq for Component<'_> {
27 fn eq(&self, other: &Self) -> bool {
28 self.key == other.key
29 }
30}
31
32impl Eq for Component<'_> {}
33
34impl Component<'_> {
35 pub fn key(&self) -> &ComponentKey {
36 &self.key
37 }
38
39 pub fn into_owned(self) -> Component<'static> {
40 Component {
41 key: self.key,
42 code: Cow::from(self.code.into_owned()),
43 }
44 }
45}
46
47impl AsRef<[u8]> for Component<'_> {
48 fn as_ref(&self) -> &[u8] {
49 self.code.borrow()
50 }
51}
52
53impl TryFrom<&Path> for Component<'static> {
54 type Error = std::io::Error;
55 fn try_from(path: &Path) -> Result<Self, Self::Error> {
56 let code = Cow::from(std::fs::read(path)?);
57 let key = ComponentKey::new(code.borrow());
58 Ok(Self { code, key })
59 }
60}
61
62impl From<Vec<u8>> for Component<'static> {
63 fn from(data: Vec<u8>) -> Self {
64 let key = ComponentKey::new(data.as_slice());
65 Component {
66 code: Cow::from(data),
67 key,
68 }
69 }
70}
71
72#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
74pub enum ComponentError {
75 #[error("de/serialization error: {0}")]
76 Deser(String),
77 #[error("{0}")]
78 Other(String),
79}
80
81#[serde_as]
82#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
83pub struct SecretsId {
84 #[serde_as(as = "serde_with::Bytes")]
85 key: Vec<u8>,
86 #[serde_as(as = "[_; 32]")]
87 hash: [u8; 32],
88}
89
90impl SecretsId {
91 pub fn new(key: Vec<u8>) -> Self {
92 let mut hasher = Blake2s256::new();
93 hasher.update(&key);
94 let hashed = hasher.finalize();
95 let mut hash = [0; 32];
96 hash.copy_from_slice(&hashed);
97 Self { key, hash }
98 }
99
100 pub fn encode(&self) -> String {
101 bs58::encode(self.hash)
102 .with_alphabet(bs58::Alphabet::BITCOIN)
103 .into_string()
104 }
105
106 pub fn code_hash(&self) -> &[u8; 32] {
108 &self.hash
109 }
110}
111
112pub trait ComponentInterface {
113 fn process(messages: InboundComponentMsg) -> Result<Vec<OutboundComponentMsg>, ComponentError>;
116}
117
118#[serde_as]
119#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
120pub struct ComponentKey(#[serde_as(as = "[_; COMPONENT_HASH_LENGTH]")] [u8; COMPONENT_HASH_LENGTH]);
121
122impl ComponentKey {
123 pub fn new(wasm_code: &[u8]) -> Self {
124 let mut hasher = Blake2s256::new();
125 hasher.update(wasm_code);
126 let hashed = hasher.finalize();
127 let mut component_key = [0; COMPONENT_HASH_LENGTH];
128 component_key.copy_from_slice(&hashed);
129 Self(component_key)
130 }
131
132 pub fn encode(&self) -> String {
133 bs58::encode(self.0)
134 .with_alphabet(bs58::Alphabet::BITCOIN)
135 .into_string()
136 }
137
138 pub fn code_hash(&self) -> &[u8; COMPONENT_HASH_LENGTH] {
140 &self.0
141 }
142}
143
144impl Display for ComponentKey {
145 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146 write!(f, "{}", self.encode())
147 }
148}
149
150#[derive(Debug, Clone, Default, Serialize, Deserialize)]
151pub struct ComponentContext(pub Vec<u8>);
152
153impl ComponentContext {
154 pub const MAX_SIZE: usize = 4096 * 10 * 10;
155
156 pub fn new(bytes: Vec<u8>) -> Self {
157 assert!(bytes.len() < Self::MAX_SIZE);
158 Self(bytes)
159 }
160
161 pub fn append(&mut self, bytes: &mut Vec<u8>) {
162 assert!(self.0.len() + bytes.len() < Self::MAX_SIZE);
163 self.0.append(bytes)
164 }
165
166 pub fn replace(&mut self, bytes: Vec<u8>) {
167 assert!(bytes.len() < Self::MAX_SIZE);
168 let _ = std::mem::replace(&mut self.0, bytes);
169 }
170}
171
172#[serde_as]
173#[derive(Serialize, Deserialize)]
174pub struct ContractHash(#[serde_as(as = "[_; APPLICATION_HASH_SIZE]")] [u8; APPLICATION_HASH_SIZE]);
175
176#[derive(Serialize, Deserialize, Debug, Clone)]
177pub enum InboundComponentMsg<'a> {
178 ApplicationMessage(ApplicationMessage),
179 GetSecretResponse(GetSecretResponse),
180 RandomBytes(Vec<u8>),
181 UserResponse(#[serde(borrow)] UserInputResponse<'a>),
182 }
189
190impl InboundComponentMsg<'_> {
191 pub fn into_owned(self) -> InboundComponentMsg<'static> {
192 match self {
193 InboundComponentMsg::ApplicationMessage(r) => {
194 InboundComponentMsg::ApplicationMessage(r)
195 }
196 InboundComponentMsg::GetSecretResponse(r) => InboundComponentMsg::GetSecretResponse(r),
197 InboundComponentMsg::RandomBytes(b) => InboundComponentMsg::RandomBytes(b),
198 InboundComponentMsg::UserResponse(r) => {
199 InboundComponentMsg::UserResponse(r.into_owned())
200 }
201 }
202 }
203
204 pub fn get_context(&self) -> Option<&ComponentContext> {
205 match self {
206 InboundComponentMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
207 Some(context)
208 }
209 InboundComponentMsg::GetSecretResponse(GetSecretResponse { context, .. }) => {
210 Some(context)
211 }
212 _ => None,
213 }
214 }
215
216 pub fn get_mut_context(&mut self) -> Option<&mut ComponentContext> {
217 match self {
218 InboundComponentMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
219 Some(context)
220 }
221 InboundComponentMsg::GetSecretResponse(GetSecretResponse { context, .. }) => {
222 Some(context)
223 }
224 _ => None,
225 }
226 }
227}
228
229#[derive(Serialize, Deserialize, Debug, Clone)]
230pub struct GetSecretResponse {
231 pub key: SecretsId,
232 pub value: Option<Vec<u8>>,
233 pub context: ComponentContext,
234}
235
236#[non_exhaustive]
237#[derive(Serialize, Deserialize, Debug, Clone)]
238pub struct ApplicationMessage {
239 pub app: ContractInstanceId,
240 pub payload: Vec<u8>,
241 pub context: ComponentContext,
242 pub processed: bool,
243}
244
245impl ApplicationMessage {
246 pub fn new(app: ContractInstanceId, payload: Vec<u8>, processed: bool) -> Self {
247 Self {
248 app,
249 payload,
250 context: ComponentContext::default(),
251 processed,
252 }
253 }
254
255 pub fn with_context(mut self, context: ComponentContext) -> Self {
256 self.context = context;
257 self
258 }
259}
260
261#[derive(Serialize, Deserialize, Debug, Clone)]
262pub struct UserInputResponse<'a> {
263 request_id: u32,
264 #[serde(borrow)]
265 response: ClientResponse<'a>,
266}
267
268impl UserInputResponse<'_> {
269 pub fn into_owned(self) -> UserInputResponse<'static> {
270 UserInputResponse {
271 request_id: self.request_id,
272 response: self.response.into_owned(),
273 }
274 }
275}
276
277#[derive(Serialize, Deserialize, Debug)]
278pub enum OutboundComponentMsg {
279 ApplicationMessage(ApplicationMessage),
281 RequestUserInput(#[serde(deserialize_with = "deser_func")] UserInputRequest<'static>),
282 GetSecretRequest(GetSecretRequest),
284 SetSecretRequest(SetSecretRequest),
285 RandomBytesRequest(usize),
286 }
291
292impl From<GetSecretRequest> for OutboundComponentMsg {
293 fn from(req: GetSecretRequest) -> Self {
294 Self::GetSecretRequest(req)
295 }
296}
297
298impl From<ApplicationMessage> for OutboundComponentMsg {
299 fn from(req: ApplicationMessage) -> Self {
300 Self::ApplicationMessage(req)
301 }
302}
303
304impl OutboundComponentMsg {
305 pub fn processed(&self) -> bool {
306 match self {
307 OutboundComponentMsg::ApplicationMessage(msg) => msg.processed,
308 OutboundComponentMsg::GetSecretRequest(msg) => msg.processed,
309 OutboundComponentMsg::RandomBytesRequest(_) => false,
310 OutboundComponentMsg::SetSecretRequest(_) => false,
311 OutboundComponentMsg::RequestUserInput(_) => true,
312 }
313 }
314
315 pub fn get_context(&self) -> Option<&ComponentContext> {
316 match self {
317 OutboundComponentMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
318 Some(context)
319 }
320 OutboundComponentMsg::GetSecretRequest(GetSecretRequest { context, .. }) => {
321 Some(context)
322 }
323 _ => None,
324 }
325 }
326
327 pub fn get_mut_context(&mut self) -> Option<&mut ComponentContext> {
328 match self {
329 OutboundComponentMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
330 Some(context)
331 }
332 OutboundComponentMsg::GetSecretRequest(GetSecretRequest { context, .. }) => {
333 Some(context)
334 }
335 _ => None,
336 }
337 }
338}
339
340fn deser_func<'de, D>(deser: D) -> Result<UserInputRequest<'static>, D::Error>
341where
342 D: serde::Deserializer<'de>,
343{
344 let value = <UserInputRequest<'de> as Deserialize>::deserialize(deser)?;
345 Ok(value.into_owned())
346}
347
348#[derive(Serialize, Deserialize, Debug)]
349pub struct GetSecretRequest {
350 pub key: SecretsId,
351 pub context: ComponentContext,
352 pub processed: bool,
353}
354
355#[derive(Serialize, Deserialize, Debug)]
356pub struct SetSecretRequest {
357 pub key: SecretsId,
358 pub value: Option<Vec<u8>>,
360}
361
362#[serde_as]
363#[derive(Serialize, Deserialize, Debug, Clone)]
364pub struct NotificationMessage<'a>(
365 #[serde_as(as = "serde_with::Bytes")]
366 #[serde(borrow)]
367 Cow<'a, [u8]>,
368);
369
370impl NotificationMessage<'_> {
371 pub fn into_owned(self) -> NotificationMessage<'static> {
372 NotificationMessage(self.0.into_owned().into())
373 }
374}
375
376#[serde_as]
377#[derive(Serialize, Deserialize, Debug, Clone)]
378pub struct ClientResponse<'a>(
379 #[serde_as(as = "serde_with::Bytes")]
380 #[serde(borrow)]
381 Cow<'a, [u8]>,
382);
383
384impl ClientResponse<'_> {
385 pub fn into_owned(self) -> ClientResponse<'static> {
386 ClientResponse(self.0.into_owned().into())
387 }
388}
389
390#[derive(Serialize, Deserialize, Debug, Clone)]
391pub struct UserInputRequest<'a> {
392 request_id: u32,
393 #[serde(borrow)]
394 message: NotificationMessage<'a>,
396 responses: Vec<ClientResponse<'a>>,
398}
399
400impl UserInputRequest<'_> {
401 pub fn into_owned(self) -> UserInputRequest<'static> {
402 UserInputRequest {
403 request_id: self.request_id,
404 message: self.message.into_owned(),
405 responses: self.responses.into_iter().map(|r| r.into_owned()).collect(),
406 }
407 }
408}
409
410#[doc(hidden)]
411pub(crate) mod wasm_interface {
412 use super::*;
415 use crate::WasmLinearMem;
416
417 #[repr(C)]
418 #[derive(Debug, Clone, Copy)]
419 pub struct ComponentInterfaceResult {
420 ptr: i64,
421 size: u32,
422 }
423
424 impl ComponentInterfaceResult {
425 pub unsafe fn from_raw(ptr: i64, mem: &WasmLinearMem) -> Self {
426 let result = Box::leak(Box::from_raw(crate::buf::compute_ptr(
427 ptr as *mut Self,
428 mem,
429 )));
430 #[cfg(feature = "trace")]
431 {
432 tracing::trace!(
433 "got FFI result @ {ptr} ({:p}) -> {result:?}",
434 ptr as *mut Self
435 );
436 }
437 *result
438 }
439
440 pub fn into_raw(self) -> i64 {
441 #[cfg(feature = "trace")]
442 {
443 tracing::trace!("returning FFI -> {self:?}");
444 }
445 let ptr = Box::into_raw(Box::new(self));
446 #[cfg(feature = "trace")]
447 {
448 tracing::trace!("FFI result ptr: {ptr:p} ({}i64)", ptr as i64);
449 }
450 ptr as _
451 }
452
453 pub unsafe fn unwrap(
454 self,
455 mem: WasmLinearMem,
456 ) -> Result<Vec<OutboundComponentMsg>, ComponentError> {
457 let ptr = crate::buf::compute_ptr(self.ptr as *mut u8, &mem);
458 let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
459 let value: Result<Vec<OutboundComponentMsg>, ComponentError> =
460 bincode::deserialize(serialized)
461 .map_err(|e| ComponentError::Other(format!("{e}")))?;
462 #[cfg(feature = "trace")]
463 {
464 tracing::trace!(
465 "got result through FFI; addr: {:p} ({}i64, mapped: {ptr:p})
466 serialized: {serialized:?}
467 value: {value:?}",
468 self.ptr as *mut u8,
469 self.ptr
470 );
471 }
472 value
473 }
474 }
475
476 impl From<Result<Vec<OutboundComponentMsg>, ComponentError>> for ComponentInterfaceResult {
477 fn from(value: Result<Vec<OutboundComponentMsg>, ComponentError>) -> Self {
478 let serialized = bincode::serialize(&value).unwrap();
479 let size = serialized.len() as _;
480 let ptr = serialized.as_ptr();
481 #[cfg(feature = "trace")]
482 {
483 tracing::trace!(
484 "sending result through FFI; addr: {ptr:p} ({}),\n serialized: {serialized:?}\n value: {value:?}",
485 ptr as i64
486 );
487 }
488 std::mem::forget(serialized);
489 Self {
490 ptr: ptr as i64,
491 size,
492 }
493 }
494 }
495}