hedera/schedule/
schedule_info.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use hedera_proto::services;
4use time::OffsetDateTime;
5
6use super::schedulable_transaction_body::SchedulableTransactionBody;
7use crate::protobuf::ToProtobuf;
8use crate::transaction::TransactionBody;
9use crate::{
10    AccountId,
11    AnyTransaction,
12    FromProtobuf,
13    Key,
14    KeyList,
15    LedgerId,
16    ScheduleId,
17    Transaction,
18    TransactionId,
19};
20
21// TODO: scheduled_transaction
22/// Response from [`ScheduleInfoQuery`][crate::ScheduleInfoQuery].
23#[derive(Debug, Clone)]
24pub struct ScheduleInfo {
25    /// The ID of the schedule for which information is requested.
26    pub schedule_id: ScheduleId,
27
28    /// The account that created the scheduled transaction.
29    pub creator_account_id: AccountId,
30
31    /// The account paying for the execution of the scheduled transaction.
32    pub payer_account_id: Option<AccountId>,
33
34    /// The signatories that have provided signatures so far for the schedule
35    /// transaction.
36    pub signatories: KeyList,
37
38    /// The key which is able to delete the schedule transaction if set.
39    pub admin_key: Option<Key>,
40
41    /// The transaction id that will be used in the record of the scheduled transaction (if
42    /// it executes).
43    pub scheduled_transaction_id: TransactionId,
44
45    scheduled_transaction: SchedulableTransactionBody,
46
47    /// When set to true, the transaction will be evaluated for execution at `expiration_time`
48    /// instead of when all required signatures are received.
49    pub wait_for_expiry: bool,
50
51    /// Publicly visible information about the Schedule entity.
52    pub memo: String,
53
54    /// The date and time the schedule transaction will expire
55    pub expiration_time: Option<OffsetDateTime>,
56
57    /// The time the schedule transaction was executed.
58    pub executed_at: Option<OffsetDateTime>,
59
60    /// The time the schedule transaction was deleted.
61    pub deleted_at: Option<OffsetDateTime>,
62
63    /// The ledger ID the response was returned from
64    pub ledger_id: LedgerId,
65}
66
67impl ScheduleInfo {
68    /// Create a new `ScheduleInfo` from protobuf-encoded `bytes`.
69    ///
70    /// # Errors
71    /// - [`Error::FromProtobuf`](crate::Error::FromProtobuf) if decoding the bytes fails to produce a valid protobuf.
72    /// - [`Error::FromProtobuf`](crate::Error::FromProtobuf) if decoding the protobuf fails.
73    pub fn from_bytes(bytes: &[u8]) -> crate::Result<Self> {
74        FromProtobuf::<services::ScheduleInfo>::from_bytes(bytes)
75    }
76
77    /// Returns the scheduled transaction.
78    ///
79    /// This is *not* guaranteed to be a constant time operation.
80    pub fn scheduled_transaction(&self) -> crate::Result<AnyTransaction> {
81        // note: this can't error *right now* but the API *will* be faliable eventually, and as such, returns a result to make the change non-breaking.
82        Ok(Transaction::from_parts(
83            TransactionBody {
84                data: (*self.scheduled_transaction.data).clone().into(),
85                node_account_ids: None,
86                transaction_valid_duration: None,
87                max_transaction_fee: None,
88                transaction_memo: self.scheduled_transaction.transaction_memo.clone(),
89                transaction_id: Some(self.scheduled_transaction_id),
90                operator: None,
91                is_frozen: true,
92                regenerate_transaction_id: Some(false),
93                custom_fee_limits: Vec::new(),
94                batch_key: None,
95            },
96            Vec::new(),
97        ))
98    }
99
100    /// Convert `self` to a protobuf-encoded [`Vec<u8>`].
101    #[must_use]
102    pub fn to_bytes(&self) -> Vec<u8> {
103        ToProtobuf::to_bytes(self)
104    }
105}
106
107impl FromProtobuf<services::response::Response> for ScheduleInfo {
108    #[allow(deprecated)]
109    fn from_protobuf(pb: services::response::Response) -> crate::Result<Self>
110    where
111        Self: Sized,
112    {
113        let response = pb_getv!(pb, ScheduleGetInfo, services::response::Response);
114        let info = pb_getf!(response, schedule_info)?;
115        Self::from_protobuf(info)
116    }
117}
118
119impl FromProtobuf<services::ScheduleInfo> for ScheduleInfo {
120    fn from_protobuf(pb: services::ScheduleInfo) -> crate::Result<Self>
121    where
122        Self: Sized,
123    {
124        let schedule_id = pb_getf!(pb, schedule_id)?;
125        let creator_account_id = pb_getf!(pb, creator_account_id)?;
126        let payer_account_id = Option::from_protobuf(pb.payer_account_id)?;
127        let admin_key = Option::from_protobuf(pb.admin_key)?;
128        let ledger_id = LedgerId::from_bytes(pb.ledger_id);
129
130        let scheduled_transaction_id =
131            TransactionId::from_protobuf(pb_getf!(pb, scheduled_transaction_id)?)?;
132
133        let transaction_body =
134            SchedulableTransactionBody::from_protobuf(pb_getf!(pb, scheduled_transaction_body)?)?;
135
136        let signatories = pb.signers.map(KeyList::from_protobuf).transpose()?.unwrap_or_default();
137
138        let (executed_at, deleted_at) = match pb.data {
139            Some(services::schedule_info::Data::DeletionTime(deleted)) => {
140                (None, Some(deleted.into()))
141            }
142
143            Some(services::schedule_info::Data::ExecutionTime(executed)) => {
144                (Some(executed.into()), None)
145            }
146
147            None => (None, None),
148        };
149
150        Ok(Self {
151            schedule_id: ScheduleId::from_protobuf(schedule_id)?,
152            executed_at,
153            deleted_at,
154            memo: pb.memo,
155            creator_account_id: AccountId::from_protobuf(creator_account_id)?,
156            payer_account_id,
157            expiration_time: pb.expiration_time.map(Into::into),
158            admin_key,
159            scheduled_transaction_id,
160            signatories,
161            wait_for_expiry: pb.wait_for_expiry,
162            ledger_id,
163            scheduled_transaction: transaction_body,
164        })
165    }
166}
167
168impl ToProtobuf for ScheduleInfo {
169    type Protobuf = services::ScheduleInfo;
170
171    fn to_protobuf(&self) -> Self::Protobuf {
172        services::ScheduleInfo {
173            schedule_id: Some(self.schedule_id.to_protobuf()),
174            expiration_time: self.expiration_time.to_protobuf(),
175            memo: self.memo.clone(),
176            admin_key: self.admin_key.to_protobuf(),
177            signers: (!self.signatories.is_empty())
178                .then(|| services::KeyList { keys: self.signatories.keys.to_protobuf() }),
179            creator_account_id: Some(self.creator_account_id.to_protobuf()),
180            payer_account_id: self.payer_account_id.to_protobuf(),
181            scheduled_transaction_id: Some(self.scheduled_transaction_id.to_protobuf()),
182            ledger_id: self.ledger_id.to_bytes(),
183            wait_for_expiry: self.wait_for_expiry,
184
185            // unimplemented fields
186            scheduled_transaction_body: Some(
187                self.scheduled_transaction.to_scheduled_body_protobuf(),
188            ),
189            data: None,
190        }
191    }
192}
193
194#[cfg(test)]
195mod tests {
196    use expect_test::expect;
197
198    use crate::protobuf::{
199        FromProtobuf,
200        ToProtobuf,
201    };
202    use crate::schedule::schedulable_transaction_body::{
203        AnySchedulableTransactionData,
204        SchedulableTransactionBody,
205    };
206    use crate::transaction::test_helpers::{
207        unused_private_key,
208        VALID_START,
209    };
210    use crate::transaction::ToSchedulableTransactionDataProtobuf;
211    use crate::{
212        AccountDeleteTransaction,
213        LedgerId,
214        ScheduleInfo,
215        TransactionId,
216    };
217
218    fn make_info() -> ScheduleInfo {
219        let schedueld = AnySchedulableTransactionData::from_protobuf(
220            AccountDeleteTransaction::new()
221                .account_id("6.6.6".parse().unwrap())
222                .data()
223                .to_schedulable_transaction_data_protobuf(),
224        )
225        .unwrap();
226
227        ScheduleInfo {
228            schedule_id: "1.2.3".parse().unwrap(),
229            creator_account_id: "4.5.6".parse().unwrap(),
230            payer_account_id: Some("2.3.4".parse().unwrap()),
231            signatories: crate::KeyList::from([unused_private_key().public_key()]),
232            admin_key: Some(unused_private_key().public_key().into()),
233            scheduled_transaction_id: TransactionId {
234                account_id: "5006".parse().unwrap(),
235                valid_start: VALID_START,
236                nonce: None,
237                scheduled: false,
238            },
239            scheduled_transaction: SchedulableTransactionBody {
240                data: Box::new(schedueld),
241                max_transaction_fee: None,
242                transaction_memo: Default::default(),
243            },
244            wait_for_expiry: true,
245            memo: "memo".to_owned(),
246            expiration_time: Some(VALID_START),
247            executed_at: Some(VALID_START),
248            deleted_at: None,
249            ledger_id: LedgerId::testnet(),
250        }
251    }
252
253    fn make_deleted_info() -> ScheduleInfo {
254        ScheduleInfo { executed_at: None, deleted_at: Some(VALID_START), ..make_info() }
255    }
256
257    #[test]
258    fn serialize() {
259        expect![[r#"
260            ScheduleInfo {
261                schedule_id: Some(
262                    ScheduleId {
263                        shard_num: 1,
264                        realm_num: 2,
265                        schedule_num: 3,
266                    },
267                ),
268                expiration_time: Some(
269                    Timestamp {
270                        seconds: 1554158542,
271                        nanos: 0,
272                    },
273                ),
274                scheduled_transaction_body: Some(
275                    SchedulableTransactionBody {
276                        transaction_fee: 200000000,
277                        memo: "",
278                        max_custom_fees: [],
279                        data: Some(
280                            CryptoDelete(
281                                CryptoDeleteTransactionBody {
282                                    transfer_account_id: None,
283                                    delete_account_id: Some(
284                                        AccountId {
285                                            shard_num: 6,
286                                            realm_num: 6,
287                                            account: Some(
288                                                AccountNum(
289                                                    6,
290                                                ),
291                                            ),
292                                        },
293                                    ),
294                                },
295                            ),
296                        ),
297                    },
298                ),
299                memo: "memo",
300                admin_key: Some(
301                    Key {
302                        key: Some(
303                            Ed25519(
304                                [
305                                    224,
306                                    200,
307                                    236,
308                                    39,
309                                    88,
310                                    165,
311                                    135,
312                                    159,
313                                    250,
314                                    194,
315                                    38,
316                                    161,
317                                    60,
318                                    12,
319                                    81,
320                                    107,
321                                    121,
322                                    158,
323                                    114,
324                                    227,
325                                    81,
326                                    65,
327                                    160,
328                                    221,
329                                    130,
330                                    143,
331                                    148,
332                                    211,
333                                    121,
334                                    136,
335                                    164,
336                                    183,
337                                ],
338                            ),
339                        ),
340                    },
341                ),
342                signers: Some(
343                    KeyList {
344                        keys: [
345                            Key {
346                                key: Some(
347                                    Ed25519(
348                                        [
349                                            224,
350                                            200,
351                                            236,
352                                            39,
353                                            88,
354                                            165,
355                                            135,
356                                            159,
357                                            250,
358                                            194,
359                                            38,
360                                            161,
361                                            60,
362                                            12,
363                                            81,
364                                            107,
365                                            121,
366                                            158,
367                                            114,
368                                            227,
369                                            81,
370                                            65,
371                                            160,
372                                            221,
373                                            130,
374                                            143,
375                                            148,
376                                            211,
377                                            121,
378                                            136,
379                                            164,
380                                            183,
381                                        ],
382                                    ),
383                                ),
384                            },
385                        ],
386                    },
387                ),
388                creator_account_id: Some(
389                    AccountId {
390                        shard_num: 4,
391                        realm_num: 5,
392                        account: Some(
393                            AccountNum(
394                                6,
395                            ),
396                        ),
397                    },
398                ),
399                payer_account_id: Some(
400                    AccountId {
401                        shard_num: 2,
402                        realm_num: 3,
403                        account: Some(
404                            AccountNum(
405                                4,
406                            ),
407                        ),
408                    },
409                ),
410                scheduled_transaction_id: Some(
411                    TransactionId {
412                        transaction_valid_start: Some(
413                            Timestamp {
414                                seconds: 1554158542,
415                                nanos: 0,
416                            },
417                        ),
418                        account_id: Some(
419                            AccountId {
420                                shard_num: 0,
421                                realm_num: 0,
422                                account: Some(
423                                    AccountNum(
424                                        5006,
425                                    ),
426                                ),
427                            },
428                        ),
429                        scheduled: false,
430                        nonce: 0,
431                    },
432                ),
433                ledger_id: [
434                    1,
435                ],
436                wait_for_expiry: true,
437                data: None,
438            }
439        "#]]
440        .assert_debug_eq(&make_info().to_protobuf());
441    }
442
443    #[test]
444    fn serialize_deleted() {
445        expect![[r#"
446            ScheduleInfo {
447                schedule_id: Some(
448                    ScheduleId {
449                        shard_num: 1,
450                        realm_num: 2,
451                        schedule_num: 3,
452                    },
453                ),
454                expiration_time: Some(
455                    Timestamp {
456                        seconds: 1554158542,
457                        nanos: 0,
458                    },
459                ),
460                scheduled_transaction_body: Some(
461                    SchedulableTransactionBody {
462                        transaction_fee: 200000000,
463                        memo: "",
464                        max_custom_fees: [],
465                        data: Some(
466                            CryptoDelete(
467                                CryptoDeleteTransactionBody {
468                                    transfer_account_id: None,
469                                    delete_account_id: Some(
470                                        AccountId {
471                                            shard_num: 6,
472                                            realm_num: 6,
473                                            account: Some(
474                                                AccountNum(
475                                                    6,
476                                                ),
477                                            ),
478                                        },
479                                    ),
480                                },
481                            ),
482                        ),
483                    },
484                ),
485                memo: "memo",
486                admin_key: Some(
487                    Key {
488                        key: Some(
489                            Ed25519(
490                                [
491                                    224,
492                                    200,
493                                    236,
494                                    39,
495                                    88,
496                                    165,
497                                    135,
498                                    159,
499                                    250,
500                                    194,
501                                    38,
502                                    161,
503                                    60,
504                                    12,
505                                    81,
506                                    107,
507                                    121,
508                                    158,
509                                    114,
510                                    227,
511                                    81,
512                                    65,
513                                    160,
514                                    221,
515                                    130,
516                                    143,
517                                    148,
518                                    211,
519                                    121,
520                                    136,
521                                    164,
522                                    183,
523                                ],
524                            ),
525                        ),
526                    },
527                ),
528                signers: Some(
529                    KeyList {
530                        keys: [
531                            Key {
532                                key: Some(
533                                    Ed25519(
534                                        [
535                                            224,
536                                            200,
537                                            236,
538                                            39,
539                                            88,
540                                            165,
541                                            135,
542                                            159,
543                                            250,
544                                            194,
545                                            38,
546                                            161,
547                                            60,
548                                            12,
549                                            81,
550                                            107,
551                                            121,
552                                            158,
553                                            114,
554                                            227,
555                                            81,
556                                            65,
557                                            160,
558                                            221,
559                                            130,
560                                            143,
561                                            148,
562                                            211,
563                                            121,
564                                            136,
565                                            164,
566                                            183,
567                                        ],
568                                    ),
569                                ),
570                            },
571                        ],
572                    },
573                ),
574                creator_account_id: Some(
575                    AccountId {
576                        shard_num: 4,
577                        realm_num: 5,
578                        account: Some(
579                            AccountNum(
580                                6,
581                            ),
582                        ),
583                    },
584                ),
585                payer_account_id: Some(
586                    AccountId {
587                        shard_num: 2,
588                        realm_num: 3,
589                        account: Some(
590                            AccountNum(
591                                4,
592                            ),
593                        ),
594                    },
595                ),
596                scheduled_transaction_id: Some(
597                    TransactionId {
598                        transaction_valid_start: Some(
599                            Timestamp {
600                                seconds: 1554158542,
601                                nanos: 0,
602                            },
603                        ),
604                        account_id: Some(
605                            AccountId {
606                                shard_num: 0,
607                                realm_num: 0,
608                                account: Some(
609                                    AccountNum(
610                                        5006,
611                                    ),
612                                ),
613                            },
614                        ),
615                        scheduled: false,
616                        nonce: 0,
617                    },
618                ),
619                ledger_id: [
620                    1,
621                ],
622                wait_for_expiry: true,
623                data: None,
624            }
625        "#]]
626        .assert_debug_eq(&make_deleted_info().to_protobuf());
627    }
628}