#![cfg_attr(not(feature = "std"), no_std)]
use fabric_system::ensure_signed;
use fabric_support::{
dispatch::DispatchResult, decl_module, decl_storage, decl_event,
};
use tp_runtime::RuntimeDebug;
use codec::{Encode, Decode};
use tetcore_std::vec::Vec;
#[cfg(test)]
mod tests;
pub trait Config: fabric_system::Config {
type Event: From<Event> + Into<<Self as fabric_system::Config>::Event>;
type Call: From<Call<Self>>;
}
decl_storage! {
trait Store for Module<T: Config> as ExampleOffchainWorker {
Participants get(fn participants): Vec<Vec<u8>>;
CurrentEventId get(fn get_current_event_id): Vec<u8>;
}
}
decl_event!(
pub enum Event {
NewEventDrafted(Vec<u8>),
}
);
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub struct EnlistedParticipant {
pub account: Vec<u8>,
pub signature: Vec<u8>,
}
impl EnlistedParticipant {
fn verify(&self, event_id: &[u8]) -> bool {
use tet_core::Public;
use std::convert::TryFrom;
use tp_runtime::traits::Verify;
match tet_core::sr25519::Signature::try_from(&self.signature[..]) {
Ok(signature) => {
let public = tet_core::sr25519::Public::from_slice(self.account.as_ref());
signature.verify(event_id, &public)
}
_ => false
}
}
}
decl_module! {
pub struct Module<T: Config> for enum Call where origin: T::Origin {
fn deposit_event() = default;
#[weight = 0]
pub fn run_event(origin, id: Vec<u8>) -> DispatchResult {
let _ = ensure_signed(origin)?;
Participants::kill();
CurrentEventId::mutate(move |event_id| *event_id = id);
Ok(())
}
#[weight = 0]
pub fn enlist_participants(origin, participants: Vec<EnlistedParticipant>)
-> DispatchResult
{
let _ = ensure_signed(origin)?;
if validate_participants_parallel(&CurrentEventId::get(), &participants[..]) {
for participant in participants {
Participants::append(participant.account);
}
}
Ok(())
}
}
}
fn validate_participants_parallel(event_id: &[u8], participants: &[EnlistedParticipant]) -> bool {
fn spawn_verify(data: Vec<u8>) -> Vec<u8> {
let stream = &mut &data[..];
let event_id = Vec::<u8>::decode(stream).expect("Failed to decode");
let participants = Vec::<EnlistedParticipant>::decode(stream).expect("Failed to decode");
for participant in participants {
if !participant.verify(&event_id) {
return false.encode()
}
}
true.encode()
}
let mut async_payload = Vec::new();
event_id.encode_to(&mut async_payload);
participants[..participants.len() / 2].encode_to(&mut async_payload);
let handle = tp_tasks::spawn(spawn_verify, async_payload);
let mut result = true;
for participant in &participants[participants.len()/2+1..] {
if !participant.verify(event_id) {
result = false;
break;
}
}
bool::decode(&mut &handle.join()[..]).expect("Failed to decode result") && result
}