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
use {
18
    frame_support::pallet_prelude::*,
19
    parity_scale_codec::DecodeAll,
20
    snowbridge_core::{Channel, PRIMARY_GOVERNANCE_CHANNEL},
21
    snowbridge_router_primitives::inbound::{envelope::Envelope, MessageProcessor},
22
    sp_runtime::DispatchError,
23
    sp_std::vec::Vec,
24
};
25

            
26
/// Magic bytes are added in every payload intended for this processor to make sure
27
/// that we are the intended recipient of the message. Reason being scale encoding is not type aware.
28
/// So a same set of bytes can be decoded for two different data structures if their
29
/// total size is same. Magic bytes can be checked after decoding to make sure that the sender
30
/// indeed send a message intended for this processor.
31
pub const MAGIC_BYTES: [u8; 4] = [112, 21, 0, 56];
32

            
33
/// Payload is the whole data we expect to receive from the relayer
34
#[derive(Encode, Decode, DebugNoBound)]
35
pub struct Payload<T>
36
where
37
    T: pallet_external_validators::Config,
38
{
39
    pub magic_bytes: [u8; 4],
40
    pub message: Message<T>,
41
}
42

            
43
/// Actual message inside the payload
44
#[derive(Encode, Decode, DebugNoBound)]
45
pub enum Message<T>
46
where
47
    T: pallet_external_validators::Config,
48
{
49
37
    V1(InboundCommand<T>),
50
}
51

            
52
/// Command to be executed by this message processor
53
#[derive(Encode, Decode, DebugNoBound)]
54
pub enum InboundCommand<T>
55
where
56
    T: pallet_external_validators::Config,
57
{
58
37
    ReceiveValidators {
59
        validators: Vec<<T as pallet_external_validators::Config>::ValidatorId>,
60
        external_index: u64,
61
    },
62
}
63

            
64
pub struct SymbioticMessageProcessor<T>(PhantomData<T>);
65

            
66
impl<T> MessageProcessor for SymbioticMessageProcessor<T>
67
where
68
    T: pallet_external_validators::Config,
69
{
70
31
    fn can_process_message(_channel: &Channel, envelope: &Envelope) -> bool {
71
31
        let decode_result = Payload::<T>::decode_all(&mut envelope.payload.as_slice());
72
31
        match decode_result {
73
12
            Ok(payload) => {
74
12
                if payload.magic_bytes == MAGIC_BYTES {
75
10
                    true
76
                } else {
77
2
                    log::debug!("SymbioticMessageProcessor: magic number mismatch, will try next processor: {:?}", payload.magic_bytes);
78
2
                    false
79
                }
80
            }
81
19
            Err(e) => {
82
19
                // Message cannot be decoded as `Payload`.
83
19
                // This is expected if the message is intended for a different processor.
84
19
                log::trace!("SymbioticMessageProcessor: failed to decode payload. This is expected if the message is not for this processor. Error: {:?}", e);
85
19
                false
86
            }
87
        }
88
31
    }
89

            
90
12
    fn process_message(_channel: Channel, envelope: Envelope) -> Result<(), DispatchError> {
91
12
        let decode_result = Payload::<T>::decode_all(&mut envelope.payload.as_slice());
92
12
        let message = if let Ok(payload) = decode_result {
93
10
            payload.message
94
        } else {
95
2
            return Err(DispatchError::Other("unable to parse the envelope payload"));
96
        };
97

            
98
10
        log::trace!("SymbioticMessageProcessor: {:?}", message);
99

            
100
10
        match message {
101
10
            Message::V1(InboundCommand::ReceiveValidators {
102
10
                validators,
103
10
                external_index,
104
10
            }) => {
105
10
                if envelope.channel_id != PRIMARY_GOVERNANCE_CHANNEL {
106
2
                    return Err(DispatchError::Other(
107
2
                        "Received governance message from invalid channel id",
108
2
                    ));
109
8
                }
110
8
                pallet_external_validators::Pallet::<T>::set_external_validators_inner(
111
8
                    validators,
112
8
                    external_index,
113
8
                )?;
114
8
                Ok(())
115
            }
116
        }
117
12
    }
118
}