1#![allow(deprecated)]
8
9use crate::{
10 base::{
11 AccountThreshold, AggregateSigPairing, AmountFraction, BakerAggregationVerifyKey,
12 BakerElectionVerifyKey, BakerKeyPairs, BakerSignatureVerifyKey, ContractAddress,
13 CredentialRegistrationID, DelegationTarget, Energy, Nonce, OpenStatus, UrlText,
14 },
15 common::{
16 self,
17 cbor::{CborDecoder, CborDeserialize, CborEncoder, CborSerializationResult, CborSerialize},
18 types::{Amount, KeyIndex, KeyPair, Timestamp, TransactionSignature, TransactionTime, *},
19 Buffer, Deserial, Get, ParseResult, Put, ReadBytesExt, SerdeDeserialize, SerdeSerialize,
20 Serial, Serialize,
21 },
22 constants::*,
23 encrypted_transfers::types::{EncryptedAmountTransferData, SecToPubAmountTransferData},
24 hashes,
25 id::types::{
26 AccountAddress, AccountCredentialMessage, AccountKeys, CredentialDeploymentInfo,
27 CredentialPublicKeys, VerifyKey,
28 },
29 protocol_level_tokens::TokenOperationsPayload,
30 random_oracle::RandomOracle,
31 smart_contracts, updates,
32};
33use concordium_contracts_common as concordium_std;
34use concordium_std::SignatureThreshold;
35use derive_more::*;
36use rand::{CryptoRng, Rng};
37use sha2::Digest;
38use std::{collections::BTreeMap, marker::PhantomData};
39use thiserror::Error;
40
41#[derive(SerdeSerialize, SerdeDeserialize, Serial, Debug, Clone, Eq, PartialEq, AsRef, Into)]
42#[serde(transparent)]
43pub struct Memo {
45 #[serde(with = "crate::internal::byte_array_hex")]
46 #[size_length = 2]
47 bytes: Vec<u8>,
48}
49
50impl CborSerialize for Memo {
51 fn serialize<C: CborEncoder>(&self, encoder: C) -> CborSerializationResult<()> {
52 encoder.encode_bytes(&self.bytes)
53 }
54}
55
56impl CborDeserialize for Memo {
57 fn deserialize<C: CborDecoder>(decoder: C) -> CborSerializationResult<Self>
58 where
59 Self: Sized,
60 {
61 let bytes = decoder.decode_bytes()?;
62
63 Ok(Self { bytes })
64 }
65}
66
67#[derive(Display, Error, Debug)]
69pub struct TooBig;
70
71impl TryFrom<Vec<u8>> for Memo {
72 type Error = TooBig;
73
74 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
75 if value.len() <= crate::constants::MAX_MEMO_SIZE {
76 Ok(Self { bytes: value })
77 } else {
78 Err(TooBig)
79 }
80 }
81}
82
83impl Deserial for Memo {
84 fn deserial<R: crate::common::ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
85 let len: u16 = source.get()?;
86 anyhow::ensure!(
87 usize::from(len) <= crate::constants::MAX_MEMO_SIZE,
88 "Memo too big.."
89 );
90 let bytes = crate::common::deserial_bytes(source, len.into())?;
91 Ok(Memo { bytes })
92 }
93}
94
95#[derive(SerdeSerialize, SerdeDeserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Display)]
96#[serde(rename_all = "camelCase")]
97pub enum TransactionType {
101 DeployModule,
103 InitContract,
105 Update,
107 Transfer,
109
110 #[deprecated(
112 since = "5.0.1",
113 note = "baking is changed in protocol 4, use ConfigureBaker or ConfigureDelegation instead"
114 )]
115 AddBaker,
116
117 #[deprecated(
119 since = "5.0.1",
120 note = "baking is changed in protocol 4, use ConfigureBaker or ConfigureDelegation instead"
121 )]
122 RemoveBaker,
123
124 #[deprecated(
126 since = "5.0.1",
127 note = "baking is changed in protocol 4, use ConfigureBaker or ConfigureDelegation instead"
128 )]
129 UpdateBakerStake,
130
131 #[deprecated(
133 since = "5.0.1",
134 note = "baking is changed in protocol 4, use ConfigureBaker or ConfigureDelegation instead"
135 )]
136 UpdateBakerRestakeEarnings,
137
138 #[deprecated(
140 since = "5.0.1",
141 note = "baking is changed in protocol 4, use ConfigureBaker or ConfigureDelegation instead"
142 )]
143 UpdateBakerKeys,
144
145 UpdateCredentialKeys,
147
148 #[deprecated(
150 since = "5.0.1",
151 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
152 )]
153 EncryptedAmountTransfer,
154
155 #[deprecated(
157 since = "5.0.1",
158 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
159 )]
160 TransferToEncrypted,
161
162 TransferToPublic,
164 TransferWithSchedule,
166 UpdateCredentials,
168 RegisterData,
170 TransferWithMemo,
172
173 #[deprecated(
175 since = "5.0.1",
176 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
177 )]
178 EncryptedAmountTransferWithMemo,
179
180 TransferWithScheduleAndMemo,
182 ConfigureBaker,
184 ConfigureDelegation,
186 TokenUpdate,
188}
189
190#[derive(Debug, Error)]
193#[error("{0} is not a valid TransactionType tag.")]
194pub struct TransactionTypeConversionError(pub i32);
195
196impl TryFrom<i32> for TransactionType {
197 type Error = TransactionTypeConversionError;
198
199 fn try_from(value: i32) -> Result<Self, Self::Error> {
200 Ok(match value {
201 0 => Self::DeployModule,
202 1 => Self::InitContract,
203 2 => Self::Update,
204 3 => Self::Transfer,
205 4 => Self::AddBaker,
206 5 => Self::RemoveBaker,
207 6 => Self::UpdateBakerStake,
208 7 => Self::UpdateBakerRestakeEarnings,
209 8 => Self::UpdateBakerKeys,
210 9 => Self::UpdateCredentialKeys,
211 10 => Self::EncryptedAmountTransfer,
212 11 => Self::TransferToEncrypted,
213 12 => Self::TransferToPublic,
214 13 => Self::TransferWithSchedule,
215 14 => Self::UpdateCredentials,
216 15 => Self::RegisterData,
217 16 => Self::TransferWithMemo,
218 17 => Self::EncryptedAmountTransferWithMemo,
219 18 => Self::TransferWithScheduleAndMemo,
220 19 => Self::ConfigureBaker,
221 20 => Self::ConfigureDelegation,
222 21 => Self::TokenUpdate,
223 n => return Err(TransactionTypeConversionError(n)),
224 })
225 }
226}
227
228#[derive(
229 Debug, Copy, Clone, Serial, SerdeSerialize, SerdeDeserialize, Into, From, Display, Eq, PartialEq,
230)]
231#[serde(transparent)]
232pub struct PayloadSize {
234 pub(crate) size: u32,
235}
236
237impl Deserial for PayloadSize {
238 fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
239 let size: u32 = source.get()?;
240 anyhow::ensure!(
241 size <= MAX_PAYLOAD_SIZE,
242 "Size of the payload exceeds maximum allowed."
243 );
244 Ok(PayloadSize { size })
245 }
246}
247
248#[derive(Debug, Clone, Serialize, SerdeSerialize, SerdeDeserialize)]
249#[serde(rename_all = "camelCase")]
250pub struct TransactionHeader {
253 pub sender: AccountAddress,
255 pub nonce: Nonce,
257 pub energy_amount: Energy,
259 pub payload_size: PayloadSize,
262 pub expiry: TransactionTime,
264}
265
266#[derive(Debug, Clone, SerdeSerialize, SerdeDeserialize, Into, AsRef)]
267#[serde(transparent)]
268pub struct EncodedPayload {
271 #[serde(with = "crate::internal::byte_array_hex")]
272 pub(crate) payload: Vec<u8>,
273}
274
275#[derive(Debug, Error)]
276#[error("The given byte array of size {actual}B exceeds maximum payload size {max}B")]
277pub struct ExceedsPayloadSize {
278 pub actual: usize,
279 pub max: u32,
280}
281
282impl TryFrom<Vec<u8>> for EncodedPayload {
283 type Error = ExceedsPayloadSize;
284
285 fn try_from(payload: Vec<u8>) -> Result<Self, Self::Error> {
286 let actual = payload.len();
287 if actual
288 .try_into()
289 .map_or(false, |x: u32| x <= MAX_PAYLOAD_SIZE)
290 {
291 Ok(Self { payload })
292 } else {
293 Err(ExceedsPayloadSize {
294 actual,
295 max: MAX_PAYLOAD_SIZE,
296 })
297 }
298 }
299}
300
301impl EncodedPayload {
302 pub fn decode(&self) -> ParseResult<Payload> {
306 let mut source = std::io::Cursor::new(&self.payload);
307 let payload = source.get()?;
308 let consumed = source.position();
310 anyhow::ensure!(
311 consumed == self.payload.len() as u64,
312 "Payload length information is inaccurate: {} bytes of input remaining.",
313 self.payload.len() as u64 - consumed
314 );
315 Ok(payload)
316 }
317}
318
319impl Serial for EncodedPayload {
322 fn serial<B: Buffer>(&self, out: &mut B) {
323 out.write_all(&self.payload)
324 .expect("Writing to buffer should succeed.");
325 }
326}
327
328pub fn get_encoded_payload<R: ReadBytesExt>(
330 source: &mut R,
331 len: PayloadSize,
332) -> ParseResult<EncodedPayload> {
333 let payload = crate::common::deserial_bytes(source, u32::from(len) as usize)?;
336 Ok(EncodedPayload { payload })
337}
338
339pub trait PayloadLike {
342 fn encode(&self) -> EncodedPayload;
344 fn encode_to_buffer<B: Buffer>(&self, out: &mut B);
348}
349
350impl PayloadLike for EncodedPayload {
351 fn encode(&self) -> EncodedPayload {
352 self.clone()
353 }
354
355 fn encode_to_buffer<B: Buffer>(&self, out: &mut B) {
356 out.write_all(&self.payload)
357 .expect("Writing to buffer is always safe.");
358 }
359}
360
361#[derive(Debug, Clone, SerdeDeserialize, SerdeSerialize)]
362#[serde(rename_all = "camelCase")]
363pub struct AccountTransaction<PayloadType> {
370 pub signature: TransactionSignature,
371 pub header: TransactionHeader,
372 pub payload: PayloadType,
373}
374
375impl<P: PayloadLike> Serial for AccountTransaction<P> {
376 fn serial<B: Buffer>(&self, out: &mut B) {
377 out.put(&self.signature);
378 out.put(&self.header);
379 self.payload.encode_to_buffer(out)
380 }
381}
382
383impl Deserial for AccountTransaction<EncodedPayload> {
384 fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
385 let signature = source.get()?;
386 let header: TransactionHeader = source.get()?;
387 let payload = get_encoded_payload(source, header.payload_size)?;
388 Ok(AccountTransaction {
389 signature,
390 header,
391 payload,
392 })
393 }
394}
395
396impl Deserial for AccountTransaction<Payload> {
397 fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
398 let signature = source.get()?;
399 let header: TransactionHeader = source.get()?;
400 let payload_len = u64::from(u32::from(header.payload_size));
401 let mut limited = <&mut R as std::io::Read>::take(source, payload_len);
402 let payload = limited.get()?;
403 anyhow::ensure!(
405 limited.limit() == 0,
406 "Payload length information is inaccurate: {} bytes of input remaining.",
407 limited.limit()
408 );
409 Ok(AccountTransaction {
410 signature,
411 header,
412 payload,
413 })
414 }
415}
416
417impl<P: PayloadLike> AccountTransaction<P> {
418 pub fn verify_transaction_signature(&self, keys: &impl HasAccountAccessStructure) -> bool {
420 let hash = compute_transaction_sign_hash(&self.header, &self.payload);
421 verify_signature_transaction_sign_hash(keys, &hash, &self.signature)
422 }
423}
424
425#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
428pub enum AddBakerKeysMarker {}
429
430#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
433pub enum UpdateBakerKeysMarker {}
434
435#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
438pub enum ConfigureBakerKeysMarker {}
439
440#[derive(Debug, Clone, SerdeDeserialize, SerdeSerialize)]
441#[serde(rename_all = "camelCase")]
442pub struct BakerKeysPayload<V> {
449 #[serde(skip)] phantom: PhantomData<V>,
451 pub election_verify_key: BakerElectionVerifyKey,
453 pub signature_verify_key: BakerSignatureVerifyKey,
455 pub aggregation_verify_key: BakerAggregationVerifyKey,
458 pub proof_sig: crate::eddsa_ed25519::Ed25519DlogProof,
461 pub proof_election: crate::eddsa_ed25519::Ed25519DlogProof,
463 pub proof_aggregation: crate::aggregate_sig::Proof<AggregateSigPairing>,
466}
467
468pub type BakerAddKeysPayload = BakerKeysPayload<AddBakerKeysMarker>;
470pub type BakerUpdateKeysPayload = BakerKeysPayload<UpdateBakerKeysMarker>;
473
474pub type ConfigureBakerKeysPayload = BakerKeysPayload<ConfigureBakerKeysMarker>;
477
478impl<T> BakerKeysPayload<T> {
479 fn new_payload<R: Rng + CryptoRng>(
481 baker_keys: &BakerKeyPairs,
482 sender: AccountAddress,
483 challenge_prefix: &[u8],
484 csprng: &mut R,
485 ) -> Self {
486 let mut challenge = challenge_prefix.to_vec();
487
488 sender.serial(&mut challenge);
489 baker_keys.election_verify.serial(&mut challenge);
490 baker_keys.signature_verify.serial(&mut challenge);
491 baker_keys.aggregation_verify.serial(&mut challenge);
492
493 let proof_election = crate::eddsa_ed25519::prove_dlog_ed25519(
494 csprng,
495 &mut RandomOracle::domain(&challenge),
496 &baker_keys.election_verify.verify_key,
497 &baker_keys.election_sign.sign_key,
498 );
499 let proof_sig = crate::eddsa_ed25519::prove_dlog_ed25519(
500 csprng,
501 &mut RandomOracle::domain(&challenge),
502 &baker_keys.signature_verify.verify_key,
503 &baker_keys.signature_sign.sign_key,
504 );
505 let proof_aggregation = baker_keys
506 .aggregation_sign
507 .prove(csprng, &mut RandomOracle::domain(&challenge));
508
509 BakerKeysPayload {
510 phantom: PhantomData,
511 election_verify_key: baker_keys.election_verify.clone(),
512 signature_verify_key: baker_keys.signature_verify.clone(),
513 aggregation_verify_key: baker_keys.aggregation_verify.clone(),
514 proof_sig,
515 proof_election,
516 proof_aggregation,
517 }
518 }
519}
520
521impl BakerAddKeysPayload {
522 pub fn new<T: Rng + CryptoRng>(
524 baker_keys: &BakerKeyPairs,
525 sender: AccountAddress,
526 csprng: &mut T,
527 ) -> Self {
528 BakerKeysPayload::new_payload(baker_keys, sender, b"addBaker", csprng)
529 }
530}
531
532impl BakerUpdateKeysPayload {
533 pub fn new<T: Rng + CryptoRng>(
535 baker_keys: &BakerKeyPairs,
536 sender: AccountAddress,
537 csprng: &mut T,
538 ) -> Self {
539 BakerKeysPayload::new_payload(baker_keys, sender, b"updateBakerKeys", csprng)
540 }
541}
542
543impl ConfigureBakerKeysPayload {
544 pub fn new<T: Rng + CryptoRng>(
546 baker_keys: &BakerKeyPairs,
547 sender: AccountAddress,
548 csprng: &mut T,
549 ) -> Self {
550 BakerKeysPayload::new_payload(baker_keys, sender, b"configureBaker", csprng)
551 }
552}
553
554#[derive(Debug, Clone, SerdeDeserialize, SerdeSerialize)]
555#[serde(rename_all = "camelCase")]
556pub struct AddBakerPayload {
559 #[serde(flatten)]
561 pub keys: BakerAddKeysPayload,
562 pub baking_stake: Amount,
564 pub restake_earnings: bool,
566}
567
568#[derive(Debug, Clone, SerdeDeserialize, SerdeSerialize)]
569#[serde(rename_all = "camelCase")]
570pub struct InitContractPayload {
572 pub amount: Amount,
574 pub mod_ref: concordium_contracts_common::ModuleReference,
576 pub init_name: smart_contracts::OwnedContractName,
578 pub param: smart_contracts::OwnedParameter,
580}
581
582impl InitContractPayload {
583 pub fn size(&self) -> usize {
585 8 + 32 + 2 + self.init_name.as_contract_name().get_chain_name().len() +
589 2 + self.param.as_ref().len()
591 }
592}
593
594#[derive(Debug, Clone, SerdeDeserialize, SerdeSerialize)]
595#[serde(rename_all = "camelCase")]
596pub struct UpdateContractPayload {
598 pub amount: Amount,
601 pub address: ContractAddress,
603 pub receive_name: smart_contracts::OwnedReceiveName,
605 pub message: smart_contracts::OwnedParameter,
607}
608
609impl UpdateContractPayload {
610 pub fn size(&self) -> usize {
612 8 + 16 + 2 + self.receive_name.as_receive_name().get_chain_name().len() +
616 2 + self.message.as_ref().len()
618 }
619}
620
621#[derive(Debug, Clone, SerdeDeserialize, SerdeSerialize, Default)]
622#[serde(rename_all = "camelCase")]
623pub struct ConfigureBakerPayload {
628 pub capital: Option<Amount>,
630 pub restake_earnings: Option<bool>,
632 pub open_for_delegation: Option<OpenStatus>,
634 pub keys_with_proofs: Option<ConfigureBakerKeysPayload>,
636 pub metadata_url: Option<UrlText>,
638 pub transaction_fee_commission: Option<AmountFraction>,
640 pub baking_reward_commission: Option<AmountFraction>,
642 pub finalization_reward_commission: Option<AmountFraction>,
644 pub suspend: Option<bool>,
646}
647
648impl ConfigureBakerPayload {
649 pub fn new() -> Self {
650 Self::default()
651 }
652
653 pub fn new_remove_baker() -> Self {
655 Self {
656 capital: Some(Amount::from_micro_ccd(0)),
657 ..Self::new()
658 }
659 }
660
661 pub fn set_capital(&mut self, amount: Amount) -> &mut Self {
663 self.capital = Some(amount);
664 self
665 }
666
667 pub fn set_restake_earnings(&mut self, restake_earnings: bool) -> &mut Self {
669 self.restake_earnings = Some(restake_earnings);
670 self
671 }
672
673 pub fn set_open_for_delegation(&mut self, open_for_delegation: OpenStatus) -> &mut Self {
675 self.open_for_delegation = Some(open_for_delegation);
676 self
677 }
678
679 pub fn add_keys<T: Rng + CryptoRng>(
682 &mut self,
683 baker_keys: &BakerKeyPairs,
684 sender: AccountAddress,
685 csprng: &mut T,
686 ) -> &mut Self {
687 let keys_with_proofs =
688 BakerKeysPayload::new_payload(baker_keys, sender, b"configureBaker", csprng);
689 self.keys_with_proofs = Some(keys_with_proofs);
690 self
691 }
692
693 pub fn set_metadata_url(&mut self, metadata_url: UrlText) -> &mut Self {
695 self.metadata_url = Some(metadata_url);
696 self
697 }
698
699 pub fn set_transaction_fee_commission(
701 &mut self,
702 transaction_fee_commission: AmountFraction,
703 ) -> &mut Self {
704 self.transaction_fee_commission = Some(transaction_fee_commission);
705 self
706 }
707
708 pub fn set_baking_reward_commission(
710 &mut self,
711 baking_reward_commission: AmountFraction,
712 ) -> &mut Self {
713 self.baking_reward_commission = Some(baking_reward_commission);
714 self
715 }
716
717 pub fn set_finalization_reward_commission(
719 &mut self,
720 finalization_reward_commission: AmountFraction,
721 ) -> &mut Self {
722 self.finalization_reward_commission = Some(finalization_reward_commission);
723 self
724 }
725
726 pub fn set_suspend(&mut self, suspend: bool) -> &mut Self {
727 self.suspend = Some(suspend);
728 self
729 }
730}
731
732#[derive(Debug, Clone, SerdeDeserialize, SerdeSerialize, Default)]
733#[serde(rename_all = "camelCase")]
734pub struct ConfigureDelegationPayload {
737 pub capital: Option<Amount>,
739 pub restake_earnings: Option<bool>,
741 pub delegation_target: Option<DelegationTarget>,
743}
744
745impl ConfigureDelegationPayload {
746 pub fn new() -> Self {
748 Self::default()
749 }
750
751 pub fn new_remove_delegation() -> Self {
753 Self {
754 capital: Some(Amount::from_micro_ccd(0)),
755 ..Self::new()
756 }
757 }
758
759 pub fn set_capital(&mut self, amount: Amount) -> &mut Self {
760 self.capital = Some(amount);
761 self
762 }
763
764 pub fn set_restake_earnings(&mut self, restake_earnings: bool) -> &mut Self {
765 self.restake_earnings = Some(restake_earnings);
766 self
767 }
768
769 pub fn set_delegation_target(&mut self, target: DelegationTarget) -> &mut Self {
770 self.delegation_target = Some(target);
771 self
772 }
773}
774
775#[derive(SerdeSerialize, SerdeDeserialize, Serial, Debug, Clone, AsRef, Into, AsMut)]
776#[serde(transparent)]
777pub struct RegisteredData {
779 #[serde(with = "crate::internal::byte_array_hex")]
780 #[size_length = 2]
781 bytes: Vec<u8>,
782}
783
784#[derive(Debug, Error, Copy, Clone)]
786#[error("Data is too large to be registered ({actual_size}).")]
787pub struct TooLargeError {
788 actual_size: usize,
789}
790
791impl TryFrom<Vec<u8>> for RegisteredData {
792 type Error = TooLargeError;
793
794 fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
795 let actual_size = bytes.len();
796 if actual_size <= crate::constants::MAX_REGISTERED_DATA_SIZE {
797 Ok(RegisteredData { bytes })
798 } else {
799 Err(TooLargeError { actual_size })
800 }
801 }
802}
803
804impl From<[u8; 32]> for RegisteredData {
805 fn from(data: [u8; 32]) -> Self {
806 Self {
807 bytes: data.to_vec(),
808 }
809 }
810}
811
812impl<M> From<crate::hashes::HashBytes<M>> for RegisteredData {
813 fn from(data: crate::hashes::HashBytes<M>) -> Self {
814 Self {
815 bytes: data.as_ref().to_vec(),
816 }
817 }
818}
819
820impl Deserial for RegisteredData {
821 fn deserial<R: crate::common::ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
822 let len: u16 = source.get()?;
823 anyhow::ensure!(
824 usize::from(len) <= crate::constants::MAX_REGISTERED_DATA_SIZE,
825 "Data too big to register."
826 );
827 let bytes = crate::common::deserial_bytes(source, len.into())?;
828 Ok(RegisteredData { bytes })
829 }
830}
831
832pub type AccountCredentialsMap = BTreeMap<
835 CredentialIndex,
836 CredentialDeploymentInfo<
837 crate::id::constants::IpPairing,
838 crate::id::constants::ArCurve,
839 crate::id::constants::AttributeKind,
840 >,
841>;
842
843#[derive(Debug, Clone, SerdeDeserialize, SerdeSerialize)]
844#[serde(rename_all = "camelCase")]
845pub enum Payload {
847 DeployModule {
849 #[serde(rename = "mod")]
850 module: smart_contracts::WasmModule,
851 },
852 InitContract {
854 #[serde(flatten)]
855 payload: InitContractPayload,
856 },
857 Update {
859 #[serde(flatten)]
860 payload: UpdateContractPayload,
861 },
862 Transfer {
864 to_address: AccountAddress,
866 amount: Amount,
868 },
869 AddBaker {
871 #[serde(flatten)]
872 payload: Box<AddBakerPayload>,
873 },
874 RemoveBaker,
876 UpdateBakerStake {
878 stake: Amount,
880 },
881 UpdateBakerRestakeEarnings {
883 restake_earnings: bool,
885 },
886 UpdateBakerKeys {
888 #[serde(flatten)]
889 payload: Box<BakerUpdateKeysPayload>,
890 },
891 UpdateCredentialKeys {
893 cred_id: CredentialRegistrationID,
895 keys: CredentialPublicKeys,
897 },
898 #[deprecated(
900 since = "5.0.1",
901 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
902 )]
903 EncryptedAmountTransfer {
904 to: AccountAddress,
906 data: Box<EncryptedAmountTransferData<EncryptedAmountsCurve>>,
909 },
910 #[deprecated(
912 since = "5.0.1",
913 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
914 )]
915 TransferToEncrypted {
916 amount: Amount,
918 },
919 TransferToPublic {
921 #[serde(flatten)]
923 data: Box<SecToPubAmountTransferData<EncryptedAmountsCurve>>,
924 },
925 TransferWithSchedule {
927 to: AccountAddress,
929 schedule: Vec<(Timestamp, Amount)>,
931 },
932 UpdateCredentials {
934 new_cred_infos: AccountCredentialsMap,
936 remove_cred_ids: Vec<CredentialRegistrationID>,
938 new_threshold: AccountThreshold,
940 },
941 RegisterData {
943 data: RegisteredData,
945 },
946 TransferWithMemo {
948 to_address: AccountAddress,
950 memo: Memo,
952 amount: Amount,
954 },
955 #[deprecated(
957 since = "5.0.1",
958 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
959 )]
960 EncryptedAmountTransferWithMemo {
961 to: AccountAddress,
963 memo: Memo,
965 data: Box<EncryptedAmountTransferData<EncryptedAmountsCurve>>,
968 },
969 TransferWithScheduleAndMemo {
971 to: AccountAddress,
973 memo: Memo,
975 schedule: Vec<(Timestamp, Amount)>,
977 },
978 ConfigureBaker {
980 #[serde(flatten)]
981 data: Box<ConfigureBakerPayload>,
982 },
983 ConfigureDelegation {
985 #[serde(flatten)]
986 data: ConfigureDelegationPayload,
987 },
988 TokenUpdate {
990 #[serde(flatten)]
991 payload: TokenOperationsPayload,
992 },
993}
994
995impl Payload {
996 pub fn transaction_type(&self) -> TransactionType {
999 match self {
1000 Payload::DeployModule { .. } => TransactionType::DeployModule,
1001 Payload::InitContract { .. } => TransactionType::InitContract,
1002 Payload::Update { .. } => TransactionType::Update,
1003 Payload::Transfer { .. } => TransactionType::Transfer,
1004 Payload::AddBaker { .. } => TransactionType::AddBaker,
1005 Payload::RemoveBaker { .. } => TransactionType::RemoveBaker,
1006 Payload::UpdateBakerStake { .. } => TransactionType::UpdateBakerStake,
1007 Payload::UpdateBakerRestakeEarnings { .. } => {
1008 TransactionType::UpdateBakerRestakeEarnings
1009 }
1010 Payload::UpdateBakerKeys { .. } => TransactionType::UpdateBakerKeys,
1011 Payload::UpdateCredentialKeys { .. } => TransactionType::UpdateCredentialKeys,
1012 Payload::EncryptedAmountTransfer { .. } => TransactionType::EncryptedAmountTransfer,
1013 Payload::TransferToEncrypted { .. } => TransactionType::TransferToEncrypted,
1014 Payload::TransferToPublic { .. } => TransactionType::TransferToPublic,
1015 Payload::TransferWithSchedule { .. } => TransactionType::TransferWithSchedule,
1016 Payload::UpdateCredentials { .. } => TransactionType::UpdateCredentials,
1017 Payload::RegisterData { .. } => TransactionType::RegisterData,
1018 Payload::TransferWithMemo { .. } => TransactionType::TransferWithMemo,
1019 Payload::EncryptedAmountTransferWithMemo { .. } => {
1020 TransactionType::EncryptedAmountTransferWithMemo
1021 }
1022 Payload::TransferWithScheduleAndMemo { .. } => {
1023 TransactionType::TransferWithScheduleAndMemo
1024 }
1025 Payload::ConfigureBaker { .. } => TransactionType::ConfigureBaker,
1026 Payload::ConfigureDelegation { .. } => TransactionType::ConfigureDelegation,
1027 Payload::TokenUpdate { .. } => TransactionType::TokenUpdate,
1028 }
1029 }
1030}
1031
1032impl Serial for Payload {
1033 fn serial<B: Buffer>(&self, out: &mut B) {
1034 match &self {
1035 Payload::DeployModule { module } => {
1036 out.put(&0u8);
1037 out.put(module);
1038 }
1039 Payload::InitContract { payload } => {
1040 out.put(&1u8);
1041 out.put(payload)
1042 }
1043 Payload::Update { payload } => {
1044 out.put(&2u8);
1045 out.put(payload)
1046 }
1047 Payload::Transfer { to_address, amount } => {
1048 out.put(&3u8);
1049 out.put(to_address);
1050 out.put(amount);
1051 }
1052 Payload::AddBaker { payload } => {
1053 out.put(&4u8);
1054 out.put(payload);
1055 }
1056 Payload::RemoveBaker => {
1057 out.put(&5u8);
1058 }
1059 Payload::UpdateBakerStake { stake } => {
1060 out.put(&6u8);
1061 out.put(stake);
1062 }
1063 Payload::UpdateBakerRestakeEarnings { restake_earnings } => {
1064 out.put(&7u8);
1065 out.put(restake_earnings);
1066 }
1067 Payload::UpdateBakerKeys { payload } => {
1068 out.put(&8u8);
1069 out.put(payload)
1070 }
1071 Payload::UpdateCredentialKeys { cred_id, keys } => {
1072 out.put(&13u8);
1073 out.put(cred_id);
1074 out.put(keys);
1075 }
1076 Payload::EncryptedAmountTransfer { to, data } => {
1077 out.put(&16u8);
1078 out.put(to);
1079 out.put(data);
1080 }
1081 Payload::TransferToEncrypted { amount } => {
1082 out.put(&17u8);
1083 out.put(amount);
1084 }
1085 Payload::TransferToPublic { data } => {
1086 out.put(&18u8);
1087 out.put(data);
1088 }
1089 Payload::TransferWithSchedule { to, schedule } => {
1090 out.put(&19u8);
1091 out.put(to);
1092 out.put(&(schedule.len() as u8));
1093 crate::common::serial_vector_no_length(schedule, out);
1094 }
1095 Payload::UpdateCredentials {
1096 new_cred_infos,
1097 remove_cred_ids,
1098 new_threshold,
1099 } => {
1100 out.put(&20u8);
1101 out.put(&(new_cred_infos.len() as u8));
1102 crate::common::serial_map_no_length(new_cred_infos, out);
1103 out.put(&(remove_cred_ids.len() as u8));
1104 crate::common::serial_vector_no_length(remove_cred_ids, out);
1105 out.put(new_threshold);
1106 }
1107 Payload::RegisterData { data } => {
1108 out.put(&21u8);
1109 out.put(data);
1110 }
1111 Payload::TransferWithMemo {
1112 to_address,
1113 memo,
1114 amount,
1115 } => {
1116 out.put(&22u8);
1117 out.put(to_address);
1118 out.put(memo);
1119 out.put(amount);
1120 }
1121 Payload::EncryptedAmountTransferWithMemo { to, memo, data } => {
1122 out.put(&23u8);
1123 out.put(to);
1124 out.put(memo);
1125 out.put(data);
1126 }
1127 Payload::TransferWithScheduleAndMemo { to, memo, schedule } => {
1128 out.put(&24u8);
1129 out.put(to);
1130 out.put(memo);
1131 out.put(&(schedule.len() as u8));
1132 crate::common::serial_vector_no_length(schedule, out);
1133 }
1134 Payload::ConfigureBaker { data } => {
1135 out.put(&25u8);
1136 let set_if = |n, b| if b { 1u16 << n } else { 0 };
1137 let bitmap: u16 = set_if(0, data.capital.is_some())
1138 | set_if(1, data.restake_earnings.is_some())
1139 | set_if(2, data.open_for_delegation.is_some())
1140 | set_if(3, data.keys_with_proofs.is_some())
1141 | set_if(4, data.metadata_url.is_some())
1142 | set_if(5, data.transaction_fee_commission.is_some())
1143 | set_if(6, data.baking_reward_commission.is_some())
1144 | set_if(7, data.finalization_reward_commission.is_some())
1145 | set_if(8, data.suspend.is_some());
1146 out.put(&bitmap);
1147 if let Some(capital) = &data.capital {
1148 out.put(capital);
1149 }
1150 if let Some(restake_earnings) = &data.restake_earnings {
1151 out.put(restake_earnings);
1152 }
1153 if let Some(open_for_delegation) = &data.open_for_delegation {
1154 out.put(open_for_delegation);
1155 }
1156 if let Some(keys_with_proofs) = &data.keys_with_proofs {
1157 out.put(&keys_with_proofs.election_verify_key);
1161 out.put(&keys_with_proofs.proof_election);
1162 out.put(&keys_with_proofs.signature_verify_key);
1163 out.put(&keys_with_proofs.proof_sig);
1164 out.put(&keys_with_proofs.aggregation_verify_key);
1165 out.put(&keys_with_proofs.proof_aggregation);
1166 }
1167 if let Some(metadata_url) = &data.metadata_url {
1168 out.put(metadata_url);
1169 }
1170 if let Some(transaction_fee_commission) = &data.transaction_fee_commission {
1171 out.put(transaction_fee_commission);
1172 }
1173 if let Some(baking_reward_commission) = &data.baking_reward_commission {
1174 out.put(baking_reward_commission);
1175 }
1176 if let Some(finalization_reward_commission) = &data.finalization_reward_commission {
1177 out.put(finalization_reward_commission);
1178 }
1179 if let Some(suspend) = &data.suspend {
1180 out.put(suspend);
1181 }
1182 }
1183 Payload::ConfigureDelegation {
1184 data:
1185 ConfigureDelegationPayload {
1186 capital,
1187 restake_earnings,
1188 delegation_target,
1189 },
1190 } => {
1191 out.put(&26u8);
1192 let set_if = |n, b| if b { 1u16 << n } else { 0 };
1193 let bitmap: u16 = set_if(0, capital.is_some())
1194 | set_if(1, restake_earnings.is_some())
1195 | set_if(2, delegation_target.is_some());
1196 out.put(&bitmap);
1197 if let Some(capital) = capital {
1198 out.put(capital);
1199 }
1200 if let Some(restake_earnings) = restake_earnings {
1201 out.put(restake_earnings);
1202 }
1203 if let Some(delegation_target) = delegation_target {
1204 out.put(delegation_target);
1205 }
1206 }
1207 Payload::TokenUpdate { payload } => {
1208 out.put(&27u8);
1209 out.put(&payload.token_id);
1210 out.put(&payload.operations);
1211 }
1212 }
1213 }
1214}
1215
1216impl Deserial for Payload {
1217 fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
1218 let tag: u8 = source.get()?;
1219 match tag {
1220 0 => {
1221 let module = source.get()?;
1222 Ok(Payload::DeployModule { module })
1223 }
1224 1 => {
1225 let payload = source.get()?;
1226 Ok(Payload::InitContract { payload })
1227 }
1228 2 => {
1229 let payload = source.get()?;
1230 Ok(Payload::Update { payload })
1231 }
1232 3 => {
1233 let to_address = source.get()?;
1234 let amount = source.get()?;
1235 Ok(Payload::Transfer { to_address, amount })
1236 }
1237 4 => {
1238 let payload_data = source.get()?;
1239 Ok(Payload::AddBaker {
1240 payload: Box::new(payload_data),
1241 })
1242 }
1243 5 => Ok(Payload::RemoveBaker),
1244 6 => {
1245 let stake = source.get()?;
1246 Ok(Payload::UpdateBakerStake { stake })
1247 }
1248 7 => {
1249 let restake_earnings = source.get()?;
1250 Ok(Payload::UpdateBakerRestakeEarnings { restake_earnings })
1251 }
1252 8 => {
1253 let payload_data = source.get()?;
1254 Ok(Payload::UpdateBakerKeys {
1255 payload: Box::new(payload_data),
1256 })
1257 }
1258 13 => {
1259 let cred_id = source.get()?;
1260 let keys = source.get()?;
1261 Ok(Payload::UpdateCredentialKeys { cred_id, keys })
1262 }
1263 16 => {
1264 let to = source.get()?;
1265 let data = source.get()?;
1266 Ok(Payload::EncryptedAmountTransfer { to, data })
1267 }
1268 17 => {
1269 let amount = source.get()?;
1270 Ok(Payload::TransferToEncrypted { amount })
1271 }
1272 18 => {
1273 let data_data = source.get()?;
1274 Ok(Payload::TransferToPublic {
1275 data: Box::new(data_data),
1276 })
1277 }
1278 19 => {
1279 let to = source.get()?;
1280 let len: u8 = source.get()?;
1281 let schedule = crate::common::deserial_vector_no_length(source, len.into())?;
1282 Ok(Payload::TransferWithSchedule { to, schedule })
1283 }
1284 20 => {
1285 let cred_infos_len: u8 = source.get()?;
1286 let new_cred_infos =
1287 crate::common::deserial_map_no_length(source, cred_infos_len.into())?;
1288 let remove_cred_ids_len: u8 = source.get()?;
1289 let remove_cred_ids =
1290 crate::common::deserial_vector_no_length(source, remove_cred_ids_len.into())?;
1291 let new_threshold = source.get()?;
1292 Ok(Payload::UpdateCredentials {
1293 new_cred_infos,
1294 remove_cred_ids,
1295 new_threshold,
1296 })
1297 }
1298 21 => {
1299 let data = source.get()?;
1300 Ok(Payload::RegisterData { data })
1301 }
1302 22 => {
1303 let to_address = source.get()?;
1304 let memo = source.get()?;
1305 let amount = source.get()?;
1306 Ok(Payload::TransferWithMemo {
1307 to_address,
1308 memo,
1309 amount,
1310 })
1311 }
1312 23 => {
1313 let to = source.get()?;
1314 let memo = source.get()?;
1315 let data = source.get()?;
1316 Ok(Payload::EncryptedAmountTransferWithMemo { to, memo, data })
1317 }
1318 24 => {
1319 let to = source.get()?;
1320 let memo = source.get()?;
1321 let len: u8 = source.get()?;
1322 let schedule = crate::common::deserial_vector_no_length(source, len.into())?;
1323 Ok(Payload::TransferWithScheduleAndMemo { to, memo, schedule })
1324 }
1325 25 => {
1326 let bitmap: u16 = source.get()?;
1327 let mut capital = None;
1328 let mut restake_earnings = None;
1329 let mut open_for_delegation = None;
1330 let mut keys_with_proofs = None;
1331 let mut metadata_url = None;
1332 let mut transaction_fee_commission = None;
1333 let mut baking_reward_commission = None;
1334 let mut finalization_reward_commission = None;
1335 let mut suspend = None;
1336 if bitmap & 1 != 0 {
1337 capital = Some(source.get()?);
1338 }
1339 if bitmap & (1 << 1) != 0 {
1340 restake_earnings = Some(source.get()?);
1341 }
1342 if bitmap & (1 << 2) != 0 {
1343 open_for_delegation = Some(source.get()?);
1344 }
1345 if bitmap & (1 << 3) != 0 {
1346 let election_verify_key = source.get()?;
1350 let proof_election = source.get()?;
1351 let signature_verify_key = source.get()?;
1352 let proof_sig = source.get()?;
1353 let aggregation_verify_key = source.get()?;
1354 let proof_aggregation = source.get()?;
1355 keys_with_proofs = Some(BakerKeysPayload {
1356 phantom: PhantomData,
1357 election_verify_key,
1358 signature_verify_key,
1359 aggregation_verify_key,
1360 proof_sig,
1361 proof_election,
1362 proof_aggregation,
1363 });
1364 }
1365 if bitmap & (1 << 4) != 0 {
1366 metadata_url = Some(source.get()?);
1367 }
1368 if bitmap & (1 << 5) != 0 {
1369 transaction_fee_commission = Some(source.get()?);
1370 }
1371 if bitmap & (1 << 6) != 0 {
1372 baking_reward_commission = Some(source.get()?);
1373 }
1374 if bitmap & (1 << 7) != 0 {
1375 finalization_reward_commission = Some(source.get()?);
1376 }
1377 if bitmap & (1 << 8) != 0 {
1378 suspend = Some(source.get()?);
1379 }
1380 let data = Box::new(ConfigureBakerPayload {
1381 capital,
1382 restake_earnings,
1383 open_for_delegation,
1384 keys_with_proofs,
1385 metadata_url,
1386 transaction_fee_commission,
1387 baking_reward_commission,
1388 finalization_reward_commission,
1389 suspend,
1390 });
1391 Ok(Payload::ConfigureBaker { data })
1392 }
1393 26 => {
1394 let mut data = ConfigureDelegationPayload::default();
1395 let bitmap: u16 = source.get()?;
1396 anyhow::ensure!(
1397 bitmap & 0b111 == bitmap,
1398 "Incorrect bitmap for configure delegation."
1399 );
1400 if bitmap & 1 != 0 {
1401 data.capital = Some(source.get()?);
1402 }
1403 if bitmap & (1 << 1) != 0 {
1404 data.restake_earnings = Some(source.get()?);
1405 }
1406 if bitmap & (1 << 2) != 0 {
1407 data.delegation_target = Some(source.get()?);
1408 }
1409 Ok(Payload::ConfigureDelegation { data })
1410 }
1411 27 => {
1412 let token_id = source.get()?;
1413 let operations = source.get()?;
1414 let payload = TokenOperationsPayload {
1415 token_id,
1416 operations,
1417 };
1418 Ok(Payload::TokenUpdate { payload })
1419 }
1420 _ => {
1421 anyhow::bail!("Unsupported transaction payload tag {}", tag)
1422 }
1423 }
1424 }
1425}
1426
1427impl PayloadLike for Payload {
1428 fn encode(&self) -> EncodedPayload {
1429 let payload = crate::common::to_bytes(&self);
1430 EncodedPayload { payload }
1431 }
1432
1433 fn encode_to_buffer<B: Buffer>(&self, out: &mut B) {
1434 out.put(&self)
1435 }
1436}
1437
1438impl EncodedPayload {
1439 pub fn size(&self) -> PayloadSize {
1440 let size = self.payload.len() as u32;
1441 PayloadSize { size }
1442 }
1443}
1444
1445pub fn compute_transaction_sign_hash(
1447 header: &TransactionHeader,
1448 payload: &impl PayloadLike,
1449) -> hashes::TransactionSignHash {
1450 let mut hasher = sha2::Sha256::new();
1451 hasher.put(header);
1452 payload.encode_to_buffer(&mut hasher);
1453 hashes::HashBytes::new(hasher.result())
1454}
1455
1456pub trait TransactionSigner {
1458 fn sign_transaction_hash(
1461 &self,
1462 hash_to_sign: &hashes::TransactionSignHash,
1463 ) -> TransactionSignature;
1464}
1465
1466pub trait ExactSizeTransactionSigner: TransactionSigner {
1468 fn num_keys(&self) -> u32;
1471}
1472
1473impl<S: TransactionSigner> TransactionSigner for std::sync::Arc<S> {
1474 fn sign_transaction_hash(
1475 &self,
1476 hash_to_sign: &hashes::TransactionSignHash,
1477 ) -> TransactionSignature {
1478 self.as_ref().sign_transaction_hash(hash_to_sign)
1479 }
1480}
1481
1482impl<S: ExactSizeTransactionSigner> ExactSizeTransactionSigner for std::sync::Arc<S> {
1483 fn num_keys(&self) -> u32 {
1484 self.as_ref().num_keys()
1485 }
1486}
1487
1488impl<S: TransactionSigner> TransactionSigner for std::rc::Rc<S> {
1489 fn sign_transaction_hash(
1490 &self,
1491 hash_to_sign: &hashes::TransactionSignHash,
1492 ) -> TransactionSignature {
1493 self.as_ref().sign_transaction_hash(hash_to_sign)
1494 }
1495}
1496
1497impl<S: ExactSizeTransactionSigner> ExactSizeTransactionSigner for std::rc::Rc<S> {
1498 fn num_keys(&self) -> u32 {
1499 self.as_ref().num_keys()
1500 }
1501}
1502
1503impl TransactionSigner for AccountKeys {
1506 fn sign_transaction_hash(
1507 &self,
1508 hash_to_sign: &hashes::TransactionSignHash,
1509 ) -> TransactionSignature {
1510 let iter = self
1511 .keys
1512 .iter()
1513 .take(usize::from(u8::from(self.threshold)))
1514 .map(|(k, v)| {
1515 (k, {
1516 let num = u8::from(v.threshold);
1517 v.keys.iter().take(num.into())
1518 })
1519 });
1520 let mut signatures = BTreeMap::<CredentialIndex, BTreeMap<KeyIndex, _>>::new();
1521 for (ci, cred_keys) in iter {
1522 let cred_sigs = cred_keys
1523 .into_iter()
1524 .map(|(ki, kp)| (*ki, kp.sign(hash_to_sign.as_ref()).into()))
1525 .collect::<BTreeMap<_, _>>();
1526 signatures.insert(*ci, cred_sigs);
1527 }
1528 TransactionSignature { signatures }
1529 }
1530}
1531
1532impl ExactSizeTransactionSigner for AccountKeys {
1533 fn num_keys(&self) -> u32 {
1534 self.keys
1535 .values()
1536 .take(usize::from(u8::from(self.threshold)))
1537 .map(|v| u32::from(u8::from(v.threshold)))
1538 .sum::<u32>()
1539 }
1540}
1541
1542impl<'a, X: TransactionSigner> TransactionSigner for &'a X {
1543 fn sign_transaction_hash(
1544 &self,
1545 hash_to_sign: &hashes::TransactionSignHash,
1546 ) -> TransactionSignature {
1547 (*self).sign_transaction_hash(hash_to_sign)
1548 }
1549}
1550
1551impl<'a, X: ExactSizeTransactionSigner> ExactSizeTransactionSigner for &'a X {
1552 fn num_keys(&self) -> u32 {
1553 (*self).num_keys()
1554 }
1555}
1556
1557impl TransactionSigner for BTreeMap<CredentialIndex, BTreeMap<KeyIndex, KeyPair>> {
1558 fn sign_transaction_hash(
1559 &self,
1560 hash_to_sign: &hashes::TransactionSignHash,
1561 ) -> TransactionSignature {
1562 let mut signatures = BTreeMap::<CredentialIndex, BTreeMap<KeyIndex, _>>::new();
1563 for (ci, cred_keys) in self {
1564 let cred_sigs = cred_keys
1565 .iter()
1566 .map(|(ki, kp)| (*ki, kp.sign(hash_to_sign.as_ref()).into()))
1567 .collect::<BTreeMap<_, _>>();
1568 signatures.insert(*ci, cred_sigs);
1569 }
1570 TransactionSignature { signatures }
1571 }
1572}
1573
1574impl ExactSizeTransactionSigner for BTreeMap<CredentialIndex, BTreeMap<KeyIndex, KeyPair>> {
1575 fn num_keys(&self) -> u32 {
1576 self.values().map(|v| v.len() as u32).sum::<u32>()
1577 }
1578}
1579
1580pub fn sign_transaction<S: TransactionSigner, P: PayloadLike>(
1582 signer: &S,
1583 header: TransactionHeader,
1584 payload: P,
1585) -> AccountTransaction<P> {
1586 let hash_to_sign = compute_transaction_sign_hash(&header, &payload);
1587 let signature = signer.sign_transaction_hash(&hash_to_sign);
1588 AccountTransaction {
1589 signature,
1590 header,
1591 payload,
1592 }
1593}
1594
1595pub trait HasAccountAccessStructure {
1598 fn threshold(&self) -> AccountThreshold;
1600 fn credential_keys(&self, idx: CredentialIndex) -> Option<&CredentialPublicKeys>;
1602}
1603
1604#[derive(PartialEq, Eq, Debug, Clone, concordium_std::Serialize)]
1605pub struct AccountAccessStructure {
1608 #[concordium(size_length = 1)]
1610 pub keys: BTreeMap<CredentialIndex, CredentialPublicKeys>,
1611 pub threshold: AccountThreshold,
1613}
1614
1615pub type AccountStructure<'a> = &'a [(
1618 CredentialIndex,
1619 SignatureThreshold,
1620 &'a [(KeyIndex, ed25519_dalek::VerifyingKey)],
1621)];
1622
1623impl AccountAccessStructure {
1624 pub fn new(account_threshold: AccountThreshold, structure: AccountStructure) -> Self {
1628 let mut map: BTreeMap<CredentialIndex, CredentialPublicKeys> = BTreeMap::new();
1629
1630 for credential_structure in structure {
1631 let mut inner_map: BTreeMap<KeyIndex, VerifyKey> = BTreeMap::new();
1632
1633 for key_structure in credential_structure.2 {
1634 inner_map.insert(
1635 key_structure.0,
1636 VerifyKey::Ed25519VerifyKey(key_structure.1),
1637 );
1638 }
1639
1640 map.insert(
1641 credential_structure.0,
1642 CredentialPublicKeys {
1643 keys: inner_map,
1644 threshold: credential_structure.1,
1645 },
1646 );
1647 }
1648
1649 AccountAccessStructure {
1650 keys: map,
1651 threshold: account_threshold,
1652 }
1653 }
1654
1655 pub fn singleton(public_key: ed25519_dalek::VerifyingKey) -> Self {
1658 Self::new(
1659 AccountThreshold::ONE,
1660 &[(0.into(), SignatureThreshold::ONE, &[(0.into(), public_key)])],
1661 )
1662 }
1663}
1664
1665impl From<&AccountKeys> for AccountAccessStructure {
1666 fn from(value: &AccountKeys) -> Self {
1667 Self {
1668 threshold: value.threshold,
1669 keys: value
1670 .keys
1671 .iter()
1672 .map(|(k, v)| {
1673 (
1674 *k,
1675 CredentialPublicKeys {
1676 keys: v
1677 .keys
1678 .iter()
1679 .map(|(ki, kp)| {
1680 (
1681 *ki,
1682 VerifyKey::Ed25519VerifyKey(kp.as_ref().verifying_key()),
1683 )
1684 })
1685 .collect(),
1686 threshold: v.threshold,
1687 },
1688 )
1689 })
1690 .collect(),
1691 }
1692 }
1693}
1694
1695impl HasAccountAccessStructure for AccountAccessStructure {
1696 fn threshold(&self) -> AccountThreshold {
1697 self.threshold
1698 }
1699
1700 fn credential_keys(&self, idx: CredentialIndex) -> Option<&CredentialPublicKeys> {
1701 self.keys.get(&idx)
1702 }
1703}
1704
1705impl Serial for AccountAccessStructure {
1708 fn serial<B: Buffer>(&self, out: &mut B) {
1709 (self.keys.len() as u8).serial(out);
1710 for (k, v) in self.keys.iter() {
1711 k.serial(out);
1712 v.serial(out);
1713 }
1714 self.threshold.serial(out)
1715 }
1716}
1717
1718impl Deserial for AccountAccessStructure {
1721 fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
1722 let len = u8::deserial(source)?;
1723 let keys = common::deserial_map_no_length(source, len.into())?;
1724 let threshold = source.get()?;
1725 Ok(Self { threshold, keys })
1726 }
1727}
1728
1729impl AccountAccessStructure {
1730 pub fn num_keys(&self) -> u32 {
1732 self.keys.values().map(|m| m.keys.len() as u32).sum()
1733 }
1734}
1735
1736pub fn verify_signature_transaction_sign_hash(
1739 keys: &impl HasAccountAccessStructure,
1740 hash: &hashes::TransactionSignHash,
1741 signature: &TransactionSignature,
1742) -> bool {
1743 verify_data_signature(keys, hash, &signature.signatures)
1744}
1745
1746pub fn verify_data_signature<T: ?Sized + AsRef<[u8]>>(
1753 keys: &impl HasAccountAccessStructure,
1754 data: &T,
1755 signatures: &BTreeMap<CredentialIndex, BTreeMap<KeyIndex, Signature>>,
1756) -> bool {
1757 if usize::from(u8::from(keys.threshold())) > signatures.len() {
1758 return false;
1759 }
1760 for (&ci, cred_sigs) in signatures.iter() {
1762 if let Some(cred_keys) = keys.credential_keys(ci) {
1763 if usize::from(u8::from(cred_keys.threshold)) > cred_sigs.len() {
1764 return false;
1765 }
1766 for (&ki, sig) in cred_sigs {
1767 if let Some(pk) = cred_keys.get(ki) {
1768 if !pk.verify(data, sig) {
1769 return false;
1770 }
1771 } else {
1772 return false;
1773 }
1774 }
1775 } else {
1776 return false;
1777 }
1778 }
1779 true
1780}
1781
1782#[derive(Debug, Clone)]
1783pub enum BlockItem<PayloadType> {
1787 AccountTransaction(AccountTransaction<PayloadType>),
1790 CredentialDeployment(
1794 Box<
1795 AccountCredentialMessage<
1796 crate::id::constants::IpPairing,
1797 crate::id::constants::ArCurve,
1798 crate::id::constants::AttributeKind,
1799 >,
1800 >,
1801 ),
1802 UpdateInstruction(updates::UpdateInstruction),
1803}
1804
1805impl<PayloadType> From<AccountTransaction<PayloadType>> for BlockItem<PayloadType> {
1806 fn from(at: AccountTransaction<PayloadType>) -> Self {
1807 Self::AccountTransaction(at)
1808 }
1809}
1810
1811impl<PayloadType>
1812 From<
1813 AccountCredentialMessage<
1814 crate::id::constants::IpPairing,
1815 crate::id::constants::ArCurve,
1816 crate::id::constants::AttributeKind,
1817 >,
1818 > for BlockItem<PayloadType>
1819{
1820 fn from(
1821 at: AccountCredentialMessage<
1822 crate::id::constants::IpPairing,
1823 crate::id::constants::ArCurve,
1824 crate::id::constants::AttributeKind,
1825 >,
1826 ) -> Self {
1827 Self::CredentialDeployment(Box::new(at))
1828 }
1829}
1830
1831impl<PayloadType> From<updates::UpdateInstruction> for BlockItem<PayloadType> {
1832 fn from(ui: updates::UpdateInstruction) -> Self {
1833 Self::UpdateInstruction(ui)
1834 }
1835}
1836
1837impl<PayloadType> BlockItem<PayloadType> {
1838 pub fn hash(&self) -> hashes::TransactionHash
1841 where
1842 BlockItem<PayloadType>: Serial,
1843 {
1844 let mut hasher = sha2::Sha256::new();
1845 hasher.put(&self);
1846 hashes::HashBytes::new(hasher.result())
1847 }
1848}
1849
1850impl<V> Serial for BakerKeysPayload<V> {
1851 fn serial<B: Buffer>(&self, out: &mut B) {
1852 out.put(&self.election_verify_key);
1853 out.put(&self.signature_verify_key);
1854 out.put(&self.aggregation_verify_key);
1855 out.put(&self.proof_sig);
1856 out.put(&self.proof_election);
1857 out.put(&self.proof_aggregation);
1858 }
1859}
1860
1861impl<V> Deserial for BakerKeysPayload<V> {
1862 fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
1863 let election_verify_key = source.get()?;
1864 let signature_verify_key = source.get()?;
1865 let aggregation_verify_key = source.get()?;
1866 let proof_sig = source.get()?;
1867 let proof_election = source.get()?;
1868 let proof_aggregation = source.get()?;
1869 Ok(Self {
1870 phantom: PhantomData,
1871 election_verify_key,
1872 signature_verify_key,
1873 aggregation_verify_key,
1874 proof_sig,
1875 proof_election,
1876 proof_aggregation,
1877 })
1878 }
1879}
1880
1881impl Serial for AddBakerPayload {
1882 fn serial<B: Buffer>(&self, out: &mut B) {
1883 out.put(&self.keys);
1884 out.put(&self.baking_stake);
1885 out.put(&self.restake_earnings);
1886 }
1887}
1888
1889impl Deserial for AddBakerPayload {
1890 fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
1891 let keys = source.get()?;
1892 let baking_stake = source.get()?;
1893 let restake_earnings = source.get()?;
1894 Ok(Self {
1895 keys,
1896 baking_stake,
1897 restake_earnings,
1898 })
1899 }
1900}
1901
1902impl Serial for InitContractPayload {
1903 fn serial<B: Buffer>(&self, out: &mut B) {
1904 out.put(&self.amount);
1905 out.put(&self.mod_ref);
1906 out.put(&self.init_name);
1907 out.put(&self.param);
1908 }
1909}
1910
1911impl Deserial for InitContractPayload {
1912 fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
1913 let amount = source.get()?;
1914 let mod_ref = source.get()?;
1915 let init_name = source.get()?;
1916 let param = source.get()?;
1917 Ok(InitContractPayload {
1918 amount,
1919 mod_ref,
1920 init_name,
1921 param,
1922 })
1923 }
1924}
1925
1926impl Serial for UpdateContractPayload {
1927 fn serial<B: Buffer>(&self, out: &mut B) {
1928 out.put(&self.amount);
1929 out.put(&self.address);
1930 out.put(&self.receive_name);
1931 out.put(&self.message);
1932 }
1933}
1934
1935impl Deserial for UpdateContractPayload {
1936 fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
1937 let amount = source.get()?;
1938 let address = source.get()?;
1939 let receive_name = source.get()?;
1940 let message = source.get()?;
1941 Ok(UpdateContractPayload {
1942 amount,
1943 address,
1944 receive_name,
1945 message,
1946 })
1947 }
1948}
1949
1950impl<P: PayloadLike> Serial for BlockItem<P> {
1951 fn serial<B: Buffer>(&self, out: &mut B) {
1952 match &self {
1953 BlockItem::AccountTransaction(at) => {
1954 out.put(&0u8);
1955 out.put(at)
1956 }
1957 BlockItem::CredentialDeployment(acdi) => {
1958 out.put(&1u8);
1959 out.put(acdi);
1960 }
1961 BlockItem::UpdateInstruction(ui) => {
1962 out.put(&2u8);
1963 out.put(ui);
1964 }
1965 }
1966 }
1967}
1968
1969impl Deserial for BlockItem<EncodedPayload> {
1970 fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
1971 let tag: u8 = source.get()?;
1972 match tag {
1973 0 => {
1974 let at = source.get()?;
1975 Ok(BlockItem::AccountTransaction(at))
1976 }
1977 1 => {
1978 let acdi = source.get()?;
1979 Ok(BlockItem::CredentialDeployment(acdi))
1980 }
1981 2 => {
1982 let ui = source.get()?;
1983 Ok(BlockItem::UpdateInstruction(ui))
1984 }
1985 _ => anyhow::bail!("Unsupported block item type: {}.", tag),
1986 }
1987 }
1988}
1989
1990pub mod cost {
1992 use crate::id::types::CredentialType;
1993
1994 use super::*;
1995
1996 pub const A: u64 = 100;
1999
2000 pub const B: u64 = 1;
2003
2004 pub fn base_cost(transaction_size: u64, num_signatures: u32) -> Energy {
2008 Energy::from(B * transaction_size + A * u64::from(num_signatures))
2009 }
2010
2011 pub const SIMPLE_TRANSFER: Energy = Energy { energy: 300 };
2013
2014 pub const PLT_OPERATIONS_TRANSACTIONS: Energy = Energy { energy: 300 };
2017
2018 pub const PLT_TRANSFER: Energy = Energy { energy: 100 };
2020
2021 pub const PLT_MINT: Energy = Energy { energy: 50 };
2023
2024 pub const PLT_BURN: Energy = Energy { energy: 50 };
2026
2027 pub const PLT_LIST_UPDATE: Energy = Energy { energy: 50 };
2029
2030 pub const PLT_PAUSE: Energy = Energy { energy: 50 };
2032
2033 #[deprecated(
2035 since = "5.0.1",
2036 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
2037 )]
2038 pub const ENCRYPTED_TRANSFER: Energy = Energy { energy: 27000 };
2039
2040 #[deprecated(
2042 since = "5.0.1",
2043 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
2044 )]
2045 pub const TRANSFER_TO_ENCRYPTED: Energy = Energy { energy: 600 };
2046
2047 pub const TRANSFER_TO_PUBLIC: Energy = Energy { energy: 14850 };
2049
2050 pub fn scheduled_transfer(num_releases: u16) -> Energy {
2052 Energy::from(u64::from(num_releases) * (300 + 64))
2053 }
2054
2055 pub const ADD_BAKER: Energy = Energy { energy: 4050 };
2057
2058 pub const UPDATE_BAKER_KEYS: Energy = Energy { energy: 4050 };
2060
2061 pub const UPDATE_BAKER_STAKE: Energy = Energy { energy: 300 };
2064
2065 pub const UPDATE_BAKER_RESTAKE: Energy = Energy { energy: 300 };
2067
2068 pub const REMOVE_BAKER: Energy = Energy { energy: 300 };
2070
2071 pub fn update_credential_keys(num_credentials_before: u16, num_keys: u16) -> Energy {
2076 Energy {
2077 energy: 500u64 * u64::from(num_credentials_before) + 100 * u64::from(num_keys),
2078 }
2079 }
2080
2081 pub fn update_credentials(num_credentials_before: u16, num_keys: &[u16]) -> Energy {
2085 UPDATE_CREDENTIALS_BASE + update_credentials_variable(num_credentials_before, num_keys)
2086 }
2087
2088 pub const REGISTER_DATA: Energy = Energy { energy: 300 };
2090
2091 pub const CONFIGURE_BAKER_WITH_KEYS: Energy = Energy { energy: 4050 };
2093
2094 pub const CONFIGURE_BAKER_WITHOUT_KEYS: Energy = Energy { energy: 300 };
2097
2098 pub const CONFIGURE_DELEGATION: Energy = Energy { energy: 300 };
2100
2101 pub fn deploy_module(module_size: u64) -> Energy {
2105 Energy::from(module_size / 10)
2106 }
2107
2108 const UPDATE_CREDENTIALS_BASE: Energy = Energy { energy: 500 };
2114
2115 pub fn deploy_credential(ty: CredentialType, num_keys: u16) -> Energy {
2118 match ty {
2119 CredentialType::Initial => Energy::from(1000 + 100 * u64::from(num_keys)),
2120 CredentialType::Normal => Energy::from(54000 + 100 * u64::from(num_keys)),
2121 }
2122 }
2123
2124 fn update_credentials_variable(num_credentials_before: u16, num_keys: &[u16]) -> Energy {
2127 let energy: u64 = 500 * u64::from(num_credentials_before)
2133 + num_keys
2134 .iter()
2135 .map(|&nk| u64::from(deploy_credential(CredentialType::Normal, nk)))
2136 .sum::<u64>();
2137 Energy::from(energy)
2138 }
2139}
2140
2141pub mod construct {
2146 use super::*;
2147 use crate::common::upward::Upward;
2148 use crate::{
2149 common::cbor,
2150 protocol_level_tokens::{RawCbor, TokenId, TokenOperation, TokenOperations},
2151 };
2152
2153 #[derive(Debug, Clone, SerdeSerialize)]
2157 #[serde(rename_all = "camelCase")]
2158 pub struct PreAccountTransaction {
2159 pub header: TransactionHeader,
2160 pub payload: Payload,
2162 #[serde(skip_serializing)]
2166 pub encoded: EncodedPayload,
2167 pub hash_to_sign: hashes::TransactionSignHash,
2169 }
2170
2171 impl PreAccountTransaction {
2172 pub fn sign(self, signer: &impl TransactionSigner) -> AccountTransaction<EncodedPayload> {
2177 sign_transaction(signer, self.header, self.encoded)
2178 }
2179 }
2180
2181 impl Serial for PreAccountTransaction {
2184 fn serial<B: Buffer>(&self, out: &mut B) {
2185 self.header.serial(out);
2186 self.encoded.serial(out);
2187 }
2188 }
2189
2190 impl Deserial for PreAccountTransaction {
2191 fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
2192 let header: TransactionHeader = source.get()?;
2193 let encoded = get_encoded_payload(source, header.payload_size)?;
2194 let payload = encoded.decode()?;
2195 let hash_to_sign = compute_transaction_sign_hash(&header, &encoded);
2196 Ok(Self {
2197 header,
2198 payload,
2199 encoded,
2200 hash_to_sign,
2201 })
2202 }
2203 }
2204
2205 struct TransactionBuilder {
2217 header: TransactionHeader,
2218 payload: Payload,
2219 encoded: EncodedPayload,
2220 }
2221
2222 pub const TRANSACTION_HEADER_SIZE: u64 = 32 + 8 + 8 + 4 + 8;
2226
2227 impl TransactionBuilder {
2228 pub fn new(
2229 sender: AccountAddress,
2230 nonce: Nonce,
2231 expiry: TransactionTime,
2232 payload: Payload,
2233 ) -> Self {
2234 let encoded = payload.encode();
2235 let header = TransactionHeader {
2236 sender,
2237 nonce,
2238 energy_amount: 0.into(),
2239 payload_size: encoded.size(),
2240 expiry,
2241 };
2242 Self {
2243 header,
2244 payload,
2245 encoded,
2246 }
2247 }
2248
2249 #[inline]
2250 fn size(&self) -> u64 {
2251 TRANSACTION_HEADER_SIZE + u64::from(u32::from(self.header.payload_size))
2252 }
2253
2254 #[inline]
2255 pub fn construct(mut self, f: impl FnOnce(u64) -> Energy) -> PreAccountTransaction {
2256 let size = self.size();
2257 self.header.energy_amount = f(size);
2258 let hash_to_sign = compute_transaction_sign_hash(&self.header, &self.encoded);
2259 PreAccountTransaction {
2260 header: self.header,
2261 payload: self.payload,
2262 encoded: self.encoded,
2263 hash_to_sign,
2264 }
2265 }
2266 }
2267
2268 pub fn transfer(
2270 num_sigs: u32,
2271 sender: AccountAddress,
2272 nonce: Nonce,
2273 expiry: TransactionTime,
2274 receiver: AccountAddress,
2275 amount: Amount,
2276 ) -> PreAccountTransaction {
2277 let payload = Payload::Transfer {
2278 to_address: receiver,
2279 amount,
2280 };
2281 make_transaction(
2282 sender,
2283 nonce,
2284 expiry,
2285 GivenEnergy::Add {
2286 num_sigs,
2287 energy: cost::SIMPLE_TRANSFER,
2288 },
2289 payload,
2290 )
2291 }
2292
2293 pub fn transfer_with_memo(
2295 num_sigs: u32,
2296 sender: AccountAddress,
2297 nonce: Nonce,
2298 expiry: TransactionTime,
2299 receiver: AccountAddress,
2300 amount: Amount,
2301 memo: Memo,
2302 ) -> PreAccountTransaction {
2303 let payload = Payload::TransferWithMemo {
2304 to_address: receiver,
2305 memo,
2306 amount,
2307 };
2308 make_transaction(
2309 sender,
2310 nonce,
2311 expiry,
2312 GivenEnergy::Add {
2313 num_sigs,
2314 energy: cost::SIMPLE_TRANSFER,
2315 },
2316 payload,
2317 )
2318 }
2319
2320 fn token_operations_txn_energy(operations: &TokenOperations) -> Energy {
2322 cost::PLT_OPERATIONS_TRANSACTIONS
2323 + operations
2324 .operations
2325 .iter()
2326 .map(|op| match op {
2327 Upward::Known(TokenOperation::Transfer(_)) => cost::PLT_TRANSFER,
2328 Upward::Known(TokenOperation::Mint(_)) => cost::PLT_MINT,
2329 Upward::Known(TokenOperation::Burn(_)) => cost::PLT_BURN,
2330 Upward::Known(TokenOperation::AddAllowList(_))
2331 | Upward::Known(TokenOperation::RemoveAllowList(_))
2332 | Upward::Known(TokenOperation::AddDenyList(_))
2333 | Upward::Known(TokenOperation::RemoveDenyList(_)) => cost::PLT_LIST_UPDATE,
2334 Upward::Known(TokenOperation::Pause(_))
2335 | Upward::Known(TokenOperation::Unpause(_)) => cost::PLT_PAUSE,
2336 Upward::Unknown(_) => Default::default(),
2337 })
2338 .sum()
2339 }
2340
2341 pub fn token_update_operations(
2347 num_sigs: u32,
2348 sender: AccountAddress,
2349 nonce: Nonce,
2350 expiry: TransactionTime,
2351 token_id: TokenId,
2352 operations: TokenOperations,
2353 ) -> CborSerializationResult<PreAccountTransaction> {
2354 let energy = token_operations_txn_energy(&operations);
2355 let operations = RawCbor::from(cbor::cbor_encode(&operations)?);
2356
2357 let payload = Payload::TokenUpdate {
2358 payload: TokenOperationsPayload {
2359 token_id,
2360 operations,
2361 },
2362 };
2363 Ok(make_transaction(
2364 sender,
2365 nonce,
2366 expiry,
2367 GivenEnergy::Add { num_sigs, energy },
2368 payload,
2369 ))
2370 }
2371
2372 #[deprecated(
2375 since = "5.0.1",
2376 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
2377 )]
2378 pub fn encrypted_transfer(
2379 num_sigs: u32,
2380 sender: AccountAddress,
2381 nonce: Nonce,
2382 expiry: TransactionTime,
2383 receiver: AccountAddress,
2384 data: EncryptedAmountTransferData<EncryptedAmountsCurve>,
2385 ) -> PreAccountTransaction {
2386 let payload = Payload::EncryptedAmountTransfer {
2387 to: receiver,
2388 data: Box::new(data),
2389 };
2390 make_transaction(
2391 sender,
2392 nonce,
2393 expiry,
2394 GivenEnergy::Add {
2395 num_sigs,
2396 energy: cost::ENCRYPTED_TRANSFER,
2397 },
2398 payload,
2399 )
2400 }
2401
2402 #[deprecated(
2406 since = "5.0.1",
2407 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
2408 )]
2409 pub fn encrypted_transfer_with_memo(
2410 num_sigs: u32,
2411 sender: AccountAddress,
2412 nonce: Nonce,
2413 expiry: TransactionTime,
2414 receiver: AccountAddress,
2415 data: EncryptedAmountTransferData<EncryptedAmountsCurve>,
2416 memo: Memo,
2417 ) -> PreAccountTransaction {
2418 let payload = Payload::EncryptedAmountTransferWithMemo {
2420 to: receiver,
2421 memo,
2422 data: Box::new(data),
2423 };
2424 make_transaction(
2425 sender,
2426 nonce,
2427 expiry,
2428 GivenEnergy::Add {
2429 num_sigs,
2430 energy: cost::ENCRYPTED_TRANSFER,
2431 },
2432 payload,
2433 )
2434 }
2435
2436 #[deprecated(
2439 since = "5.0.1",
2440 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
2441 )]
2442 pub fn transfer_to_encrypted(
2443 num_sigs: u32,
2444 sender: AccountAddress,
2445 nonce: Nonce,
2446 expiry: TransactionTime,
2447 amount: Amount,
2448 ) -> PreAccountTransaction {
2449 let payload = Payload::TransferToEncrypted { amount };
2450 make_transaction(
2451 sender,
2452 nonce,
2453 expiry,
2454 GivenEnergy::Add {
2455 num_sigs,
2456 energy: cost::TRANSFER_TO_ENCRYPTED,
2457 },
2458 payload,
2459 )
2460 }
2461
2462 pub fn transfer_to_public(
2468 num_sigs: u32,
2469 sender: AccountAddress,
2470 nonce: Nonce,
2471 expiry: TransactionTime,
2472 data: SecToPubAmountTransferData<EncryptedAmountsCurve>,
2473 ) -> PreAccountTransaction {
2474 let payload = Payload::TransferToPublic {
2476 data: Box::new(data),
2477 };
2478 make_transaction(
2479 sender,
2480 nonce,
2481 expiry,
2482 GivenEnergy::Add {
2483 num_sigs,
2484 energy: cost::TRANSFER_TO_PUBLIC,
2485 },
2486 payload,
2487 )
2488 }
2489
2490 pub fn transfer_with_schedule(
2493 num_sigs: u32,
2494 sender: AccountAddress,
2495 nonce: Nonce,
2496 expiry: TransactionTime,
2497 receiver: AccountAddress,
2498 schedule: Vec<(Timestamp, Amount)>,
2499 ) -> PreAccountTransaction {
2500 let num_releases = schedule.len() as u16;
2501 let payload = Payload::TransferWithSchedule {
2502 to: receiver,
2503 schedule,
2504 };
2505 make_transaction(
2506 sender,
2507 nonce,
2508 expiry,
2509 GivenEnergy::Add {
2510 num_sigs,
2511 energy: cost::scheduled_transfer(num_releases),
2512 },
2513 payload,
2514 )
2515 }
2516
2517 pub fn transfer_with_schedule_and_memo(
2520 num_sigs: u32,
2521 sender: AccountAddress,
2522 nonce: Nonce,
2523 expiry: TransactionTime,
2524 receiver: AccountAddress,
2525 schedule: Vec<(Timestamp, Amount)>,
2526 memo: Memo,
2527 ) -> PreAccountTransaction {
2528 let num_releases = schedule.len() as u16;
2529 let payload = Payload::TransferWithScheduleAndMemo {
2530 to: receiver,
2531 memo,
2532 schedule,
2533 };
2534 make_transaction(
2535 sender,
2536 nonce,
2537 expiry,
2538 GivenEnergy::Add {
2539 num_sigs,
2540 energy: cost::scheduled_transfer(num_releases),
2541 },
2542 payload,
2543 )
2544 }
2545
2546 #[deprecated(
2552 since = "2.0.0",
2553 note = "This transaction only applies to protocol versions 1-3. Use configure_baker \
2554 instead."
2555 )]
2556 #[doc(hidden)]
2557 pub fn add_baker(
2558 num_sigs: u32,
2559 sender: AccountAddress,
2560 nonce: Nonce,
2561 expiry: TransactionTime,
2562 baking_stake: Amount,
2563 restake_earnings: bool,
2564 keys: BakerAddKeysPayload,
2565 ) -> PreAccountTransaction {
2566 let payload = Payload::AddBaker {
2567 payload: Box::new(AddBakerPayload {
2568 keys,
2569 baking_stake,
2570 restake_earnings,
2571 }),
2572 };
2573 make_transaction(
2574 sender,
2575 nonce,
2576 expiry,
2577 GivenEnergy::Add {
2578 num_sigs,
2579 energy: cost::ADD_BAKER,
2580 },
2581 payload,
2582 )
2583 }
2584
2585 #[deprecated(
2591 since = "2.0.0",
2592 note = "This transaction only applies to protocol versions 1-3. Use configure_baker \
2593 instead."
2594 )]
2595 #[doc(hidden)]
2596 pub fn update_baker_keys(
2597 num_sigs: u32,
2598 sender: AccountAddress,
2599 nonce: Nonce,
2600 expiry: TransactionTime,
2601 keys: BakerUpdateKeysPayload,
2602 ) -> PreAccountTransaction {
2603 let payload = Payload::UpdateBakerKeys {
2605 payload: Box::new(keys),
2606 };
2607 make_transaction(
2608 sender,
2609 nonce,
2610 expiry,
2611 GivenEnergy::Add {
2612 num_sigs,
2613 energy: cost::UPDATE_BAKER_KEYS,
2614 },
2615 payload,
2616 )
2617 }
2618
2619 #[deprecated(
2625 since = "2.0.0",
2626 note = "This transaction only applies to protocol versions 1-3. Use configure_baker \
2627 instead."
2628 )]
2629 #[doc(hidden)]
2630 pub fn remove_baker(
2631 num_sigs: u32,
2632 sender: AccountAddress,
2633 nonce: Nonce,
2634 expiry: TransactionTime,
2635 ) -> PreAccountTransaction {
2636 let payload = Payload::RemoveBaker;
2638 make_transaction(
2639 sender,
2640 nonce,
2641 expiry,
2642 GivenEnergy::Add {
2643 num_sigs,
2644 energy: cost::REMOVE_BAKER,
2645 },
2646 payload,
2647 )
2648 }
2649
2650 #[deprecated(
2656 since = "2.0.0",
2657 note = "This transaction only applies to protocol versions 1-3. Use configure_baker \
2658 instead."
2659 )]
2660 #[doc(hidden)]
2661 pub fn update_baker_stake(
2662 num_sigs: u32,
2663 sender: AccountAddress,
2664 nonce: Nonce,
2665 expiry: TransactionTime,
2666 new_stake: Amount,
2667 ) -> PreAccountTransaction {
2668 let payload = Payload::UpdateBakerStake { stake: new_stake };
2670 make_transaction(
2671 sender,
2672 nonce,
2673 expiry,
2674 GivenEnergy::Add {
2675 num_sigs,
2676 energy: cost::UPDATE_BAKER_STAKE,
2677 },
2678 payload,
2679 )
2680 }
2681
2682 #[deprecated(
2689 since = "2.0.0",
2690 note = "This transaction only applies to protocol versions 1-3. Use configure_baker \
2691 instead."
2692 )]
2693 #[doc(hidden)]
2694 pub fn update_baker_restake_earnings(
2695 num_sigs: u32,
2696 sender: AccountAddress,
2697 nonce: Nonce,
2698 expiry: TransactionTime,
2699 restake_earnings: bool,
2700 ) -> PreAccountTransaction {
2701 let payload = Payload::UpdateBakerRestakeEarnings { restake_earnings };
2703 make_transaction(
2704 sender,
2705 nonce,
2706 expiry,
2707 GivenEnergy::Add {
2708 num_sigs,
2709 energy: cost::UPDATE_BAKER_RESTAKE,
2710 },
2711 payload,
2712 )
2713 }
2714
2715 pub fn register_data(
2717 num_sigs: u32,
2718 sender: AccountAddress,
2719 nonce: Nonce,
2720 expiry: TransactionTime,
2721 data: RegisteredData,
2722 ) -> PreAccountTransaction {
2723 let payload = Payload::RegisterData { data };
2724 make_transaction(
2725 sender,
2726 nonce,
2727 expiry,
2728 GivenEnergy::Add {
2729 num_sigs,
2730 energy: cost::REGISTER_DATA,
2731 },
2732 payload,
2733 )
2734 }
2735
2736 pub fn deploy_module(
2739 num_sigs: u32,
2740 sender: AccountAddress,
2741 nonce: Nonce,
2742 expiry: TransactionTime,
2743 module: smart_contracts::WasmModule,
2744 ) -> PreAccountTransaction {
2745 let module_size = module.source.size();
2746 let payload = Payload::DeployModule { module };
2747 make_transaction(
2748 sender,
2749 nonce,
2750 expiry,
2751 GivenEnergy::Add {
2752 num_sigs,
2753 energy: cost::deploy_module(module_size),
2754 },
2755 payload,
2756 )
2757 }
2758
2759 pub fn init_contract(
2765 num_sigs: u32,
2766 sender: AccountAddress,
2767 nonce: Nonce,
2768 expiry: TransactionTime,
2769 payload: InitContractPayload,
2770 energy: Energy,
2771 ) -> PreAccountTransaction {
2772 let payload = Payload::InitContract { payload };
2773 make_transaction(
2774 sender,
2775 nonce,
2776 expiry,
2777 GivenEnergy::Add { num_sigs, energy },
2778 payload,
2779 )
2780 }
2781
2782 pub fn update_contract(
2788 num_sigs: u32,
2789 sender: AccountAddress,
2790 nonce: Nonce,
2791 expiry: TransactionTime,
2792 payload: UpdateContractPayload,
2793 energy: Energy,
2794 ) -> PreAccountTransaction {
2795 let payload = Payload::Update { payload };
2796 make_transaction(
2797 sender,
2798 nonce,
2799 expiry,
2800 GivenEnergy::Add { num_sigs, energy },
2801 payload,
2802 )
2803 }
2804
2805 pub fn configure_baker(
2808 num_sigs: u32,
2809 sender: AccountAddress,
2810 nonce: Nonce,
2811 expiry: TransactionTime,
2812 payload: ConfigureBakerPayload,
2813 ) -> PreAccountTransaction {
2814 let energy = if payload.keys_with_proofs.is_some() {
2815 cost::CONFIGURE_BAKER_WITH_KEYS
2816 } else {
2817 cost::CONFIGURE_BAKER_WITHOUT_KEYS
2818 };
2819 let payload = Payload::ConfigureBaker {
2820 data: Box::new(payload),
2821 };
2822 make_transaction(
2823 sender,
2824 nonce,
2825 expiry,
2826 GivenEnergy::Add { num_sigs, energy },
2827 payload,
2828 )
2829 }
2830
2831 pub fn configure_delegation(
2834 num_sigs: u32,
2835 sender: AccountAddress,
2836 nonce: Nonce,
2837 expiry: TransactionTime,
2838 payload: ConfigureDelegationPayload,
2839 ) -> PreAccountTransaction {
2840 let payload = Payload::ConfigureDelegation { data: payload };
2841 make_transaction(
2842 sender,
2843 nonce,
2844 expiry,
2845 GivenEnergy::Add {
2846 num_sigs,
2847 energy: cost::CONFIGURE_DELEGATION,
2848 },
2849 payload,
2850 )
2851 }
2852
2853 pub fn update_credential_keys(
2862 num_sigs: u32,
2863 sender: AccountAddress,
2864 nonce: Nonce,
2865 expiry: TransactionTime,
2866 num_existing_credentials: u16,
2867 cred_id: CredentialRegistrationID,
2868 keys: CredentialPublicKeys,
2869 ) -> PreAccountTransaction {
2870 let num_cred_keys = keys.keys.len() as u16;
2871 let payload = Payload::UpdateCredentialKeys { cred_id, keys };
2872 make_transaction(
2873 sender,
2874 nonce,
2875 expiry,
2876 GivenEnergy::Add {
2877 energy: cost::update_credential_keys(num_existing_credentials, num_cred_keys),
2878 num_sigs,
2879 },
2880 payload,
2881 )
2882 }
2883
2884 #[allow(clippy::too_many_arguments)]
2897 pub fn update_credentials(
2898 num_sigs: u32,
2899 sender: AccountAddress,
2900 nonce: Nonce,
2901 expiry: TransactionTime,
2902 num_existing_credentials: u16,
2903 new_credentials: AccountCredentialsMap,
2904 remove_credentials: Vec<CredentialRegistrationID>,
2905 new_threshold: AccountThreshold,
2906 ) -> PreAccountTransaction {
2907 let num_cred_keys = new_credentials
2908 .values()
2909 .map(|v| v.values.cred_key_info.keys.len() as u16)
2910 .collect::<Vec<_>>();
2911 let payload = Payload::UpdateCredentials {
2912 new_cred_infos: new_credentials,
2913 remove_cred_ids: remove_credentials,
2914 new_threshold,
2915 };
2916 make_transaction(
2917 sender,
2918 nonce,
2919 expiry,
2920 GivenEnergy::Add {
2921 energy: cost::update_credentials(num_existing_credentials, &num_cred_keys),
2922 num_sigs,
2923 },
2924 payload,
2925 )
2926 }
2927
2928 pub enum GivenEnergy {
2936 Absolute(Energy),
2938 Add { energy: Energy, num_sigs: u32 },
2941 }
2942
2943 pub fn make_transaction(
2947 sender: AccountAddress,
2948 nonce: Nonce,
2949 expiry: TransactionTime,
2950 energy: GivenEnergy,
2951 payload: Payload,
2952 ) -> PreAccountTransaction {
2953 let builder = TransactionBuilder::new(sender, nonce, expiry, payload);
2954 let cost = |size| match energy {
2955 GivenEnergy::Absolute(energy) => energy,
2956 GivenEnergy::Add { num_sigs, energy } => cost::base_cost(size, num_sigs) + energy,
2957 };
2958 builder.construct(cost)
2959 }
2960}
2961
2962pub mod send {
2966 use super::*;
2967 use crate::protocol_level_tokens::{TokenId, TokenOperations};
2968
2969 pub fn transfer(
2971 signer: &impl ExactSizeTransactionSigner,
2972 sender: AccountAddress,
2973 nonce: Nonce,
2974 expiry: TransactionTime,
2975 receiver: AccountAddress,
2976 amount: Amount,
2977 ) -> AccountTransaction<EncodedPayload> {
2978 construct::transfer(signer.num_keys(), sender, nonce, expiry, receiver, amount).sign(signer)
2979 }
2980
2981 pub fn transfer_with_memo(
2983 signer: &impl ExactSizeTransactionSigner,
2984 sender: AccountAddress,
2985 nonce: Nonce,
2986 expiry: TransactionTime,
2987 receiver: AccountAddress,
2988 amount: Amount,
2989 memo: Memo,
2990 ) -> AccountTransaction<EncodedPayload> {
2991 construct::transfer_with_memo(
2992 signer.num_keys(),
2993 sender,
2994 nonce,
2995 expiry,
2996 receiver,
2997 amount,
2998 memo,
2999 )
3000 .sign(signer)
3001 }
3002
3003 pub fn token_update_operations(
3009 signer: &impl ExactSizeTransactionSigner,
3010 sender: AccountAddress,
3011 nonce: Nonce,
3012 expiry: TransactionTime,
3013 token_id: TokenId,
3014 operations: TokenOperations,
3015 ) -> CborSerializationResult<AccountTransaction<EncodedPayload>> {
3016 Ok(construct::token_update_operations(
3017 signer.num_keys(),
3018 sender,
3019 nonce,
3020 expiry,
3021 token_id,
3022 operations,
3023 )?
3024 .sign(signer))
3025 }
3026
3027 #[deprecated(
3030 since = "5.0.1",
3031 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
3032 )]
3033 pub fn encrypted_transfer(
3034 signer: &impl ExactSizeTransactionSigner,
3035 sender: AccountAddress,
3036 nonce: Nonce,
3037 expiry: TransactionTime,
3038 receiver: AccountAddress,
3039 data: EncryptedAmountTransferData<EncryptedAmountsCurve>,
3040 ) -> AccountTransaction<EncodedPayload> {
3041 construct::encrypted_transfer(signer.num_keys(), sender, nonce, expiry, receiver, data)
3042 .sign(signer)
3043 }
3044
3045 #[deprecated(
3049 since = "5.0.1",
3050 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
3051 )]
3052 pub fn encrypted_transfer_with_memo(
3053 signer: &impl ExactSizeTransactionSigner,
3054 sender: AccountAddress,
3055 nonce: Nonce,
3056 expiry: TransactionTime,
3057 receiver: AccountAddress,
3058 data: EncryptedAmountTransferData<EncryptedAmountsCurve>,
3059 memo: Memo,
3060 ) -> AccountTransaction<EncodedPayload> {
3061 construct::encrypted_transfer_with_memo(
3062 signer.num_keys(),
3063 sender,
3064 nonce,
3065 expiry,
3066 receiver,
3067 data,
3068 memo,
3069 )
3070 .sign(signer)
3071 }
3072
3073 #[deprecated(
3076 since = "5.0.1",
3077 note = "encrypted transfers are deprecated and partially removed since protocol version 7"
3078 )]
3079 pub fn transfer_to_encrypted(
3080 signer: &impl ExactSizeTransactionSigner,
3081 sender: AccountAddress,
3082 nonce: Nonce,
3083 expiry: TransactionTime,
3084 amount: Amount,
3085 ) -> AccountTransaction<EncodedPayload> {
3086 construct::transfer_to_encrypted(signer.num_keys(), sender, nonce, expiry, amount)
3087 .sign(signer)
3088 }
3089
3090 pub fn transfer_to_public(
3097 signer: &impl ExactSizeTransactionSigner,
3098 sender: AccountAddress,
3099 nonce: Nonce,
3100 expiry: TransactionTime,
3101 data: SecToPubAmountTransferData<EncryptedAmountsCurve>,
3102 ) -> AccountTransaction<EncodedPayload> {
3103 construct::transfer_to_public(signer.num_keys(), sender, nonce, expiry, data).sign(signer)
3104 }
3105
3106 pub fn transfer_with_schedule(
3109 signer: &impl ExactSizeTransactionSigner,
3110 sender: AccountAddress,
3111 nonce: Nonce,
3112 expiry: TransactionTime,
3113 receiver: AccountAddress,
3114 schedule: Vec<(Timestamp, Amount)>,
3115 ) -> AccountTransaction<EncodedPayload> {
3116 construct::transfer_with_schedule(
3117 signer.num_keys(),
3118 sender,
3119 nonce,
3120 expiry,
3121 receiver,
3122 schedule,
3123 )
3124 .sign(signer)
3125 }
3126
3127 pub fn transfer_with_schedule_and_memo(
3130 signer: &impl ExactSizeTransactionSigner,
3131 sender: AccountAddress,
3132 nonce: Nonce,
3133 expiry: TransactionTime,
3134 receiver: AccountAddress,
3135 schedule: Vec<(Timestamp, Amount)>,
3136 memo: Memo,
3137 ) -> AccountTransaction<EncodedPayload> {
3138 construct::transfer_with_schedule_and_memo(
3139 signer.num_keys(),
3140 sender,
3141 nonce,
3142 expiry,
3143 receiver,
3144 schedule,
3145 memo,
3146 )
3147 .sign(signer)
3148 }
3149
3150 #[deprecated(
3156 since = "2.0.0",
3157 note = "This transaction only applies to protocol versions 1-3. Use configure_baker \
3158 instead."
3159 )]
3160 #[doc(hidden)]
3161 pub fn add_baker(
3162 signer: &impl ExactSizeTransactionSigner,
3163 sender: AccountAddress,
3164 nonce: Nonce,
3165 expiry: TransactionTime,
3166 baking_stake: Amount,
3167 restake_earnings: bool,
3168 keys: BakerAddKeysPayload,
3169 ) -> AccountTransaction<EncodedPayload> {
3170 construct::add_baker(
3171 signer.num_keys(),
3172 sender,
3173 nonce,
3174 expiry,
3175 baking_stake,
3176 restake_earnings,
3177 keys,
3178 )
3179 .sign(signer)
3180 }
3181
3182 #[deprecated(
3188 since = "2.0.0",
3189 note = "This transaction only applies to protocol versions 1-3. Use configure_baker \
3190 instead."
3191 )]
3192 #[doc(hidden)]
3193 pub fn update_baker_keys(
3194 signer: &impl ExactSizeTransactionSigner,
3195 sender: AccountAddress,
3196 nonce: Nonce,
3197 expiry: TransactionTime,
3198 keys: BakerUpdateKeysPayload,
3199 ) -> AccountTransaction<EncodedPayload> {
3200 construct::update_baker_keys(signer.num_keys(), sender, nonce, expiry, keys).sign(signer)
3201 }
3202
3203 #[deprecated(
3209 since = "2.0.0",
3210 note = "This transaction only applies to protocol versions 1-3. Use configure_baker \
3211 instead."
3212 )]
3213 #[doc(hidden)]
3214 pub fn remove_baker(
3215 signer: &impl ExactSizeTransactionSigner,
3216 sender: AccountAddress,
3217 nonce: Nonce,
3218 expiry: TransactionTime,
3219 ) -> AccountTransaction<EncodedPayload> {
3220 construct::remove_baker(signer.num_keys(), sender, nonce, expiry).sign(signer)
3221 }
3222
3223 #[deprecated(
3225 since = "2.0.0",
3226 note = "This transaction only applies to protocol versions 1-3. Use configure_baker \
3227 instead."
3228 )]
3229 #[doc(hidden)]
3230 pub fn update_baker_stake(
3231 signer: &impl ExactSizeTransactionSigner,
3232 sender: AccountAddress,
3233 nonce: Nonce,
3234 expiry: TransactionTime,
3235 new_stake: Amount,
3236 ) -> AccountTransaction<EncodedPayload> {
3237 construct::update_baker_stake(signer.num_keys(), sender, nonce, expiry, new_stake)
3238 .sign(signer)
3239 }
3240
3241 #[deprecated(
3244 since = "2.0.0",
3245 note = "This transaction only applies to protocol versions 1-3. Use configure_baker \
3246 instead."
3247 )]
3248 #[doc(hidden)]
3249 pub fn update_baker_restake_earnings(
3250 signer: &impl ExactSizeTransactionSigner,
3251 sender: AccountAddress,
3252 nonce: Nonce,
3253 expiry: TransactionTime,
3254 restake_earnings: bool,
3255 ) -> AccountTransaction<EncodedPayload> {
3256 construct::update_baker_restake_earnings(
3257 signer.num_keys(),
3258 sender,
3259 nonce,
3260 expiry,
3261 restake_earnings,
3262 )
3263 .sign(signer)
3264 }
3265
3266 pub fn configure_baker(
3269 signer: &impl ExactSizeTransactionSigner,
3270 sender: AccountAddress,
3271 nonce: Nonce,
3272 expiry: TransactionTime,
3273 payload: ConfigureBakerPayload,
3274 ) -> AccountTransaction<EncodedPayload> {
3275 construct::configure_baker(signer.num_keys(), sender, nonce, expiry, payload).sign(signer)
3276 }
3277
3278 pub fn configure_delegation(
3281 signer: &impl ExactSizeTransactionSigner,
3282 sender: AccountAddress,
3283 nonce: Nonce,
3284 expiry: TransactionTime,
3285 payload: ConfigureDelegationPayload,
3286 ) -> AccountTransaction<EncodedPayload> {
3287 construct::configure_delegation(signer.num_keys(), sender, nonce, expiry, payload)
3288 .sign(signer)
3289 }
3290
3291 pub fn update_credential_keys(
3300 signer: &impl ExactSizeTransactionSigner,
3301 sender: AccountAddress,
3302 nonce: Nonce,
3303 expiry: TransactionTime,
3304 num_existing_credentials: u16,
3305 cred_id: CredentialRegistrationID,
3306 keys: CredentialPublicKeys,
3307 ) -> AccountTransaction<EncodedPayload> {
3308 construct::update_credential_keys(
3309 signer.num_keys(),
3310 sender,
3311 nonce,
3312 expiry,
3313 num_existing_credentials,
3314 cred_id,
3315 keys,
3316 )
3317 .sign(signer)
3318 }
3319
3320 #[allow(clippy::too_many_arguments)]
3333 pub fn update_credentials(
3334 signer: &impl ExactSizeTransactionSigner,
3335 sender: AccountAddress,
3336 nonce: Nonce,
3337 expiry: TransactionTime,
3338 num_existing_credentials: u16,
3339 new_credentials: AccountCredentialsMap,
3340 remove_credentials: Vec<CredentialRegistrationID>,
3341 new_threshold: AccountThreshold,
3342 ) -> AccountTransaction<EncodedPayload> {
3343 construct::update_credentials(
3344 signer.num_keys(),
3345 sender,
3346 nonce,
3347 expiry,
3348 num_existing_credentials,
3349 new_credentials,
3350 remove_credentials,
3351 new_threshold,
3352 )
3353 .sign(signer)
3354 }
3355
3356 pub fn register_data(
3358 signer: &impl ExactSizeTransactionSigner,
3359 sender: AccountAddress,
3360 nonce: Nonce,
3361 expiry: TransactionTime,
3362 data: RegisteredData,
3363 ) -> AccountTransaction<EncodedPayload> {
3364 construct::register_data(signer.num_keys(), sender, nonce, expiry, data).sign(signer)
3365 }
3366
3367 pub fn deploy_module(
3370 signer: &impl ExactSizeTransactionSigner,
3371 sender: AccountAddress,
3372 nonce: Nonce,
3373 expiry: TransactionTime,
3374 module: smart_contracts::WasmModule,
3375 ) -> AccountTransaction<EncodedPayload> {
3376 construct::deploy_module(signer.num_keys(), sender, nonce, expiry, module).sign(signer)
3377 }
3378
3379 pub fn init_contract(
3385 signer: &impl ExactSizeTransactionSigner,
3386 sender: AccountAddress,
3387 nonce: Nonce,
3388 expiry: TransactionTime,
3389 payload: InitContractPayload,
3390 energy: Energy,
3391 ) -> AccountTransaction<EncodedPayload> {
3392 construct::init_contract(signer.num_keys(), sender, nonce, expiry, payload, energy)
3393 .sign(signer)
3394 }
3395
3396 pub fn update_contract(
3402 signer: &impl ExactSizeTransactionSigner,
3403 sender: AccountAddress,
3404 nonce: Nonce,
3405 expiry: TransactionTime,
3406 payload: UpdateContractPayload,
3407 energy: Energy,
3408 ) -> AccountTransaction<EncodedPayload> {
3409 construct::update_contract(signer.num_keys(), sender, nonce, expiry, payload, energy)
3410 .sign(signer)
3411 }
3412
3413 #[derive(Debug, Copy, Clone)]
3414 pub enum GivenEnergy {
3422 Absolute(Energy),
3424 Add(Energy),
3427 }
3428
3429 pub fn make_and_sign_transaction(
3433 signer: &impl ExactSizeTransactionSigner,
3434 sender: AccountAddress,
3435 nonce: Nonce,
3436 expiry: TransactionTime,
3437 energy: GivenEnergy,
3438 payload: Payload,
3439 ) -> AccountTransaction<EncodedPayload> {
3440 match energy {
3441 GivenEnergy::Absolute(energy) => construct::make_transaction(
3442 sender,
3443 nonce,
3444 expiry,
3445 construct::GivenEnergy::Absolute(energy),
3446 payload,
3447 )
3448 .sign(signer),
3449 GivenEnergy::Add(energy) => construct::make_transaction(
3450 sender,
3451 nonce,
3452 expiry,
3453 construct::GivenEnergy::Add {
3454 energy,
3455 num_sigs: signer.num_keys(),
3456 },
3457 payload,
3458 )
3459 .sign(signer),
3460 }
3461 }
3462}
3463
3464#[cfg(test)]
3465mod tests {
3466 use crate::{
3467 hashes::TransactionSignHash,
3468 id::types::{SignatureThreshold, VerifyKey},
3469 };
3470 use rand::Rng;
3471 use std::convert::TryFrom;
3472
3473 use super::*;
3474 #[test]
3475 fn test_transaction_signature_check() {
3476 let mut rng = rand::thread_rng();
3477 let mut keys = BTreeMap::<CredentialIndex, BTreeMap<KeyIndex, KeyPair>>::new();
3478 let bound: usize = rng.gen_range(1..20);
3479 for _ in 0..bound {
3480 let c_idx = CredentialIndex::from(rng.gen::<u8>());
3481 if keys.get(&c_idx).is_none() {
3482 let inner_bound: usize = rng.gen_range(1..20);
3483 let mut cred_keys = BTreeMap::new();
3484 for _ in 0..inner_bound {
3485 let k_idx = KeyIndex::from(rng.gen::<u8>());
3486 cred_keys.insert(k_idx, KeyPair::generate(&mut rng));
3487 }
3488 keys.insert(c_idx, cred_keys);
3489 }
3490 }
3491 let hash = TransactionSignHash::new(rng.gen());
3492 let sig = keys.sign_transaction_hash(&hash);
3493 let threshold =
3494 AccountThreshold::try_from(rng.gen_range(1..(keys.len() + 1) as u8)).unwrap();
3495 let pub_keys = keys
3496 .iter()
3497 .map(|(&ci, keys)| {
3498 let threshold =
3499 SignatureThreshold::try_from(rng.gen_range(1..keys.len() + 1) as u8).unwrap();
3500 let keys = keys
3501 .iter()
3502 .map(|(&ki, kp)| (ki, VerifyKey::from(kp)))
3503 .collect();
3504 (ci, CredentialPublicKeys { keys, threshold })
3505 })
3506 .collect::<BTreeMap<_, _>>();
3507 let mut access_structure = AccountAccessStructure {
3508 threshold,
3509 keys: pub_keys,
3510 };
3511 assert!(
3512 verify_signature_transaction_sign_hash(&access_structure, &hash, &sig),
3513 "Transaction signature must validate."
3514 );
3515
3516 access_structure.threshold = AccountThreshold::try_from((keys.len() + 1) as u8).unwrap();
3517
3518 assert!(
3519 !verify_signature_transaction_sign_hash(&access_structure, &hash, &sig),
3520 "Transaction signature must not validate with invalid threshold."
3521 );
3522 }
3523}