1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Copyright 2023 Axiom-Team
//
// This file is part of Duniter-v2S.
//
// Duniter-v2S is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Duniter-v2S is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.

//! Defines types and traits for users of pallet distance.

#![cfg_attr(not(feature = "std"), no_std)]
#![allow(clippy::type_complexity)]

use codec::{Decode, Encode};
use frame_support::pallet_prelude::RuntimeDebug;
use scale_info::TypeInfo;
use sp_inherents::{InherentData, InherentIdentifier, IsFatalError};
use sp_runtime::Perbill;
#[cfg(feature = "std")]
use std::marker::PhantomData;

pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"distanc0";

/// Represents the result of a distance computation.
#[derive(Clone, Decode, Encode, PartialEq, RuntimeDebug, TypeInfo)]
pub struct ComputationResult {
    pub distances: sp_std::vec::Vec<Perbill>,
}

#[derive(Encode, sp_runtime::RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Decode, thiserror::Error))]
pub enum InherentError {
    #[cfg_attr(feature = "std", error("InvalidComputationResultFile"))]
    InvalidComputationResultFile,
}

impl IsFatalError for InherentError {
    fn is_fatal_error(&self) -> bool {
        match self {
            InherentError::InvalidComputationResultFile => false,
        }
    }
}

impl InherentError {
    #[cfg(feature = "std")]
    pub fn try_from(id: &InherentIdentifier, mut data: &[u8]) -> Option<Self> {
        if id == &INHERENT_IDENTIFIER {
            <InherentError as codec::Decode>::decode(&mut data).ok()
        } else {
            None
        }
    }
}

#[cfg(feature = "std")]
pub struct InherentDataProvider<IdtyIndex: Decode + Encode + PartialEq + TypeInfo> {
    computation_result: Option<ComputationResult>,
    _p: PhantomData<IdtyIndex>,
}

#[cfg(feature = "std")]
impl<IdtyIndex: Decode + Encode + PartialEq + TypeInfo> InherentDataProvider<IdtyIndex> {
    pub fn new(computation_result: Option<ComputationResult>) -> Self {
        Self {
            computation_result,
            _p: PhantomData,
        }
    }
}

#[cfg(feature = "std")]
#[async_trait::async_trait]
impl<IdtyIndex: Decode + Encode + PartialEq + TypeInfo + Send + Sync>
    sp_inherents::InherentDataProvider for InherentDataProvider<IdtyIndex>
{
    async fn provide_inherent_data(
        &self,
        inherent_data: &mut InherentData,
    ) -> Result<(), sp_inherents::Error> {
        if let Some(computation_result) = &self.computation_result {
            inherent_data.put_data(INHERENT_IDENTIFIER, computation_result)?;
        }
        Ok(())
    }

    async fn try_handle_error(
        &self,
        identifier: &InherentIdentifier,
        error: &[u8],
    ) -> Option<Result<(), sp_inherents::Error>> {
        if *identifier != INHERENT_IDENTIFIER {
            return None;
        }

        Some(Err(sp_inherents::Error::Application(Box::from(
            InherentError::try_from(&INHERENT_IDENTIFIER, error)?,
        ))))
    }
}