1use derive_more::From;
2#[cfg(feature = "serde-conversion")]
3use serde::{Deserialize, Serialize};
4use state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransition;
5use std::collections::BTreeMap;
6use std::ops::RangeInclusive;
7
8pub use abstract_state_transition::state_transition_helpers;
9
10use platform_value::{BinaryData, Identifier};
11pub use state_transition_types::*;
12
13use bincode::{Decode, Encode};
14#[cfg(any(
15 feature = "state-transition-signing",
16 feature = "state-transition-validation"
17))]
18use dashcore::signer;
19#[cfg(feature = "state-transition-validation")]
20use dashcore::signer::double_sha;
21use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable};
22use platform_version::version::{PlatformVersion, ProtocolVersion, ALL_VERSIONS, LATEST_VERSION};
23
24mod abstract_state_transition;
25#[cfg(any(
26 feature = "state-transition-signing",
27 feature = "state-transition-validation"
28))]
29use crate::BlsModule;
30use crate::ProtocolError;
31
32mod state_transition_types;
33
34pub mod state_transition_factory;
35
36pub mod errors;
37#[cfg(feature = "state-transition-signing")]
38use crate::util::hash::ripemd160_sha256;
39use crate::util::hash::{hash_double_to_vec, hash_single};
40
41pub mod proof_result;
42mod serialization;
43pub mod state_transitions;
44mod traits;
45
46#[cfg(feature = "state-transition-validation")]
49use crate::consensus::basic::UnsupportedFeatureError;
50#[cfg(feature = "state-transition-signing")]
51use crate::consensus::signature::InvalidSignaturePublicKeySecurityLevelError;
52#[cfg(feature = "state-transition-validation")]
53use crate::consensus::signature::{
54 InvalidStateTransitionSignatureError, PublicKeyIsDisabledError, SignatureError,
55};
56#[cfg(feature = "state-transition-validation")]
57use crate::consensus::ConsensusError;
58pub use traits::*;
59
60use crate::address_funds::PlatformAddress;
61use crate::data_contract::serialized_version::DataContractInSerializationFormat;
62use crate::fee::Credits;
63#[cfg(any(
64 feature = "state-transition-signing",
65 feature = "state-transition-validation"
66))]
67use crate::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0;
68#[cfg(feature = "state-transition-signing")]
69use crate::identity::signer::Signer;
70use crate::identity::state_transition::OptionallyAssetLockProved;
71use crate::identity::Purpose;
72#[cfg(any(
73 feature = "state-transition-signing",
74 feature = "state-transition-validation"
75))]
76use crate::identity::{IdentityPublicKey, KeyType};
77use crate::identity::{KeyID, SecurityLevel};
78use crate::prelude::{AddressNonce, AssetLockProof, UserFeeIncrease};
79use crate::serialization::{PlatformDeserializable, Signable};
80use crate::state_transition::address_credit_withdrawal_transition::{
81 AddressCreditWithdrawalTransition, AddressCreditWithdrawalTransitionSignable,
82};
83use crate::state_transition::address_funding_from_asset_lock_transition::{
84 AddressFundingFromAssetLockTransition, AddressFundingFromAssetLockTransitionSignable,
85};
86use crate::state_transition::address_funds_transfer_transition::{
87 AddressFundsTransferTransition, AddressFundsTransferTransitionSignable,
88};
89use crate::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0;
90use crate::state_transition::batch_transition::batched_transition::BatchedTransitionRef;
91#[cfg(feature = "state-transition-signing")]
92use crate::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0;
93use crate::state_transition::batch_transition::{BatchTransition, BatchTransitionSignable};
94use crate::state_transition::data_contract_create_transition::accessors::DataContractCreateTransitionAccessorsV0;
95use crate::state_transition::data_contract_create_transition::{
96 DataContractCreateTransition, DataContractCreateTransitionSignable,
97};
98use crate::state_transition::data_contract_update_transition::accessors::DataContractUpdateTransitionAccessorsV0;
99use crate::state_transition::data_contract_update_transition::{
100 DataContractUpdateTransition, DataContractUpdateTransitionSignable,
101};
102#[cfg(feature = "state-transition-signing")]
103use crate::state_transition::errors::InvalidSignaturePublicKeyError;
104#[cfg(all(feature = "state-transitions", feature = "validation"))]
105use crate::state_transition::errors::StateTransitionError::StateTransitionIsNotActiveError;
106#[cfg(feature = "state-transition-signing")]
107use crate::state_transition::errors::WrongPublicKeyPurposeError;
108#[cfg(feature = "state-transition-validation")]
109use crate::state_transition::errors::{
110 InvalidIdentityPublicKeyTypeError, PublicKeyMismatchError, StateTransitionIsNotSignedError,
111};
112use crate::state_transition::identity_create_from_addresses_transition::{
113 IdentityCreateFromAddressesTransition, IdentityCreateFromAddressesTransitionSignable,
114};
115use crate::state_transition::identity_create_transition::{
116 IdentityCreateTransition, IdentityCreateTransitionSignable,
117};
118use crate::state_transition::identity_credit_transfer_to_addresses_transition::{
119 IdentityCreditTransferToAddressesTransition,
120 IdentityCreditTransferToAddressesTransitionSignable,
121};
122use crate::state_transition::identity_credit_transfer_transition::{
123 IdentityCreditTransferTransition, IdentityCreditTransferTransitionSignable,
124};
125use crate::state_transition::identity_credit_withdrawal_transition::{
126 IdentityCreditWithdrawalTransition, IdentityCreditWithdrawalTransitionSignable,
127};
128use crate::state_transition::identity_topup_from_addresses_transition::{
129 IdentityTopUpFromAddressesTransition, IdentityTopUpFromAddressesTransitionSignable,
130};
131use crate::state_transition::identity_topup_transition::{
132 IdentityTopUpTransition, IdentityTopUpTransitionSignable,
133};
134use crate::state_transition::identity_update_transition::{
135 IdentityUpdateTransition, IdentityUpdateTransitionSignable,
136};
137use crate::state_transition::masternode_vote_transition::MasternodeVoteTransition;
138use crate::state_transition::masternode_vote_transition::MasternodeVoteTransitionSignable;
139use crate::state_transition::shield_from_asset_lock_transition::{
140 ShieldFromAssetLockTransition, ShieldFromAssetLockTransitionSignable,
141};
142use crate::state_transition::shield_transition::{ShieldTransition, ShieldTransitionSignable};
143use crate::state_transition::shielded_transfer_transition::{
144 ShieldedTransferTransition, ShieldedTransferTransitionSignable,
145};
146use crate::state_transition::shielded_withdrawal_transition::{
147 ShieldedWithdrawalTransition, ShieldedWithdrawalTransitionSignable,
148};
149#[cfg(feature = "state-transition-signing")]
150use crate::state_transition::state_transitions::document::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0;
151use crate::state_transition::unshield_transition::{
152 UnshieldTransition, UnshieldTransitionSignable,
153};
154use state_transitions::document::batch_transition::batched_transition::token_transition::TokenTransition;
155pub use state_transitions::*;
156
157pub type GetDataContractSecurityLevelRequirementFn =
158 fn(Identifier, String) -> Result<SecurityLevel, ProtocolError>;
159
160macro_rules! call_method {
161 ($state_transition:expr, $method:ident, $args:tt ) => {
162 match $state_transition {
163 StateTransition::DataContractCreate(st) => st.$method($args),
164 StateTransition::DataContractUpdate(st) => st.$method($args),
165 StateTransition::Batch(st) => st.$method($args),
166 StateTransition::IdentityCreate(st) => st.$method($args),
167 StateTransition::IdentityTopUp(st) => st.$method($args),
168 StateTransition::IdentityCreditWithdrawal(st) => st.$method($args),
169 StateTransition::IdentityUpdate(st) => st.$method($args),
170 StateTransition::IdentityCreditTransfer(st) => st.$method($args),
171 StateTransition::MasternodeVote(st) => st.$method($args),
172 StateTransition::IdentityCreditTransferToAddresses(st) => st.$method($args),
173 StateTransition::IdentityCreateFromAddresses(st) => st.$method($args),
174 StateTransition::IdentityTopUpFromAddresses(st) => st.$method($args),
175 StateTransition::AddressFundsTransfer(st) => st.$method($args),
176 StateTransition::AddressFundingFromAssetLock(st) => st.$method($args),
177 StateTransition::AddressCreditWithdrawal(st) => st.$method($args),
178 StateTransition::Shield(st) => st.$method($args),
179 StateTransition::ShieldedTransfer(st) => st.$method($args),
180 StateTransition::Unshield(st) => st.$method($args),
181 StateTransition::ShieldFromAssetLock(st) => st.$method($args),
182 StateTransition::ShieldedWithdrawal(st) => st.$method($args),
183 }
184 };
185 ($state_transition:expr, $method:ident ) => {
186 match $state_transition {
187 StateTransition::DataContractCreate(st) => st.$method(),
188 StateTransition::DataContractUpdate(st) => st.$method(),
189 StateTransition::Batch(st) => st.$method(),
190 StateTransition::IdentityCreate(st) => st.$method(),
191 StateTransition::IdentityTopUp(st) => st.$method(),
192 StateTransition::IdentityCreditWithdrawal(st) => st.$method(),
193 StateTransition::IdentityUpdate(st) => st.$method(),
194 StateTransition::IdentityCreditTransfer(st) => st.$method(),
195 StateTransition::MasternodeVote(st) => st.$method(),
196 StateTransition::IdentityCreditTransferToAddresses(st) => st.$method(),
197 StateTransition::IdentityCreateFromAddresses(st) => st.$method(),
198 StateTransition::IdentityTopUpFromAddresses(st) => st.$method(),
199 StateTransition::AddressFundsTransfer(st) => st.$method(),
200 StateTransition::AddressFundingFromAssetLock(st) => st.$method(),
201 StateTransition::AddressCreditWithdrawal(st) => st.$method(),
202 StateTransition::Shield(st) => st.$method(),
203 StateTransition::ShieldedTransfer(st) => st.$method(),
204 StateTransition::Unshield(st) => st.$method(),
205 StateTransition::ShieldFromAssetLock(st) => st.$method(),
206 StateTransition::ShieldedWithdrawal(st) => st.$method(),
207 }
208 };
209}
210
211macro_rules! call_getter_method_identity_signed {
212 ($state_transition:expr, $method:ident, $args:tt ) => {
213 match $state_transition {
214 StateTransition::DataContractCreate(st) => Some(st.$method($args)),
215 StateTransition::DataContractUpdate(st) => Some(st.$method($args)),
216 StateTransition::Batch(st) => Some(st.$method($args)),
217 StateTransition::IdentityCreate(_) => None,
218 StateTransition::IdentityTopUp(_) => None,
219 StateTransition::IdentityCreditWithdrawal(st) => Some(st.$method($args)),
220 StateTransition::IdentityUpdate(st) => Some(st.$method($args)),
221 StateTransition::IdentityCreditTransfer(st) => Some(st.$method($args)),
222 StateTransition::MasternodeVote(st) => Some(st.$method($args)),
223 StateTransition::IdentityCreditTransferToAddresses(st) => Some(st.$method($args)),
224 StateTransition::IdentityCreateFromAddresses(_) => None,
225 StateTransition::IdentityTopUpFromAddresses(_) => None,
226 StateTransition::AddressFundsTransfer(_) => None,
227 StateTransition::AddressFundingFromAssetLock(_) => None,
228 StateTransition::AddressCreditWithdrawal(_) => None,
229 StateTransition::Shield(_) => None,
230 StateTransition::ShieldedTransfer(_) => None,
231 StateTransition::Unshield(_) => None,
232 StateTransition::ShieldFromAssetLock(_) => None,
233 StateTransition::ShieldedWithdrawal(_) => None,
234 }
235 };
236 ($state_transition:expr, $method:ident ) => {
237 match $state_transition {
238 StateTransition::DataContractCreate(st) => Some(st.$method()),
239 StateTransition::DataContractUpdate(st) => Some(st.$method()),
240 StateTransition::Batch(st) => Some(st.$method()),
241 StateTransition::IdentityCreate(_) => None,
242 StateTransition::IdentityTopUp(_) => None,
243 StateTransition::IdentityCreditWithdrawal(st) => Some(st.$method()),
244 StateTransition::IdentityUpdate(st) => Some(st.$method()),
245 StateTransition::IdentityCreditTransfer(st) => Some(st.$method()),
246 StateTransition::MasternodeVote(st) => Some(st.$method()),
247 StateTransition::IdentityCreditTransferToAddresses(st) => Some(st.$method()),
248 StateTransition::IdentityCreateFromAddresses(_) => None,
249 StateTransition::IdentityTopUpFromAddresses(_) => None,
250 StateTransition::AddressFundsTransfer(_) => None,
251 StateTransition::AddressFundingFromAssetLock(_) => None,
252 StateTransition::AddressCreditWithdrawal(_) => None,
253 StateTransition::Shield(_) => None,
254 StateTransition::ShieldedTransfer(_) => None,
255 StateTransition::Unshield(_) => None,
256 StateTransition::ShieldFromAssetLock(_) => None,
257 StateTransition::ShieldedWithdrawal(_) => None,
258 }
259 };
260}
261
262macro_rules! call_method_identity_signed {
263 ($state_transition:expr, $method:ident, $args:tt ) => {
264 match $state_transition {
265 StateTransition::DataContractCreate(st) => st.$method($args),
266 StateTransition::DataContractUpdate(st) => st.$method($args),
267 StateTransition::Batch(st) => st.$method($args),
268 StateTransition::IdentityCreate(_st) => {}
269 StateTransition::IdentityTopUp(_st) => {}
270 StateTransition::IdentityCreditWithdrawal(st) => st.$method($args),
271 StateTransition::IdentityUpdate(st) => st.$method($args),
272 StateTransition::IdentityCreditTransfer(st) => st.$method($args),
273 StateTransition::MasternodeVote(st) => st.$method($args),
274 StateTransition::IdentityCreditTransferToAddresses(st) => st.$method($args),
275 StateTransition::IdentityCreateFromAddresses(_) => {}
276 StateTransition::IdentityTopUpFromAddresses(_) => {}
277 StateTransition::AddressFundsTransfer(_) => {}
278 StateTransition::AddressFundingFromAssetLock(_) => {}
279 StateTransition::AddressCreditWithdrawal(_) => {}
280 StateTransition::Shield(_) => {}
281 StateTransition::ShieldedTransfer(_) => {}
282 StateTransition::Unshield(_) => {}
283 StateTransition::ShieldFromAssetLock(_) => {}
284 StateTransition::ShieldedWithdrawal(_) => {}
285 }
286 };
287 ($state_transition:expr, $method:ident ) => {
288 match $state_transition {
289 StateTransition::DataContractCreate(st) => st.$method(),
290 StateTransition::DataContractUpdate(st) => st.$method(),
291 StateTransition::Batch(st) => st.$method(),
292 StateTransition::IdentityCreate(st) => {}
293 StateTransition::IdentityTopUp(st) => {}
294 StateTransition::IdentityCreditWithdrawal(st) => st.$method(),
295 StateTransition::IdentityUpdate(st) => st.$method(),
296 StateTransition::IdentityCreditTransfer(st) => st.$method(),
297 StateTransition::MasternodeVote(st) => st.$method(),
298 StateTransition::IdentityCreditTransferToAddresses(st) => st.$method(),
299 StateTransition::IdentityCreateFromAddresses(_) => {}
300 StateTransition::IdentityTopUpFromAddresses(_) => {}
301 StateTransition::AddressFundsTransfer(_) => {}
302 StateTransition::AddressFundingFromAssetLock(_) => {}
303 StateTransition::AddressCreditWithdrawal(_) => {}
304 StateTransition::Shield(_) => {}
305 StateTransition::ShieldedTransfer(_) => {}
306 StateTransition::Unshield(_) => {}
307 StateTransition::ShieldFromAssetLock(_) => {}
308 StateTransition::ShieldedWithdrawal(_) => {}
309 }
310 };
311}
312
313#[cfg(feature = "state-transition-signing")]
314macro_rules! call_errorable_method_identity_signed {
315 ($state_transition:expr, $method:ident, $( $arg:expr ),* ) => {
316 match $state_transition {
317 StateTransition::DataContractCreate(st) => st.$method($( $arg ),*),
318 StateTransition::DataContractUpdate(st) => st.$method($( $arg ),*),
319 StateTransition::Batch(st) => st.$method($( $arg ),*),
320 StateTransition::IdentityCreate(_) => Err(ProtocolError::CorruptedCodeExecution(
321 "identity create can not be called for identity signing".to_string(),
322 )),
323 StateTransition::IdentityTopUp(_) => Err(ProtocolError::CorruptedCodeExecution(
324 "identity top up can not be called for identity signing".to_string(),
325 )),
326 StateTransition::IdentityCreditWithdrawal(st) => st.$method($( $arg ),*),
327 StateTransition::IdentityUpdate(st) => st.$method($( $arg ),*),
328 StateTransition::IdentityCreditTransfer(st) => st.$method($( $arg ),*),
329 StateTransition::MasternodeVote(st) => st.$method($( $arg ),*),
330 StateTransition::IdentityCreditTransferToAddresses(st) => st.$method($( $arg ),*),
331 StateTransition::IdentityCreateFromAddresses(_) => Err(ProtocolError::CorruptedCodeExecution(
332 "identity create from addresses can not be called for identity signing".to_string(),
333 )),
334 StateTransition::IdentityTopUpFromAddresses(_) => Err(ProtocolError::CorruptedCodeExecution(
335 "identity top up from addresses can not be called for identity signing".to_string(),
336 )),
337 StateTransition::AddressFundsTransfer(_) => Err(ProtocolError::CorruptedCodeExecution(
338 "address funds transfer can not be called for identity signing".to_string(),
339 )),
340 StateTransition::AddressFundingFromAssetLock(_) => Err(ProtocolError::CorruptedCodeExecution(
341 "address funding from asset lock can not be called for identity signing".to_string(),
342 )),
343 StateTransition::AddressCreditWithdrawal(_) => Err(ProtocolError::CorruptedCodeExecution(
344 "address credit withdrawal can not be called for identity signing".to_string(),
345 )),
346 StateTransition::Shield(_) => Err(ProtocolError::CorruptedCodeExecution(
347 "shield transition can not be called for identity signing".to_string(),
348 )),
349 StateTransition::ShieldedTransfer(_) => Err(ProtocolError::CorruptedCodeExecution(
350 "shielded transfer transition can not be called for identity signing".to_string(),
351 )),
352 StateTransition::Unshield(_) => Err(ProtocolError::CorruptedCodeExecution(
353 "unshield transition can not be called for identity signing".to_string(),
354 )),
355 StateTransition::ShieldFromAssetLock(_) => Err(ProtocolError::CorruptedCodeExecution(
356 "shield from asset lock transition can not be called for identity signing".to_string(),
357 )),
358 StateTransition::ShieldedWithdrawal(_) => Err(ProtocolError::CorruptedCodeExecution(
359 "shielded withdrawal transition can not be called for identity signing".to_string(),
360 )),
361 }
362 };
363 ($state_transition:expr, $method:ident) => {
364 match $state_transition {
365 StateTransition::DataContractCreate(st) => st.$method(),
366 StateTransition::DataContractUpdate(st) => st.$method(),
367 StateTransition::Batch(st) => st.$method(),
368 StateTransition::IdentityCreate(_) => Err(ProtocolError::CorruptedCodeExecution(
369 "identity create can not be called for identity signing".to_string(),
370 )),
371 StateTransition::IdentityTopUp(_) => Err(ProtocolError::CorruptedCodeExecution(
372 "identity top up can not be called for identity signing".to_string(),
373 )),
374 StateTransition::IdentityCreditWithdrawal(st) => st.$method(),
375 StateTransition::IdentityUpdate(st) => st.$method(),
376 StateTransition::IdentityCreditTransfer(st) => st.$method(),
377 StateTransition::MasternodeVote(st) => st.$method(),
378 StateTransition::IdentityCreditTransferToAddresses(st) => st.$method(),
379 StateTransition::IdentityCreateFromAddresses(st) => Err(ProtocolError::CorruptedCodeExecution(
380 "identity create from addresses can not be called for identity signing".to_string(),
381 )),
382 StateTransition::IdentityTopUpFromAddresses(_) => Err(ProtocolError::CorruptedCodeExecution(
383 "identity top up from addresses can not be called for identity signing".to_string(),
384 )),
385 StateTransition::AddressFundsTransfer(_) => Err(ProtocolError::CorruptedCodeExecution(
386 "address funds transfer can not be called for identity signing".to_string(),
387 )),
388 StateTransition::AddressFundingFromAssetLock(_) => Err(ProtocolError::CorruptedCodeExecution(
389 "address funding from asset lock can not be called for identity signing".to_string(),
390 )),
391 StateTransition::AddressCreditWithdrawal(_) => Err(ProtocolError::CorruptedCodeExecution(
392 "address credit withdrawal can not be called for identity signing".to_string(),
393 )),
394 StateTransition::Shield(_) => Err(ProtocolError::CorruptedCodeExecution(
395 "shield transition can not be called for identity signing".to_string(),
396 )),
397 StateTransition::ShieldedTransfer(_) => Err(ProtocolError::CorruptedCodeExecution(
398 "shielded transfer transition can not be called for identity signing".to_string(),
399 )),
400 StateTransition::Unshield(_) => Err(ProtocolError::CorruptedCodeExecution(
401 "unshield transition can not be called for identity signing".to_string(),
402 )),
403 StateTransition::ShieldFromAssetLock(_) => Err(ProtocolError::CorruptedCodeExecution(
404 "shield from asset lock transition can not be called for identity signing".to_string(),
405 )),
406 StateTransition::ShieldedWithdrawal(_) => Err(ProtocolError::CorruptedCodeExecution(
407 "shielded withdrawal transition can not be called for identity signing".to_string(),
408 )),
409 }
410 };
411}
412
413#[derive(
414 Debug,
415 Clone,
416 Encode,
417 Decode,
418 PlatformSerialize,
419 PlatformDeserialize,
420 PlatformSignable,
421 From,
422 PartialEq,
423)]
424#[cfg_attr(
425 feature = "serde-conversion",
426 derive(Serialize, Deserialize),
427 serde(untagged)
428)]
429#[platform_serialize(unversioned)] #[platform_serialize(limit = 100000)]
431pub enum StateTransition {
432 DataContractCreate(DataContractCreateTransition),
433 DataContractUpdate(DataContractUpdateTransition),
434 Batch(BatchTransition),
435 IdentityCreate(IdentityCreateTransition),
436 IdentityTopUp(IdentityTopUpTransition),
437 IdentityCreditWithdrawal(IdentityCreditWithdrawalTransition),
438 IdentityUpdate(IdentityUpdateTransition),
439 IdentityCreditTransfer(IdentityCreditTransferTransition),
440 MasternodeVote(MasternodeVoteTransition),
441 IdentityCreditTransferToAddresses(IdentityCreditTransferToAddressesTransition),
442 IdentityCreateFromAddresses(IdentityCreateFromAddressesTransition),
443 IdentityTopUpFromAddresses(IdentityTopUpFromAddressesTransition),
444 AddressFundsTransfer(AddressFundsTransferTransition),
445 AddressFundingFromAssetLock(AddressFundingFromAssetLockTransition),
446 AddressCreditWithdrawal(AddressCreditWithdrawalTransition),
447 Shield(ShieldTransition),
448 ShieldedTransfer(ShieldedTransferTransition),
449 Unshield(UnshieldTransition),
450 ShieldFromAssetLock(ShieldFromAssetLockTransition),
451 ShieldedWithdrawal(ShieldedWithdrawalTransition),
452}
453
454impl OptionallyAssetLockProved for StateTransition {
455 fn optional_asset_lock_proof(&self) -> Option<&AssetLockProof> {
456 match self {
457 StateTransition::IdentityCreate(st) => st.optional_asset_lock_proof(),
458 StateTransition::IdentityTopUp(st) => st.optional_asset_lock_proof(),
459 StateTransition::ShieldFromAssetLock(st) => st.optional_asset_lock_proof(),
460 _ => None,
461 }
462 }
463}
464
465#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
467pub struct StateTransitionSigningOptions {
468 pub allow_signing_with_any_security_level: bool,
470 pub allow_signing_with_any_purpose: bool,
472}
473
474impl StateTransition {
475 #[allow(unused_variables)]
476 pub fn deserialize_from_bytes_in_version(
477 bytes: &[u8],
478 platform_version: &PlatformVersion,
479 ) -> Result<Self, ProtocolError> {
480 let state_transition = StateTransition::deserialize_from_bytes(bytes)?;
481 #[cfg(all(feature = "state-transitions", feature = "validation"))]
482 {
483 let active_version_range = state_transition.active_version_range();
484
485 if active_version_range.contains(&platform_version.protocol_version)
488 || platform_version.protocol_version > 268435456
489 {
490 Ok(state_transition)
491 } else {
492 Err(ProtocolError::StateTransitionError(
493 StateTransitionIsNotActiveError {
494 state_transition_type: state_transition.name(),
495 active_version_range,
496 current_protocol_version: platform_version.protocol_version,
497 },
498 ))
499 }
500 }
501 #[cfg(not(all(feature = "state-transitions", feature = "validation")))]
502 Ok(state_transition)
503 }
504
505 pub fn active_version_range(&self) -> RangeInclusive<ProtocolVersion> {
506 match self {
507 StateTransition::DataContractCreate(data_contract_create_transition) => {
508 match data_contract_create_transition.data_contract() {
509 DataContractInSerializationFormat::V0(_) => ALL_VERSIONS,
510 DataContractInSerializationFormat::V1(_) => 9..=LATEST_VERSION,
511 }
512 }
513 StateTransition::DataContractUpdate(data_contract_update_transition) => {
514 match data_contract_update_transition.data_contract() {
515 DataContractInSerializationFormat::V0(_) => ALL_VERSIONS,
516 DataContractInSerializationFormat::V1(_) => 9..=LATEST_VERSION,
517 }
518 }
519 StateTransition::Batch(batch_transition) => match batch_transition {
520 BatchTransition::V0(_) => ALL_VERSIONS,
521 BatchTransition::V1(_) => 9..=LATEST_VERSION,
522 },
523 StateTransition::IdentityCreate(_)
524 | StateTransition::IdentityTopUp(_)
525 | StateTransition::IdentityCreditWithdrawal(_)
526 | StateTransition::IdentityUpdate(_)
527 | StateTransition::IdentityCreditTransfer(_)
528 | StateTransition::MasternodeVote(_) => ALL_VERSIONS,
529 StateTransition::IdentityCreditTransferToAddresses(_)
530 | StateTransition::IdentityCreateFromAddresses(_)
531 | StateTransition::IdentityTopUpFromAddresses(_)
532 | StateTransition::AddressFundsTransfer(_)
533 | StateTransition::AddressFundingFromAssetLock(_)
534 | StateTransition::AddressCreditWithdrawal(_) => 11..=LATEST_VERSION,
535 StateTransition::Shield(_)
536 | StateTransition::ShieldedTransfer(_)
537 | StateTransition::Unshield(_)
538 | StateTransition::ShieldFromAssetLock(_)
539 | StateTransition::ShieldedWithdrawal(_) => 12..=LATEST_VERSION,
540 }
541 }
542
543 pub fn is_identity_signed(&self) -> bool {
544 !matches!(
545 self,
546 StateTransition::IdentityCreate(_)
547 | StateTransition::IdentityTopUp(_)
548 | StateTransition::Shield(_)
549 | StateTransition::ShieldedTransfer(_)
550 | StateTransition::Unshield(_)
551 | StateTransition::ShieldFromAssetLock(_)
552 | StateTransition::ShieldedWithdrawal(_)
553 )
554 }
555
556 pub fn required_asset_lock_balance_for_processing_start(
557 &self,
558 platform_version: &PlatformVersion,
559 ) -> Result<Credits, ProtocolError> {
560 match self {
561 StateTransition::IdentityCreate(st) => {
562 st.calculate_min_required_fee(platform_version)
563 }
564 StateTransition::IdentityTopUp(st) => {
565 st.calculate_min_required_fee(platform_version)
566 }
567 StateTransition::AddressFundingFromAssetLock(st) => {
568 st.calculate_min_required_fee(platform_version)
569 }
570 StateTransition::ShieldFromAssetLock(st) => {
571 st.calculate_min_required_fee(platform_version)
572 }
573 st => Err(ProtocolError::CorruptedCodeExecution(format!("{} is not an asset lock transaction, but we are calling required_asset_lock_balance_for_processing_start", st.name()))),
574 }
575 }
576
577 fn hash(&self, skip_signature: bool) -> Result<Vec<u8>, ProtocolError> {
578 if skip_signature {
579 Ok(hash_double_to_vec(self.signable_bytes()?))
580 } else {
581 Ok(hash_double_to_vec(
582 crate::serialization::PlatformSerializable::serialize_to_bytes(self)?,
583 ))
584 }
585 }
586
587 pub fn name(&self) -> String {
589 match self {
590 Self::DataContractCreate(_) => "DataContractCreate".to_string(),
591 Self::DataContractUpdate(_) => "DataContractUpdate".to_string(),
592 Self::Batch(batch_transition) => {
593 let mut document_transition_types = vec![];
594 for transition in batch_transition.transitions_iter() {
595 let document_transition_name = match transition {
596 BatchedTransitionRef::Document(DocumentTransition::Create(_)) => "Create",
597 BatchedTransitionRef::Document(DocumentTransition::Replace(_)) => "Replace",
598 BatchedTransitionRef::Document(DocumentTransition::Delete(_)) => "Delete",
599 BatchedTransitionRef::Document(DocumentTransition::Transfer(_)) => {
600 "Transfer"
601 }
602 BatchedTransitionRef::Document(DocumentTransition::UpdatePrice(_)) => {
603 "UpdatePrice"
604 }
605 BatchedTransitionRef::Document(DocumentTransition::Purchase(_)) => {
606 "Purchase"
607 }
608 BatchedTransitionRef::Token(TokenTransition::Transfer(_)) => {
609 "TokenTransfer"
610 }
611 BatchedTransitionRef::Token(TokenTransition::Mint(_)) => "TokenMint",
612 BatchedTransitionRef::Token(TokenTransition::Burn(_)) => "TokenBurn",
613 BatchedTransitionRef::Token(TokenTransition::Freeze(_)) => "TokenFreeze",
614 BatchedTransitionRef::Token(TokenTransition::Unfreeze(_)) => {
615 "TokenUnfreeze"
616 }
617 BatchedTransitionRef::Token(TokenTransition::DestroyFrozenFunds(_)) => {
618 "TokenDestroyFrozenFunds"
619 }
620 BatchedTransitionRef::Token(TokenTransition::EmergencyAction(_)) => {
621 "TokenEmergencyAction"
622 }
623 BatchedTransitionRef::Token(TokenTransition::ConfigUpdate(_)) => {
624 "TokenConfigUpdate"
625 }
626 BatchedTransitionRef::Token(TokenTransition::Claim(_)) => "TokenClaim",
627 BatchedTransitionRef::Token(TokenTransition::DirectPurchase(_)) => {
628 "TokenDirectPurchase"
629 }
630 BatchedTransitionRef::Token(
631 TokenTransition::SetPriceForDirectPurchase(_),
632 ) => "SetPriceForDirectPurchase",
633 };
634 document_transition_types.push(document_transition_name);
635 }
636 format!("DocumentsBatch([{}])", document_transition_types.join(", "))
637 }
638 Self::IdentityCreate(_) => "IdentityCreate".to_string(),
639 Self::IdentityTopUp(_) => "IdentityTopUp".to_string(),
640 Self::IdentityCreditWithdrawal(_) => "IdentityCreditWithdrawal".to_string(),
641 Self::IdentityUpdate(_) => "IdentityUpdate".to_string(),
642 Self::IdentityCreditTransfer(_) => "IdentityCreditTransfer".to_string(),
643 Self::MasternodeVote(_) => "MasternodeVote".to_string(),
644 Self::IdentityCreditTransferToAddresses(_) => {
645 "IdentityCreditTransferToAddresses".to_string()
646 }
647 Self::IdentityCreateFromAddresses(_) => "IdentityCreateFromAddresses".to_string(),
648 Self::IdentityTopUpFromAddresses(_) => "IdentityTopUpFromAddresses".to_string(),
649 Self::AddressFundsTransfer(_) => "AddressFundsTransfer".to_string(),
650 Self::AddressFundingFromAssetLock(_) => "AddressFundingFromAssetLock".to_string(),
651 Self::AddressCreditWithdrawal(_) => "AddressCreditWithdrawal".to_string(),
652 Self::Shield(_) => "Shield".to_string(),
653 Self::ShieldedTransfer(_) => "ShieldedTransfer".to_string(),
654 Self::Unshield(_) => "Unshield".to_string(),
655 Self::ShieldFromAssetLock(_) => "ShieldFromAssetLock".to_string(),
656 Self::ShieldedWithdrawal(_) => "ShieldedWithdrawal".to_string(),
657 }
658 }
659
660 pub fn signature(&self) -> Option<&BinaryData> {
662 match self {
663 StateTransition::DataContractCreate(st) => Some(st.signature()),
664 StateTransition::DataContractUpdate(st) => Some(st.signature()),
665 StateTransition::Batch(st) => Some(st.signature()),
666 StateTransition::IdentityCreate(st) => Some(st.signature()),
667 StateTransition::IdentityTopUp(st) => Some(st.signature()),
668 StateTransition::IdentityCreditWithdrawal(st) => Some(st.signature()),
669 StateTransition::IdentityUpdate(st) => Some(st.signature()),
670 StateTransition::IdentityCreditTransfer(st) => Some(st.signature()),
671 StateTransition::MasternodeVote(st) => Some(st.signature()),
672 StateTransition::IdentityCreditTransferToAddresses(st) => Some(st.signature()),
673 StateTransition::IdentityCreateFromAddresses(_) => None,
674 StateTransition::IdentityTopUpFromAddresses(_) => None,
675 StateTransition::AddressFundsTransfer(_) => None,
676 StateTransition::AddressFundingFromAssetLock(st) => Some(st.signature()),
677 StateTransition::AddressCreditWithdrawal(_) => None,
678 StateTransition::Shield(_) => None,
679 StateTransition::ShieldedTransfer(_) => None,
680 StateTransition::Unshield(_) => None,
681 StateTransition::ShieldFromAssetLock(st) => Some(st.signature()),
682 StateTransition::ShieldedWithdrawal(_) => None,
683 }
684 }
685
686 pub fn required_number_of_private_keys(&self) -> u16 {
688 match self {
689 StateTransition::IdentityCreateFromAddresses(st) => st.inputs().len() as u16,
690 StateTransition::IdentityTopUpFromAddresses(st) => st.inputs().len() as u16,
691 StateTransition::AddressFundsTransfer(st) => st.inputs().len() as u16,
692 StateTransition::AddressCreditWithdrawal(st) => st.inputs().len() as u16,
693 StateTransition::Shield(st) => st.inputs().len() as u16,
694 StateTransition::ShieldedTransfer(_) => 0,
695 StateTransition::Unshield(_) => 0,
696 StateTransition::ShieldFromAssetLock(_) => 0,
697 StateTransition::ShieldedWithdrawal(_) => 0,
698 _ => 1,
699 }
700 }
701
702 pub fn user_fee_increase(&self) -> UserFeeIncrease {
704 match self {
705 StateTransition::DataContractCreate(st) => st.user_fee_increase(),
706 StateTransition::DataContractUpdate(st) => st.user_fee_increase(),
707 StateTransition::Batch(st) => st.user_fee_increase(),
708 StateTransition::IdentityCreate(st) => st.user_fee_increase(),
709 StateTransition::IdentityTopUp(st) => st.user_fee_increase(),
710 StateTransition::IdentityCreditWithdrawal(st) => st.user_fee_increase(),
711 StateTransition::IdentityUpdate(st) => st.user_fee_increase(),
712 StateTransition::IdentityCreditTransfer(st) => st.user_fee_increase(),
713 StateTransition::IdentityCreditTransferToAddresses(st) => st.user_fee_increase(),
714 StateTransition::IdentityCreateFromAddresses(st) => st.user_fee_increase(),
715 StateTransition::IdentityTopUpFromAddresses(st) => st.user_fee_increase(),
716 StateTransition::AddressFundsTransfer(st) => st.user_fee_increase(),
717 StateTransition::AddressFundingFromAssetLock(st) => st.user_fee_increase(),
718 StateTransition::AddressCreditWithdrawal(st) => st.user_fee_increase(),
719 StateTransition::Shield(st) => st.user_fee_increase(),
720 StateTransition::ShieldFromAssetLock(_) => 0,
722 StateTransition::MasternodeVote(_) => 0,
723 StateTransition::ShieldedTransfer(_) => 0,
724 StateTransition::Unshield(_) => 0,
725 StateTransition::ShieldedWithdrawal(_) => 0,
726 }
727 }
728
729 fn calculate_estimated_fee(
742 &self,
743 platform_version: &PlatformVersion,
744 ) -> Result<Credits, ProtocolError> {
745 call_method!(self, calculate_min_required_fee, platform_version)
746 }
747
748 pub fn transaction_id(&self) -> Result<[u8; 32], ProtocolError> {
750 Ok(hash_single(
751 crate::serialization::PlatformSerializable::serialize_to_bytes(self)?,
752 ))
753 }
754
755 pub fn signature_public_key_id(&self) -> Option<KeyID> {
757 call_getter_method_identity_signed!(self, signature_public_key_id)
758 }
759
760 pub fn security_level_requirement(&self, purpose: Purpose) -> Option<Vec<SecurityLevel>> {
762 call_getter_method_identity_signed!(self, security_level_requirement, purpose)
763 }
764
765 pub fn purpose_requirement(&self) -> Option<Vec<Purpose>> {
767 call_getter_method_identity_signed!(self, purpose_requirement)
768 }
769
770 pub fn owner_id(&self) -> Option<Identifier> {
772 match self {
773 StateTransition::DataContractCreate(st) => Some(st.owner_id()),
774 StateTransition::DataContractUpdate(st) => Some(st.owner_id()),
775 StateTransition::Batch(st) => Some(st.owner_id()),
776 StateTransition::IdentityCreate(st) => Some(st.owner_id()),
777 StateTransition::IdentityTopUp(st) => Some(st.owner_id()),
778 StateTransition::IdentityCreditWithdrawal(st) => Some(st.owner_id()),
779 StateTransition::IdentityUpdate(st) => Some(st.owner_id()),
780 StateTransition::IdentityCreditTransfer(st) => Some(st.owner_id()),
781 StateTransition::MasternodeVote(st) => Some(st.owner_id()),
782 StateTransition::IdentityCreditTransferToAddresses(st) => Some(st.owner_id()),
783 StateTransition::IdentityCreateFromAddresses(_) => None,
784 StateTransition::IdentityTopUpFromAddresses(_) => None,
785 StateTransition::AddressFundsTransfer(_) => None,
786 StateTransition::AddressFundingFromAssetLock(_) => None,
787 StateTransition::AddressCreditWithdrawal(_) => None,
788 StateTransition::Shield(_) => None,
789 StateTransition::ShieldedTransfer(_) => None,
790 StateTransition::Unshield(_) => None,
791 StateTransition::ShieldFromAssetLock(_) => None,
792 StateTransition::ShieldedWithdrawal(_) => None,
793 }
794 }
795
796 pub fn inputs(&self) -> Option<&BTreeMap<PlatformAddress, (AddressNonce, Credits)>> {
798 match self {
799 StateTransition::DataContractCreate(_)
800 | StateTransition::DataContractUpdate(_)
801 | StateTransition::Batch(_)
802 | StateTransition::IdentityCreate(_)
803 | StateTransition::IdentityTopUp(_)
804 | StateTransition::IdentityCreditWithdrawal(_)
805 | StateTransition::IdentityUpdate(_)
806 | StateTransition::IdentityCreditTransfer(_)
807 | StateTransition::MasternodeVote(_)
808 | StateTransition::IdentityCreditTransferToAddresses(_) => None,
809 StateTransition::IdentityCreateFromAddresses(st) => Some(st.inputs()),
810 StateTransition::IdentityTopUpFromAddresses(st) => Some(st.inputs()),
811 StateTransition::AddressFundsTransfer(st) => Some(st.inputs()),
812 StateTransition::AddressFundingFromAssetLock(st) => Some(st.inputs()),
813 StateTransition::AddressCreditWithdrawal(st) => Some(st.inputs()),
814 StateTransition::Shield(st) => Some(st.inputs()),
815 StateTransition::ShieldedTransfer(_) => None,
816 StateTransition::Unshield(_) => None,
817 StateTransition::ShieldFromAssetLock(_) => None,
818 StateTransition::ShieldedWithdrawal(_) => None,
819 }
820 }
821
822 pub fn state_transition_type(&self) -> StateTransitionType {
824 call_method!(self, state_transition_type)
825 }
826
827 pub fn unique_identifiers(&self) -> Vec<String> {
829 call_method!(self, unique_identifiers)
830 }
831
832 pub fn set_signature(&mut self, signature: BinaryData) -> bool {
834 match self {
835 StateTransition::DataContractCreate(st) => {
836 st.set_signature(signature);
837 true
838 }
839 StateTransition::DataContractUpdate(st) => {
840 st.set_signature(signature);
841 true
842 }
843 StateTransition::Batch(st) => {
844 st.set_signature(signature);
845 true
846 }
847 StateTransition::IdentityCreate(st) => {
848 st.set_signature(signature);
849 true
850 }
851 StateTransition::IdentityTopUp(st) => {
852 st.set_signature(signature);
853 true
854 }
855 StateTransition::IdentityCreditWithdrawal(st) => {
856 st.set_signature(signature);
857 true
858 }
859 StateTransition::IdentityUpdate(st) => {
860 st.set_signature(signature);
861 true
862 }
863 StateTransition::IdentityCreditTransfer(st) => {
864 st.set_signature(signature);
865 true
866 }
867 StateTransition::MasternodeVote(st) => {
868 st.set_signature(signature);
869 true
870 }
871 StateTransition::IdentityCreditTransferToAddresses(st) => {
872 st.set_signature(signature);
873 true
874 }
875 StateTransition::IdentityCreateFromAddresses(_)
876 | StateTransition::IdentityTopUpFromAddresses(_)
877 | StateTransition::AddressFundsTransfer(_)
878 | StateTransition::Shield(_)
879 | StateTransition::ShieldedTransfer(_)
880 | StateTransition::Unshield(_)
881 | StateTransition::ShieldedWithdrawal(_) => false,
882 StateTransition::AddressFundingFromAssetLock(st) => {
883 st.set_signature(signature);
884 true
885 }
886 StateTransition::ShieldFromAssetLock(st) => {
887 st.set_signature(signature);
888 true
889 }
890 StateTransition::AddressCreditWithdrawal(_) => false,
891 }
892 }
893
894 pub fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) {
896 match self {
897 StateTransition::DataContractCreate(st) => st.set_user_fee_increase(user_fee_increase),
898 StateTransition::DataContractUpdate(st) => st.set_user_fee_increase(user_fee_increase),
899 StateTransition::Batch(st) => st.set_user_fee_increase(user_fee_increase),
900 StateTransition::IdentityCreate(st) => st.set_user_fee_increase(user_fee_increase),
901 StateTransition::IdentityTopUp(st) => st.set_user_fee_increase(user_fee_increase),
902 StateTransition::IdentityCreditWithdrawal(st) => {
903 st.set_user_fee_increase(user_fee_increase)
904 }
905 StateTransition::IdentityUpdate(st) => st.set_user_fee_increase(user_fee_increase),
906 StateTransition::IdentityCreditTransfer(st) => {
907 st.set_user_fee_increase(user_fee_increase)
908 }
909 StateTransition::IdentityCreditTransferToAddresses(st) => {
910 st.set_user_fee_increase(user_fee_increase)
911 }
912 StateTransition::IdentityCreateFromAddresses(st) => {
913 st.set_user_fee_increase(user_fee_increase)
914 }
915 StateTransition::IdentityTopUpFromAddresses(st) => {
916 st.set_user_fee_increase(user_fee_increase)
917 }
918 StateTransition::AddressFundsTransfer(st) => {
919 st.set_user_fee_increase(user_fee_increase)
920 }
921 StateTransition::AddressFundingFromAssetLock(st) => {
922 st.set_user_fee_increase(user_fee_increase)
923 }
924 StateTransition::AddressCreditWithdrawal(st) => {
925 st.set_user_fee_increase(user_fee_increase)
926 }
927 StateTransition::Shield(st) => st.set_user_fee_increase(user_fee_increase),
928 StateTransition::ShieldFromAssetLock(_) => {}
930 StateTransition::MasternodeVote(_) => {}
931 StateTransition::ShieldedTransfer(_) => {}
932 StateTransition::Unshield(_) => {}
933 StateTransition::ShieldedWithdrawal(_) => {}
934 }
935 }
936
937 pub fn set_signature_public_key_id(&mut self, public_key_id: KeyID) {
939 call_method_identity_signed!(self, set_signature_public_key_id, public_key_id)
940 }
941
942 #[cfg(feature = "state-transition-signing")]
943 pub fn sign_external<S: Signer<IdentityPublicKey>>(
944 &mut self,
945 identity_public_key: &IdentityPublicKey,
946 signer: &S,
947 get_data_contract_security_level_requirement: Option<
948 impl Fn(Identifier, String) -> Result<SecurityLevel, ProtocolError>,
949 >,
950 ) -> Result<(), ProtocolError> {
951 self.sign_external_with_options(
952 identity_public_key,
953 signer,
954 get_data_contract_security_level_requirement,
955 StateTransitionSigningOptions::default(),
956 )
957 }
958
959 #[cfg(feature = "state-transition-signing")]
960 pub fn sign_external_with_options<S: Signer<IdentityPublicKey>>(
961 &mut self,
962 identity_public_key: &IdentityPublicKey,
963 signer: &S,
964 get_data_contract_security_level_requirement: Option<
965 impl Fn(Identifier, String) -> Result<SecurityLevel, ProtocolError>,
966 >,
967 options: StateTransitionSigningOptions,
968 ) -> Result<(), ProtocolError> {
969 match self {
970 StateTransition::DataContractCreate(st) => {
971 st.verify_public_key_level_and_purpose(identity_public_key, options)?;
972 st.verify_public_key_is_enabled(identity_public_key)?;
973 }
974 StateTransition::DataContractUpdate(st) => {
975 st.verify_public_key_level_and_purpose(identity_public_key, options)?;
976 st.verify_public_key_is_enabled(identity_public_key)?;
977 }
978 StateTransition::Batch(st) => {
979 let allow_token_transfer_keys = st.transitions_len() == 1
980 && (st
981 .first_transition()
982 .expect("expected first transition with len 1")
983 .as_transition_token_claim()
984 .is_some()
985 || st
986 .first_transition()
987 .expect("expected first transition with len 1")
988 .as_transition_token_transfer()
989 .is_some());
990 let allowed_key_purposes = if allow_token_transfer_keys {
991 vec![Purpose::AUTHENTICATION, Purpose::TRANSFER]
992 } else {
993 vec![Purpose::AUTHENTICATION]
994 };
995 if !options.allow_signing_with_any_purpose
996 && !allowed_key_purposes.contains(&identity_public_key.purpose())
997 {
998 return Err(ProtocolError::WrongPublicKeyPurposeError(
999 WrongPublicKeyPurposeError::new(
1000 identity_public_key.purpose(),
1001 allowed_key_purposes,
1002 ),
1003 ));
1004 }
1005 if !options.allow_signing_with_any_security_level {
1006 let security_level_requirement = st.combined_security_level_requirement(
1007 get_data_contract_security_level_requirement,
1008 )?;
1009 if !security_level_requirement.contains(&identity_public_key.security_level()) {
1010 return Err(ProtocolError::InvalidSignaturePublicKeySecurityLevelError(
1011 InvalidSignaturePublicKeySecurityLevelError::new(
1012 identity_public_key.security_level(),
1013 security_level_requirement,
1014 ),
1015 ));
1016 }
1017 }
1018 st.verify_public_key_is_enabled(identity_public_key)?;
1019 }
1020 StateTransition::IdentityCreditWithdrawal(st) => {
1021 st.verify_public_key_level_and_purpose(identity_public_key, options)?;
1022 st.verify_public_key_is_enabled(identity_public_key)?;
1023 }
1024 StateTransition::IdentityUpdate(st) => {
1025 st.verify_public_key_level_and_purpose(identity_public_key, options)?;
1026 st.verify_public_key_is_enabled(identity_public_key)?;
1027 }
1028 StateTransition::IdentityCreditTransfer(st) => {
1029 st.verify_public_key_level_and_purpose(identity_public_key, options)?;
1030 st.verify_public_key_is_enabled(identity_public_key)?;
1031 }
1032 StateTransition::IdentityCreate(_) => {
1033 return Err(ProtocolError::CorruptedCodeExecution(
1034 "identity create can not be called for identity signing".to_string(),
1035 ))
1036 }
1037 StateTransition::IdentityTopUp(_) => {
1038 return Err(ProtocolError::CorruptedCodeExecution(
1039 "identity top up can not be called for identity signing".to_string(),
1040 ))
1041 }
1042 StateTransition::MasternodeVote(st) => {
1043 st.verify_public_key_level_and_purpose(identity_public_key, options)?;
1044 st.verify_public_key_is_enabled(identity_public_key)?;
1045 }
1046 StateTransition::IdentityCreditTransferToAddresses(st) => {
1047 st.verify_public_key_level_and_purpose(identity_public_key, options)?;
1048 st.verify_public_key_is_enabled(identity_public_key)?;
1049 }
1050 StateTransition::IdentityCreateFromAddresses(_) => {
1051 return Err(ProtocolError::CorruptedCodeExecution(
1052 "identity create from addresses can not be called for identity signing"
1053 .to_string(),
1054 ))
1055 }
1056 StateTransition::IdentityTopUpFromAddresses(_) => {
1057 return Err(ProtocolError::CorruptedCodeExecution(
1058 "identity top up from addresses can not be called for identity signing"
1059 .to_string(),
1060 ))
1061 }
1062 StateTransition::AddressFundsTransfer(_) => {
1063 return Err(ProtocolError::CorruptedCodeExecution(
1064 "address funds transfer transition can not be called for identity signing"
1065 .to_string(),
1066 ))
1067 }
1068 StateTransition::AddressFundingFromAssetLock(_) => {
1069 return Err(ProtocolError::CorruptedCodeExecution(
1070 "address funding from asset lock transition can not be called for identity signing"
1071 .to_string(),
1072 ))
1073 }
1074 StateTransition::AddressCreditWithdrawal(_) => {
1075 return Err(ProtocolError::CorruptedCodeExecution(
1076 "address credit withdrawal transition can not be called for identity signing"
1077 .to_string(),
1078 ))
1079 }
1080 StateTransition::Shield(_) => {
1081 return Err(ProtocolError::CorruptedCodeExecution(
1082 "shield transition can not be called for identity signing".to_string(),
1083 ))
1084 }
1085 StateTransition::ShieldedTransfer(_) => {
1086 return Err(ProtocolError::CorruptedCodeExecution(
1087 "shielded transfer transition can not be called for identity signing"
1088 .to_string(),
1089 ))
1090 }
1091 StateTransition::Unshield(_) => {
1092 return Err(ProtocolError::CorruptedCodeExecution(
1093 "unshield transition can not be called for identity signing".to_string(),
1094 ))
1095 }
1096 StateTransition::ShieldFromAssetLock(_) => {
1097 return Err(ProtocolError::CorruptedCodeExecution(
1098 "shield from asset lock transition can not be called for identity signing"
1099 .to_string(),
1100 ))
1101 }
1102 StateTransition::ShieldedWithdrawal(_) => {
1103 return Err(ProtocolError::CorruptedCodeExecution(
1104 "shielded withdrawal transition can not be called for identity signing"
1105 .to_string(),
1106 ))
1107 }
1108 }
1109 let data = self.signable_bytes()?;
1110 self.set_signature(signer.sign(identity_public_key, data.as_slice())?);
1111 self.set_signature_public_key_id(identity_public_key.id());
1112 Ok(())
1113 }
1114
1115 #[cfg(feature = "state-transition-signing")]
1116 pub fn sign(
1117 &mut self,
1118 identity_public_key: &IdentityPublicKey,
1119 private_key: &[u8],
1120 bls: &impl BlsModule,
1121 ) -> Result<(), ProtocolError> {
1122 self.sign_with_options(
1123 identity_public_key,
1124 private_key,
1125 bls,
1126 StateTransitionSigningOptions::default(),
1127 )
1128 }
1129
1130 #[cfg(feature = "state-transition-signing")]
1131 pub fn sign_with_options(
1132 &mut self,
1133 identity_public_key: &IdentityPublicKey,
1134 private_key: &[u8],
1135 bls: &impl BlsModule,
1136 options: StateTransitionSigningOptions,
1137 ) -> Result<(), ProtocolError> {
1138 call_errorable_method_identity_signed!(
1139 self,
1140 verify_public_key_level_and_purpose,
1141 identity_public_key,
1142 options
1143 )?;
1144 call_errorable_method_identity_signed!(
1145 self,
1146 verify_public_key_is_enabled,
1147 identity_public_key
1148 )?;
1149
1150 match identity_public_key.key_type() {
1151 KeyType::ECDSA_SECP256K1 => {
1152 let public_key_compressed = get_compressed_public_ec_key(private_key)?;
1153
1154 if public_key_compressed.as_slice() != identity_public_key.data().as_slice() {
1159 return Err(ProtocolError::InvalidSignaturePublicKeyError(
1160 InvalidSignaturePublicKeyError::new(identity_public_key.data().to_vec()),
1161 ));
1162 }
1163
1164 self.sign_by_private_key(private_key, identity_public_key.key_type(), bls)
1165 }
1166 KeyType::ECDSA_HASH160 => {
1167 let public_key_compressed = get_compressed_public_ec_key(private_key)?;
1168 let pub_key_hash = ripemd160_sha256(&public_key_compressed);
1169
1170 if identity_public_key.data().as_slice() != pub_key_hash {
1171 return Err(ProtocolError::InvalidSignaturePublicKeyError(
1172 InvalidSignaturePublicKeyError::new(identity_public_key.data().to_vec()),
1173 ));
1174 }
1175 self.sign_by_private_key(private_key, identity_public_key.key_type(), bls)
1176 }
1177 KeyType::BLS12_381 => {
1178 let public_key = bls.private_key_to_public_key(private_key)?;
1179
1180 if public_key != identity_public_key.data().as_slice() {
1181 return Err(ProtocolError::InvalidSignaturePublicKeyError(
1182 InvalidSignaturePublicKeyError::new(identity_public_key.data().to_vec()),
1183 ));
1184 }
1185 self.sign_by_private_key(private_key, identity_public_key.key_type(), bls)
1186 }
1187
1188 KeyType::BIP13_SCRIPT_HASH | KeyType::EDDSA_25519_HASH160 => {
1192 Err(ProtocolError::InvalidIdentityPublicKeyTypeError(
1193 InvalidIdentityPublicKeyTypeError::new(identity_public_key.key_type()),
1194 ))
1195 }
1196 }?;
1197
1198 self.set_signature_public_key_id(identity_public_key.id());
1199
1200 Ok(())
1201 }
1202
1203 #[cfg(feature = "state-transition-signing")]
1204 pub fn sign_by_private_key(
1206 &mut self,
1207 private_key: &[u8],
1208 key_type: KeyType,
1209 bls: &impl BlsModule,
1210 ) -> Result<(), ProtocolError> {
1211 let data = self.signable_bytes()?;
1212 match key_type {
1213 KeyType::BLS12_381 => {
1214 if !self.set_signature(bls.sign(&data, private_key)?.into()) {
1215 return Err(ProtocolError::InvalidVerificationWrongNumberOfElements {
1216 needed: self.required_number_of_private_keys(),
1217 using: 1,
1218 msg: "failed to set BLS signature",
1219 });
1220 }
1221 }
1222
1223 KeyType::ECDSA_SECP256K1 | KeyType::ECDSA_HASH160 => {
1225 let signature = signer::sign(&data, private_key)?;
1226 if !self.set_signature(signature.to_vec().into()) {
1227 return Err(ProtocolError::InvalidVerificationWrongNumberOfElements {
1228 needed: self.required_number_of_private_keys(),
1229 using: 1,
1230 msg: "failed to set ECDSA signature",
1231 });
1232 };
1233 }
1234
1235 KeyType::BIP13_SCRIPT_HASH | KeyType::EDDSA_25519_HASH160 => {
1239 return Err(ProtocolError::InvalidIdentityPublicKeyTypeError(
1240 InvalidIdentityPublicKeyTypeError::new(key_type),
1241 ))
1242 }
1243 };
1244 Ok(())
1245 }
1246
1247 #[cfg(feature = "state-transition-validation")]
1248 fn verify_by_raw_public_key<T: BlsModule>(
1249 &self,
1250 public_key: &[u8],
1251 public_key_type: KeyType,
1252 bls: &T,
1253 ) -> Result<(), ProtocolError> {
1254 match public_key_type {
1255 KeyType::ECDSA_SECP256K1 => self.verify_ecdsa_signature_by_public_key(public_key),
1256 KeyType::ECDSA_HASH160 => {
1257 self.verify_ecdsa_hash_160_signature_by_public_key_hash(public_key)
1258 }
1259 KeyType::BLS12_381 => self.verify_bls_signature_by_public_key(public_key, bls),
1260 KeyType::BIP13_SCRIPT_HASH | KeyType::EDDSA_25519_HASH160 => {
1261 Err(ProtocolError::InvalidIdentityPublicKeyTypeError(
1262 InvalidIdentityPublicKeyTypeError::new(public_key_type),
1263 ))
1264 }
1265 }
1266 }
1267
1268 #[cfg(feature = "state-transition-validation")]
1269 pub fn verify_identity_signed_signature(
1270 &self,
1271 public_key: &IdentityPublicKey,
1272 bls: &impl BlsModule,
1273 ) -> Result<(), ProtocolError> {
1274 if public_key.disabled_at().is_some() {
1276 return Err(ProtocolError::PublicKeyIsDisabledError(
1277 PublicKeyIsDisabledError::new(public_key.id()),
1278 ));
1279 }
1280
1281 let Some(signature) = self.signature() else {
1282 return Err(ProtocolError::CorruptedCodeExecution("verifying identity signature for a state transition that doesn't use identity signatures".to_string()));
1283 };
1284 if signature.is_empty() {
1285 return Err(ProtocolError::StateTransitionIsNotSignedError(
1286 StateTransitionIsNotSignedError::new(self.clone()),
1287 ));
1288 }
1289
1290 if self.signature_public_key_id() != Some(public_key.id()) {
1291 return Err(ProtocolError::PublicKeyMismatchError(
1292 PublicKeyMismatchError::new(public_key.clone()),
1293 ));
1294 }
1295
1296 let public_key_bytes = public_key.data().as_slice();
1297 match public_key.key_type() {
1298 KeyType::ECDSA_HASH160 => {
1299 self.verify_ecdsa_hash_160_signature_by_public_key_hash(public_key_bytes)
1300 }
1301
1302 KeyType::ECDSA_SECP256K1 => self.verify_ecdsa_signature_by_public_key(public_key_bytes),
1303
1304 KeyType::BLS12_381 => self.verify_bls_signature_by_public_key(public_key_bytes, bls),
1305
1306 KeyType::BIP13_SCRIPT_HASH | KeyType::EDDSA_25519_HASH160 => Ok(()),
1308 }
1309 }
1310
1311 #[cfg(feature = "state-transition-validation")]
1312 fn verify_ecdsa_hash_160_signature_by_public_key_hash(
1313 &self,
1314 public_key_hash: &[u8],
1315 ) -> Result<(), ProtocolError> {
1316 let Some(signature) = self.signature() else {
1317 return Err(ProtocolError::InvalidVerificationWrongNumberOfElements {
1318 needed: self.required_number_of_private_keys(),
1319 using: 1,
1320 msg: "This state transition type should a single signature",
1321 });
1322 };
1323 if signature.is_empty() {
1324 return Err(ProtocolError::StateTransitionIsNotSignedError(
1325 StateTransitionIsNotSignedError::new(self.clone()),
1326 ));
1327 }
1328 let data = self.signable_bytes()?;
1329 let data_hash = double_sha(data);
1330 signer::verify_hash_signature(&data_hash, signature.as_slice(), public_key_hash).map_err(
1331 |e| {
1332 ProtocolError::from(ConsensusError::SignatureError(
1333 SignatureError::InvalidStateTransitionSignatureError(
1334 InvalidStateTransitionSignatureError::new(e.to_string()),
1335 ),
1336 ))
1337 },
1338 )
1339 }
1340
1341 #[cfg(feature = "state-transition-validation")]
1342 fn verify_ecdsa_signature_by_public_key(&self, public_key: &[u8]) -> Result<(), ProtocolError> {
1344 let Some(signature) = self.signature() else {
1345 return Err(ProtocolError::InvalidVerificationWrongNumberOfElements {
1346 needed: self.required_number_of_private_keys(),
1347 using: 1,
1348 msg: "This state transition type should a single signature",
1349 });
1350 };
1351 if signature.is_empty() {
1352 return Err(ProtocolError::StateTransitionIsNotSignedError(
1353 StateTransitionIsNotSignedError::new(self.clone()),
1354 ));
1355 }
1356 let data = self.signable_bytes()?;
1357 signer::verify_data_signature(&data, signature.as_slice(), public_key).map_err(|e| {
1358 ProtocolError::from(ConsensusError::SignatureError(
1361 SignatureError::InvalidStateTransitionSignatureError(
1362 InvalidStateTransitionSignatureError::new(e.to_string()),
1363 ),
1364 ))
1365 })
1366 }
1367
1368 #[cfg(feature = "state-transition-validation")]
1369 fn verify_bls_signature_by_public_key<T: BlsModule>(
1371 &self,
1372 public_key: &[u8],
1373 bls: &T,
1374 ) -> Result<(), ProtocolError> {
1375 let Some(signature) = self.signature() else {
1376 return Err(ProtocolError::InvalidVerificationWrongNumberOfElements {
1377 needed: self.required_number_of_private_keys(),
1378 using: 1,
1379 msg: "This state transition type should a single signature",
1380 });
1381 };
1382 if signature.is_empty() {
1383 return Err(ProtocolError::StateTransitionIsNotSignedError(
1384 StateTransitionIsNotSignedError::new(self.clone()),
1385 ));
1386 }
1387
1388 let data = self.signable_bytes()?;
1389
1390 bls.verify_signature(signature.as_slice(), &data, public_key)
1391 .map(|_| ())
1392 .map_err(|e| {
1393 ProtocolError::from(ConsensusError::SignatureError(
1395 SignatureError::InvalidStateTransitionSignatureError(
1396 InvalidStateTransitionSignatureError::new(e.to_string()),
1397 ),
1398 ))
1399 })
1400 }
1401}
1402
1403#[cfg(feature = "state-transition-validation")]
1404impl StateTransitionStructureValidation for StateTransition {
1405 fn validate_structure(
1406 &self,
1407 platform_version: &PlatformVersion,
1408 ) -> crate::validation::SimpleConsensusValidationResult {
1409 match self {
1410 StateTransition::DataContractCreate(_)
1411 | StateTransition::DataContractUpdate(_)
1412 | StateTransition::Batch(_)
1413 | StateTransition::IdentityCreate(_)
1414 | StateTransition::IdentityTopUp(_)
1415 | StateTransition::IdentityCreditWithdrawal(_)
1416 | StateTransition::IdentityUpdate(_)
1417 | StateTransition::IdentityCreditTransfer(_)
1418 | StateTransition::MasternodeVote(_) => {
1419 crate::validation::SimpleConsensusValidationResult::new_with_error(
1420 UnsupportedFeatureError::new(
1421 "structure validation for identity-based state transitions".to_string(),
1422 platform_version.protocol_version,
1423 )
1424 .into(),
1425 )
1426 }
1427 StateTransition::IdentityCreditTransferToAddresses(transition) => {
1428 transition.validate_structure(platform_version)
1429 }
1430 StateTransition::IdentityCreateFromAddresses(transition) => {
1431 transition.validate_structure(platform_version)
1432 }
1433 StateTransition::IdentityTopUpFromAddresses(transition) => {
1434 transition.validate_structure(platform_version)
1435 }
1436 StateTransition::AddressFundsTransfer(transition) => {
1437 transition.validate_structure(platform_version)
1438 }
1439 StateTransition::AddressFundingFromAssetLock(transition) => {
1440 transition.validate_structure(platform_version)
1441 }
1442 StateTransition::AddressCreditWithdrawal(transition) => {
1443 transition.validate_structure(platform_version)
1444 }
1445 StateTransition::Shield(transition) => transition.validate_structure(platform_version),
1446 StateTransition::ShieldedTransfer(transition) => {
1447 transition.validate_structure(platform_version)
1448 }
1449 StateTransition::Unshield(transition) => {
1450 transition.validate_structure(platform_version)
1451 }
1452 StateTransition::ShieldFromAssetLock(transition) => {
1453 transition.validate_structure(platform_version)
1454 }
1455 StateTransition::ShieldedWithdrawal(transition) => {
1456 transition.validate_structure(platform_version)
1457 }
1458 }
1459 }
1460}
1461
1462#[cfg(test)]
1463mod tests {
1464 use super::*;
1465
1466 #[test]
1471 fn test_signing_options_default() {
1472 let opts = StateTransitionSigningOptions::default();
1473 assert!(!opts.allow_signing_with_any_security_level);
1474 assert!(!opts.allow_signing_with_any_purpose);
1475 }
1476
1477 #[test]
1478 fn test_signing_options_equality() {
1479 let a = StateTransitionSigningOptions {
1480 allow_signing_with_any_security_level: true,
1481 allow_signing_with_any_purpose: false,
1482 };
1483 let b = StateTransitionSigningOptions {
1484 allow_signing_with_any_security_level: true,
1485 allow_signing_with_any_purpose: false,
1486 };
1487 assert_eq!(a, b);
1488 }
1489
1490 #[test]
1491 fn test_signing_options_inequality() {
1492 let a = StateTransitionSigningOptions {
1493 allow_signing_with_any_security_level: true,
1494 allow_signing_with_any_purpose: false,
1495 };
1496 let b = StateTransitionSigningOptions {
1497 allow_signing_with_any_security_level: false,
1498 allow_signing_with_any_purpose: false,
1499 };
1500 assert_ne!(a, b);
1501 }
1502
1503 #[test]
1504 fn test_signing_options_clone() {
1505 let original = StateTransitionSigningOptions {
1506 allow_signing_with_any_security_level: true,
1507 allow_signing_with_any_purpose: true,
1508 };
1509 let cloned = original.clone();
1510 assert_eq!(original, cloned);
1511 }
1512
1513 #[test]
1514 fn test_signing_options_copy() {
1515 let original = StateTransitionSigningOptions {
1516 allow_signing_with_any_security_level: true,
1517 allow_signing_with_any_purpose: false,
1518 };
1519 let copied = original;
1520 assert_eq!(original, copied);
1521 }
1522
1523 #[test]
1524 fn test_signing_options_debug() {
1525 let opts = StateTransitionSigningOptions::default();
1526 let debug_str = format!("{:?}", opts);
1527 assert!(debug_str.contains("StateTransitionSigningOptions"));
1528 assert!(debug_str.contains("allow_signing_with_any_security_level"));
1529 assert!(debug_str.contains("allow_signing_with_any_purpose"));
1530 }
1531}