1#![allow(clippy::missing_safety_doc, renamed_and_removed_lints)]
16
17mod externs;
18pub mod log;
19pub mod protocol;
20pub mod protos;
21
22use std::collections::HashMap;
23use std::string::FromUtf8Error;
24
25pub use crate::externs::{WasmPtr, WasmPtrList};
26
27pub struct Header {
28 signer: String,
29}
30
31impl Header {
32 pub fn new(signer: String) -> Header {
33 Header { signer }
34 }
35
36 pub fn get_signer_public_key(&self) -> &str {
37 &self.signer
38 }
39}
40
41pub struct TpProcessRequest<'a> {
42 payload: Vec<u8>,
43 header: &'a mut Header,
44 signature: String,
45}
46
47impl<'a> TpProcessRequest<'a> {
48 pub fn new(payload: Vec<u8>, header: &'a mut Header, signature: String) -> TpProcessRequest {
49 TpProcessRequest {
50 payload,
51 header,
52 signature,
53 }
54 }
55
56 pub fn get_payload(&self) -> &[u8] {
57 &self.payload
58 }
59
60 pub fn get_header(&self) -> &Header {
61 self.header
62 }
63
64 pub fn get_signature(&self) -> String {
65 self.signature.to_string()
66 }
67}
68
69pub trait TransactionContext {
70 #[deprecated(
71 since = "0.2.0",
72 note = "please use `get_state_entry` or `get_state_entries` instead"
73 )]
74 fn get_state(&self, addresses: &[String]) -> Result<Vec<(String, Vec<u8>)>, WasmSdkError> {
83 self.get_state_entries(addresses)
84 }
85 fn get_state_entry(&self, address: &str) -> Result<Option<Vec<u8>>, WasmSdkError> {
92 Ok(self
93 .get_state_entries(&[address.to_string()])?
94 .into_iter()
95 .map(|(_, val)| val)
96 .next())
97 }
98
99 fn get_state_entries(
107 &self,
108 addresses: &[String],
109 ) -> Result<Vec<(String, Vec<u8>)>, WasmSdkError>;
110
111 #[deprecated(
112 since = "0.2.0",
113 note = "please use `set_state_entry` or `set_state_entries` instead"
114 )]
115 fn set_state(&self, entries: HashMap<String, Vec<u8>>) -> Result<(), WasmSdkError> {
123 let state_entries: Vec<(String, Vec<u8>)> = entries.into_iter().collect();
124 self.set_state_entries(state_entries)
125 }
126
127 fn set_state_entry(&self, address: String, data: Vec<u8>) -> Result<(), WasmSdkError> {
135 self.set_state_entries(vec![(address, data)])
136 }
137
138 fn set_state_entries(&self, entries: Vec<(String, Vec<u8>)>) -> Result<(), WasmSdkError>;
145
146 #[deprecated(
154 since = "0.2.0",
155 note = "please use `delete_state_entry` or `delete_state_entries` instead"
156 )]
157 fn delete_state(&self, addresses: &[String]) -> Result<Vec<String>, WasmSdkError> {
158 self.delete_state_entries(addresses)
159 }
160
161 fn delete_state_entry(&self, address: &str) -> Result<Option<String>, WasmSdkError> {
169 Ok(self
170 .delete_state_entries(&[address.to_string()])?
171 .into_iter()
172 .next())
173 }
174
175 fn delete_state_entries(&self, addresses: &[String]) -> Result<Vec<String>, WasmSdkError>;
183
184 fn add_event(
195 &self,
196 event_type: String,
197 attributes: Vec<(String, String)>,
198 data: &[u8],
199 ) -> Result<(), WasmSdkError>;
200}
201
202#[derive(Default)]
203pub struct SabreTransactionContext {}
204
205impl SabreTransactionContext {
206 pub fn new() -> SabreTransactionContext {
207 SabreTransactionContext {}
208 }
209}
210
211impl TransactionContext for SabreTransactionContext {
212 fn get_state_entries(
213 &self,
214 addresses: &[String],
215 ) -> Result<Vec<(String, Vec<u8>)>, WasmSdkError> {
216 unsafe {
217 if addresses.is_empty() {
218 return Err(WasmSdkError::InvalidTransaction("No address to get".into()));
219 }
220 let head = &addresses[0];
221 let header_address_buffer = WasmBuffer::new(head.as_bytes())?;
222 externs::create_collection(header_address_buffer.to_raw());
223
224 for addr in addresses[1..].iter() {
225 let wasm_buffer = WasmBuffer::new(addr.as_bytes())?;
226 externs::add_to_collection(header_address_buffer.to_raw(), wasm_buffer.to_raw());
227 }
228
229 let results =
230 WasmBuffer::from_list(externs::get_state(header_address_buffer.to_raw()))?;
231 let mut result_vec = Vec::new();
232
233 if (result_vec.len() % 2) != 0 {
234 return Err(WasmSdkError::InvalidTransaction(
235 "Get state returned incorrect data fmt".into(),
236 ));
237 }
238
239 for result in results.chunks(2) {
240 let addr = String::from_utf8(result[0].to_bytes())?;
241 result_vec.push((addr, result[1].to_bytes()))
242 }
243 Ok(result_vec)
244 }
245 }
246
247 fn set_state_entries(&self, entries: Vec<(String, Vec<u8>)>) -> Result<(), WasmSdkError> {
248 unsafe {
249 let mut entries_iter = entries.iter();
250 let (head, head_data) = match entries_iter.next() {
251 Some((addr, data)) => (addr, data),
252 None => return Err(WasmSdkError::InvalidTransaction("No entries to set".into())),
253 };
254
255 let header_address_buffer = WasmBuffer::new(head.as_bytes())?;
256 externs::create_collection(header_address_buffer.to_raw());
257
258 let wasm_head_data_buffer = WasmBuffer::new(head_data)?;
259 externs::add_to_collection(
260 header_address_buffer.to_raw(),
261 wasm_head_data_buffer.to_raw(),
262 );
263
264 for (address, data) in entries_iter {
265 let wasm_addr_buffer = WasmBuffer::new(address.as_bytes())?;
266 externs::add_to_collection(
267 header_address_buffer.to_raw(),
268 wasm_addr_buffer.to_raw(),
269 );
270
271 let wasm_data_buffer = WasmBuffer::new(data)?;
272 externs::add_to_collection(
273 header_address_buffer.to_raw(),
274 wasm_data_buffer.to_raw(),
275 );
276 }
277
278 let result = externs::set_state(header_address_buffer.to_raw());
279
280 if result == 0 {
281 return Err(WasmSdkError::InvalidTransaction(
282 "Unable to set state".into(),
283 ));
284 }
285 }
286 Ok(())
287 }
288
289 fn delete_state_entries(&self, addresses: &[String]) -> Result<Vec<String>, WasmSdkError> {
290 unsafe {
291 if addresses.is_empty() {
292 return Err(WasmSdkError::InvalidTransaction(
293 "No address to delete".into(),
294 ));
295 }
296 let head = &addresses[0];
297 let header_address_buffer = WasmBuffer::new(head.as_bytes())?;
298 externs::create_collection(header_address_buffer.to_raw());
299
300 for addr in addresses[1..].iter() {
301 let wasm_buffer = WasmBuffer::new(addr.as_bytes())?;
302 externs::add_to_collection(header_address_buffer.to_raw(), wasm_buffer.to_raw());
303 }
304 let result =
305 WasmBuffer::from_list(externs::delete_state(header_address_buffer.to_raw()))?;
306 let mut result_vec = Vec::new();
307 for i in result {
308 let addr = String::from_utf8(i.data)?;
309 result_vec.push(addr);
310 }
311 Ok(result_vec)
312 }
313 }
314
315 fn add_event(
316 &self,
317 event_type: String,
318 attributes: Vec<(String, String)>,
319 data: &[u8],
320 ) -> Result<(), WasmSdkError> {
321 unsafe {
322 let event_type_buffer = WasmBuffer::new(event_type.as_bytes())?;
324
325 let data_buffer = WasmBuffer::new(data)?;
327
328 let attributes_iter = attributes.iter();
334 let attributes_buffer = WasmBuffer::new(b"attributes")?;
335 externs::create_collection(attributes_buffer.to_raw());
336
337 for (key, value) in attributes_iter {
338 let key_buffer = WasmBuffer::new(key.as_bytes())?;
339 externs::add_to_collection(attributes_buffer.to_raw(), key_buffer.to_raw());
340 let value_buffer = WasmBuffer::new(value.as_bytes())?;
341 externs::add_to_collection(attributes_buffer.to_raw(), value_buffer.to_raw());
342 }
343
344 let result = externs::add_event(
345 event_type_buffer.to_raw(),
346 attributes_buffer.to_raw(),
347 data_buffer.to_raw(),
348 );
349
350 if result != 0 {
351 return Err(WasmSdkError::InvalidTransaction(
352 "Unable to add event".into(),
353 ));
354 }
355
356 Ok(())
357 }
358 }
359}
360
361pub trait TransactionHandler {
363 fn family_name(&self) -> String;
364 fn family_versions(&self) -> Vec<String>;
365 fn namespaces(&self) -> Vec<String>;
366 fn apply(
367 &self,
368 request: &TpProcessRequest,
369 context: &mut dyn TransactionContext,
370 ) -> Result<(), ApplyError>;
371}
372
373pub unsafe fn execute_entrypoint<F>(
383 payload_ptr: WasmPtr,
384 signer_ptr: WasmPtr,
385 signature_ptr: WasmPtr,
386 apply: F,
387) -> i32
388where
389 F: Fn(&TpProcessRequest, &mut dyn TransactionContext) -> Result<bool, ApplyError>,
390{
391 let payload = if let Ok(i) = WasmBuffer::from_raw(payload_ptr) {
392 i.to_bytes()
393 } else {
394 return -1;
395 };
396
397 let signature = if let Ok(i) = WasmBuffer::from_raw(signature_ptr) {
398 match i.to_string() {
399 Ok(s) => s,
400 Err(_) => return -2,
401 }
402 } else {
403 return -1;
404 };
405
406 let signer = if let Ok(i) = WasmBuffer::from_raw(signer_ptr) {
407 match i.to_string() {
408 Ok(s) => s,
409 Err(_) => return -2,
410 }
411 } else {
412 return -1;
413 };
414
415 let mut header = Header::new(signer);
416 match apply(
417 &TpProcessRequest::new(payload, &mut header, signature),
418 &mut SabreTransactionContext::new(),
419 ) {
420 Ok(r) => {
421 if r {
422 1
423 } else {
424 0
425 }
426 }
427 Err(ApplyError::InvalidTransaction(_)) => -3,
428 Err(ApplyError::InternalError(_)) => -4,
429 }
430}
431
432pub struct Request {
433 roles: Vec<String>,
434 org_id: String,
435 public_key: String,
436 payload: Vec<u8>,
437}
438
439impl Request {
440 pub fn new(
441 roles: Vec<String>,
442 org_id: String,
443 public_key: String,
444 payload: Vec<u8>,
445 ) -> Request {
446 Request {
447 roles,
448 org_id,
449 public_key,
450 payload,
451 }
452 }
453
454 pub fn get_roles(&self) -> Vec<String> {
455 self.roles.clone()
456 }
457
458 pub fn get_org_id(&self) -> String {
459 self.org_id.clone()
460 }
461
462 pub fn get_public_key(&self) -> String {
463 self.public_key.clone()
464 }
465
466 pub fn get_state(&self, address: String) -> Result<Option<Vec<u8>>, WasmSdkError> {
467 unsafe {
468 let wasm_buffer = WasmBuffer::new(address.as_bytes())?;
469 ptr_to_vec(externs::get_state(wasm_buffer.to_raw()))
470 }
471 }
472
473 pub fn get_payload<T>(&self) -> Vec<u8> {
474 self.payload.clone()
475 }
476}
477
478pub struct WasmBuffer {
487 raw: WasmPtr,
488 data: Vec<u8>,
489}
490
491impl WasmBuffer {
492 pub unsafe fn new(buffer: &[u8]) -> Result<WasmBuffer, WasmSdkError> {
493 let raw = externs::alloc(buffer.len());
494
495 if raw < 0 {
496 return Err(WasmSdkError::AllocError(
497 "Failed to allocate host memory".into(),
498 ));
499 }
500
501 for (i, byte) in buffer.iter().enumerate() {
502 if externs::write_byte(raw, i as u32, *byte) < 0 {
503 return Err(WasmSdkError::MemoryWriteError(
504 "Failed to write data to host memory".into(),
505 ));
506 }
507 }
508
509 Ok(WasmBuffer {
510 raw,
511 data: buffer.to_vec(),
512 })
513 }
514
515 pub unsafe fn from_raw(raw: WasmPtr) -> Result<WasmBuffer, WasmSdkError> {
516 let data = ptr_to_vec(raw)?.unwrap_or_default();
517 Ok(WasmBuffer { raw, data })
518 }
519
520 pub unsafe fn from_list(ptr: WasmPtrList) -> Result<Vec<WasmBuffer>, WasmSdkError> {
521 let mut wasm_buffers = Vec::new();
522
523 if ptr >= 0 {
524 for i in 0..externs::get_ptr_collection_len(ptr) {
525 let ptr = externs::get_ptr_from_collection(ptr, i as u32);
526
527 if ptr < 0 {
528 return Err(WasmSdkError::MemoryRetrievalError(
529 "pointer not found".into(),
530 ));
531 }
532 wasm_buffers.push(WasmBuffer::from_raw(ptr)?);
533 }
534 }
535
536 Ok(wasm_buffers)
537 }
538
539 pub fn to_bytes(&self) -> Vec<u8> {
540 self.data.clone()
541 }
542
543 pub fn to_raw(&self) -> WasmPtr {
544 self.raw
545 }
546
547 pub fn to_string(&self) -> Result<String, WasmSdkError> {
548 String::from_utf8(self.data.clone()).map_err(WasmSdkError::from)
549 }
550}
551
552#[derive(Debug)]
553pub enum WasmSdkError {
554 InvalidTransaction(String),
555 InternalError(String),
556 StateSetError(String),
557 AllocError(String),
558 MemoryWriteError(String),
559 MemoryRetrievalError(String),
560 Utf8EncodeError(FromUtf8Error),
561 ProtobufError(protobuf::ProtobufError),
562}
563
564impl std::fmt::Display for WasmSdkError {
565 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
566 match *self {
567 WasmSdkError::InvalidTransaction(ref s) => write!(f, "InvalidTransactio: {}", s),
568 WasmSdkError::InternalError(ref s) => write!(f, "InternalError: {}", s),
569 WasmSdkError::StateSetError(ref s) => write!(f, "StateSetError: {}", s),
570 WasmSdkError::AllocError(ref s) => write!(f, "AllocError: {}", s),
571 WasmSdkError::MemoryWriteError(ref s) => write!(f, "MemoryWriteError: {}", s),
572 WasmSdkError::MemoryRetrievalError(ref s) => write!(f, "MemoryRetrievalError: {}", s),
573 WasmSdkError::Utf8EncodeError(ref err) => write!(f, "Utf8EncodeError: {}", err),
574 WasmSdkError::ProtobufError(ref err) => write!(f, "ProtobufError: {}", err),
575 }
576 }
577}
578
579impl From<FromUtf8Error> for WasmSdkError {
580 fn from(e: FromUtf8Error) -> Self {
581 WasmSdkError::Utf8EncodeError(e)
582 }
583}
584
585impl From<protobuf::ProtobufError> for WasmSdkError {
586 fn from(e: protobuf::ProtobufError) -> Self {
587 WasmSdkError::ProtobufError(e)
588 }
589}
590
591#[derive(Debug)]
592pub enum ApplyError {
593 InvalidTransaction(String),
594 InternalError(String),
595}
596
597impl std::fmt::Display for ApplyError {
598 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
599 match *self {
600 ApplyError::InvalidTransaction(ref s) => write!(f, "InvalidTransaction: {}", s),
601 ApplyError::InternalError(ref s) => write!(f, "InternalError: {}", s),
602 }
603 }
604}
605
606impl From<WasmSdkError> for ApplyError {
607 fn from(e: WasmSdkError) -> Self {
608 match e {
609 WasmSdkError::InternalError(..) => ApplyError::InternalError(format!("{}", e)),
610 _ => ApplyError::InvalidTransaction(format!("{}", e)),
611 }
612 }
613}
614
615unsafe fn ptr_to_vec(ptr: WasmPtr) -> Result<Option<Vec<u8>>, WasmSdkError> {
616 let mut vec = Vec::new();
617
618 let ptr_len = externs::get_ptr_len(ptr);
619 if ptr_len == -1 {
620 return Err(WasmSdkError::MemoryRetrievalError(
621 "WasmPtr does not exist".to_string(),
622 ));
623 }
624
625 for i in 0..ptr_len {
626 vec.push(externs::read_byte(ptr as isize + i));
627 }
628
629 if vec.is_empty() {
630 return Ok(None);
631 }
632 Ok(Some(vec))
633}
634
635#[derive(PartialOrd, PartialEq, Copy, Clone)]
636pub enum LogLevel {
637 Trace,
638 Debug,
639 Info,
640 Warn,
641 Error,
642}
643
644pub fn log_message(log_level: LogLevel, log_string: String) {
645 unsafe {
646 if let Ok(log_buffer) = WasmBuffer::new(log_string.as_bytes()) {
648 match log_level {
649 LogLevel::Trace => externs::log_buffer(4, log_buffer.to_raw()),
650 LogLevel::Debug => externs::log_buffer(3, log_buffer.to_raw()),
651 LogLevel::Info => externs::log_buffer(2, log_buffer.to_raw()),
652 LogLevel::Warn => externs::log_buffer(1, log_buffer.to_raw()),
653 LogLevel::Error => externs::log_buffer(0, log_buffer.to_raw()),
654 };
655 }
656 }
657}
658
659pub fn log_level() -> LogLevel {
660 unsafe {
661 match externs::log_level() {
662 4 => LogLevel::Trace,
663 3 => LogLevel::Debug,
664 2 => LogLevel::Info,
665 1 => LogLevel::Warn,
666 _ => LogLevel::Error,
667 }
668 }
669}
670
671pub fn log_enabled(lvl: LogLevel) -> bool {
672 lvl >= log_level()
673}