Skip to content
This repository has been archived by the owner on Feb 21, 2024. It is now read-only.

Commit

Permalink
Merge pull request #149 from Acurast/feat/rpc
Browse files Browse the repository at this point in the history
feat: RPCs to replace direct storage access
  • Loading branch information
godenzim authored Feb 6, 2024
2 parents f929ff7 + da5f827 commit a9bcef9
Show file tree
Hide file tree
Showing 15 changed files with 415 additions and 45 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ exclude = ["pallets/proxy"]
[workspace.package]
authors = [ "Papers AG" ]
repository = "https://github.com/Acurast/acurast-core"
version = "0.3.1"
version = "0.3.2"

# TODO: Temporary workaround (https://substrate.stackexchange.com/questions/9870)
[patch.crates-io]
Expand Down
14 changes: 14 additions & 0 deletions pallets/acurast/common/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ pub type CertificateRevocationListUpdate = ListUpdate<SerialNumber>;

/// Structure representing a job registration.
#[derive(RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
pub struct JobRegistration<AccountId, MaxAllowedSources: Get<u32>, Extra> {
/// The script to execute. It is a vector of bytes representing a utf8 string. The string needs to be a ipfs url that points to the script.
pub script: Script,
Expand All @@ -109,6 +111,8 @@ pub type PubKeyBytes = BoundedVec<u8, ConstU32<PUB_KEYS_MAX_LENGTH>>;

/// Structure representing execution environment variables encrypted for a specific processor.
#[derive(RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
pub struct Environment<
MaxEnvVars: ParameterBound,
KeyMaxSize: ParameterBound,
Expand Down Expand Up @@ -331,6 +335,16 @@ impl<const T: u32> TypedGet for CU32<T> {
}
}

#[cfg(feature = "std")]
impl<const T: u32> Serialize for CU32<T> {
fn serialize<D>(&self, serializer: D) -> Result<D::Ok, D::Error>
where
D: serde::Serializer,
{
serializer.serialize_u32(<Self as TypedGet>::get())
}
}

#[cfg(feature = "std")]
impl<'de, const T: u32> Deserialize<'de> for CU32<T> {
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
Expand Down
10 changes: 5 additions & 5 deletions pallets/marketplace/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,17 @@ frame-benchmarking = { git = "https://github.com/paritytech/polkadot-sdk", defau
frame-support = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, tag = "polkadot-v1.1.0" }
frame-system = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, tag = "polkadot-v1.1.0" }
sp-std = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, tag = "polkadot-v1.1.0" }
sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, tag = "polkadot-v1.1.0" }
sp-io = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, tag = "polkadot-v1.1.0" }
sp-core = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, tag = "polkadot-v1.1.0" }
jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"], optional = true }
sp-blockchain = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, tag = "polkadot-v1.1.0", optional = true }
pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, tag = "polkadot-v1.1.0" }
pallet-timestamp = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, tag = "polkadot-v1.1.0" }

# for RPC
sp-blockchain = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, tag = "polkadot-v1.1.0", optional = true }
jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"], optional = true }
sp-api = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-v1.1.0", default-features = false }
serde = { version = "1.0.188", features = ["derive"], default-features = false }
thiserror = "1.0"
thiserror = { version = "1.0", optional = true }
log = { version = "0.4.17", default-features = false }

# Polkadot
Expand Down Expand Up @@ -92,7 +91,6 @@ std = [
"scale-info/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
"sp-version/std",
"xcm-builder/std",
Expand All @@ -103,5 +101,7 @@ std = [
"jsonrpsee",
"sp-blockchain",
"log/std",
"thiserror",
"sp-blockchain",
]
try-runtime = ["frame-support/try-runtime"]
8 changes: 4 additions & 4 deletions pallets/marketplace/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use frame_benchmarking::{benchmarks, whitelist_account};
use frame_support::{assert_ok, traits::IsType};
use frame_system::RawOrigin;
use sp_core::*;
use sp_runtime::{
use frame_support::sp_runtime::{
traits::{IdentifyAccount, Verify},
DispatchError,
};
use frame_support::{assert_ok, traits::IsType};
use frame_system::RawOrigin;
use sp_core::*;
use sp_std::prelude::*;

use crate::Config;
Expand Down
41 changes: 35 additions & 6 deletions pallets/marketplace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,16 @@ pub mod weights;

pub(crate) use pallet::STORAGE_VERSION;

use frame_support::pallet_prelude::Get;
use pallet_acurast::MultiOrigin;
use pallet_acurast::{Attestation, Environment, JobId, MultiOrigin, ParameterBound};
use sp_std::prelude::*;

#[cfg(feature = "runtime-benchmarks")]
pub use benchmarking::BenchmarkHelper;

#[frame_support::pallet]
pub mod pallet {
use frame_support::sp_runtime::traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub};
use frame_support::sp_runtime::{FixedPointOperand, FixedU128, Permill, SaturatedConversion};
use frame_support::traits::tokens::Balance;
use frame_support::{
dispatch::DispatchResultWithPostInfo, ensure, pallet_prelude::*, traits::UnixTime,
Expand All @@ -45,8 +46,6 @@ pub mod pallet {
use frame_system::pallet_prelude::*;
use itertools::Itertools;
use reputation::{BetaParameters, BetaReputation, ReputationEngine};
use sp_runtime::traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub};
use sp_runtime::{FixedPointOperand, FixedU128, Permill, SaturatedConversion};
use sp_std::iter::once;
use sp_std::prelude::*;

Expand Down Expand Up @@ -1175,6 +1174,8 @@ pub mod pallet {

/// Filters the given `sources` by those recently seen and matching partially specified `registration`
/// and whitelisting `consumer` if specifying a whitelist.
///
/// Intended to be called for providing runtime API, might return corresponding error.
pub fn filter_matching_sources(
registration: PartialJobRegistration<T::Balance, T::AccountId, T::MaxAllowedSources>,
sources: Vec<T::AccountId>,
Expand Down Expand Up @@ -1488,6 +1489,21 @@ pub mod pallet {
Ok(().into())
}

/// Returns the stored matches for a source.
///
/// Intended to be called for providing runtime API, might return corresponding error.
pub fn stored_matches_for_source(
source: T::AccountId,
) -> Result<Vec<JobAssignmentFor<T>>, RuntimeApiError> {
<StoredMatches<T>>::iter_prefix(source)
.map(|(job_id, assignment)| {
let job = <StoredJobRegistration<T>>::get(&job_id.0, &job_id.1)
.ok_or(RuntimeApiError::MatchedJobs)?;
Ok(JobAssignment { job, assignment })
})
.collect()
}

/// Returns the current timestamp.
pub fn now() -> Result<u64, Error<T>> {
Ok(<T as pallet_acurast::Config>::UnixTime::now()
Expand All @@ -1500,12 +1516,25 @@ pub mod pallet {

sp_api::decl_runtime_apis! {
/// API to interact with Acurast marketplace pallet.
pub trait MarketplaceRuntimeApi<R: codec::Codec, AccountId: codec::Codec, MaxAllowedSources: Get<u32>> {
pub trait MarketplaceRuntimeApi<Reward: codec::Codec, AccountId: codec::Codec, Extra: codec::Codec, MaxAllowedSources: ParameterBound, MaxEnvVars: ParameterBound, EnvKeyMaxSize: ParameterBound, EnvValueMaxSize: ParameterBound> {
fn filter_matching_sources(
registration: PartialJobRegistration<R, AccountId, MaxAllowedSources>,
registration: PartialJobRegistration<Reward, AccountId, MaxAllowedSources>,
sources: Vec<AccountId>,
consumer: Option<MultiOrigin<AccountId>>,
latest_seen_after: Option<u128>,
) -> Result<Vec<AccountId>, RuntimeApiError>;

fn job_environment(
job_id: JobId<AccountId>,
source: AccountId,
) -> Result<Option<Environment<MaxEnvVars, EnvKeyMaxSize, EnvValueMaxSize>>, RuntimeApiError>;

fn matched_jobs(
source: AccountId,
) -> Result<Vec<JobAssignment<Reward, AccountId, MaxAllowedSources, Extra>>, RuntimeApiError>;

fn attestation(
source: AccountId,
) -> Result<Option<Attestation>, RuntimeApiError>;
}
}
6 changes: 3 additions & 3 deletions pallets/marketplace/src/mock.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use frame_support::sp_runtime::traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256};
use frame_support::sp_runtime::DispatchError;
use frame_support::sp_runtime::{BuildStorage, Percent};
use frame_support::{parameter_types, traits::Everything, PalletId};
use sp_core::*;
use sp_io;
use sp_runtime::traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256};
use sp_runtime::DispatchError;
use sp_runtime::{BuildStorage, Percent};
use sp_std::prelude::*;

use pallet_acurast::{
Expand Down
2 changes: 1 addition & 1 deletion pallets/marketplace/src/payments.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::marker::PhantomData;

use frame_support::sp_runtime::SaturatedConversion;
use frame_support::traits::tokens::Preservation;
use frame_support::{
pallet_prelude::Member,
Expand All @@ -10,7 +11,6 @@ use frame_support::{
traits::tokens::fungible,
PalletId,
};
use sp_runtime::SaturatedConversion;
use sp_std::prelude::*;
use xcm::prelude::AssetId;

Expand Down
119 changes: 106 additions & 13 deletions pallets/marketplace/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,31 @@
use std::{marker::PhantomData, sync::Arc};

use crate::{MarketplaceRuntimeApi, PartialJobRegistration, RuntimeApiError};
use crate::{JobAssignment, MarketplaceRuntimeApi, PartialJobRegistration, RuntimeApiError};
use codec::Codec;
use frame_support::pallet_prelude::Get;
use frame_support::sp_runtime::traits::{Block as BlockT, HashingFor, MaybeSerializeDeserialize};
use jsonrpsee::{
core::{async_trait, RpcResult},
proc_macros::rpc,
types::error::{CallError, ErrorObject},
};
use pallet_acurast::MultiOrigin;
use pallet_acurast::{Attestation, Environment, JobId, MultiOrigin, ParameterBound};
use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_runtime::traits::Block as BlockT;
use sp_runtime::traits::HashingFor;
use sp_runtime::traits::MaybeSerializeDeserialize;

const RUNTIME_ERROR: i32 = 8001;
const MARKETPLACE_ERROR: i32 = 8011;

/// Hyperdrive RPC methods.
#[rpc(client, server)]
pub trait MarketplaceApi<
BlockHash,
Reward: MaybeSerializeDeserialize,
AccountId: MaybeSerializeDeserialize,
MaxAllowedSources: Get<u32>,
Extra: MaybeSerializeDeserialize,
MaxAllowedSources: ParameterBound,
MaxEnvVars: ParameterBound,
EnvKeyMaxSize: ParameterBound,
EnvValueMaxSize: ParameterBound,
>
{
/// Filters the given `sources` by those recently seen and matching partially specified `registration`
Expand All @@ -39,6 +39,29 @@ pub trait MarketplaceApi<
consumer: Option<MultiOrigin<AccountId>>,
latest_seen_after: Option<u128>,
) -> RpcResult<Vec<AccountId>>;

/// Retrieves the job environment.
#[method(name = "orchestrator_jobEnvironment")]
fn job_environment(
&self,
job_id: JobId<AccountId>,
source: AccountId,
) -> RpcResult<Option<Environment<MaxEnvVars, EnvKeyMaxSize, EnvValueMaxSize>>>;

/// Retrieves the job assignment with the aggregated job.
#[method(name = "orchestrator_matchedJobs")]
fn matched_jobs(
&self,
source: AccountId,
) -> RpcResult<Vec<JobAssignment<Reward, AccountId, MaxAllowedSources, Extra>>>;

/// Retrieves a processor's attestation.
#[method(name = "orchestrator_attestation")]
fn attestation(&self, source: AccountId) -> RpcResult<Option<Attestation>>;

/// Retrieves a processor's attestation.
#[method(name = "orchestrator_is_attested")]
fn is_attested(&self, source: AccountId) -> RpcResult<bool>;
}

/// RPC methods.
Expand All @@ -58,16 +81,47 @@ impl<C, B> Marketplace<C, B> {
}

#[async_trait]
impl<Client, Block, Reward, AccountId, MaxAllowedSources>
MarketplaceApiServer<HashingFor<Block>, Reward, AccountId, MaxAllowedSources>
for Marketplace<Client, (Block, Reward, AccountId)>
impl<
Client,
Block,
Reward,
AccountId,
Extra,
MaxAllowedSources,
MaxEnvVars,
EnvKeyMaxSize,
EnvValueMaxSize,
>
MarketplaceApiServer<
HashingFor<Block>,
Reward,
AccountId,
Extra,
MaxAllowedSources,
MaxEnvVars,
EnvKeyMaxSize,
EnvValueMaxSize,
> for Marketplace<Client, Block>
where
Block: BlockT,
Client: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
Client::Api: MarketplaceRuntimeApi<Block, Reward, AccountId, MaxAllowedSources>,
Client::Api: MarketplaceRuntimeApi<
Block,
Reward,
AccountId,
Extra,
MaxAllowedSources,
MaxEnvVars,
EnvKeyMaxSize,
EnvValueMaxSize,
>,
Reward: MaybeSerializeDeserialize + Codec + Send + Sync + 'static,
AccountId: MaybeSerializeDeserialize + Codec + Send + Sync + 'static,
MaxAllowedSources: Get<u32>,
Extra: MaybeSerializeDeserialize + Codec + Send + Sync + 'static,
MaxAllowedSources: ParameterBound,
MaxEnvVars: ParameterBound,
EnvKeyMaxSize: ParameterBound,
EnvValueMaxSize: ParameterBound,
{
fn filter_matching_sources(
&self,
Expand All @@ -89,13 +143,52 @@ where
.map_err(marketplace_error_into_rpc_error)?;
Ok(roots)
}

fn job_environment(
&self,
job_id: JobId<AccountId>,
source: AccountId,
) -> RpcResult<Option<Environment<MaxEnvVars, EnvKeyMaxSize, EnvValueMaxSize>>> {
let api = self.client.runtime_api();
let env = api
.job_environment(self.client.info().best_hash, job_id, source)
.map_err(runtime_error_into_rpc_error)?
.map_err(marketplace_error_into_rpc_error)?;
Ok(env)
}

fn matched_jobs(
&self,
source: AccountId,
) -> RpcResult<Vec<JobAssignment<Reward, AccountId, MaxAllowedSources, Extra>>> {
let api = self.client.runtime_api();
let jobs = api
.matched_jobs(self.client.info().best_hash, source)
.map_err(runtime_error_into_rpc_error)?
.map_err(marketplace_error_into_rpc_error)?;
Ok(jobs)
}

fn attestation(&self, source: AccountId) -> RpcResult<Option<Attestation>> {
let api = self.client.runtime_api();
let attestation = api
.attestation(self.client.info().best_hash, source)
.map_err(runtime_error_into_rpc_error)?
.map_err(marketplace_error_into_rpc_error)?;
Ok(attestation)
}

fn is_attested(&self, source: AccountId) -> RpcResult<bool> {
Ok(self.attestation(source)?.is_some())
}
}

/// Converts an marketplace-specific error into a [`CallError`].
fn marketplace_error_into_rpc_error(err: RuntimeApiError) -> CallError {
let error_code = MARKETPLACE_ERROR
+ match err {
RuntimeApiError::FilterMatchingSources => 1,
RuntimeApiError::MatchedJobs => 3,
};

CallError::Custom(ErrorObject::owned(
Expand Down
2 changes: 1 addition & 1 deletion pallets/marketplace/src/stub.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![allow(dead_code)]

use frame_support::sp_runtime::AccountId32;
use hex_literal::hex;
use sp_runtime::AccountId32;

use pallet_acurast::{AttestationChain, Script, SerialNumber};

Expand Down
Loading

0 comments on commit a9bcef9

Please sign in to comment.