Coverage Report

Created: 2022-11-10 19:56

/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;