neo3/neo_builder/transaction/
invocation_script.rs1use std::hash::Hash;
2
3use crate::{
4 builder::{BuilderError, ScriptBuilder},
5 codec::{Decoder, Encoder, NeoSerializable},
6 crypto::{KeyPair, Secp256r1Signature},
7 var_size, OpCode,
8};
9use getset::{Getters, Setters};
10use serde_derive::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash, Getters, Setters, Serialize, Deserialize)]
18pub struct InvocationScript {
19 #[getset(get = "pub", set = "pub")]
21 script: Vec<u8>,
22}
23
24impl InvocationScript {
25 pub fn new() -> Self {
27 Self { script: Vec::new() }
28 }
29
30 pub fn new_with_script(script: Vec<u8>) -> Self {
39 Self { script }
40 }
41
42 pub fn from_serialized_script(script: Vec<u8>) -> Self {
43 let mut decoder = Decoder::new(&script);
44 Self::decode(&mut decoder).unwrap()
45 }
46
47 pub fn from_signature(signature: Secp256r1Signature) -> Self {
57 let mut script = ScriptBuilder::new();
58 let signature_bytes = signature.to_bytes();
59 script.push_data(signature_bytes.to_vec());
60 Self { script: script.to_bytes() }
61 }
62
63 pub fn from_message_and_key_pair(
74 message: Vec<u8>,
75 key_pair: &KeyPair,
76 ) -> Result<Self, BuilderError> {
77 let signature = key_pair.private_key.sign_tx(&message)?;
78 Ok(Self::from_signature(signature))
79 }
80
81 pub fn from_signatures(signatures: &[Secp256r1Signature]) -> Self {
91 let mut builder = ScriptBuilder::new();
92 for signature in signatures {
93 let signature_bytes = signature.to_bytes();
94 builder.push_data(signature_bytes.to_vec());
95 }
96 Self { script: builder.to_bytes() }
97 }
98}
99
100impl InvocationScript {
101 pub fn get_signatures(&self) -> Vec<Secp256r1Signature> {
107 let mut reader = Decoder::new(&self.script);
108 let mut sigs = Vec::new();
109 while reader.available() > 0 && reader.read_u8() == OpCode::PushData1 as u8 {
110 reader.read_u8(); if let Ok(signature) = Secp256r1Signature::from_bytes(&reader.read_bytes(64).unwrap()) {
112 sigs.push(signature);
113 }
114 }
115 sigs
116 }
117}
118
119impl NeoSerializable for InvocationScript {
120 type Error = BuilderError;
121
122 fn size(&self) -> usize {
123 return var_size(self.script.len()) + self.script.len();
124 }
125
126 fn encode(&self, writer: &mut Encoder) {
127 writer.write_var_bytes(&self.script);
128 }
129
130 fn decode(reader: &mut Decoder) -> Result<Self, Self::Error> {
131 let script = reader.read_var_bytes()?;
132 Ok(Self { script })
133 }
134 fn to_array(&self) -> Vec<u8> {
135 let mut writer = Encoder::new();
136 self.encode(&mut writer);
137 writer.to_bytes()
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use crate::neo_crypto::utils::ToHexString;
144
145 use super::*;
146
147 #[test]
148 fn test_from_message_and_key_pair() {
149 let message = vec![0u8; 10];
150 let key_pair = KeyPair::new_random();
151 let script =
152 InvocationScript::from_message_and_key_pair(message.clone(), &key_pair).unwrap();
153 let expected_signature = key_pair.private_key().sign_tx(&message).unwrap();
154 let expected = format!(
155 "{}40{}",
156 OpCode::PushData1.to_hex_string(),
157 hex::encode(expected_signature.to_bytes())
158 );
159 assert_eq!(hex::decode(&expected).unwrap(), script.script);
160 assert_eq!(hex::decode(&format!("42{}", expected)).unwrap(), script.to_array());
161 }
162
163 #[test]
164 fn test_serialize_random_invocation_script() {
165 let message = vec![1; 10];
166 let script = InvocationScript::new_with_script(message.clone());
167 assert_eq!(message, script.script);
168 }
169
170 #[test]
171 fn test_deserialize_custom_invocation_script() {
172 let message = vec![1; 256];
173 let script = format!("{}0001{}", OpCode::PushData2.to_hex_string(), hex::encode(&message));
174 let serialized_script = format!("FD0301{}", script);
175 let deserialized =
176 InvocationScript::from_serialized_script(hex::decode(&serialized_script).unwrap());
177 assert_eq!(deserialized.script, hex::decode(&script).unwrap());
178 }
179
180 #[test]
181 fn test_deserialize_signature_invocation_script() {
182 let message = vec![0u8; 10];
183 let key_pair = KeyPair::new_random();
184 let signature = key_pair.private_key().sign_tx(&message).unwrap();
185 let script =
186 format!("{}40{}", OpCode::PushData1.to_hex_string(), hex::encode(signature.to_bytes()));
187 let deserialized = InvocationScript::from_serialized_script(
188 hex::decode(&format!("42{}", script)).unwrap(),
189 );
190 assert_eq!(deserialized.script, hex::decode(&script).unwrap());
191 }
192
193 #[test]
194 fn test_size() {
195 let script = hex::decode("147e5f3c929dd830d961626551dbea6b70e4b2837ed2fe9089eed2072ab3a655523ae0fa8711eee4769f1913b180b9b3410bbb2cf770f529c85f6886f22cbaaf").unwrap();
196 let s = InvocationScript::new_with_script(script);
197 assert_eq!(s.size(), 65);
198 }
199
200 #[test]
201 fn test_get_signatures() {
202 let message = vec![0u8; 10];
203 let key_pair = KeyPair::new_random();
204 let signature = key_pair.private_key.sign_tx(&message).unwrap();
205 let inv = InvocationScript::from_signatures(&vec![
206 signature.clone(),
207 signature.clone(),
208 signature.clone(),
209 ]);
210 inv.get_signatures().iter().for_each(|sig| assert_eq!(*sig, signature));
211 }
212}