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
#![cfg(test)]
18

            
19
use {
20
    crate::{
21
        tests::common::*, ConvictionVoting, OpenTechCommitteeCollective, Referenda, RuntimeCall,
22
    },
23
    alloc::vec,
24
    frame_support::{
25
        assert_ok,
26
        traits::{schedule::DispatchTime, Bounded},
27
        weights::Weight,
28
    },
29
    pallet_referenda::TracksInfo,
30
    parity_scale_codec::Encode,
31
    sp_core::H256,
32
    sp_runtime::traits::{BlakeTwo256, Hash},
33
};
34

            
35
#[test]
36
1
fn test_root_track_executes_with_root_origin() {
37
1
    ExtBuilder::default()
38
1
        .with_balances(vec![
39
1
            (AccountId::from(ALICE), 100_000 * UNIT),
40
1
            (AccountId::from(BOB), 100_000 * UNIT),
41
1
        ])
42
1
        .build()
43
1
        .execute_with(|| {
44
1
            let random_code_hash = H256::random();
45
1
            let proposal_call =
46
1
                RuntimeCall::System(frame_system::Call::<Runtime>::authorize_upgrade {
47
1
                    code_hash: random_code_hash,
48
1
                })
49
1
                .encode();
50
1
            assert_ok!(Referenda::submit(
51
1
                origin_of(ALICE.into()),
52
1
                Box::new(frame_support::dispatch::RawOrigin::Root.into()),
53
1
                Bounded::Inline(proposal_call.clone().try_into().unwrap()),
54
1
                DispatchTime::At(10),
55
            ));
56
1
            let index = pallet_referenda::ReferendumCount::<Runtime>::get() - 1;
57
1
            assert_ok!(Referenda::place_decision_deposit(
58
1
                origin_of(ALICE.into()),
59
1
                index
60
            ));
61
1
            let vote = pallet_conviction_voting::AccountVote::<Balance>::Standard {
62
1
                vote: pallet_conviction_voting::Vote {
63
1
                    aye: true,
64
1
                    conviction: pallet_conviction_voting::Conviction::None,
65
1
                },
66
1
                balance: 90_000 * UNIT,
67
1
            };
68
1
            assert_ok!(ConvictionVoting::vote(origin_of(ALICE.into()), index, vote));
69
1
            assert_ok!(ConvictionVoting::vote(origin_of(BOB.into()), index, vote));
70

            
71
1
            wait_for_democracy_to_pass(index);
72

            
73
            // Now we need to wait for the enactment period
74
1
            let current_block = System::block_number();
75
            // Root track is number 0
76
1
            let enactment_period = crate::governance::TracksInfo::info(0)
77
1
                .unwrap()
78
1
                .min_enactment_period;
79
1
            run_to_block(current_block + enactment_period);
80

            
81
            // We assert the call went through
82
1
            assert!(System::authorized_upgrade().is_some());
83
1
        });
84
1
}
85

            
86
#[test]
87
1
fn test_whitelist_track_executes_with_whitelist_origin_but_fails_if_not_whitelisted() {
88
1
    ExtBuilder::default()
89
1
        .with_balances(vec![
90
1
            (AccountId::from(ALICE), 100_000 * UNIT),
91
1
            (AccountId::from(BOB), 100_000 * UNIT),
92
1
        ])
93
1
        .build()
94
1
        .execute_with(|| {
95
1
            let random_code_hash = H256::random();
96
1
            let proposal_call =
97
1
                RuntimeCall::System(frame_system::Call::<Runtime>::authorize_upgrade {
98
1
                    code_hash: random_code_hash,
99
1
                });
100

            
101
1
            let proposal_call_hash = BlakeTwo256::hash(&proposal_call.encode());
102

            
103
            // We propose the whitelist call dispatch in the referenda but we will never whitelist it
104
1
            let whitelist_call = RuntimeCall::Whitelist(
105
1
                pallet_whitelist::Call::<Runtime>::dispatch_whitelisted_call {
106
1
                    call_hash: proposal_call_hash,
107
1
                    call_encoded_len: proposal_call.encode().len() as u32,
108
1
                    call_weight_witness: Weight::from_parts(1_000_000_000, 1_000_000),
109
1
                },
110
1
            )
111
1
            .encode();
112

            
113
1
            assert_ok!(Referenda::submit(
114
1
                origin_of(ALICE.into()),
115
1
                Box::new(crate::pallet_custom_origins::Origin::WhitelistedCaller.into()),
116
1
                Bounded::Inline(whitelist_call.clone().try_into().unwrap()),
117
1
                DispatchTime::At(10),
118
            ));
119
1
            let index = pallet_referenda::ReferendumCount::<Runtime>::get() - 1;
120
1
            assert_ok!(Referenda::place_decision_deposit(
121
1
                origin_of(ALICE.into()),
122
1
                index
123
            ));
124
1
            let vote = pallet_conviction_voting::AccountVote::<Balance>::Standard {
125
1
                vote: pallet_conviction_voting::Vote {
126
1
                    aye: true,
127
1
                    conviction: pallet_conviction_voting::Conviction::None,
128
1
                },
129
1
                balance: 90_000 * UNIT,
130
1
            };
131
1
            assert_ok!(ConvictionVoting::vote(origin_of(ALICE.into()), index, vote));
132
1
            assert_ok!(ConvictionVoting::vote(origin_of(BOB.into()), index, vote));
133

            
134
1
            wait_for_democracy_to_pass(index);
135

            
136
            // Now we need to wait for the enactment period
137
1
            let current_block = System::block_number();
138
            // whitelist caller track is number 1
139
1
            let enactment_period = crate::governance::TracksInfo::info(1)
140
1
                .unwrap()
141
1
                .min_enactment_period;
142
1
            run_to_block(current_block + enactment_period);
143

            
144
            // not whitelisted ergo it will fail
145
1
            assert!(System::authorized_upgrade().is_none());
146
1
        });
147
1
}
148

            
149
#[test]
150
1
fn test_whitelist_track_executes_with_whitelist_origin_works_if_whitelisted() {
151
1
    ExtBuilder::default()
152
1
        .with_balances(vec![
153
1
            (AccountId::from(ALICE), 100_000 * UNIT),
154
1
            (AccountId::from(BOB), 100_000 * UNIT),
155
1
        ])
156
1
        .build()
157
1
        .execute_with(|| {
158
            // Let's first set alice as the committee member
159
1
            assert_ok!(OpenTechCommitteeCollective::set_members(
160
1
                root_origin(),
161
1
                vec![AccountId::from(ALICE)],
162
1
                None,
163
                0
164
            ));
165

            
166
1
            let random_code_hash = H256::random();
167
1
            let proposal_call =
168
1
                RuntimeCall::System(frame_system::Call::<Runtime>::authorize_upgrade {
169
1
                    code_hash: random_code_hash,
170
1
                });
171

            
172
1
            let authorize_hash = note_preimage(AccountId::from(ALICE), &proposal_call.encode());
173

            
174
1
            let whitelist_call_dispatch = RuntimeCall::Whitelist(
175
1
                pallet_whitelist::Call::<Runtime>::dispatch_whitelisted_call {
176
1
                    call_hash: authorize_hash,
177
1
                    call_encoded_len: proposal_call.encode().len() as u32,
178
1
                    call_weight_witness: Weight::from_parts(1_000_000_000, 1_000_000),
179
1
                },
180
1
            )
181
1
            .encode();
182

            
183
1
            assert_ok!(Referenda::submit(
184
1
                origin_of(ALICE.into()),
185
1
                Box::new(crate::pallet_custom_origins::Origin::WhitelistedCaller.into()),
186
1
                Bounded::Inline(whitelist_call_dispatch.clone().try_into().unwrap()),
187
1
                DispatchTime::At(10),
188
            ));
189
1
            let index = pallet_referenda::ReferendumCount::<Runtime>::get() - 1;
190
1
            assert_ok!(Referenda::place_decision_deposit(
191
1
                origin_of(ALICE.into()),
192
1
                index
193
            ));
194
1
            let vote = pallet_conviction_voting::AccountVote::<Balance>::Standard {
195
1
                vote: pallet_conviction_voting::Vote {
196
1
                    aye: true,
197
1
                    conviction: pallet_conviction_voting::Conviction::None,
198
1
                },
199
1
                balance: 90_000 * UNIT,
200
1
            };
201
1
            assert_ok!(ConvictionVoting::vote(origin_of(ALICE.into()), index, vote));
202
1
            assert_ok!(ConvictionVoting::vote(origin_of(BOB.into()), index, vote));
203

            
204
1
            let whitelist_call =
205
1
                RuntimeCall::Whitelist(pallet_whitelist::Call::<Runtime>::whitelist_call {
206
1
                    call_hash: authorize_hash,
207
1
                });
208

            
209
            // let's waitlist!
210
            // Alice should be enough as threshold is one
211
1
            assert_ok!(OpenTechCommitteeCollective::propose(
212
1
                origin_of(ALICE.into()),
213
                //threshold
214
                1,
215
1
                Box::new(whitelist_call.clone()),
216
1
                whitelist_call.encode().len() as u32
217
            ));
218

            
219
1
            assert!(pallet_whitelist::WhitelistedCall::<Runtime>::get(authorize_hash).is_some());
220

            
221
1
            wait_for_democracy_to_pass(index);
222

            
223
            // Now we need to wait for the enactment period
224
1
            let current_block = System::block_number();
225
            // whitelist caller track is number 1
226
1
            let enactment_period = crate::governance::TracksInfo::info(1)
227
1
                .unwrap()
228
1
                .min_enactment_period;
229
1
            run_to_block(current_block + enactment_period);
230

            
231
            // whitelisted ergo it should succeed
232
1
            assert!(System::authorized_upgrade().is_some());
233
1
        });
234
1
}