/home/runner/work/creditcoin/creditcoin/pallets/creditcoin/src/ocw.rs
Line | Count | Source (jump to first uncovered line) |
1 | | pub(crate) mod errors; |
2 | | mod nonce; |
3 | | pub(crate) mod rpc; |
4 | | pub(crate) mod tasks; |
5 | | |
6 | | use self::{errors::RpcUrlError, rpc::errors::RpcError}; |
7 | | use super::{ |
8 | | pallet::{Config, Error, Pallet}, |
9 | | ExternalAddress, |
10 | | }; |
11 | | use crate::{Blockchain, Call, ExternalTxId}; |
12 | | use alloc::string::String; |
13 | | pub(crate) use errors::{OffchainError, VerificationFailureCause, VerificationResult}; |
14 | | use frame_support::traits::IsType; |
15 | | use frame_system::offchain::{Account, SendSignedTransaction, Signer}; |
16 | | use frame_system::Config as SystemConfig; |
17 | | use frame_system::Pallet as System; |
18 | | use nonce::lock_key; |
19 | | pub use nonce::nonce_key; |
20 | | use sp_runtime::offchain::storage::StorageValueRef; |
21 | | use sp_runtime::traits::{One, Saturating}; |
22 | | use sp_std::prelude::*; |
23 | | |
24 | | pub(crate) type OffchainResult<T, E = errors::OffchainError> = Result<T, E>; |
25 | | |
26 | | impl Blockchain { |
27 | 31 | pub fn rpc_url(&self) -> OffchainResult<String, RpcUrlError> { |
28 | 31 | let key = self.rpc_key(); |
29 | 31 | let rpc_url_storage = StorageValueRef::persistent(&key); |
30 | 31 | if let Some(url_bytes27 ) = rpc_url_storage.get::<Vec<u8>>()?1 { |
31 | 27 | Ok(String::from_utf8(url_bytes)?1 ) |
32 | | } else { |
33 | 3 | Err(RpcUrlError::NoValue) |
34 | | } |
35 | 31 | } |
36 | | |
37 | 53 | pub fn rpc_key(&self) -> Vec<u8> { |
38 | 53 | let chain_prefix = self.as_bytes(); |
39 | 53 | let mut buf = Vec::from(chain_prefix); |
40 | 53 | buf.extend("-rpc-uri".bytes()); |
41 | 53 | buf |
42 | 53 | } |
43 | | } |
44 | | |
45 | | const ETH_CONFIRMATIONS: u64 = 12; |
46 | | |
47 | 39 | fn parse_eth_address(address: &ExternalAddress) -> OffchainResult<rpc::Address> { |
48 | 39 | let address_bytes34 = <[u8; 20]>::try_from(address.as_slice()) |
49 | 39 | .map_err(|_| VerificationFailureCause::InvalidAddress5 )?5 ; |
50 | 34 | let address = rpc::Address::from(address_bytes); |
51 | 34 | Ok(address) |
52 | 39 | } |
53 | | |
54 | 24 | fn eth_get_transaction(tx_id: &ExternalTxId, rpc_url: &str) -> OffchainResult<rpc::EthTransaction> { |
55 | 24 | rpc::eth_get_transaction(tx_id, rpc_url).map_err(|e| { |
56 | 3 | if let RpcError::NoResult = e { |
57 | 2 | OffchainError::InvalidTask(VerificationFailureCause::TransactionNotFound) |
58 | | } else { |
59 | 1 | e.into() |
60 | | } |
61 | 24 | }) |
62 | 24 | } |
63 | | |
64 | | impl<T: Config> Pallet<T> { |
65 | 16 | fn offchain_signed_tx( |
66 | 16 | auth_id: T::FromAccountId, |
67 | 16 | call: impl Fn(&Account<T>) -> Call<T>, |
68 | 16 | ) -> Result<(), Error<T>> { |
69 | 16 | use sp_core::crypto::UncheckedFrom; |
70 | 16 | let auth_bytes: &[u8; 32] = auth_id.as_ref(); |
71 | 16 | let public: T::PublicSigning = T::InternalPublic::unchecked_from(*auth_bytes).into(); |
72 | 16 | let signer = |
73 | 16 | Signer::<T, T::AuthorityId>::any_account().with_filter(sp_std::vec![public.into()]); |
74 | 16 | let result = signer.send_signed_transaction(call); |
75 | | |
76 | 16 | if let Some((acc, res14 )) = result { |
77 | 14 | if res.is_err() { |
78 | 0 | log::error!("failure: offchain_signed_tx: tx sent: {:?}", acc.id); |
79 | 0 | return Err(Error::OffchainSignedTxFailed); |
80 | | } else { |
81 | 14 | return Ok(()); |
82 | | } |
83 | 2 | } |
84 | 2 | |
85 | 2 | log::error!("No local account available"); |
86 | 2 | Err(Error::NoLocalAcctForSignedTx) |
87 | 16 | } |
88 | | |
89 | 14 | pub fn submit_txn_with_synced_nonce( |
90 | 14 | auth_id: T::FromAccountId, |
91 | 14 | call: impl Fn(&Account<T>) -> Call<T>, |
92 | 14 | ) -> Result<(), Error<T>> { |
93 | 14 | let acc_id: &<T as SystemConfig>::AccountId = auth_id.into_ref(); |
94 | 14 | let mut account_data = System::<T>::account(acc_id); |
95 | 14 | |
96 | 14 | let key = &lock_key(auth_id.into_ref()); |
97 | 14 | let mut lock = Pallet::<T>::nonce_lock_new(key); |
98 | 14 | let _guard = lock.lock(); |
99 | 14 | |
100 | 14 | let key = &nonce_key(auth_id.into_ref()); |
101 | 14 | let synced_nonce_storage = StorageValueRef::persistent(key); |
102 | 14 | let synced_nonce = synced_nonce_storage.get::<T::Index>().ok().flatten(); |
103 | 14 | |
104 | 14 | let n = Self::block_number(); |
105 | 14 | tracing::trace!(target: "OCW", "@{n:?} Offnonce {synced_nonce:?} Onnonce {:?}", account_data.nonce); |
106 | | |
107 | 14 | if let Some(nonce3 ) = synced_nonce { |
108 | 3 | if nonce > account_data.nonce { |
109 | 2 | account_data.nonce = nonce; |
110 | 2 | frame_system::Account::<T>::insert(acc_id, account_data.clone()); |
111 | 2 | }1 |
112 | 11 | } |
113 | | |
114 | 14 | Pallet::<T>::offchain_signed_tx(auth_id, call) |
115 | 14 | .map(|_| synced_nonce_storage.set(&account_data.nonce.saturating_add(One::one()))12 ) |
116 | 14 | } |
117 | | } |
118 | | |
119 | | #[cfg(test)] |
120 | | mod tests; |