1use hex::FromHexError;
2use serde::{Deserialize, Serialize};
3use serde_json::json;
4use snafu::{Snafu, OptionExt, ensure};
5
6use crate::{
7 AccountName, ActionName, Contract,
8 PermissionName, Name, ABISerializable,
9 abiserializable::to_bin, Bytes, JsonValue,
10 ByteStream, ABIProvider, ABIError, InvalidName,
11 with_location, impl_auto_error_conversion,
12};
13
14extern crate self as kudu;
17
18
19#[derive(Eq, Hash, PartialEq, Debug, Copy, Clone, Default, Deserialize, Serialize, ABISerializable)]
23pub struct PermissionLevel {
24 pub actor: AccountName,
25 pub permission: PermissionName,
26}
27
28pub trait IntoPermissionVec {
29 fn into_permission_vec(self) -> Vec<PermissionLevel>;
30}
31
32impl IntoPermissionVec for Vec<PermissionLevel> {
33 fn into_permission_vec(self) -> Vec<PermissionLevel> {
34 self
35 }
36}
37
38impl IntoPermissionVec for PermissionLevel {
39 fn into_permission_vec(self) -> Vec<PermissionLevel> {
40 vec![self]
41 }
42}
43
44impl IntoPermissionVec for (&str, &str) {
46 fn into_permission_vec(self) -> Vec<PermissionLevel> {
47 vec![PermissionLevel {
48 actor: AccountName::constant(self.0),
49 permission: PermissionName::constant(self.1)
50 }]
51 }
52}
53
54
55#[with_location]
56#[derive(Debug, Snafu)]
57pub enum ActionError {
59 #[snafu(display("Cannot convert action['{field_name}'] to str, actual type: {value:?}"))]
60 FieldType {
61 field_name: String,
62 value: JsonValue,
63 },
64
65 #[snafu(display("Invalid name"))]
66 Name { source: InvalidName },
67
68 #[snafu(display("invalid hex representation"))]
69 FromHex { source: FromHexError },
70
71 #[snafu(display("missing ABIProvider, required to encode action data"))]
72 MissingABIProvider,
73
74 #[snafu(display("could not match JSON object to transaction"))]
75 FromJson { source: serde_json::Error },
76
77 #[snafu(display("ABI error"))]
78 ABI { source: ABIError },
79}
80
81impl_auto_error_conversion!(InvalidName, ActionError, NameSnafu);
82impl_auto_error_conversion!(FromHexError, ActionError, FromHexSnafu);
83impl_auto_error_conversion!(ABIError, ActionError, ABISnafu);
84impl_auto_error_conversion!(serde_json::Error, ActionError, FromJsonSnafu);
85
86
87#[derive(Eq, Hash, PartialEq, Debug, Clone, Default, Deserialize, Serialize, ABISerializable)]
105pub struct Action {
106 pub account: AccountName,
107 pub name: ActionName,
108 pub authorization: Vec<PermissionLevel>,
109 pub data: Bytes,
110}
111
112impl Action {
113 pub fn new<T: Contract>(authorization: impl IntoPermissionVec, contract: &T) -> Action {
114 Action {
115 account: T::account(),
116 name: T::name(),
117 authorization: authorization.into_permission_vec(),
118 data: to_bin(contract)
119 }
120 }
121
122 pub fn conv_action_field_str<'a>(
123 action: &'a JsonValue,
124 field: &str
125 ) -> Result<&'a str, ActionError> {
126 action[field].as_str().with_context(|| FieldTypeSnafu {
127 field_name: field,
128 value: action[field].clone(),
129 })
130 }
131
132 pub fn from_json(abi_provider: Option<&ABIProvider>, action: &JsonValue) -> Result<Action, ActionError> {
133 let account = Action::conv_action_field_str(action, "account")?;
135 let action_name = Action::conv_action_field_str(action, "name")?;
136
137 let authorization: Vec<PermissionLevel> = serde_json::from_str(&action["authorization"].to_string())?;
139
140 let data: Bytes = if action["data"].is_string() {
141 Bytes::from_hex(action["data"].as_str().unwrap())? }
144 else {
145 let data = &action["data"];
147 let mut ds = ByteStream::new();
148 ensure!(abi_provider.is_some(), MissingABIProviderSnafu);
149 let abi = abi_provider.unwrap().get_abi(account)?; abi.encode_variant(&mut ds, action_name, data)?;
151 ds.into()
152 };
153
154 Ok(Action {
155 account: Name::new(account)?,
156 name: Name::new(action_name)?,
157 authorization,
158 data,
159 })
160 }
161
162 pub fn from_json_array(
163 abi_provider: Option<&ABIProvider>,
164 actions: &JsonValue
165 ) -> Result<Vec<Action>, ActionError> {
166 Ok(actions.as_array().unwrap().iter()
167 .map(|v| Action::from_json(abi_provider, v).unwrap())
168 .collect())
169 }
170
171 pub fn decode_data(&self, abi_provider: &ABIProvider) -> JsonValue {
172 let mut ds = ByteStream::from(self.data.clone());
174 let abi = abi_provider.get_abi(&self.account.to_string()).unwrap();
175 abi.decode_variant(&mut ds, &self.name.to_string()).unwrap()
176 }
177
178 pub fn with_data(mut self, abi_provider: &ABIProvider, value: &JsonValue) -> Self {
179 let mut ds = ByteStream::new();
180 let abi = abi_provider.get_abi(&self.account.to_string()).unwrap();
181 abi.encode_variant(&mut ds, &self.name.to_string(), value).unwrap();
182 self.data = ds.into();
183 self
184 }
185
186 pub fn to_json(&self, abi_provider: &ABIProvider) -> JsonValue {
187 json!({
188 "account": self.account.to_string(),
189 "name": self.name.to_string(),
190 "authorization": serde_json::to_value(&self.authorization).unwrap(),
191 "data": self.decode_data(abi_provider),
192 })
193 }
194}