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

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

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

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

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

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

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

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

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

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

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

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