1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Tanssi is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>
16

            
17
//! Crate containing various data structure used by both xcm-core-buyer pallet
18
//! as well as the client.
19

            
20
#![cfg_attr(not(feature = "std"), no_std)]
21
extern crate alloc;
22

            
23
use {
24
    alloc::vec::Vec,
25
    frame_support::{
26
        pallet_prelude::{Decode, DecodeWithMemTracking, Encode, TypeInfo},
27
        CloneNoBound, DebugNoBound,
28
    },
29
    sp_runtime::{app_crypto::AppCrypto, RuntimeAppPublic},
30
    tp_traits::ParaId,
31
};
32

            
33
#[cfg(feature = "std")]
34
use sp_keystore::{Keystore, KeystorePtr};
35

            
36
/// Proof that I am a collator, assigned to a para_id, and I can buy a core for that para_id
37
#[derive(
38
    Encode, Decode, CloneNoBound, PartialEq, Eq, DebugNoBound, TypeInfo, DecodeWithMemTracking,
39
)]
40
pub struct BuyCoreCollatorProof<PublicKey>
41
where
42
    PublicKey: RuntimeAppPublic + Clone + core::fmt::Debug,
43
{
44
    pub nonce: u64,
45
    pub public_key: PublicKey,
46
    pub signature: PublicKey::Signature,
47
}
48

            
49
#[cfg(feature = "std")]
50
#[derive(Debug)]
51
pub enum BuyCollatorProofCreationError {
52
    SignatureDecodingError(parity_scale_codec::Error),
53
    KeyStoreError(sp_keystore::Error),
54
}
55

            
56
#[cfg(feature = "std")]
57
impl From<parity_scale_codec::Error> for BuyCollatorProofCreationError {
58
    fn from(error: parity_scale_codec::Error) -> Self {
59
        BuyCollatorProofCreationError::SignatureDecodingError(error)
60
    }
61
}
62

            
63
#[cfg(feature = "std")]
64
impl From<sp_keystore::Error> for BuyCollatorProofCreationError {
65
    fn from(error: sp_keystore::Error) -> Self {
66
        BuyCollatorProofCreationError::KeyStoreError(error)
67
    }
68
}
69

            
70
impl<PublicKey> BuyCoreCollatorProof<PublicKey>
71
where
72
    PublicKey: AppCrypto + RuntimeAppPublic + Clone + core::fmt::Debug,
73
{
74
13
    pub fn prepare_payload(nonce: u64, para_id: ParaId) -> Vec<u8> {
75
13
        (nonce, para_id).encode()
76
13
    }
77

            
78
15
    pub fn verify_signature(&self, para_id: ParaId) -> bool {
79
15
        let payload = (self.nonce, para_id).encode();
80
15
        self.public_key.verify(&payload, &self.signature)
81
15
    }
82

            
83
13
    pub fn new(nonce: u64, para_id: ParaId, public_key: PublicKey) -> Option<Self> {
84
13
        let payload = Self::prepare_payload(nonce, para_id);
85
13
        public_key
86
13
            .sign(&payload)
87
13
            .map(|signature| BuyCoreCollatorProof {
88
13
                nonce,
89
13
                public_key,
90
13
                signature,
91
13
            })
92
13
    }
93

            
94
    #[cfg(feature = "std")]
95
    pub fn new_with_keystore(
96
        nonce: u64,
97
        para_id: ParaId,
98
        public_key: PublicKey,
99
        keystore: &KeystorePtr,
100
    ) -> Result<Option<Self>, BuyCollatorProofCreationError> {
101
        let payload = Self::prepare_payload(nonce, para_id);
102

            
103
        Ok(Keystore::sign_with(
104
            keystore,
105
            <PublicKey as AppCrypto>::ID,
106
            <PublicKey as AppCrypto>::CRYPTO_ID,
107
            &public_key.to_raw_vec(),
108
            payload.as_ref(),
109
        )?
110
        .map(|signature| Decode::decode(&mut signature.as_ref()))
111
        .transpose()?
112
        .map(|signature| BuyCoreCollatorProof {
113
            nonce,
114
            public_key,
115
            signature,
116
        }))
117
    }
118
}