1use super::{ABIDecodable, ABIDecodeError, ABIVariable};
6use cfx_bytes::Bytes;
7use cfx_types::U256;
8use std::{collections::LinkedList, slice::Iter};
9
10pub struct LinkedBytes {
11 length: usize,
12 data: LinkedList<Vec<u8>>,
13}
14
15pub fn padded_big_endian(length: usize) -> Vec<u8> {
16 U256::from(length).to_big_endian().to_vec()
17}
18
19impl LinkedBytes {
20 pub fn new() -> Self {
21 Self {
22 length: 0,
23 data: LinkedList::new(),
24 }
25 }
26
27 pub fn from_bytes(bytes: Vec<u8>) -> Self {
28 let mut answer = Self::new();
29 answer.length = bytes.len();
30 answer.data.push_back(bytes);
31 answer
32 }
33
34 pub fn append(&mut self, other: &mut Self) {
35 self.length += other.length;
36 self.data.append(&mut other.data);
37 other.length = 0;
38 }
39
40 pub fn to_vec(&self) -> Vec<u8> {
41 let mut answer = Vec::new();
42 for slice in &self.data {
43 answer.extend_from_slice(&slice)
44 }
45 answer
46 }
47
48 pub fn len(&self) -> usize { self.length }
49}
50
51pub fn read_abi_list<T: ABIVariable>(
52 data: &[u8], pointer: &mut Iter<u8>,
53) -> Result<T, ABIDecodeError> {
54 let res = if let Some(len) = T::STATIC_LENGTH {
55 pull_slice(pointer, len, "Incomplete static input parameter")?
56 } else {
57 let location = U256::from_big_endian(pull_slice(
58 pointer,
59 32,
60 "Incomplete location for dynamic input parameter",
61 )?);
62 abi_require(
63 location < U256::from(data.len()),
64 "Location out of bounds",
65 )?;
66 let loc = location.as_u64() as usize;
67 &data[loc..]
68 };
69 T::from_abi(res)
70}
71
72pub struct ABIListWriter {
73 heads_length: usize,
74 heads: LinkedBytes,
75 tails: LinkedBytes,
76}
77
78impl ABIListWriter {
79 pub fn with_heads_length(heads_length: usize) -> Self {
80 Self {
81 heads_length,
82 heads: LinkedBytes::new(),
83 tails: LinkedBytes::new(),
84 }
85 }
86
87 pub fn write_down<T: ABIVariable>(&mut self, input: &T) {
88 let mut encoded = input.to_abi();
89 if let Some(len) = T::STATIC_LENGTH {
90 assert_eq!(encoded.len(), len);
91 self.heads.append(&mut encoded);
92 } else {
93 let mut location = LinkedBytes::from_bytes(padded_big_endian(
94 self.tails.len() + self.heads_length,
95 ));
96 self.heads.append(&mut location);
97 self.tails.append(&mut encoded);
98 }
99 }
100
101 pub fn into_linked_bytes(mut self) -> LinkedBytes {
102 assert_eq!(self.heads.len(), self.heads_length);
103 self.heads.append(&mut self.tails);
104 self.heads
105 }
106}
107
108#[inline]
109pub fn abi_require(
110 claim: bool, desc: &'static str,
111) -> Result<(), ABIDecodeError> {
112 if !claim {
113 Err(ABIDecodeError(desc))
114 } else {
115 Ok(())
116 }
117}
118
119#[inline]
120pub fn pull_slice<'a>(
121 iter: &mut Iter<'a, u8>, n: usize, err_desc: &'static str,
122) -> Result<&'a [u8], ABIDecodeError> {
123 abi_require(iter.len() >= n, err_desc)?;
124
125 let slice = iter.as_slice();
126 let result = &slice[0..n];
127 *iter = slice[n..].iter();
128 Ok(result)
129}
130
131pub fn string_revert_reason_decode(output: &Bytes) -> String {
133 const MAX_LENGTH: usize = 50;
134 let decode_result = if output.len() < 4 {
135 Err(ABIDecodeError("Uncompleted Signature"))
136 } else {
137 let (sig, data) = output.split_at(4);
138 if sig != [8, 195, 121, 160] {
139 Err(ABIDecodeError("Unrecognized Signature"))
140 } else {
141 String::abi_decode(data)
142 }
143 };
144 match decode_result {
145 Ok(str) => {
146 if str.chars().count() <= MAX_LENGTH {
147 str
148 } else {
149 let truncated: String = str.chars().take(MAX_LENGTH).collect();
150 format!("{}...", truncated)
151 }
152 }
153 Err(_) => "".to_string(),
154 }
155}
156
157#[cfg(test)]
158mod test {
159 use super::string_revert_reason_decode;
160 use cfx_bytes::Bytes;
161 use rustc_hex::FromHex;
162
163 #[test]
164 fn test_decode_result() {
165 let input_hex = "08c379a0\
166 0000000000000000000000000000000000000000000000000000000000000020\
167 0000000000000000000000000000000000000000000000000000000000000018\
168 5468697320697320616e206572726f72206d6573736167650000000000000000\
169 ";
170 assert_eq!(
171 "This is an error message".to_string(),
172 string_revert_reason_decode(&input_hex.from_hex().unwrap())
173 );
174 }
175
176 #[test]
177 fn test_decode_result_with_utf8_multibyte() {
178 let long_str: String = "测".repeat(60);
180 let data_len = long_str.len();
181 let padded_len = (data_len + 31) / 32 * 32;
182 let mut data = vec![0u8; 32 + 32 + padded_len];
183 data[31] = 0x20;
185 data[63] = data_len as u8;
187 data[64..64 + data_len].copy_from_slice(long_str.as_bytes());
189 let mut output = Bytes::from(vec![8, 195, 121, 160]);
190 output.extend(data);
191 let result = string_revert_reason_decode(&output);
192 assert_eq!(result.len(), 153); assert!(result.ends_with("..."));
195 assert_eq!(result.chars().count(), 53); }
197
198 #[test]
199 fn test_decode_result_short_utf8() {
200 let short_str = "中文测试";
202 let data_len = short_str.len();
203 let padded_len = (data_len + 31) / 32 * 32;
204 let mut data = vec![0u8; 32 + 32 + padded_len];
205 data[31] = 0x20;
207 data[63] = data_len as u8;
209 data[64..64 + data_len].copy_from_slice(short_str.as_bytes());
211 let mut output = Bytes::from(vec![8, 195, 121, 160]);
212 output.extend(data);
213 let result = string_revert_reason_decode(&output);
214 assert_eq!(result, "中文测试");
215 }
216}