fuel_tx/transaction/types/
witness.rs1use educe::Educe;
2use fuel_types::fmt_truncated_hex;
3
4use alloc::vec::Vec;
5
6use crate::{
7 Input,
8 TxId,
9 ValidityError,
10};
11use fuel_crypto::{
12 Message,
13 Signature,
14};
15
16#[cfg(feature = "random")]
17use rand::{
18 distributions::{
19 Distribution,
20 Standard,
21 },
22 Rng,
23};
24
25#[derive(Educe, Default, Clone, PartialEq, Eq, Hash)]
26#[educe(Debug)]
27#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
28#[derive(serde::Serialize, serde::Deserialize)]
29#[cfg_attr(
30 feature = "da-compression",
31 derive(fuel_compression::Compress, fuel_compression::Decompress)
32)]
33#[derive(fuel_types::canonical::Deserialize, fuel_types::canonical::Serialize)]
34pub struct Witness {
35 #[educe(Debug(method(fmt_truncated_hex::<16>)))]
36 data: Vec<u8>,
37}
38
39impl Witness {
40 pub const fn as_vec(&self) -> &Vec<u8> {
41 &self.data
42 }
43
44 pub fn as_vec_mut(&mut self) -> &mut Vec<u8> {
45 &mut self.data
46 }
47
48 pub fn into_inner(self) -> Vec<u8> {
49 self.data
50 }
51
52 pub fn recover_witness(
54 &self,
55 txhash: &TxId,
56 input_index: usize,
57 ) -> Result<fuel_types::Address, ValidityError> {
58 let bytes = <[u8; Signature::LEN]>::try_from(self.as_ref())
59 .map_err(|_| ValidityError::InputInvalidSignature { index: input_index })?;
60 let signature = Signature::from_bytes(bytes);
61
62 let message = Message::from_bytes_ref(txhash);
63
64 signature
65 .recover(message)
66 .map_err(|_| ValidityError::InputInvalidSignature { index: input_index })
67 .map(|pk| Input::owner(&pk))
68 }
69}
70
71impl From<Vec<u8>> for Witness {
72 fn from(data: Vec<u8>) -> Self {
73 Self { data }
74 }
75}
76
77impl From<&[u8]> for Witness {
78 fn from(data: &[u8]) -> Self {
79 data.to_vec().into()
80 }
81}
82
83impl AsRef<[u8]> for Witness {
84 fn as_ref(&self) -> &[u8] {
85 self.data.as_ref()
86 }
87}
88
89impl AsMut<[u8]> for Witness {
90 fn as_mut(&mut self) -> &mut [u8] {
91 self.data.as_mut()
92 }
93}
94
95impl Extend<u8> for Witness {
96 fn extend<T: IntoIterator<Item = u8>>(&mut self, iter: T) {
97 self.data.extend(iter);
98 }
99}
100
101#[cfg(feature = "random")]
102impl Distribution<Witness> for Standard {
103 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Witness {
104 let len = rng.gen_range(0..512);
105
106 let mut data = alloc::vec![0u8; len];
107 rng.fill_bytes(data.as_mut_slice());
108
109 data.into()
110 }
111}
112
113#[cfg(feature = "typescript")]
114pub mod typescript {
115 use wasm_bindgen::prelude::*;
116
117 use super::Witness;
118
119 use alloc::{
120 format,
121 string::String,
122 vec::Vec,
123 };
124
125 #[wasm_bindgen]
126 impl Witness {
127 #[wasm_bindgen(js_name = toJSON)]
128 pub fn to_json(&self) -> String {
129 serde_json::to_string(&self.data).expect("unable to json format")
130 }
131
132 #[wasm_bindgen(js_name = toString)]
133 pub fn typescript_to_string(&self) -> String {
134 format!("{:?}", self.data)
135 }
136
137 #[wasm_bindgen(js_name = to_bytes)]
138 pub fn typescript_to_bytes(&self) -> Vec<u8> {
139 use fuel_types::canonical::Serialize;
140 self.to_bytes()
141 }
142
143 #[wasm_bindgen(js_name = from_bytes)]
144 pub fn typescript_from_bytes(value: &[u8]) -> Result<Witness, js_sys::Error> {
145 use alloc::string::ToString;
146 use fuel_types::canonical::Deserialize;
147 <Self as Deserialize>::from_bytes(value)
148 .map_err(|e| js_sys::Error::new(&e.to_string()))
149 }
150 }
151}