1use super::{GearApi, Result};
20use crate::{Error, api::storage::account_id::IntoAccountId32, utils};
21use anyhow::anyhow;
22use gear_core::{gas::LockId, ids::*, memory::PageBuf, pages::GearPage};
23use gear_utils::{MemoryPageDump, ProgramMemoryDump};
24use gsdk::{
25 AsGear, Error as GsdkError, GearGasNode, GearGasNodeId, IntoSubstrate, IntoSubxt,
26 config::GearConfig,
27 ext::{
28 sp_runtime::{AccountId32, MultiAddress},
29 subxt::{blocks::ExtrinsicEvents, utils::H256},
30 },
31 gear::{
32 Event,
33 balances::Event as BalancesEvent,
34 gear::Event as GearEvent,
35 gear_eth_bridge::Event as GearEthBridgeEvent,
36 runtime_types::{
37 frame_system::pallet::Call as SystemCall,
38 gear_common::event::{CodeChangeKind, MessageEntry},
39 gear_core::program::ActiveProgram,
40 pallet_balances::{pallet::Call as BalancesCall, types::AccountData},
41 pallet_gear::pallet::Call as GearCall,
42 pallet_gear_bank::pallet::BankAccount,
43 pallet_gear_voucher::internal::VoucherId,
44 sp_weights::weight_v2::Weight,
45 vara_runtime::RuntimeCall,
46 },
47 system::Event as SystemEvent,
48 utility::Event as UtilityEvent,
49 },
50};
51use hex::ToHex;
52use parity_scale_codec::{Decode, Encode};
53use std::{
54 collections::{BTreeMap, HashMap, HashSet},
55 path::Path,
56};
57
58impl GearApi {
59 pub async fn reset_overflowed_queue(&self, encoded_finality_proof: Vec<u8>) -> Result<H256> {
63 let tx = self
64 .0
65 .calls()
66 .reset_overflowed_queue(encoded_finality_proof)
67 .await?;
68
69 for event in tx.wait_for_success().await?.iter() {
70 if let Event::GearEthBridge(GearEthBridgeEvent::QueueReset) = event?.as_gear()? {
71 return Ok(tx.block_hash());
72 }
73 }
74
75 Err(Error::EventNotFound)
76 }
77
78 pub async fn original_code_at(
81 &self,
82 code_id: CodeId,
83 at_block_hash: Option<H256>,
84 ) -> Result<Vec<u8>> {
85 self.0
86 .api()
87 .original_code_storage_at(code_id, at_block_hash)
88 .await
89 .map_err(Into::into)
90 }
91
92 pub async fn program_at(
95 &self,
96 program_id: ActorId,
97 at_block_hash: Option<H256>,
98 ) -> Result<ActiveProgram<u32>> {
99 self.0
100 .api()
101 .gprog_at(program_id, at_block_hash)
102 .await
103 .map_err(Into::into)
104 }
105
106 pub async fn transfer_keep_alive(&self, destination: ActorId, value: u128) -> Result<H256> {
114 let destination: [u8; 32] = destination.into();
115
116 let tx = self
117 .0
118 .calls()
119 .transfer_keep_alive(destination, value)
120 .await?;
121
122 for event in tx.wait_for_success().await?.iter() {
123 if let Event::Balances(BalancesEvent::Transfer { .. }) = event?.as_gear()? {
124 return Ok(tx.block_hash());
125 }
126 }
127
128 if value == 0 {
130 return Ok(tx.block_hash());
131 }
132
133 Err(Error::EventNotFound)
134 }
135
136 pub async fn transfer_allow_death(&self, destination: ActorId, value: u128) -> Result<H256> {
144 let destination: [u8; 32] = destination.into();
145
146 let tx = self
147 .0
148 .calls()
149 .transfer_allow_death(destination, value)
150 .await?;
151
152 for event in tx.wait_for_success().await?.iter() {
153 if let Event::Balances(BalancesEvent::Transfer { .. }) = event?.as_gear()? {
154 return Ok(tx.block_hash());
155 }
156 }
157
158 if value == 0 {
160 return Ok(tx.block_hash());
161 }
162
163 Err(Error::EventNotFound)
164 }
165
166 pub async fn transfer_all(&self, destination: ActorId, keep_alive: bool) -> Result<H256> {
174 let destination: [u8; 32] = destination.into();
175
176 let tx = self.0.calls().transfer_all(destination, keep_alive).await?;
177
178 for event in tx.wait_for_success().await?.iter() {
179 if let Event::Balances(BalancesEvent::Transfer { .. }) = event?.as_gear()? {
180 return Ok(tx.block_hash());
181 }
182 }
183
184 Err(Error::EventNotFound)
185 }
186
187 pub async fn create_program_bytes(
224 &self,
225 code_id: CodeId,
226 salt: impl AsRef<[u8]>,
227 payload: impl AsRef<[u8]>,
228 gas_limit: u64,
229 value: u128,
230 ) -> Result<(MessageId, ActorId, H256)> {
231 let salt = salt.as_ref().to_vec();
232 let payload = payload.as_ref().to_vec();
233
234 let tx = self
235 .0
236 .calls()
237 .create_program(code_id, salt, payload, gas_limit, value)
238 .await?;
239
240 for event in tx.wait_for_success().await?.iter() {
241 if let Event::Gear(GearEvent::MessageQueued {
242 id,
243 destination,
244 entry: MessageEntry::Init,
245 ..
246 }) = event?.as_gear()?
247 {
248 return Ok((id, destination, tx.block_hash()));
249 }
250 }
251
252 Err(Error::EventNotFound)
253 }
254
255 pub async fn create_program_bytes_batch(
262 &self,
263 args: impl IntoIterator<Item = (CodeId, impl AsRef<[u8]>, impl AsRef<[u8]>, u64, u128)>,
264 ) -> Result<(Vec<Result<(MessageId, ActorId)>>, H256)> {
265 let calls: Vec<_> = args
266 .into_iter()
267 .map(|(code_id, salt, payload, gas_limit, value)| {
268 RuntimeCall::Gear(GearCall::create_program {
269 code_id,
270 salt: salt.as_ref().to_vec(),
271 init_payload: payload.as_ref().to_vec(),
272 gas_limit,
273 value,
274 keep_alive: false,
275 })
276 })
277 .collect();
278
279 let amount = calls.len();
280
281 let tx = self.0.calls().force_batch(calls).await?;
282 let mut res = Vec::with_capacity(amount);
283
284 for event in tx.wait_for_success().await?.iter() {
285 match event?.as_gear()? {
286 Event::Gear(GearEvent::MessageQueued {
287 id,
288 destination,
289 entry: MessageEntry::Init,
290 ..
291 }) => res.push(Ok((id, destination))),
292 Event::Utility(UtilityEvent::ItemFailed { error }) => {
293 res.push(Err(self.0.api().decode_error(error).into()))
294 }
295 _ => (),
296 }
297 }
298
299 if res.len() == amount {
300 Ok((res, tx.block_hash()))
301 } else {
302 Err(Error::IncompleteBatchResult(res.len(), amount))
303 }
304 }
305
306 pub async fn create_program(
316 &self,
317 code_id: CodeId,
318 salt: impl AsRef<[u8]>,
319 payload: impl Encode,
320 gas_limit: u64,
321 value: u128,
322 ) -> Result<(MessageId, ActorId, H256)> {
323 self.create_program_bytes(code_id, salt, payload.encode(), gas_limit, value)
324 .await
325 }
326
327 pub async fn migrate_program(
332 &self,
333 src_program_id: ActorId,
334 src_block_hash: Option<H256>,
335 dest_node_api: &GearApi,
336 ) -> Result<ActorId> {
337 if dest_node_api.0.api().gprog(src_program_id).await.is_ok() {
338 return Err(Error::ProgramAlreadyExists(
339 src_program_id.as_ref().encode_hex(),
340 ));
341 }
342
343 let mut src_block_hash = src_block_hash;
344 if src_block_hash.is_none() {
345 src_block_hash = Some(self.last_block_hash().await?);
346 }
347
348 let dest_program_id = src_program_id;
349
350 let src_program_account_data = self
352 .account_data_at(src_program_id, src_block_hash)
353 .await
354 .or_else(|e| {
355 if let Error::GearSDK(GsdkError::StorageEntryNotFound) = e {
356 Ok(AccountData {
357 free: 0u128,
358 reserved: 0,
359 frozen: 0,
360 flags: gsdk::gear::runtime_types::pallet_balances::types::ExtraFlags(
361 170141183460469231731687303715884105728,
362 ),
363 })
364 } else {
365 Err(e)
366 }
367 })?;
368
369 let src_program_account_bank_data = self
370 .bank_data_at(src_program_id, src_block_hash)
371 .await
372 .or_else(|e| {
373 if let Error::GearSDK(GsdkError::StorageEntryNotFound) = e {
374 Ok(BankAccount { gas: 0, value: 0 })
375 } else {
376 Err(e)
377 }
378 })?;
379
380 let bank_address = self.bank_address().await?;
381
382 let src_bank_account_data = self
383 .account_data_at(bank_address.clone(), src_block_hash)
384 .await
385 .or_else(|e| {
386 if let Error::GearSDK(GsdkError::StorageEntryNotFound) = e {
387 Ok(AccountData {
388 free: 0u128,
389 reserved: 0,
390 frozen: 0,
391 flags: gsdk::gear::runtime_types::pallet_balances::types::ExtraFlags(
392 170141183460469231731687303715884105728,
393 ),
394 })
395 } else {
396 Err(e)
397 }
398 })?;
399
400 let mut src_program = self
401 .0
402 .api()
403 .gprog_at(src_program_id, src_block_hash)
404 .await?;
405
406 let src_program_pages = self
407 .0
408 .api()
409 .gpages_at(
410 src_program_id,
411 Some(src_program.memory_infix),
412 src_block_hash,
413 )
414 .await?;
415
416 let src_program_reserved_gas_node_ids: Vec<GearGasNodeId> = src_program
417 .gas_reservation_map
418 .iter()
419 .map(|gr| GearGasNodeId::Reservation(gr.0))
420 .collect();
421
422 let src_program_reserved_gas_nodes = self
423 .0
424 .api()
425 .gas_nodes_at(src_program_reserved_gas_node_ids, src_block_hash)
426 .await?;
427
428 let mut src_program_reserved_gas_total = 0u64;
429 let mut accounts_with_reserved_funds = HashSet::new();
430 for gas_node in &src_program_reserved_gas_nodes {
431 if let GearGasNode::Reserved {
432 id, value, lock, ..
433 } = &gas_node.1
434 {
435 accounts_with_reserved_funds.insert(id.clone().into_substrate());
436 src_program_reserved_gas_total += value + lock.0[LockId::Reservation as usize];
437 } else {
438 unreachable!("Unexpected gas node type");
439 }
440 }
441
442 let src_code_id = src_program.code_id;
443
444 let src_instrumented_code = self
445 .0
446 .api()
447 .instrumented_code_storage_at(src_code_id, src_block_hash)
448 .await?;
449
450 let src_code_metadata = self
451 .0
452 .api()
453 .code_metadata_storage_at(src_code_id, src_block_hash)
454 .await?;
455
456 dest_node_api
458 .force_set_balance(
459 dest_program_id.into_account_id(),
460 src_program_account_data.free,
461 )
462 .await?;
463
464 dest_node_api
465 .force_set_balance(bank_address, src_bank_account_data.free)
466 .await?;
467
468 dest_node_api
469 .0
470 .storage()
471 .set_bank_account_storage(
472 src_program_id.into_account_id(),
473 src_program_account_bank_data,
474 )
475 .await?;
476
477 dest_node_api
478 .0
479 .storage()
480 .set_instrumented_code_storage(src_code_id, &src_instrumented_code)
481 .await?;
482
483 dest_node_api
484 .0
485 .storage()
486 .set_code_metadata_storage(src_code_id, &src_code_metadata)
487 .await?;
488
489 dest_node_api
490 .0
491 .storage()
492 .set_gas_nodes(&src_program_reserved_gas_nodes)
493 .await?;
494
495 for account_with_reserved_funds in accounts_with_reserved_funds {
496 let src_account_bank_data = self
497 .bank_data_at(account_with_reserved_funds.clone(), src_block_hash)
498 .await
499 .or_else(|e| {
500 if let Error::GearSDK(GsdkError::StorageEntryNotFound) = e {
501 Ok(BankAccount { gas: 0, value: 0 })
502 } else {
503 Err(e)
504 }
505 })?;
506
507 let dest_account_data = dest_node_api
508 .account_data(account_with_reserved_funds.clone())
509 .await
510 .or_else(|e| {
511 if let Error::GearSDK(GsdkError::StorageEntryNotFound) = e {
512 Ok(AccountData {
513 free: 0u128,
514 reserved: 0,
515 frozen: 0,
516 flags: gsdk::gear::runtime_types::pallet_balances::types::ExtraFlags(
517 170141183460469231731687303715884105728,
518 ),
519 })
520 } else {
521 Err(e)
522 }
523 })?;
524 let dest_account_bank_data = self
525 .bank_data_at(account_with_reserved_funds.clone(), None)
526 .await
527 .or_else(|e| {
528 if let Error::GearSDK(GsdkError::StorageEntryNotFound) = e {
529 Ok(BankAccount { gas: 0, value: 0 })
530 } else {
531 Err(e)
532 }
533 })?;
534
535 dest_node_api
536 .force_set_balance(
537 account_with_reserved_funds.clone().into_account_id(),
538 dest_account_data.free,
539 )
540 .await?;
541
542 dest_node_api
543 .0
544 .storage()
545 .set_bank_account_storage(
546 account_with_reserved_funds.into_account_id(),
547 BankAccount {
548 gas: src_account_bank_data
549 .gas
550 .saturating_add(dest_account_bank_data.gas),
551 value: src_account_bank_data
552 .value
553 .saturating_add(dest_account_bank_data.value),
554 },
555 )
556 .await?;
557 }
558
559 let dest_gas_total_issuance =
560 dest_node_api.0.api().total_issuance().await.or_else(|e| {
561 if let GsdkError::StorageEntryNotFound = e {
562 Ok(0)
563 } else {
564 Err(e)
565 }
566 })?;
567
568 dest_node_api
569 .0
570 .storage()
571 .set_total_issuance(
572 dest_gas_total_issuance.saturating_add(src_program_reserved_gas_total),
573 )
574 .await?;
575
576 dest_node_api
577 .0
578 .storage()
579 .set_gpages(
580 dest_program_id,
581 src_program.memory_infix,
582 &src_program_pages,
583 )
584 .await?;
585
586 src_program.expiration_block = dest_node_api.last_block_number().await?;
587 dest_node_api
588 .0
589 .storage()
590 .set_gprog(dest_program_id, src_program)
591 .await?;
592
593 Ok(dest_program_id)
594 }
595
596 pub async fn get_program_pages_data_at(
598 &self,
599 program_id: ActorId,
600 block_hash: Option<H256>,
601 ) -> Result<BTreeMap<GearPage, PageBuf>> {
602 let pages_data = self.0.api().gpages_at(program_id, None, block_hash).await?;
603
604 let mut res = BTreeMap::new();
605 for (page, data) in pages_data.into_iter() {
606 res.insert(
607 GearPage::try_from(page).map_err(|err| anyhow!("{err}"))?,
608 data,
609 );
610 }
611
612 Ok(res)
613 }
614
615 pub async fn get_program_specified_pages_data_at(
617 &self,
618 program_id: ActorId,
619 pages: impl Iterator<Item = GearPage>,
620 block_hash: Option<H256>,
621 ) -> Result<BTreeMap<GearPage, PageBuf>> {
622 let pages_data = self
623 .0
624 .api()
625 .specified_gpages_at(program_id, None, pages.map(Into::into), block_hash)
626 .await?;
627
628 let mut res = BTreeMap::new();
629 for (page, data) in pages_data.into_iter() {
630 res.insert(
631 GearPage::try_from(page).map_err(|err| anyhow::Error::msg(err.to_string()))?,
632 data,
633 );
634 }
635
636 Ok(res)
637 }
638
639 pub async fn save_program_memory_dump_at<P: AsRef<Path>>(
643 &self,
644 program_id: ActorId,
645 block_hash: Option<H256>,
646 file_path: P,
647 ) -> Result {
648 let program = self.0.api().gprog_at(program_id, block_hash).await?;
649
650 let program_pages = self
651 .0
652 .api()
653 .gpages_at(program_id, Some(program.memory_infix), block_hash)
654 .await?
655 .into_iter()
656 .map(|(page, data)| {
657 MemoryPageDump::new(
658 GearPage::try_from(page)
659 .unwrap_or_else(|_| panic!("Couldn't decode GearPage from u32: {page}")),
660 PageBuf::decode(&mut &*data).expect("Couldn't decode PageBuf"),
661 )
662 })
663 .collect();
664
665 let program_account_data =
666 self.account_data_at(program_id, block_hash)
667 .await
668 .or_else(|e| {
669 if let Error::GearSDK(GsdkError::StorageEntryNotFound) = e {
670 Ok(AccountData {
671 free: 0u128,
672 reserved: 0,
673 frozen: 0,
674 flags: gsdk::gear::runtime_types::pallet_balances::types::ExtraFlags(
675 170141183460469231731687303715884105728,
676 ),
677 })
678 } else {
679 Err(e)
680 }
681 })?;
682
683 ProgramMemoryDump {
684 pages: program_pages,
685 balance: program_account_data.free,
686 reserved_balance: program_account_data.reserved,
687 }
688 .save_to_file(file_path);
689
690 Ok(())
691 }
692
693 pub async fn replace_program_memory<P: AsRef<Path>>(
695 &self,
696 program_id: ActorId,
697 file_path: P,
698 ) -> Result {
699 let memory_dump = ProgramMemoryDump::load_from_file(file_path);
700 let pages = memory_dump
701 .pages
702 .into_iter()
703 .map(|page| page.into_gear_page())
704 .map(|(page, page_buffer)| (page.into(), page_buffer))
705 .collect::<HashMap<u32, _>>();
706
707 self.force_set_balance(
708 MultiAddress::Id(program_id.into_account_id()),
709 memory_dump.balance,
710 )
711 .await?;
712
713 let program = self.0.api().gprog_at(program_id, None).await?;
714
715 self.0
716 .storage()
717 .set_gpages(program_id, program.memory_infix, &pages)
718 .await?;
719
720 Ok(())
721 }
722
723 pub async fn claim_value(&self, message_id: MessageId) -> Result<(u128, H256)> {
737 let value = self
738 .get_mailbox_message(message_id)
739 .await?
740 .map(|(message, _interval)| message.value());
741
742 let tx = self.0.calls().claim_value(message_id).await?;
743
744 for event in tx.wait_for_success().await?.iter() {
745 if let Event::Gear(GearEvent::UserMessageRead { .. }) = event?.as_gear()? {
746 return Ok((
747 value.expect("Data appearance guaranteed above"),
748 tx.block_hash(),
749 ));
750 }
751 }
752
753 Err(Error::EventNotFound)
754 }
755
756 pub async fn claim_value_batch(
763 &self,
764 args: impl IntoIterator<Item = MessageId> + Clone,
765 ) -> Result<(Vec<Result<u128>>, H256)> {
766 let message_ids: Vec<_> = args.clone().into_iter().collect();
767
768 let messages = futures::future::try_join_all(
769 message_ids.iter().map(|mid| self.get_mailbox_message(*mid)),
770 )
771 .await?;
772
773 let mut values: BTreeMap<_, _> = messages
774 .into_iter()
775 .flatten()
776 .map(|(msg, _interval)| (msg.id(), msg.value()))
777 .collect();
778
779 let calls: Vec<_> = args
780 .into_iter()
781 .map(|message_id| RuntimeCall::Gear(GearCall::claim_value { message_id }))
782 .collect();
783
784 let amount = calls.len();
785
786 let tx = self.0.calls().force_batch(calls).await?;
787 let mut res = Vec::with_capacity(amount);
788
789 for event in tx.wait_for_success().await?.iter() {
790 match event?.as_gear()? {
791 Event::Gear(GearEvent::UserMessageRead { id, .. }) => res.push(Ok(values
792 .remove(&id)
793 .expect("Data appearance guaranteed above"))),
794 Event::Utility(UtilityEvent::ItemFailed { error }) => {
795 res.push(Err(self.0.api().decode_error(error).into()))
796 }
797 _ => (),
798 }
799 }
800
801 if res.len() == amount {
802 Ok((res, tx.block_hash()))
803 } else {
804 Err(Error::IncompleteBatchResult(res.len(), amount))
805 }
806 }
807
808 pub async fn send_message_bytes(
827 &self,
828 destination: ActorId,
829 payload: impl AsRef<[u8]>,
830 gas_limit: u64,
831 value: u128,
832 ) -> Result<(MessageId, H256)> {
833 let payload = payload.as_ref().to_vec();
834
835 let tx = self
836 .0
837 .calls()
838 .send_message(destination, payload, gas_limit, value)
839 .await?;
840
841 for event in tx.wait_for_success().await?.iter() {
842 if let Event::Gear(GearEvent::MessageQueued {
843 id,
844 entry: MessageEntry::Handle,
845 ..
846 }) = event?.as_gear()?
847 {
848 return Ok((id, tx.block_hash()));
849 }
850 }
851
852 Err(Error::EventNotFound)
853 }
854
855 pub async fn send_message_bytes_batch(
863 &self,
864 args: impl IntoIterator<Item = (ActorId, impl AsRef<[u8]>, u64, u128)>,
865 ) -> Result<(Vec<Result<(MessageId, ActorId)>>, H256)> {
866 let calls: Vec<_> = args
867 .into_iter()
868 .map(|(destination, payload, gas_limit, value)| {
869 RuntimeCall::Gear(GearCall::send_message {
870 destination,
871 payload: payload.as_ref().to_vec(),
872 gas_limit,
873 value,
874 keep_alive: false,
875 })
876 })
877 .collect();
878
879 let amount = calls.len();
880
881 let tx = self.0.calls().force_batch(calls).await?;
882 let mut res = Vec::with_capacity(amount);
883
884 for event in tx.wait_for_success().await?.iter() {
885 match event?.as_gear()? {
886 Event::Gear(GearEvent::MessageQueued {
887 id,
888 destination,
889 entry: MessageEntry::Handle,
890 ..
891 }) => res.push(Ok((id, destination))),
892 Event::Utility(UtilityEvent::ItemFailed { error }) => {
893 res.push(Err(self.0.api().decode_error(error).into()))
894 }
895 _ => (),
896 }
897 }
898
899 if res.len() == amount {
900 Ok((res, tx.block_hash()))
901 } else {
902 Err(Error::IncompleteBatchResult(res.len(), amount))
903 }
904 }
905
906 pub async fn send_message(
909 &self,
910 destination: ActorId,
911 payload: impl Encode,
912 gas_limit: u64,
913 value: u128,
914 ) -> Result<(MessageId, H256)> {
915 self.send_message_bytes(destination, payload.encode(), gas_limit, value)
916 .await
917 }
918
919 pub async fn send_reply_bytes(
939 &self,
940 reply_to_id: MessageId,
941 payload: impl AsRef<[u8]>,
942 gas_limit: u64,
943 value: u128,
944 ) -> Result<(MessageId, u128, H256)> {
945 let payload = payload.as_ref().to_vec();
946
947 let data = self.get_mailbox_message(reply_to_id).await?;
948
949 let tx = self
950 .0
951 .calls()
952 .send_reply(reply_to_id, payload, gas_limit, value)
953 .await?;
954
955 let events = tx.wait_for_success().await?;
956
957 let (message, _interval) = data.expect("Data appearance guaranteed above");
958
959 for event in events.iter() {
960 if let Event::Gear(GearEvent::MessageQueued {
961 id,
962 entry: MessageEntry::Reply(_),
963 ..
964 }) = event?.as_gear()?
965 {
966 return Ok((id, message.value(), tx.block_hash()));
967 }
968 }
969
970 Err(Error::EventNotFound)
971 }
972
973 pub async fn send_reply_bytes_batch(
984 &self,
985 args: impl IntoIterator<Item = (MessageId, impl AsRef<[u8]>, u64, u128)> + Clone,
986 ) -> Result<(Vec<Result<(MessageId, ActorId, u128)>>, H256)> {
987 let message_ids: Vec<_> = args.clone().into_iter().map(|(mid, _, _, _)| mid).collect();
988
989 let messages = futures::future::try_join_all(
990 message_ids.iter().map(|mid| self.get_mailbox_message(*mid)),
991 )
992 .await?;
993
994 let mut values: BTreeMap<_, _> = messages
995 .into_iter()
996 .flatten()
997 .map(|(msg, _interval)| (msg.id(), msg.value()))
998 .collect();
999
1000 let calls: Vec<_> = args
1001 .into_iter()
1002 .map(|(reply_to_id, payload, gas_limit, value)| {
1003 RuntimeCall::Gear(GearCall::send_reply {
1004 reply_to_id,
1005 payload: payload.as_ref().to_vec(),
1006 gas_limit,
1007 value,
1008 keep_alive: false,
1009 })
1010 })
1011 .collect();
1012
1013 let amount = calls.len();
1014
1015 let tx = self.0.calls().force_batch(calls).await?;
1016 let mut res = Vec::with_capacity(amount);
1017
1018 for event in tx.wait_for_success().await?.iter() {
1019 match event?.as_gear()? {
1020 Event::Gear(GearEvent::MessageQueued {
1021 id,
1022 entry: MessageEntry::Reply(reply_to_id),
1023 destination,
1024 ..
1025 }) => res.push(Ok((
1026 id,
1027 destination,
1028 values
1029 .remove(&reply_to_id)
1030 .expect("Data appearance guaranteed above"),
1031 ))),
1032 Event::Utility(UtilityEvent::ItemFailed { error }) => {
1033 res.push(Err(self.0.api().decode_error(error).into()))
1034 }
1035 _ => (),
1036 }
1037 }
1038
1039 if res.len() == amount {
1040 Ok((res, tx.block_hash()))
1041 } else {
1042 Err(Error::IncompleteBatchResult(res.len(), amount))
1043 }
1044 }
1045
1046 pub async fn send_reply(
1049 &self,
1050 reply_to_id: MessageId,
1051 payload: impl Encode,
1052 gas_limit: u64,
1053 value: u128,
1054 ) -> Result<(MessageId, u128, H256)> {
1055 self.send_reply_bytes(reply_to_id, payload.encode(), gas_limit, value)
1056 .await
1057 }
1058
1059 pub async fn upload_code(&self, code: impl AsRef<[u8]>) -> Result<(CodeId, H256)> {
1077 let tx = self.0.calls().upload_code(code.as_ref().to_vec()).await?;
1078
1079 for event in tx.wait_for_success().await?.iter() {
1080 if let Event::Gear(GearEvent::CodeChanged {
1081 id,
1082 change: CodeChangeKind::Active { .. },
1083 }) = event?.as_gear()?
1084 {
1085 return Ok((id, tx.block_hash()));
1086 }
1087 }
1088
1089 Err(Error::EventNotFound)
1090 }
1091
1092 pub async fn upload_code_batch(
1099 &self,
1100 args: impl IntoIterator<Item = impl AsRef<[u8]>>,
1101 ) -> Result<(Vec<Result<CodeId>>, H256)> {
1102 let calls: Vec<_> = args
1103 .into_iter()
1104 .map(|code| {
1105 RuntimeCall::Gear(GearCall::upload_code {
1106 code: code.as_ref().to_vec(),
1107 })
1108 })
1109 .collect();
1110
1111 let amount = calls.len();
1112
1113 let tx = self.0.calls().force_batch(calls).await?;
1114 let mut res = Vec::with_capacity(amount);
1115
1116 for event in tx.wait_for_success().await?.iter() {
1117 match event?.as_gear()? {
1118 Event::Gear(GearEvent::CodeChanged {
1119 id,
1120 change: CodeChangeKind::Active { .. },
1121 }) => {
1122 res.push(Ok(id));
1123 }
1124 Event::Utility(UtilityEvent::ItemFailed { error }) => {
1125 res.push(Err(self.0.api().decode_error(error).into()))
1126 }
1127 _ => (),
1128 }
1129 }
1130
1131 if res.len() == amount {
1132 Ok((res, tx.block_hash()))
1133 } else {
1134 Err(Error::IncompleteBatchResult(res.len(), amount))
1135 }
1136 }
1137
1138 pub async fn upload_code_by_path(&self, path: impl AsRef<Path>) -> Result<(CodeId, H256)> {
1147 let code = utils::code_from_os(path)?;
1148 self.upload_code(code).await
1149 }
1150
1151 pub async fn upload_program_bytes(
1179 &self,
1180 code: impl AsRef<[u8]>,
1181 salt: impl AsRef<[u8]>,
1182 payload: impl AsRef<[u8]>,
1183 gas_limit: u64,
1184 value: u128,
1185 ) -> Result<(MessageId, ActorId, H256)> {
1186 let code = code.as_ref().to_vec();
1187 let salt = salt.as_ref().to_vec();
1188 let payload = payload.as_ref().to_vec();
1189
1190 let tx = self
1191 .0
1192 .calls()
1193 .upload_program(code, salt, payload, gas_limit, value)
1194 .await?;
1195
1196 for event in tx.wait_for_success().await?.iter() {
1197 if let Event::Gear(GearEvent::MessageQueued {
1198 id,
1199 destination,
1200 entry: MessageEntry::Init,
1201 ..
1202 }) = event?.as_gear()?
1203 {
1204 return Ok((id, destination, tx.block_hash()));
1205 }
1206 }
1207
1208 Err(Error::EventNotFound)
1209 }
1210
1211 pub async fn upload_program_bytes_batch(
1218 &self,
1219 args: impl IntoIterator<
1220 Item = (
1221 impl AsRef<[u8]>,
1222 impl AsRef<[u8]>,
1223 impl AsRef<[u8]>,
1224 u64,
1225 u128,
1226 ),
1227 >,
1228 ) -> Result<(Vec<Result<(MessageId, ActorId)>>, H256)> {
1229 let calls: Vec<_> = args
1230 .into_iter()
1231 .map(|(code, salt, payload, gas_limit, value)| {
1232 RuntimeCall::Gear(GearCall::upload_program {
1233 code: code.as_ref().to_vec(),
1234 salt: salt.as_ref().to_vec(),
1235 init_payload: payload.as_ref().to_vec(),
1236 gas_limit,
1237 value,
1238 keep_alive: false,
1239 })
1240 })
1241 .collect();
1242
1243 let amount = calls.len();
1244
1245 let tx = self.0.calls().force_batch(calls).await?;
1246 let mut res = Vec::with_capacity(amount);
1247
1248 for event in tx.wait_for_success().await?.iter() {
1249 match event?.as_gear()? {
1250 Event::Gear(GearEvent::MessageQueued {
1251 id,
1252 destination,
1253 entry: MessageEntry::Init,
1254 ..
1255 }) => res.push(Ok((id, destination))),
1256 Event::Utility(UtilityEvent::ItemFailed { error }) => {
1257 res.push(Err(self.0.api().decode_error(error).into()))
1258 }
1259 _ => (),
1260 }
1261 }
1262
1263 if res.len() == amount {
1264 Ok((res, tx.block_hash()))
1265 } else {
1266 Err(Error::IncompleteBatchResult(res.len(), amount))
1267 }
1268 }
1269
1270 pub async fn upload_program_bytes_by_path(
1279 &self,
1280 path: impl AsRef<Path>,
1281 salt: impl AsRef<[u8]>,
1282 payload: impl AsRef<[u8]>,
1283 gas_limit: u64,
1284 value: u128,
1285 ) -> Result<(MessageId, ActorId, H256)> {
1286 let code = utils::code_from_os(path)?;
1287 self.upload_program_bytes(code, salt, payload, gas_limit, value)
1288 .await
1289 }
1290
1291 pub async fn upload_program(
1301 &self,
1302 code: impl AsRef<[u8]>,
1303 salt: impl AsRef<[u8]>,
1304 payload: impl Encode,
1305 gas_limit: u64,
1306 value: u128,
1307 ) -> Result<(MessageId, ActorId, H256)> {
1308 self.upload_program_bytes(code, salt, payload.encode(), gas_limit, value)
1309 .await
1310 }
1311
1312 pub async fn upload_program_by_path(
1321 &self,
1322 path: impl AsRef<Path>,
1323 salt: impl AsRef<[u8]>,
1324 payload: impl Encode,
1325 gas_limit: u64,
1326 value: u128,
1327 ) -> Result<(MessageId, ActorId, H256)> {
1328 let code = utils::code_from_os(path)?;
1329 self.upload_program(code, salt, payload, gas_limit, value)
1330 .await
1331 }
1332
1333 fn process_set_code(&self, events: &ExtrinsicEvents<GearConfig>) -> Result<()> {
1334 for event in events.iter() {
1335 let event = event?.as_gear()?;
1336 if let Event::System(SystemEvent::CodeUpdated) = event {
1337 return Ok(());
1338 }
1339 }
1340
1341 Err(Error::EventNotFound)
1342 }
1343
1344 pub async fn set_code(&self, code: impl AsRef<[u8]>) -> Result<H256> {
1351 let (block_hash, events) = self
1352 .0
1353 .calls()
1354 .sudo_unchecked_weight(
1355 RuntimeCall::System(SystemCall::set_code {
1356 code: code.as_ref().to_vec(),
1357 }),
1358 Weight {
1359 ref_time: 0,
1360 proof_size: 0,
1361 },
1362 )
1363 .await?;
1364 self.process_set_code(&events)?;
1365 Ok(block_hash)
1366 }
1367
1368 pub async fn set_code_by_path(&self, path: impl AsRef<Path>) -> Result<H256> {
1374 let code = utils::code_from_os(path)?;
1375 self.set_code(code).await
1376 }
1377
1378 pub async fn set_code_without_checks(&self, code: impl AsRef<[u8]>) -> Result<H256> {
1385 let (block_hash, events) = self
1386 .0
1387 .calls()
1388 .sudo_unchecked_weight(
1389 RuntimeCall::System(SystemCall::set_code_without_checks {
1390 code: code.as_ref().to_vec(),
1391 }),
1392 Weight {
1393 ref_time: 0,
1394 proof_size: 0,
1395 },
1396 )
1397 .await?;
1398 self.process_set_code(&events)?;
1399 Ok(block_hash)
1400 }
1401
1402 pub async fn set_code_without_checks_by_path(&self, path: impl AsRef<Path>) -> Result<H256> {
1408 let code = utils::code_from_os(path)?;
1409 self.set_code_without_checks(code).await
1410 }
1411
1412 pub async fn force_set_balance(
1416 &self,
1417 to: impl Into<MultiAddress<AccountId32, ()>>,
1418 new_free: u128,
1419 ) -> Result<H256> {
1420 let events = self
1421 .0
1422 .calls()
1423 .sudo_unchecked_weight(
1424 RuntimeCall::Balances(BalancesCall::force_set_balance {
1425 who: to.into().into_subxt(),
1426 new_free,
1427 }),
1428 Weight {
1429 ref_time: 0,
1430 proof_size: Default::default(),
1434 },
1435 )
1436 .await?;
1437 Ok(events.0)
1438 }
1439
1440 pub async fn upload_code_with_voucher(
1443 &self,
1444 voucher_id: VoucherId,
1445 code: impl AsRef<[u8]>,
1446 ) -> Result<(CodeId, H256)> {
1447 let tx = self
1448 .0
1449 .calls()
1450 .upload_code_with_voucher(voucher_id, code.as_ref().to_vec())
1451 .await?;
1452
1453 for event in tx.wait_for_success().await?.iter() {
1454 if let Event::Gear(GearEvent::CodeChanged {
1455 id,
1456 change: CodeChangeKind::Active { .. },
1457 }) = event?.as_gear()?
1458 {
1459 return Ok((id, tx.block_hash()));
1460 }
1461 }
1462
1463 Err(Error::EventNotFound)
1464 }
1465
1466 pub async fn send_message_bytes_with_voucher(
1469 &self,
1470 voucher_id: VoucherId,
1471 destination: ActorId,
1472 payload: impl AsRef<[u8]>,
1473 gas_limit: u64,
1474 value: u128,
1475 keep_alive: bool,
1476 ) -> Result<(MessageId, H256)> {
1477 let payload = payload.as_ref().to_vec();
1478
1479 let tx = self
1480 .0
1481 .calls()
1482 .send_message_with_voucher(
1483 voucher_id,
1484 destination,
1485 payload,
1486 gas_limit,
1487 value,
1488 keep_alive,
1489 )
1490 .await?;
1491
1492 for event in tx.wait_for_success().await?.iter() {
1493 if let Event::Gear(GearEvent::MessageQueued {
1494 id,
1495 entry: MessageEntry::Handle,
1496 ..
1497 }) = event?.as_gear()?
1498 {
1499 return Ok((id, tx.block_hash()));
1500 }
1501 }
1502
1503 Err(Error::EventNotFound)
1504 }
1505
1506 pub async fn send_message_with_voucher(
1509 &self,
1510 voucher_id: VoucherId,
1511 destination: ActorId,
1512 payload: impl Encode,
1513 gas_limit: u64,
1514 value: u128,
1515 keep_alive: bool,
1516 ) -> Result<(MessageId, H256)> {
1517 self.send_message_bytes_with_voucher(
1518 voucher_id,
1519 destination,
1520 payload.encode(),
1521 gas_limit,
1522 value,
1523 keep_alive,
1524 )
1525 .await
1526 }
1527
1528 pub async fn send_reply_bytes_with_voucher(
1531 &self,
1532 voucher_id: VoucherId,
1533 reply_to_id: MessageId,
1534 payload: impl AsRef<[u8]>,
1535 gas_limit: u64,
1536 value: u128,
1537 keep_alive: bool,
1538 ) -> Result<(MessageId, u128, H256)> {
1539 let payload = payload.as_ref().to_vec();
1540
1541 let data = self.get_mailbox_message(reply_to_id).await?;
1542
1543 let tx = self
1544 .0
1545 .calls()
1546 .send_reply_with_voucher(
1547 voucher_id,
1548 reply_to_id,
1549 payload,
1550 gas_limit,
1551 value,
1552 keep_alive,
1553 )
1554 .await?;
1555
1556 let events = tx.wait_for_success().await?;
1557
1558 let (message, _interval) = data.expect("Data appearance guaranteed above");
1559
1560 for event in events.iter() {
1561 if let Event::Gear(GearEvent::MessageQueued {
1562 id,
1563 entry: MessageEntry::Reply(_),
1564 ..
1565 }) = event?.as_gear()?
1566 {
1567 return Ok((id, message.value(), tx.block_hash()));
1568 }
1569 }
1570
1571 Err(Error::EventNotFound)
1572 }
1573
1574 pub async fn send_reply_with_voucher(
1577 &self,
1578 voucher_id: VoucherId,
1579 reply_to_id: MessageId,
1580 payload: impl Encode,
1581 gas_limit: u64,
1582 value: u128,
1583 keep_alive: bool,
1584 ) -> Result<(MessageId, u128, H256)> {
1585 self.send_reply_bytes_with_voucher(
1586 voucher_id,
1587 reply_to_id,
1588 payload.encode(),
1589 gas_limit,
1590 value,
1591 keep_alive,
1592 )
1593 .await
1594 }
1595}