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, 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
1854
#[derive(Encode, Decode, CloneNoBound, PartialEq, Eq, DebugNoBound, TypeInfo)]
37
pub struct BuyCoreCollatorProof<PublicKey>
38
where
39
    PublicKey: RuntimeAppPublic + Clone + core::fmt::Debug,
40
{
41
    pub nonce: u64,
42
    pub public_key: PublicKey,
43
    pub signature: PublicKey::Signature,
44
}
45

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

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

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

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

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

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

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

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