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

Commit

Permalink
feat/ota-support (#144)
Browse files Browse the repository at this point in the history
* feat: added extrinsics and storage for ota support

* fix: reverted to resolver version 1

* fix: added conditional std for dependencies

* fix: updated to latest version of asn1 and combined insert_binary_hash and remove_binary_hash into update_binary_hash

* fix: adapted benchmarks
  • Loading branch information
godenzim committed Dec 15, 2023
1 parent 742f1ec commit cedcc0b
Show file tree
Hide file tree
Showing 13 changed files with 595 additions and 145 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
panic = "unwind"

[workspace]
resolver = "1"
members = [
"pallets/*",
"pallets/acurast/common",
Expand Down
9 changes: 8 additions & 1 deletion pallets/acurast/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ scale-info = { version = "2.2.0", features = ["derive"], default-features = fals
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.43" }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.43" }
# Attestation
asn1 = { version = "0.11.0", default-features = false, features = ["derive"], optional = true }
asn1 = { version = "0.15.5", default-features = false, optional = true }
p256 = { git = "https://github.com/Acurast/elliptic-curves", default-features = false, features = ["ecdsa", "sha256"], optional = true }
p384 = { package = "p384_vendored", path = "../p384", default-features = false, features = ["ecdsa", "arithmetic", "expose-field"], optional = true }
sha2 = { version = "0.10", default-features = false, optional = true }
num-bigint = { version = "0.4.3", default-features = false, optional = true }
ecdsa-vendored = { package = "ecdsa_vendored", path = "../p384/ecdsa", default-features = false, optional = true }
serde = { version = "1.0.136", optional = true, features = ["derive"] }
chrono = { version = "^0.4", default-features = false, optional = true }

[dev-dependencies]
base64 = { version = "0.13.0", default-features = false, features = ["alloc"] }
Expand All @@ -36,7 +37,12 @@ std = [
"codec/std",
"scale-info/std",
"asn1?/std",
"p256?/std",
"p384?/std",
"sha2?/std",
"num-bigint?/std",
"serde",
"chrono?/std",
]
attestation = [
"asn1",
Expand All @@ -45,4 +51,5 @@ attestation = [
"sha2",
"num-bigint",
"ecdsa-vendored",
"chrono",
]
21 changes: 7 additions & 14 deletions pallets/acurast/common/src/attestation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,38 +60,31 @@ pub fn extract_attestation<'a>(

match version {
1 => {
let parsed = asn1::parse_single::<KeyDescriptionV1>(extension.extn_value)
.map_err(|error| ValidationError::ParseError(error.to_string()))?;
let parsed = asn1::parse_single::<KeyDescriptionV1>(extension.extn_value)?;
Ok(KeyDescription::V1(parsed))
}
2 => {
let parsed = asn1::parse_single::<KeyDescriptionV2>(extension.extn_value)
.map_err(|error| ValidationError::ParseError(error.to_string()))?;
let parsed = asn1::parse_single::<KeyDescriptionV2>(extension.extn_value)?;
Ok(KeyDescription::V2(parsed))
}
3 => {
let parsed = asn1::parse_single::<KeyDescriptionV3>(extension.extn_value)
.map_err(|error| ValidationError::ParseError(error.to_string()))?;
let parsed = asn1::parse_single::<KeyDescriptionV3>(extension.extn_value)?;
Ok(KeyDescription::V3(parsed))
}
4 => {
let parsed = asn1::parse_single::<KeyDescriptionV4>(extension.extn_value)
.map_err(|error| ValidationError::ParseError(error.to_string()))?;
let parsed = asn1::parse_single::<KeyDescriptionV4>(extension.extn_value)?;
Ok(KeyDescription::V4(parsed))
}
100 => {
let parsed = asn1::parse_single::<KeyDescriptionKeyMint>(extension.extn_value)
.map_err(|error| ValidationError::ParseError(error.to_string()))?;
let parsed = asn1::parse_single::<KeyDescriptionKeyMint>(extension.extn_value)?;
Ok(KeyDescription::V100(parsed))
}
200 => {
let parsed = asn1::parse_single::<KeyDescriptionKeyMint>(extension.extn_value)
.map_err(|error| ValidationError::ParseError(error.to_string()))?;
let parsed = asn1::parse_single::<KeyDescriptionKeyMint>(extension.extn_value)?;
Ok(KeyDescription::V200(parsed))
}
300 => {
let parsed = asn1::parse_single::<KeyDescriptionKeyMint>(extension.extn_value)
.map_err(|error| ValidationError::ParseError(error.to_string()))?;
let parsed = asn1::parse_single::<KeyDescriptionKeyMint>(extension.extn_value)?;
Ok(KeyDescription::V300(parsed))
}
_ => Err(ValidationError::UnsupportedAttestationVersion(version)),
Expand Down
35 changes: 31 additions & 4 deletions pallets/acurast/common/src/attestation/asn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use asn1::{
ObjectIdentifier, ParseResult, SequenceOf, SetOf, SimpleAsn1Readable, SimpleAsn1Writable, Tag,
Tlv, WriteBuf, WriteResult,
};
use chrono;
use chrono::{Datelike, Timelike};
use sp_std::prelude::*;

#[derive(Asn1Read, Asn1Write, Clone)]
Expand Down Expand Up @@ -94,10 +96,35 @@ pub enum Time {

impl Time {
pub fn timestamp_millis(&self) -> u64 {
match self {
Time::UTCTime(time) => time.as_chrono().timestamp_millis().try_into().unwrap(),
Time::GeneralizedTime(time) => time.as_chrono().timestamp_millis().try_into().unwrap(),
}
let date_time = match self {
Time::UTCTime(time) => time.as_datetime(), //time.as_chrono().timestamp_millis().try_into().unwrap(),
Time::GeneralizedTime(time) => time.as_datetime(), //time.as_chrono().timestamp_millis().try_into().unwrap(),
};
let initial = chrono::NaiveDateTime::default();
let milliseconds = initial
.with_second(date_time.second().into())
.map(|t| {
t.with_minute(date_time.minute().into())
.map(|t| {
t.with_hour(date_time.hour().into())
.map(|t| {
t.with_day(date_time.day().into())
.map(|t| {
t.with_month(date_time.month().into())
.map(|t| t.with_year(date_time.year().into()))
.flatten()
})
.flatten()
})
.flatten()
})
.flatten()
})
.flatten()
.map(|t| t.timestamp_millis())
.unwrap_or(0);

milliseconds.try_into().unwrap()
}
}

Expand Down
2 changes: 1 addition & 1 deletion pallets/acurast/common/src/attestation/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub enum ValidationError {
/// Generic decode error
DecodeError,
/// Generic parse error
ParseError(String),
ParseError,
/// The root certificate is not trusted
UntrustedRoot,
/// Missing extension field in certificate
Expand Down
4 changes: 2 additions & 2 deletions pallets/processor-manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.43" }

acurast-common = { path = "../acurast/common", default-features = false }

# Benchmarks
frame-benchmarking = { git = "https://github.com/paritytech/substrate", optional = true, default-features = false, branch = "polkadot-v0.9.43" }
sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.43" }
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.43" }
pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.43" }
pallet-assets = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.43" }
pallet-uniques = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.43" }
Expand Down Expand Up @@ -50,11 +50,11 @@ std = [
"frame-system/std",
"frame-benchmarking/std",
"acurast-common/std",
"sp-core/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"sp-io",
"sp-core",
"pallet-balances/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
"pallet-uniques/runtime-benchmarks",
Expand Down
42 changes: 42 additions & 0 deletions pallets/processor-manager/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,47 @@ benchmarks! {
let ad = T::BenchmarkHelper::advertisement();
}: _(RawOrigin::Signed(caller), update.item.account.into().into(), ad)

heartbeat_with_version {
let caller: T::AccountId = alice_account_id().into();
whitelist_account!(caller);
let update = generate_pairing_update_add::<T>(0);
Pallet::<T>::update_processor_pairings(RawOrigin::Signed(caller.clone()).into(), vec![update.clone()].try_into().unwrap())?;
let version = Version {
platform: 0,
build_number: 1,
};
}: _(RawOrigin::Signed(caller), version)

update_binary_hash {
let version = Version {
platform: 0,
build_number: 1,
};
let hash: BinaryHash = [1; 32].into();
}: _(RawOrigin::Root, version, Some(hash))

set_processor_update_info {
let x in 1 .. T::MaxProcessorsInSetUpdateInfo::get();
let caller: T::AccountId = alice_account_id().into();
whitelist_account!(caller);
let mut processors = Vec::<T::AccountId>::new();
for i in 0..x {
let update = generate_pairing_update_add::<T>(i);
processors.push(update.item.account.clone());
Pallet::<T>::update_processor_pairings(RawOrigin::Signed(caller.clone()).into(), vec![update.clone()].try_into().unwrap())?;
}
let version = Version {
platform: 0,
build_number: 1,
};
let hash: BinaryHash = [1; 32].into();
Pallet::<T>::update_binary_hash(RawOrigin::Root.into(), version.clone(), Some(hash))?;
let binary_location: BinaryLocation = b"https://github.com/Acurast/acurast-processor-update/releases/download/processor-1.3.31/processor-1.3.31-devnet.apk".to_vec().try_into().unwrap();
let update_info = UpdateInfo {
version,
binary_location,
};
}: _(RawOrigin::Signed(caller), update_info, processors.try_into().unwrap())

impl_benchmark_test_suite!(Pallet, mock::ExtBuilder::default().build(), mock::Test);
}
94 changes: 91 additions & 3 deletions pallets/processor-manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod benchmarking;

#[cfg(feature = "runtime-benchmarks")]
pub use benchmarking::BenchmarkHelper;
use frame_support::BoundedVec;
pub use functions::*;
pub use pallet::*;
pub use traits::*;
Expand All @@ -29,7 +30,9 @@ pub type ProcessorPairingUpdateFor<T> =
ProcessorPairingUpdate<<T as frame_system::Config>::AccountId, <T as Config>::Proof>;

pub type ProcessorUpdatesFor<T> =
frame_support::BoundedVec<ProcessorPairingUpdateFor<T>, <T as Config>::MaxPairingUpdates>;
BoundedVec<ProcessorPairingUpdateFor<T>, <T as Config>::MaxPairingUpdates>;
pub type ProcessorList<T> =
BoundedVec<<T as frame_system::Config>::AccountId, <T as Config>::MaxProcessorsInSetUpdateInfo>;

#[frame_support::pallet]
pub mod pallet {
Expand All @@ -44,10 +47,13 @@ pub mod pallet {
traits::{Get, UnixTime},
Blake2_128, Parameter,
};
use frame_system::{ensure_signed, pallet_prelude::OriginFor};
use frame_system::{ensure_root, ensure_signed, pallet_prelude::OriginFor};
use sp_std::prelude::*;

use crate::{traits::*, ProcessorPairingFor, ProcessorUpdatesFor};
use crate::{
traits::*, BinaryHash, ProcessorList, ProcessorPairingFor, ProcessorUpdatesFor, UpdateInfo,
Version,
};

/// Configure the pallet by specifying the parameters and types on which it depends.
#[pallet::config]
Expand All @@ -59,6 +65,7 @@ pub mod pallet {
type ManagerIdProvider: ManagerIdProvider<Self>;
type ProcessorAssetRecovery: ProcessorAssetRecovery<Self>;
type MaxPairingUpdates: Get<u32>;
type MaxProcessorsInSetUpdateInfo: Get<u32>;
type Counter: Parameter + Member + MaxEncodedLen + Copy + CheckedAdd + Ord + From<u8>;
type PairingProofExpirationTime: Get<u128>;
type Advertisement: Parameter + Member;
Expand Down Expand Up @@ -140,6 +147,21 @@ pub mod pallet {
#[pallet::getter(fn processor_last_seen)]
pub(super) type ProcessorHeartbeat<T: Config> = StorageMap<_, Blake2_128, T::AccountId, u128>;

#[pallet::storage]
#[pallet::getter(fn processor_version)]
pub(super) type ProcessorVersion<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, Version>;

#[pallet::storage]
#[pallet::getter(fn known_binary_hash)]
pub(super) type KnownBinaryHash<T: Config> =
StorageMap<_, Blake2_128Concat, Version, BinaryHash>;

#[pallet::storage]
#[pallet::getter(fn processor_update_info)]
pub(super) type ProcessorUpdateInfo<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, UpdateInfo>;

#[pallet::pallet]
pub struct Pallet<T>(_);

Expand All @@ -158,6 +180,12 @@ pub mod pallet {
ProcessorHeartbeat(T::AccountId),
/// Processor advertisement. [manager_account_id, processor_account_id, advertisement]
ProcessorAdvertisement(T::AccountId, T::AccountId, T::Advertisement),
/// Heartbeat with version information. [processor_account_id, version]
ProcessorHeartbeatWithVersion(T::AccountId, Version),
/// Binary hash updated. [version, binary_hash]
BinaryHashUpdated(Version, Option<BinaryHash>),
/// Set update info for processor. [manager_account_id, update_info]
ProcessorUpdateInfoSet(T::AccountId, UpdateInfo),
}

// Errors inform users that something went wrong.
Expand All @@ -170,6 +198,7 @@ pub mod pallet {
ProcessorHasNoManager,
CounterOverflow,
PairingProofExpired,
UnknownProcessorVersion,
}

impl<T: Config> Pallet<T> {
Expand Down Expand Up @@ -333,5 +362,64 @@ pub mod pallet {

Ok(().into())
}

#[pallet::call_index(5)]
#[pallet::weight(T::WeightInfo::heartbeat_with_version())]
pub fn heartbeat_with_version(
origin: OriginFor<T>,
version: Version,
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
_ = Self::manager_id_for_processor(&who).ok_or(Error::<T>::ProcessorHasNoManager)?;

<ProcessorHeartbeat<T>>::insert(&who, T::UnixTime::now().as_millis());
<ProcessorVersion<T>>::insert(&who, version.clone());

Self::deposit_event(Event::<T>::ProcessorHeartbeatWithVersion(who, version));

Ok(().into())
}

#[pallet::call_index(6)]
#[pallet::weight(T::WeightInfo::update_binary_hash())]
pub fn update_binary_hash(
origin: OriginFor<T>,
version: Version,
hash: Option<BinaryHash>,
) -> DispatchResultWithPostInfo {
ensure_root(origin)?;

if let Some(hash) = &hash {
<KnownBinaryHash<T>>::insert(&version, hash.clone());
} else {
<KnownBinaryHash<T>>::remove(&version)
}

Self::deposit_event(Event::<T>::BinaryHashUpdated(version, hash));

Ok(().into())
}

#[pallet::call_index(8)]
#[pallet::weight(T::WeightInfo::set_processor_update_info(processors.len() as u32))]
pub fn set_processor_update_info(
origin: OriginFor<T>,
update_info: UpdateInfo,
processors: ProcessorList<T>,
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;

_ = Self::known_binary_hash(&update_info.version)
.ok_or(Error::<T>::UnknownProcessorVersion)?;

for processor in processors {
_ = Self::ensure_managed(&who, &processor)?;
<ProcessorUpdateInfo<T>>::insert(&processor, update_info.clone());
}

Self::deposit_event(Event::<T>::ProcessorUpdateInfoSet(who, update_info));

Ok(().into())
}
}
}
1 change: 1 addition & 0 deletions pallets/processor-manager/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ impl Config for Test {
type ManagerIdProvider = AcurastManagerIdProvider;
type ProcessorAssetRecovery = AcurastProcessorAssetRecovery;
type MaxPairingUpdates = ConstU32<5>;
type MaxProcessorsInSetUpdateInfo = ConstU32<100>;
type Counter = u64;
type PairingProofExpirationTime = ConstU128<600000>;
type UnixTime = pallet_timestamp::Pallet<Test>;
Expand Down
Loading

0 comments on commit cedcc0b

Please sign in to comment.