From 4bf55fd60438ef8d3298d4ee96d938f38299d4da Mon Sep 17 00:00:00 2001 From: mrisholukamba Date: Sat, 3 Sep 2022 14:31:32 +0300 Subject: [PATCH] review structure --- .idea/.gitignore | 3 + .idea/modules.xml | 8 + .idea/substrate-tutorials.iml | 17 ++ .idea/vcs.xml | 6 + exercises/ex05-offchain-workers/README.md | 0 .../http-call/Cargo.toml | 40 ++++ .../ex05-offchain-workers/http-call/README.md | 0 .../http-call/src/lib.rs | 74 +++++++ .../http-call/src/tests.rs | 95 +++++++++ .../offchain-call/Cargo.toml | 43 ++++ .../offchain-call/README.md | 0 .../offchain-call/src/lib.rs | 150 ++++++++++++++ .../offchain-call/src/ocw_test_mod.rs | 22 +++ .../offchain-call/src/tests.rs | 184 ++++++++++++++++++ .../transaction-function/Cargo.toml | 39 ++++ .../transaction-function/README.md | 0 .../transaction-function/src/lib.rs | 88 +++++++++ .../transaction-function/src/ocw_test_mod.rs | 22 +++ .../transaction-function/src/tests.rs | 124 ++++++++++++ 19 files changed, 915 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/modules.xml create mode 100644 .idea/substrate-tutorials.iml create mode 100644 .idea/vcs.xml create mode 100644 exercises/ex05-offchain-workers/README.md create mode 100644 exercises/ex05-offchain-workers/http-call/Cargo.toml create mode 100644 exercises/ex05-offchain-workers/http-call/README.md create mode 100644 exercises/ex05-offchain-workers/http-call/src/lib.rs create mode 100644 exercises/ex05-offchain-workers/http-call/src/tests.rs create mode 100644 exercises/ex05-offchain-workers/offchain-call/Cargo.toml create mode 100644 exercises/ex05-offchain-workers/offchain-call/README.md create mode 100644 exercises/ex05-offchain-workers/offchain-call/src/lib.rs create mode 100644 exercises/ex05-offchain-workers/offchain-call/src/ocw_test_mod.rs create mode 100644 exercises/ex05-offchain-workers/offchain-call/src/tests.rs create mode 100644 exercises/ex05-offchain-workers/transaction-function/Cargo.toml create mode 100644 exercises/ex05-offchain-workers/transaction-function/README.md create mode 100644 exercises/ex05-offchain-workers/transaction-function/src/lib.rs create mode 100644 exercises/ex05-offchain-workers/transaction-function/src/ocw_test_mod.rs create mode 100644 exercises/ex05-offchain-workers/transaction-function/src/tests.rs diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..c4aa550 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/substrate-tutorials.iml b/.idea/substrate-tutorials.iml new file mode 100644 index 0000000..b4a7307 --- /dev/null +++ b/.idea/substrate-tutorials.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/exercises/ex05-offchain-workers/README.md b/exercises/ex05-offchain-workers/README.md new file mode 100644 index 0000000..e69de29 diff --git a/exercises/ex05-offchain-workers/http-call/Cargo.toml b/exercises/ex05-offchain-workers/http-call/Cargo.toml new file mode 100644 index 0000000..f6fd913 --- /dev/null +++ b/exercises/ex05-offchain-workers/http-call/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "pallet-http-call" +version = "2.5.0" +edition = "2021" +authors = ["Mrisho Lukamba"] +description = "https://github.com/MrishoLukamba/MrishoLukamba" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-runtime = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-std = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.27"} + +log = "0.4.17" +lite-json = "0.2.0" + +[dev-dependencies] +sp-core = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-io = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-runtime = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", +] diff --git a/exercises/ex05-offchain-workers/http-call/README.md b/exercises/ex05-offchain-workers/http-call/README.md new file mode 100644 index 0000000..e69de29 diff --git a/exercises/ex05-offchain-workers/http-call/src/lib.rs b/exercises/ex05-offchain-workers/http-call/src/lib.rs new file mode 100644 index 0000000..96feb3f --- /dev/null +++ b/exercises/ex05-offchain-workers/http-call/src/lib.rs @@ -0,0 +1,74 @@ +#![cfg_attr(not(feature = "std"),no_std)] +#[cfg(test)] +mod tests; + +pub use pallet::*; +#[frame_support::pallet] +pub mod pallet{ + use frame_system::pallet_prelude::*; + use frame_support::pallet_prelude::*; + use sp_runtime::offchain::{http}; + use log; + use lite_json; + use lite_json::JsonValue; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + + impl Pallet { + pub fn get_external_data() -> Result { + + let request = http::Request::get("https://api.fda.gov/food/enforcement.json?limit=0"); + let pending = request.send().map_err(|_|http::Error::Unknown)?; + let result = pending.wait(); + + let response = result.map_err(|_| http::Error::IoError)?; + + if response.code != 200 { + log::info!("Failed Response Code {}",response.code); + return Err(http::Error::IoError) + } + log::info!("fetched success"); + + let body = response.body().collect::>(); + let body_str = sp_std::str::from_utf8(&body[..]) + .map_err(|_| http::Error::Unknown)?; + let body_json = lite_json::json_parser::parse_json(body_str) + .map_err(|_|http::Error::Unknown)?; + let result_total = Self::parse_to_int(body_json).unwrap(); + Ok(result_total) + + } + + pub fn parse_to_int(body: JsonValue) -> Option{ + let result = match body { + JsonValue::Object(obj) => { + let (_,val) = obj.into_iter().find(|(k,_)| k.iter().copied().eq("meta".chars()))?; + match val { + JsonValue::Object(obj) => { + let (_,val) = obj.into_iter().find(|(k,_)|k.iter().copied().eq("results".chars()))?; + match val { + JsonValue::Object(obj) => { + let (_,val) = obj.into_iter().find(|(k,_)|k.iter().copied().eq("total".chars()))?; + match val { + JsonValue::Number(num) => Some(num), + _=> None + } + }, + _=> None + } + }, + _=> None + } + }, + _=> None + }; + Some(result.unwrap().integer as u32) + } + } + +} diff --git a/exercises/ex05-offchain-workers/http-call/src/tests.rs b/exercises/ex05-offchain-workers/http-call/src/tests.rs new file mode 100644 index 0000000..d1f16e6 --- /dev/null +++ b/exercises/ex05-offchain-workers/http-call/src/tests.rs @@ -0,0 +1,95 @@ +use crate as pallet_http_call; +use frame_support::traits::{ConstU16, ConstU32, ConstU64}; +use sp_runtime::{ + testing::{Header}, + traits::{Extrinsic, IdentifyAccount, Verify} +}; +use sp_core::H256; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, +}; +use sp_core::{ + offchain::{testing, OffchainWorkerExt, TransactionPoolExt}, + sr25519::Signature, +}; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum TestRuntime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + HttpCall: pallet_http_call, + } +); + + +impl frame_system::Config for TestRuntime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<42>; + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_http_call::Config for TestRuntime {} + +#[test] +fn test_htt_call(){ + let mut test_ext = sp_io::TestExternalities::default(); + let (ocw, ocw_state) = testing::TestOffchainExt::new(); + let ocw_ext = OffchainWorkerExt::new(ocw); + test_ext.register_extension(ocw_ext); + + ocw_state.write().expect_request(testing::PendingRequest { + method: "GET".into(), + uri: "https://api.fda.gov/food/enforcement.json?limit=0".into(), + response: Some(br#" + { + "meta": { + "disclaimer": "Do not rely on openFDA to make decisions regarding medical care. While we make every effort to ensure that data is accurate, you should assume all results are unvalidated. We may limit or otherwise restrict your access to the API in line with our Terms of Service.", + "terms": "https://open.fda.gov/terms/", + "license": "https://open.fda.gov/license/", + "last_updated": "2022-08-31", + "results": { + "skip": 0, + "limit": 0, + "total": 22840 + } + }, + "results": [] + } + "#.to_vec()), + sent: true, + ..Default::default() + }); + + + test_ext.execute_with(||{ + let total_result = HttpCall::get_external_data().unwrap(); + assert_eq!(total_result,22840); + }) +} diff --git a/exercises/ex05-offchain-workers/offchain-call/Cargo.toml b/exercises/ex05-offchain-workers/offchain-call/Cargo.toml new file mode 100644 index 0000000..16dfec6 --- /dev/null +++ b/exercises/ex05-offchain-workers/offchain-call/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "pallet-offchain-call" +version = "2.5.0" +edition = "2021" +authors = ["Mrisho Lukamba"] +description = "https://github.com/MrishoLukamba/MrishoLukamba" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-runtime = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-core = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +log = "0.4.17" +sp-std = { default-features = false, version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.27"} +lite-json = "0.2.0" + +[dev-dependencies] +sp-core = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-io = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-runtime = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-keystore = { version="0.12.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28"} + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-runtime/std", + "sp-core/std", + "sp-std/std" +] diff --git a/exercises/ex05-offchain-workers/offchain-call/README.md b/exercises/ex05-offchain-workers/offchain-call/README.md new file mode 100644 index 0000000..e69de29 diff --git a/exercises/ex05-offchain-workers/offchain-call/src/lib.rs b/exercises/ex05-offchain-workers/offchain-call/src/lib.rs new file mode 100644 index 0000000..d66042f --- /dev/null +++ b/exercises/ex05-offchain-workers/offchain-call/src/lib.rs @@ -0,0 +1,150 @@ +#![cfg_attr(not(feature ="std"),no_std)] +#[cfg(test)] +mod tests; +#[cfg(test)] +mod ocw_test_mod; + +use sp_runtime::offchain::KeyTypeId; +pub use offchain::*; +pub const KEY_TYPE:KeyTypeId = KeyTypeId(*b"test"); +pub mod offchain { + use super::KEY_TYPE; + use sp_core::sr25519::Signature as Sr25519Signature; + use sp_runtime::{ + app_crypto::{app_crypto, sr25519}, + traits::Verify, + MultiSignature, MultiSigner + }; + app_crypto!(sr25519,KEY_TYPE); + pub struct Authority; + + impl frame_system::offchain::AppCrypto for Authority { + type RuntimeAppPublic = sr25519::AppPublic; + type GenericSignature = Sr25519Signature; + type GenericPublic = sp_core::sr25519::Public; + } +} + +pub use pallet::*; +#[frame_support::pallet] +pub mod pallet{ + use frame_system::pallet_prelude::*; + use frame_support::pallet_prelude::*; + use super::*; + use log; + use sp_runtime::offchain::{http}; + use lite_json; + use lite_json::JsonValue; + use frame_system::offchain::{ + AppCrypto, CreateSignedTransaction, SendSignedTransaction, + SignedPayload, Signer, SigningTypes, SubmitTransaction, + }; + #[pallet::config] + pub trait Config: CreateSignedTransaction> + frame_system::Config { + type Event: From> + IsType<::Event>; + type Authority: AppCrypto; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + ValueStored + } + + #[pallet::storage] + #[pallet::getter(fn get_value)] + pub type ResultValue = StorageValue<_, u32, ValueQuery>; + + #[pallet::hooks] + impl Hooks> for Pallet{ + fn offchain_worker(_n: BlockNumberFor) { + Self::send_signed_transaction().map_err(|_|log::info!("Failed Function")); + } + } + + #[pallet::call] + impl Pallet { + #[pallet::weight(10)] + pub fn set_value(origin: OriginFor, value: u32) ->DispatchResult { + ensure_signed(origin)?; + ResultValue::::put(value); + Self::deposit_event(Event::::ValueStored); + Ok(()) + + } + } + + impl Pallet{ + + pub fn send_signed_transaction()-> Result<(),&'static str> { + let signer = Signer::::all_accounts(); + let value = Self::get_external_data().unwrap(); + let result = signer.send_signed_transaction(|account|{ + Call::set_value{value} + }); + for (acc, res) in result{ + match res { + Ok(()) => log::info!("Success submitted by {:?}",acc.id), + Err(()) => log::info!("Failed submitted by {:?}",acc.id) + } + }; + Ok(()) + } + } + + impl Pallet { + pub fn get_external_data() -> Result { + + let request = http::Request::get("https://api.fda.gov/food/enforcement.json?limit=0"); + let pending = request.send().map_err(|_|http::Error::Unknown)?; + let result = pending.wait(); + + let response = result.map_err(|_| http::Error::IoError)?; + + if response.code != 200 { + log::info!("Failed Response Code {}",response.code); + return Err(http::Error::IoError) + } + log::info!("fetched success"); + + let body = response.body().collect::>(); + let body_str = sp_std::str::from_utf8(&body[..]) + .map_err(|_| http::Error::Unknown)?; + let body_json = lite_json::json_parser::parse_json(body_str) + .map_err(|_|http::Error::Unknown)?; + let result_total = Self::parse_to_int(body_json).unwrap(); + Ok(result_total) + + } + + pub fn parse_to_int(body: JsonValue) -> Option{ + let result = match body { + JsonValue::Object(obj) => { + let (_,val) = obj.into_iter().find(|(k,_)| k.iter().copied().eq("meta".chars()))?; + match val { + JsonValue::Object(obj) => { + let (_,val) = obj.into_iter().find(|(k,_)|k.iter().copied().eq("results".chars()))?; + match val { + JsonValue::Object(obj) => { + let (_,val) = obj.into_iter().find(|(k,_)|k.iter().copied().eq("total".chars()))?; + match val { + JsonValue::Number(num) => Some(num), + _=> None + } + }, + _=> None + } + }, + _=> None + } + }, + _=> None + }; + Some(result.unwrap().integer as u32) + } + } + +} diff --git a/exercises/ex05-offchain-workers/offchain-call/src/ocw_test_mod.rs b/exercises/ex05-offchain-workers/offchain-call/src/ocw_test_mod.rs new file mode 100644 index 0000000..30ba28b --- /dev/null +++ b/exercises/ex05-offchain-workers/offchain-call/src/ocw_test_mod.rs @@ -0,0 +1,22 @@ + +use sp_runtime::offchain::KeyTypeId; + +pub const KEY_TEST:KeyTypeId = KeyTypeId(*b"test"); + +pub use ocw_test::*; +pub mod ocw_test{ + use super::KEY_TEST; + use sp_runtime::{ + testing::{UintAuthorityId, TestSignature}, + app_crypto::{app_crypto, sr25519}, + traits::Verify + }; + pub struct Authority; + + impl frame_system::offchain::AppCrypto for Authority { + type RuntimeAppPublic = UintAuthorityId; + type GenericSignature = TestSignature; + type GenericPublic = UintAuthorityId; + } + +} diff --git a/exercises/ex05-offchain-workers/offchain-call/src/tests.rs b/exercises/ex05-offchain-workers/offchain-call/src/tests.rs new file mode 100644 index 0000000..50e93d5 --- /dev/null +++ b/exercises/ex05-offchain-workers/offchain-call/src/tests.rs @@ -0,0 +1,184 @@ +use crate as pallet_offchain_call; +use frame_support::traits::{ConstU16, ConstU32, ConstU64}; +use frame_support::{assert_ok, assert_noop}; +use sp_runtime::{ + testing::{Header,TestSignature, TestXt}, + traits::{BlakeTwo256, IdentityLookup}, +}; +use sp_runtime::DispatchError::BadOrigin; +use sp_runtime::{ + traits::{Extrinsic, IdentifyAccount, Verify} +}; +use frame_system::offchain::{AppCrypto,SigningTypes, CreateSignedTransaction, SendTransactionTypes}; + +use sp_core::H256; + +use sp_core::{ + offchain::{testing, OffchainWorkerExt, TransactionPoolExt}, + sr25519::Signature, +}; +use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStore}; +use crate::ocw_test_mod::ocw_test; + +use sp_core::ExecutionContext::OffchainCall; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum TestRuntime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Offchain: pallet_offchain_call, + } +); + + +impl frame_system::Config for TestRuntime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<42>; + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +//Implementing CreateSignedTransaction trait and other dependency traits +type AccountId = <::Signer as IdentifyAccount>::AccountId; +type TestExtrinsic = TestXt; + +impl CreateSignedTransaction for TestRuntime where Call: From,{ + fn create_transaction> + (call: Call, + _public:::Signer, + _account: AccountId, + nonce: u64 + ) -> Option<(Call, ::SignaturePayload)> { + Some((call,(nonce,()))) + } +} + +impl SendTransactionTypes for TestRuntime where Call: From{ + type Extrinsic = TestExtrinsic; + type OverarchingCall = Call; +} +impl SigningTypes for TestRuntime { + type Public = ::Signer; + type Signature = TestSignature; +} + + +impl pallet_offchain_call::Config for TestRuntime { + type Event = Event; + type Authority = ocw_test::Authority; +} + +#[test] +fn test_set_value_call(){ + let mut test_ext = sp_io::TestExternalities::default(); + + test_ext.execute_with(||{ + assert_ok!(Offchain::set_value(Origin::signed(1),230)); + assert_eq!(Offchain::get_value(),230); + //Should Fail + assert_noop!(Offchain::set_value(Origin::root(),203), BadOrigin); + + }) +} + +#[test] +fn test_send_signed_transaction(){ + let mut test_ext = sp_io::TestExternalities::default(); + + let (ocw, ocw_state) = testing::TestOffchainExt::new(); + let ocw_ext = OffchainWorkerExt::new(ocw); + test_ext.register_extension(ocw_ext); + + ocw_state.write().expect_request(testing::PendingRequest { + method: "GET".into(), + uri: "https://api.fda.gov/food/enforcement.json?limit=0".into(), + response: Some(br#" + { + "meta": { + "disclaimer": "Do not rely on openFDA to make decisions regarding medical care. While we make every effort to ensure that data is accurate, you should assume all results are unvalidated. We may limit or otherwise restrict your access to the API in line with our Terms of Service.", + "terms": "https://open.fda.gov/terms/", + "license": "https://open.fda.gov/license/", + "last_updated": "2022-08-31", + "results": { + "skip": 0, + "limit": 0, + "total": 22840 + } + }, + "results": [] + } + "#.to_vec()), + sent: true, + ..Default::default() + }); + + test_ext.execute_with(||{ + + assert_eq!(Offchain::send_signed_transaction().unwrap(),()); + + }) +} + +#[test] +fn test_htt_call(){ + let mut test_ext = sp_io::TestExternalities::default(); + let (ocw, ocw_state) = testing::TestOffchainExt::new(); + let ocw_ext = OffchainWorkerExt::new(ocw); + test_ext.register_extension(ocw_ext); + + ocw_state.write().expect_request(testing::PendingRequest { + method: "GET".into(), + uri: "https://api.fda.gov/food/enforcement.json?limit=0".into(), + response: Some(br#" + { + "meta": { + "disclaimer": "Do not rely on openFDA to make decisions regarding medical care. While we make every effort to ensure that data is accurate, you should assume all results are unvalidated. We may limit or otherwise restrict your access to the API in line with our Terms of Service.", + "terms": "https://open.fda.gov/terms/", + "license": "https://open.fda.gov/license/", + "last_updated": "2022-08-31", + "results": { + "skip": 0, + "limit": 0, + "total": 22840 + } + }, + "results": [] + } + "#.to_vec()), + sent: true, + ..Default::default() + }); + + + test_ext.execute_with(||{ + let total_result = Offchain::get_external_data().unwrap(); + assert_eq!(total_result,22840); + }) +} diff --git a/exercises/ex05-offchain-workers/transaction-function/Cargo.toml b/exercises/ex05-offchain-workers/transaction-function/Cargo.toml new file mode 100644 index 0000000..69b585b --- /dev/null +++ b/exercises/ex05-offchain-workers/transaction-function/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "pallet-transaction-function" +version = "2.5.0" +edition = "2021" +authors = ["Mrisho Lukamba"] +description = "https://github.com/MrishoLukamba/MrishoLukamba" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-runtime = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-core = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +log = "0.4.17" +[dev-dependencies] +sp-core = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-io = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-runtime = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28" } +sp-keystore = { version="0.12.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.28"} + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-runtime/std", + "sp-core/std" +] diff --git a/exercises/ex05-offchain-workers/transaction-function/README.md b/exercises/ex05-offchain-workers/transaction-function/README.md new file mode 100644 index 0000000..e69de29 diff --git a/exercises/ex05-offchain-workers/transaction-function/src/lib.rs b/exercises/ex05-offchain-workers/transaction-function/src/lib.rs new file mode 100644 index 0000000..c137ffa --- /dev/null +++ b/exercises/ex05-offchain-workers/transaction-function/src/lib.rs @@ -0,0 +1,88 @@ +#![cfg_attr(not(feature = "std"),no_std)] +#[cfg(test)] +mod tests; + +#[cfg(test)] +mod ocw_test_mod; + +use sp_runtime::offchain::KeyTypeId; +pub use offchain::*; +pub const KEY_TYPE:KeyTypeId = KeyTypeId(*b"test"); +pub mod offchain { + use super::KEY_TYPE; + use sp_core::sr25519::Signature as Sr25519Signature; + use sp_runtime::{ + app_crypto::{app_crypto, sr25519}, + traits::Verify, + MultiSignature, MultiSigner + }; + app_crypto!(sr25519,KEY_TYPE); + pub struct Authority; + + impl frame_system::offchain::AppCrypto for Authority { + type RuntimeAppPublic = sr25519::AppPublic; + type GenericSignature = Sr25519Signature; + type GenericPublic = sp_core::sr25519::Public; + } +} +pub use pallet::*; +#[frame_support::pallet] +pub mod pallet{ + use frame_system::pallet_prelude::*; + use frame_support::pallet_prelude::*; + use super::*; + use log; + use frame_system::offchain::{ + AppCrypto, CreateSignedTransaction, SendSignedTransaction, + SignedPayload, Signer, SigningTypes, SubmitTransaction, + }; + #[pallet::config] + pub trait Config: CreateSignedTransaction> + frame_system::Config { + type Event: From> + IsType<::Event>; + type Authority: AppCrypto; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + ValueStored + } + + #[pallet::storage] + #[pallet::getter(fn get_value)] + pub type ResultValue = StorageValue<_, u32, ValueQuery>; + + + #[pallet::call] + impl Pallet { + #[pallet::weight(10)] + pub fn set_value(origin: OriginFor, value: u32) ->DispatchResult { + ensure_signed(origin)?; + ResultValue::::put(value); + Self::deposit_event(Event::::ValueStored); + Ok(()) + + } + } + + impl Pallet{ + + pub fn send_signed_transaction()-> Result<(),&'static str> { + let signer = Signer::::all_accounts(); + let result = signer.send_signed_transaction(|account|{ + Call::set_value{value: 230} + }); + for (acc, res) in result{ + match res { + Ok(()) => log::info!("Success submitted by {:?}",acc.id), + Err(()) => log::info!("Failed submitted by {:?}",acc.id) + } + }; + Ok(()) + } + } + +} diff --git a/exercises/ex05-offchain-workers/transaction-function/src/ocw_test_mod.rs b/exercises/ex05-offchain-workers/transaction-function/src/ocw_test_mod.rs new file mode 100644 index 0000000..30ba28b --- /dev/null +++ b/exercises/ex05-offchain-workers/transaction-function/src/ocw_test_mod.rs @@ -0,0 +1,22 @@ + +use sp_runtime::offchain::KeyTypeId; + +pub const KEY_TEST:KeyTypeId = KeyTypeId(*b"test"); + +pub use ocw_test::*; +pub mod ocw_test{ + use super::KEY_TEST; + use sp_runtime::{ + testing::{UintAuthorityId, TestSignature}, + app_crypto::{app_crypto, sr25519}, + traits::Verify + }; + pub struct Authority; + + impl frame_system::offchain::AppCrypto for Authority { + type RuntimeAppPublic = UintAuthorityId; + type GenericSignature = TestSignature; + type GenericPublic = UintAuthorityId; + } + +} diff --git a/exercises/ex05-offchain-workers/transaction-function/src/tests.rs b/exercises/ex05-offchain-workers/transaction-function/src/tests.rs new file mode 100644 index 0000000..ca703cf --- /dev/null +++ b/exercises/ex05-offchain-workers/transaction-function/src/tests.rs @@ -0,0 +1,124 @@ +#[allow(unused_imports)] +use super::*; +use crate as pallet_transaction_function; +use frame_support::{assert_ok,assert_err,assert_noop}; +use frame_support::traits::{ConstU16, ConstU32, ConstU64}; +use frame_system as system; +use frame_system::offchain::{AppCrypto,SigningTypes, CreateSignedTransaction, SendTransactionTypes}; +use sp_core::H256; +use sp_runtime::{ + testing::{Header,TestSignature, TestXt}, + traits::{BlakeTwo256, IdentityLookup}, +}; +use sp_core::{ + offchain::{testing, OffchainWorkerExt, TransactionPoolExt}, + sr25519::Signature, +}; +use sp_core::offchain::testing::TestTransactionPoolExt; + +use sp_runtime::{ + traits::{Extrinsic, IdentifyAccount, Verify} +}; +use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStore}; +use sp_runtime::DispatchError::BadOrigin; +use crate::Event::ValueStored; +use crate::ocw_test_mod::ocw_test; +use crate::offchain; + + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum TestRuntime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + TxnFunction: pallet_transaction_function, + } +); + +impl system::Config for TestRuntime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<42>; + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +//Implementing CreateSignedTransaction trait and other dependency traits +type AccountId = <::Signer as IdentifyAccount>::AccountId; +type TestExtrinsic = TestXt; + +impl CreateSignedTransaction for TestRuntime where Call: From,{ + fn create_transaction> + (call: Call, + _public:::Signer, + _account: AccountId, + nonce: u64 + ) -> Option<(Call, ::SignaturePayload)> { + Some((call,(nonce,()))) + } +} + +impl SendTransactionTypes for TestRuntime where Call: From{ + type Extrinsic = TestExtrinsic; + type OverarchingCall = Call; +} +impl SigningTypes for TestRuntime { + type Public = ::Signer; + type Signature = TestSignature; +} + + + impl pallet_transaction_function::Config for TestRuntime { + type Event = Event; + type Authority = ocw_test::Authority; + } + + +#[test] +fn test_set_value_call(){ + let mut test_ext = sp_io::TestExternalities::default(); + + test_ext.execute_with(||{ + assert_ok!(TxnFunction::set_value(Origin::signed(1),230)); + assert_eq!(TxnFunction::get_value(),230); + //Should Fail + assert_noop!(TxnFunction::set_value(Origin::root(),203), BadOrigin); + + }) +} + +#[test] +fn test_send_signed_transaction(){ + let mut test_ext = sp_io::TestExternalities::default(); + + test_ext.execute_with(||{ + + assert_eq!(TxnFunction::send_signed_transaction().unwrap(),()); + + }) +}