pchain_runtime/execution/
execute.rs

1/*
2    Copyright © 2023, ParallelChain Lab
3    Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
4*/
5
6//! Implementation of execution process on a sequence of Commands. The process starts from Pre-Charge phase,
7//! and then goes into Commands Phases, and finally Charge Phase.
8//!
9//! Processes include execution of:
10//! - [Commands](pchain_types::blockchain::Command) from a transaction (Account Command and Staking Command).
11//! - [View call](https://github.com/parallelchain-io/parallelchain-protocol/blob/master/Contracts.md#view-calls).
12//! - [Next Epoch](pchain_types::blockchain::Command::NextEpoch) Command.
13//!
14//! ### Executing Commands from a Transaction
15//!
16//! It is the normal flow of a transaction. Firstly, basic checking is performed and
17//! cancel the execution if it fails, and Balance of signer is deducted beforehand (Pre-Charge).
18//!
19//! Then Commands are encapsulated into `Command Tasks`. Each command task is an item in
20//! a stack. Execution order starts from the top item. When [Call](pchain_types::blockchain::Command::Call)
21//! Command is executed successfully with `Deferred Command`, the Deferred Commands are then
22//! encapsulated into Command Task and put to the stack. This stack model allows the Deferred Command
23//! to be executed right after its parent Call Command in the same way other commands do.
24//!
25//! Each command task completes with a [Command Receipt](pchain_types::blockchain::CommandReceipt). If
26//! it fails, the process aborts and then goes to Charge Phase immediately.
27//!
28//! Finally in the Charge Phase, the signer balance is adjusted according to the gas used. Some fees are also
29//! transferred to Proposer and Treasury.
30//!
31//! ### Executing a View Call
32//!
33//! View Call means execution of a contract by calling its view-only methods. There is not Pre-Charge Phase nor
34//! Charge Phase. The gas used in the resulting command receipt is only catered for the gas consumption of this
35//! contract call.
36//!
37//! ### Executing Next Epoch Command
38//!
39//! Next Epoch Command is a special command that does not go through Pre-Charge Phase or Charge Phase, but
40//! will modify the state and update signers nonce. Its goal is to compute the resulting state of
41//! Network Account and return changes to a validator set for next epoch in [TransitionResult].
42
43use pchain_types::blockchain::{Command, CommandReceipt, ExitStatus};
44use pchain_types::cryptography::PublicAddress;
45use pchain_world_state::storage::WorldStateStorage;
46
47use crate::{
48    transition::StateChangesResult, types::DeferredCommand, TransitionError, TransitionResult,
49};
50
51use super::{
52    account,
53    phase::{self},
54    protocol, staking,
55    state::ExecutionState,
56};
57
58/// Backbone logic of Commands Execution
59pub(crate) fn execute_commands<S>(
60    mut state: ExecutionState<S>,
61    commands: Vec<Command>,
62) -> TransitionResult<S>
63where
64    S: WorldStateStorage + Send + Sync + Clone,
65{
66    // Phase: Pre-Charge
67    if let Err(err) = phase::pre_charge(&mut state) {
68        return TransitionResult {
69            new_state: state.ctx.rw_set.ws,
70            receipt: None,
71            error: Some(err),
72            validator_changes: None,
73        };
74    }
75    let mut prev_gas_used = state.gas_consumed();
76
77    // Phase: Command(s)
78    let mut command_task_results = CommandTaskResults::new();
79    let mut command_tasks = CommandTasks::new();
80    command_tasks.append(
81        commands
82            .into_iter()
83            .map(CommandTaskItem::TransactionCommmand)
84            .collect(),
85        None,
86    );
87    while let Some(command_task) = command_tasks.next_task() {
88        let task_id = command_task.task_id;
89        let (actor, command) = match command_task.command {
90            CommandTaskItem::TransactionCommmand(command) => (state.tx.signer, command),
91            CommandTaskItem::DeferredCommand(deferred_command) => {
92                (deferred_command.contract_address, deferred_command.command)
93            }
94        };
95
96        // Execute command triggered from the Transaction
97        let ret = account::try_execute(state, &command)
98            .or_else(|state| staking::try_execute(actor, state, &command))
99            .unwrap();
100
101        // Proceed execution result
102        state = match ret {
103            // command execution is not completed, continue with resulting state
104            Ok(mut state_of_success_execution) => {
105                // append command triggered from Call
106                if let Some(commands_from_call) = state_of_success_execution.ctx.pop_commands() {
107                    command_tasks.append(
108                        commands_from_call
109                            .into_iter()
110                            .map(CommandTaskItem::DeferredCommand)
111                            .collect(),
112                        Some(task_id),
113                    );
114                }
115                // extract receipt from current execution result
116                let cmd_receipt =
117                    state_of_success_execution.extract(prev_gas_used, ExitStatus::Success);
118                command_task_results.push(task_id, cmd_receipt);
119                state_of_success_execution
120            }
121            // in case of error, create the last Command receipt and return result
122            Err(StateChangesResult {
123                state: mut state_of_abort_result,
124                error,
125            }) => {
126                // extract receipt from last execution result
127                let cmd_receipt =
128                    state_of_abort_result.extract(prev_gas_used, error.as_ref().unwrap().into());
129                command_task_results.push(task_id, cmd_receipt);
130                return StateChangesResult::new(state_of_abort_result, error)
131                    .finalize(command_task_results.command_receipts());
132            }
133        };
134        prev_gas_used = state.gas_consumed();
135    }
136
137    // Phase: Charge
138    phase::charge(state, None).finalize(command_task_results.command_receipts())
139}
140
141/// Execute a View Call
142pub(crate) fn execute_view<S>(
143    state: ExecutionState<S>,
144    target: PublicAddress,
145    method: String,
146    arguments: Option<Vec<Vec<u8>>>,
147) -> (CommandReceipt, Option<TransitionError>)
148where
149    S: WorldStateStorage + Send + Sync + Clone,
150{
151    match account::call(state, true, target, method, arguments, None) {
152        // not yet finish. continue command execution with resulting state
153        Ok(mut state_of_success_execution) => {
154            let cmd_receipt = state_of_success_execution.extract(0, ExitStatus::Success);
155            (cmd_receipt, None)
156        }
157        Err(StateChangesResult {
158            state: mut state_of_abort_result,
159            error,
160        }) => {
161            let cmd_receipt = state_of_abort_result.extract(0, error.as_ref().unwrap().into());
162            (cmd_receipt, error)
163        }
164    }
165}
166
167/// Execution of NextEpoch Command.
168pub(crate) fn execute_next_epoch_command<S>(
169    state: ExecutionState<S>,
170    commands: Vec<Command>,
171) -> TransitionResult<S>
172where
173    S: WorldStateStorage + Send + Sync + Clone,
174{
175    let signer = state.tx.signer;
176
177    // Validate the input transaction:
178    // - There can only be one NextEpoch Command in a transaction.
179    // - Block performance is required for execution of next epoch transaction.
180    // - Transaction nonce matches with the nonce in state
181    if  commands.len() != 1 || commands.first() != Some(&Command::NextEpoch) ||
182        state.bd.validator_performance.is_none() ||
183        state.tx.nonce != state.ws.nonce(signer)
184    {
185        return TransitionResult {
186            new_state: state.ctx.rw_set.ws,
187            receipt: None,
188            error: Some(TransitionError::InvalidNextEpochCommand),
189            validator_changes: None,
190        };
191    }
192
193    // State transition
194    let (mut state, new_vs) = protocol::next_epoch(state);
195
196    // Update Nonce for the transaction. This step ensures future epoch transaction produced
197    // by the signer will have different transaction hash.
198    let nonce = state.ws.nonce(signer).saturating_add(1);
199    state.ws.with_commit().set_nonce(signer, nonce);
200
201    // Extract receipt from current execution result
202    let cmd_receipt = state.extract(0, ExitStatus::Success);
203
204    let mut result = StateChangesResult::new(state, None).finalize(vec![cmd_receipt]);
205    result.validator_changes = Some(new_vs);
206    result
207}
208
209type TaskID = u32;
210
211/// CommandTasks is a sequence of CommandTask, which follows the properties of CommandTask.
212#[derive(Debug)]
213pub(crate) struct CommandTasks(Vec<CommandTask>);
214
215impl CommandTasks {
216    fn new() -> Self {
217        Self(Vec::new())
218    }
219
220    /// append a sequence of Commands and store as CommandTask with assigned task ID.
221    fn append(&mut self, mut commands: Vec<CommandTaskItem>, same_task_id: Option<u32>) {
222        let mut task_id = match same_task_id {
223            Some(id) => id,
224            None => self.0.last().map_or(0, |t| t.task_id + 1),
225        };
226        commands.reverse();
227        for command in commands {
228            self.0.push(CommandTask { task_id, command });
229            if same_task_id.is_none() {
230                task_id += 1;
231            }
232        }
233    }
234
235    /// Pop the next task to execute
236    fn next_task(&mut self) -> Option<CommandTask> {
237        self.0.pop()
238    }
239}
240
241/// CommandTask encapsulates the task to execute a command. An ID number is assigned to a task.
242/// There may be multple command tasks sharing the same Task ID. In this case, the commands are
243/// considered as one command such that their results should be combined together as one receipt.
244#[derive(Debug)]
245pub(crate) struct CommandTask {
246    task_id: TaskID,
247    command: CommandTaskItem,
248}
249
250/// CommandTaskItem defines types of command to be executed in a Command Task.
251#[derive(Debug)]
252pub(crate) enum CommandTaskItem {
253    /// The Command that is submitted from Transaction input
254    TransactionCommmand(Command),
255    /// The Command that is submitted (deferred) from a Contract Call
256    DeferredCommand(DeferredCommand),
257}
258
259/// CommandTaskResults is a sequence of CommandTaskResult, which follows the properties of CommandTaskResult.
260pub(crate) struct CommandTaskResults(Vec<CommandTaskResult>);
261
262impl CommandTaskResults {
263    fn new() -> Self {
264        Self(Vec::new())
265    }
266
267    /// push the next Command Receipt into Results. Combine with the last
268    /// receipt if Task ID is as same as the last one.
269    fn push(&mut self, task_id: TaskID, command_receipt: CommandReceipt) {
270        if let Some(last_result) = self.0.last_mut() {
271            if last_result.task_id == task_id {
272                last_result.combine(command_receipt);
273                return;
274            }
275        }
276        self.0.push(CommandTaskResult {
277            task_id,
278            command_receipt,
279        });
280    }
281
282    fn command_receipts(self) -> Vec<CommandReceipt> {
283        self.0.into_iter().map(|r| r.command_receipt).collect()
284    }
285}
286
287/// CommandTaskResult is the result of execution of a CommandTask, which is used to combine
288/// the Command Receipt into one if the tasks are sharing same Task ID:
289/// - Gas used is added up by the later command receipt
290/// - Exit status is overwritten by the later command receipt (i.e. if the last command fails, the exit status should also be failed.)
291/// - Return value is overwritten by the later command receipt
292pub(crate) struct CommandTaskResult {
293    task_id: TaskID,
294    command_receipt: CommandReceipt,
295}
296
297impl CommandTaskResult {
298    /// Combine the information from next Command Receipt
299    fn combine(&mut self, next_command_receipt: CommandReceipt) {
300        self.command_receipt.gas_used = self
301            .command_receipt
302            .gas_used
303            .saturating_add(next_command_receipt.gas_used);
304        self.command_receipt.exit_status = next_command_receipt.exit_status;
305        self.command_receipt.return_values = next_command_receipt.return_values;
306    }
307}
308
309/// TryExecuteResult defines what result information the Command Execution should end up with. In general,
310/// it defines two resulting states Ok (command is executed with a result) and Err (command is not accepted to be executed).
311pub(crate) enum TryExecuteResult<S>
312where
313    S: WorldStateStorage + Send + Sync + Clone + 'static,
314{
315    Ok(Result<ExecutionState<S>, StateChangesResult<S>>),
316    Err(ExecutionState<S>),
317}
318
319impl<S> TryExecuteResult<S>
320where
321    S: WorldStateStorage + Send + Sync + Clone + 'static,
322{
323    pub fn or_else<O: FnOnce(ExecutionState<S>) -> TryExecuteResult<S>>(
324        self,
325        op: O,
326    ) -> TryExecuteResult<S> {
327        match self {
328            TryExecuteResult::Ok(t) => TryExecuteResult::Ok(t),
329            TryExecuteResult::Err(e) => op(e),
330        }
331    }
332
333    pub fn unwrap(self) -> Result<ExecutionState<S>, StateChangesResult<S>> {
334        match self {
335            TryExecuteResult::Ok(ret) => ret,
336            TryExecuteResult::Err(_) => panic!(),
337        }
338    }
339}
340
341#[cfg(test)]
342mod test {
343    use std::collections::HashMap;
344
345    use pchain_types::blockchain::{Command, ExitStatus, Transaction};
346    use pchain_types::cryptography::PublicAddress;
347    use pchain_types::runtime::*;
348    use pchain_types::serialization::Serializable;
349    use pchain_world_state::network::constants;
350    use pchain_world_state::{
351        network::{
352            network_account::NetworkAccountSized,
353            pool::{Pool, PoolKey},
354            stake::{Stake, StakeValue},
355        },
356        states::WorldState,
357        storage::{Key, Value, WorldStateStorage},
358    };
359
360    use crate::gas;
361    use crate::{
362        execution::{
363            execute::{execute_commands, execute_next_epoch_command},
364            state::ExecutionState,
365        },
366        transition::TransitionContext,
367        types::BaseTx,
368        BlockProposalStats, BlockchainParams, TransitionError, ValidatorPerformance,
369    };
370
371    const TEST_MAX_VALIDATOR_SET_SIZE: u16 = constants::MAX_VALIDATOR_SET_SIZE;
372    const TEST_MAX_STAKES_PER_POOL: u16 = constants::MAX_STAKES_PER_POOL;
373    const MIN_BASE_FEE: u64 = 8;
374    type NetworkAccount<'a, S> =
375        NetworkAccountSized<'a, S, { TEST_MAX_VALIDATOR_SET_SIZE }, { TEST_MAX_STAKES_PER_POOL }>;
376
377    #[derive(Clone)]
378    struct SimpleStore {
379        inner: HashMap<Key, Value>,
380    }
381    impl WorldStateStorage for SimpleStore {
382        fn get(&self, key: &Key) -> Option<Value> {
383            match self.inner.get(key) {
384                Some(v) => Some(v.clone()),
385                None => None,
386            }
387        }
388    }
389
390    const ACCOUNT_A: [u8; 32] = [1u8; 32];
391    const ACCOUNT_B: [u8; 32] = [2u8; 32];
392    const ACCOUNT_C: [u8; 32] = [3u8; 32];
393    const ACCOUNT_D: [u8; 32] = [4u8; 32];
394
395    /// Null test on empty transaction commands
396    #[test]
397    fn test_empty_commands() {
398        let mut state = create_state(None);
399        let owner_balance_before = state.ctx.rw_set.ws.balance(ACCOUNT_A);
400        let tx_base_cost = set_tx(&mut state, ACCOUNT_A, 0, &vec![]);
401        let ret = execute_commands(state, vec![]);
402        assert_eq!((&ret.error, &ret.receipt), (&None, &Some(vec![])));
403        let gas_used = ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>();
404        println!("gas_consumed {gas_used}");
405
406        let state = create_state(Some(ret.new_state));
407        let owner_balance_after = state.ctx.rw_set.ws.balance(ACCOUNT_A);
408        assert_eq!(
409            owner_balance_before,
410            owner_balance_after + gas_used + tx_base_cost
411        );
412    }
413
414    // Commands: Create Pool
415    // Exception:
416    // - Create Pool again
417    // - Pool commission rate > 100
418    #[test]
419    fn test_create_pool() {
420        let state = create_state(None);
421        let ret = execute_commands(
422            state,
423            vec![Command::CreatePool(CreatePoolInput { commission_rate: 1 })],
424        );
425        assert_eq!(
426            (
427                &ret.error,
428                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
429            ),
430            (&None, &ExitStatus::Success)
431        );
432        println!(
433            "gas_consumed {}",
434            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
435        );
436
437        let mut state = create_state(Some(ret.new_state));
438        assert_eq!(
439            NetworkAccount::pools(&mut state, ACCOUNT_A)
440                .operator()
441                .unwrap(),
442            ACCOUNT_A
443        );
444        assert_eq!(
445            NetworkAccount::pools(&mut state, ACCOUNT_A)
446                .commission_rate()
447                .unwrap(),
448            1
449        );
450
451        ///// Exceptions: /////
452
453        let mut state = create_state(Some(state.ws.to_owned()));
454        state.tx.nonce = 1;
455        let ret = execute_commands(
456            state,
457            vec![Command::CreatePool(CreatePoolInput { commission_rate: 1 })],
458        );
459        assert_eq!(ret.error, Some(TransitionError::PoolAlreadyExists));
460        println!(
461            "gas_consumed {}",
462            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
463        );
464
465        let mut state = create_state(Some(ret.new_state));
466        state.tx.nonce = 2;
467        let ret = execute_commands(
468            state,
469            vec![Command::CreatePool(CreatePoolInput {
470                commission_rate: 101,
471            })],
472        );
473        assert_eq!(ret.error, Some(TransitionError::InvalidPoolPolicy));
474        println!(
475            "gas_consumed {}",
476            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
477        );
478    }
479
480    // Commands: Create Pool, Set Pool Settings
481    // Exception:
482    // - Pool Not exist
483    // - Pool commission rate > 100
484    // - Same commission rate
485    #[test]
486    fn test_create_pool_set_policy() {
487        let state = create_state(None);
488        let ret = execute_commands(
489            state,
490            vec![
491                Command::CreatePool(CreatePoolInput { commission_rate: 1 }),
492                Command::SetPoolSettings(SetPoolSettingsInput { commission_rate: 2 }),
493            ],
494        );
495        assert_eq!(
496            (
497                &ret.error,
498                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
499            ),
500            (&None, &ExitStatus::Success)
501        );
502        println!(
503            "gas_consumed {}",
504            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
505        );
506
507        let mut state = create_state(Some(ret.new_state));
508        assert_eq!(
509            NetworkAccount::pools(&mut state, ACCOUNT_A)
510                .commission_rate()
511                .unwrap(),
512            2
513        );
514
515        ///// Exceptions: /////
516
517        let mut state = create_state(Some(state.ws.to_owned()));
518        state.tx.signer = ACCOUNT_B;
519        let ret = execute_commands(
520            state,
521            vec![Command::SetPoolSettings(SetPoolSettingsInput {
522                commission_rate: 3,
523            })],
524        );
525        assert_eq!(ret.error, Some(TransitionError::PoolNotExists));
526        println!(
527            "gas_consumed {}",
528            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
529        );
530
531        let mut state = create_state(Some(ret.new_state));
532        state.tx.signer = ACCOUNT_A;
533        state.tx.nonce = 1;
534        let ret = execute_commands(
535            state,
536            vec![Command::SetPoolSettings(SetPoolSettingsInput {
537                commission_rate: 101,
538            })],
539        );
540        assert_eq!(ret.error, Some(TransitionError::InvalidPoolPolicy));
541        println!(
542            "gas_consumed {}",
543            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
544        );
545
546        let mut state = create_state(Some(ret.new_state));
547        state.tx.nonce = 2;
548        let ret = execute_commands(
549            state,
550            vec![Command::SetPoolSettings(SetPoolSettingsInput {
551                commission_rate: 2,
552            })],
553        );
554        assert_eq!(ret.error, Some(TransitionError::InvalidPoolPolicy));
555        println!(
556            "gas_consumed {}",
557            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
558        );
559    }
560
561    // Commands: Create Pool, Delete Pool
562    // Exception:
563    // - Pool Not exist
564    #[test]
565    fn test_create_delete_pool() {
566        let state = create_state(None);
567        let ret = execute_commands(
568            state,
569            vec![
570                Command::CreatePool(CreatePoolInput { commission_rate: 1 }),
571                Command::DeletePool,
572            ],
573        );
574        assert_eq!(
575            (
576                &ret.error,
577                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
578            ),
579            (&None, &ExitStatus::Success)
580        );
581        println!(
582            "gas_consumed {}",
583            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
584        );
585
586        let mut state = create_state(Some(ret.new_state));
587        assert!(NetworkAccount::pools(&mut state, ACCOUNT_A)
588            .operator()
589            .is_none());
590        assert!(NetworkAccount::pools(&mut state, ACCOUNT_A)
591            .commission_rate()
592            .is_none());
593        assert!(NetworkAccount::pools(&mut state, ACCOUNT_A)
594            .operator_stake()
595            .is_none());
596        assert!(NetworkAccount::pools(&mut state, ACCOUNT_A)
597            .power()
598            .is_none());
599        assert!(
600            NetworkAccount::pools(&mut state, ACCOUNT_A)
601                .delegated_stakes()
602                .length()
603                == 0
604        );
605
606        ///// Exceptions: /////
607
608        let mut state = create_state(Some(state.ws.to_owned()));
609        state.tx.signer = ACCOUNT_B;
610        let ret = execute_commands(state, vec![Command::DeletePool]);
611        assert_eq!(ret.error, Some(TransitionError::PoolNotExists));
612        println!(
613            "gas_consumed {}",
614            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
615        );
616    }
617
618    // Command 1 (account a): Create Pool
619    // Command 2 (account b): Create Deposit
620    // Exception:
621    // - Pool Not exist
622    // - Deposit already exists
623    // - Not enough balance
624    #[test]
625    fn test_create_pool_create_deposit() {
626        let state = create_state(None);
627        let ret = execute_commands(
628            state,
629            vec![Command::CreatePool(CreatePoolInput { commission_rate: 1 })],
630        );
631        assert_eq!(
632            (
633                &ret.error,
634                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
635            ),
636            (&None, &ExitStatus::Success)
637        );
638
639        let mut state = create_state(Some(ret.new_state));
640        let commands = vec![Command::CreateDeposit(CreateDepositInput {
641            operator: ACCOUNT_A,
642            balance: 500_000,
643            auto_stake_rewards: false,
644        })];
645        set_tx(&mut state, ACCOUNT_B, 0, &commands);
646        let ret = execute_commands(state, commands);
647        assert_eq!(
648            (
649                &ret.error,
650                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
651            ),
652            (&None, &ExitStatus::Success)
653        );
654        println!(
655            "gas_consumed {}",
656            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
657        );
658
659        let mut state = create_state(Some(ret.new_state));
660        assert_eq!(
661            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B)
662                .balance()
663                .unwrap(),
664            500_000
665        );
666        assert_eq!(
667            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B)
668                .auto_stake_rewards()
669                .unwrap(),
670            false
671        );
672
673        ///// Exceptions: /////
674
675        let mut state = create_state(Some(state.ws.to_owned()));
676        state.tx.nonce = 1;
677        let ret = execute_commands(
678            state,
679            vec![Command::CreateDeposit(CreateDepositInput {
680                operator: ACCOUNT_B,
681                balance: 500_000,
682                auto_stake_rewards: false,
683            })],
684        );
685        assert_eq!(ret.error, Some(TransitionError::PoolNotExists));
686        println!(
687            "gas_consumed {}",
688            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
689        );
690
691        let mut state = create_state(Some(ret.new_state));
692        let commands = vec![Command::CreateDeposit(CreateDepositInput {
693            operator: ACCOUNT_A,
694            balance: 500_000,
695            auto_stake_rewards: false,
696        })];
697        set_tx(&mut state, ACCOUNT_B, 1, &commands);
698        let ret = execute_commands(state, commands);
699        assert_eq!(ret.error, Some(TransitionError::DepositsAlreadyExists));
700        println!(
701            "gas_consumed {}",
702            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
703        );
704
705        let mut state = create_state(Some(ret.new_state));
706        let commands = vec![Command::CreateDeposit(CreateDepositInput {
707            operator: ACCOUNT_A,
708            balance: 500_000_000,
709            auto_stake_rewards: false,
710        })];
711        set_tx(&mut state, ACCOUNT_C, 0, &commands);
712        let ret = execute_commands(state, commands);
713        assert_eq!(
714            ret.error,
715            Some(TransitionError::NotEnoughBalanceForTransfer)
716        );
717        println!(
718            "gas_consumed {}",
719            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
720        );
721    }
722
723    // Prepare: pool (account a) in world state
724    // Commands (account b): Create Deposit, Set Deposit Settings
725    // Exception:
726    // - Deposit not exist
727    // - same deposit policy
728    #[test]
729    fn test_create_deposit_set_policy() {
730        let mut state = create_state(None);
731        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
732        pool.set_operator(ACCOUNT_A);
733        pool.set_power(100_000);
734        pool.set_commission_rate(1);
735        pool.set_operator_stake(None);
736        let ws = state.ctx.rw_set.commit_to_world_state();
737
738        let mut state = create_state(Some(ws));
739        let commands = vec![
740            Command::CreateDeposit(CreateDepositInput {
741                operator: ACCOUNT_A,
742                balance: 500_000,
743                auto_stake_rewards: false,
744            }),
745            Command::SetDepositSettings(SetDepositSettingsInput {
746                operator: ACCOUNT_A,
747                auto_stake_rewards: true,
748            }),
749        ];
750        set_tx(&mut state, ACCOUNT_B, 0, &commands);
751        let ret = execute_commands(state, commands);
752        assert_eq!(
753            (
754                &ret.error,
755                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
756            ),
757            (&None, &ExitStatus::Success)
758        );
759        println!(
760            "gas_consumed {}",
761            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
762        );
763
764        let mut state = create_state(Some(ret.new_state));
765        assert_eq!(
766            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B)
767                .balance()
768                .unwrap(),
769            500_000
770        );
771        assert_eq!(
772            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B)
773                .auto_stake_rewards()
774                .unwrap(),
775            true
776        );
777
778        ///// Exceptions: /////
779
780        let state = create_state(Some(state.ws.to_owned()));
781        let ret = execute_commands(
782            state,
783            vec![Command::SetDepositSettings(SetDepositSettingsInput {
784                operator: ACCOUNT_B,
785                auto_stake_rewards: true,
786            })],
787        );
788        assert_eq!(ret.error, Some(TransitionError::DepositsNotExists));
789        println!(
790            "gas_consumed {}",
791            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
792        );
793
794        let mut state = create_state(Some(ret.new_state));
795        let commands = vec![
796            Command::SetDepositSettings(SetDepositSettingsInput {
797                operator: ACCOUNT_A,
798                auto_stake_rewards: true,
799            }), // Same deposit plocy
800        ];
801        set_tx(&mut state, ACCOUNT_B, 1, &commands);
802        let ret = execute_commands(state, commands);
803        assert_eq!(ret.error, Some(TransitionError::InvalidDepositPolicy));
804        println!(
805            "gas_consumed {}",
806            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
807        );
808    }
809
810    // Prepare: pool (account a) in world state
811    // Commands (account b): Create Deposit, Topup Deposit
812    // Exception:
813    // - Deposit not exist
814    // - Not enough balance
815    #[test]
816    fn test_create_deposit_topupdeposit() {
817        let mut state = create_state(None);
818        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
819        pool.set_operator(ACCOUNT_A);
820        pool.set_power(100_000);
821        pool.set_commission_rate(1);
822        pool.set_operator_stake(None);
823        let ws = state.ctx.rw_set.commit_to_world_state();
824
825        let mut state = create_state(Some(ws));
826        let commands = vec![
827            Command::CreateDeposit(CreateDepositInput {
828                operator: ACCOUNT_A,
829                balance: 500_000,
830                auto_stake_rewards: false,
831            }),
832            Command::TopUpDeposit(TopUpDepositInput {
833                operator: ACCOUNT_A,
834                amount: 100,
835            }),
836        ];
837        set_tx(&mut state, ACCOUNT_B, 0, &commands);
838        let ret = execute_commands(state, commands);
839        assert_eq!(
840            (
841                &ret.error,
842                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
843            ),
844            (&None, &ExitStatus::Success)
845        );
846        println!(
847            "gas_consumed {}",
848            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
849        );
850
851        let mut state = create_state(Some(ret.new_state));
852        assert_eq!(
853            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B)
854                .balance()
855                .unwrap(),
856            500_100
857        );
858        assert_eq!(
859            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B)
860                .auto_stake_rewards()
861                .unwrap(),
862            false
863        );
864
865        ///// Exceptions: /////
866
867        let state = create_state(Some(state.ws.to_owned()));
868        let ret = execute_commands(
869            state,
870            vec![Command::TopUpDeposit(TopUpDepositInput {
871                operator: ACCOUNT_A,
872                amount: 100,
873            })],
874        );
875        assert_eq!(ret.error, Some(TransitionError::DepositsNotExists));
876        println!(
877            "gas_consumed {}",
878            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
879        );
880
881        let mut state = create_state(Some(ret.new_state));
882        let commands = vec![Command::CreateDeposit(CreateDepositInput {
883            operator: ACCOUNT_A,
884            balance: 500_000_000,
885            auto_stake_rewards: false,
886        })];
887        set_tx(&mut state, ACCOUNT_C, 0, &commands);
888        let ret = execute_commands(state, commands);
889        assert_eq!(
890            ret.error,
891            Some(TransitionError::NotEnoughBalanceForTransfer)
892        );
893        println!(
894            "gas_consumed {}",
895            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
896        );
897    }
898
899    // Prepare: pool (account a) in world state
900    // Prepare: deposits (account b) to pool (account a)
901    // Commands (account b): Stake Deposit
902    // Exception:
903    // - Deposit not exist
904    // - Reach limit (Deposit amount)
905    // - Pool not exist
906    #[test]
907    fn test_stake_deposit_delegated_stakes() {
908        let mut state = create_state(None);
909        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
910        pool.set_operator(ACCOUNT_A);
911        pool.set_power(100_000);
912        pool.set_commission_rate(1);
913        pool.set_operator_stake(None);
914        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B);
915        deposit.set_balance(20_000);
916        deposit.set_auto_stake_rewards(false);
917
918        let ws = state.ctx.rw_set.commit_to_world_state();
919
920        let mut state = create_state(Some(ws));
921        let commands = vec![
922            Command::StakeDeposit(StakeDepositInput {
923                operator: ACCOUNT_A,
924                max_amount: 20_000 + 1,
925            }), // stake more than deposit
926        ];
927        set_tx(&mut state, ACCOUNT_B, 0, &commands);
928        let ret = execute_commands(state, commands);
929        assert_eq!(
930            (
931                &ret.error,
932                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
933            ),
934            (&None, &ExitStatus::Success)
935        );
936        assert_eq!(
937            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
938            20_000_u64.to_le_bytes().to_vec()
939        );
940        println!(
941            "gas_consumed {}",
942            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
943        );
944
945        let mut state = create_state(Some(ret.new_state));
946        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
947        assert_eq!(pool.power().unwrap(), 120_000);
948        let delegated_stake = pool.delegated_stakes();
949        let delegated_stake = delegated_stake.get_by(&ACCOUNT_B).unwrap();
950        assert_eq!(delegated_stake.power, 20_000);
951
952        ///// Exceptions: /////
953
954        let mut state = create_state(Some(state.ws.to_owned()));
955        let commands = vec![Command::StakeDeposit(StakeDepositInput {
956            operator: ACCOUNT_A,
957            max_amount: 20_000,
958        })];
959        set_tx(&mut state, ACCOUNT_C, 0, &commands);
960        let ret = execute_commands(state, commands);
961        assert_eq!(ret.error, Some(TransitionError::DepositsNotExists));
962        println!(
963            "gas_consumed {}",
964            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
965        );
966
967        let mut state = create_state(Some(ret.new_state));
968        let commands = vec![Command::StakeDeposit(StakeDepositInput {
969            operator: ACCOUNT_A,
970            max_amount: 1,
971        })];
972        set_tx(&mut state, ACCOUNT_B, 1, &commands);
973        let ret = execute_commands(state, commands);
974        assert_eq!(ret.error, Some(TransitionError::InvalidStakeAmount));
975        println!(
976            "gas_consumed {}",
977            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
978        );
979
980        // Delete Pool first
981        let mut state = create_state(Some(ret.new_state));
982        let commands = vec![Command::DeletePool];
983        set_tx(&mut state, ACCOUNT_A, 0, &commands);
984        let ret = execute_commands(state, commands);
985        assert_eq!(ret.error, None);
986        println!(
987            "gas_consumed {}",
988            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
989        );
990        // and then stake deposit
991        let mut state = create_state(Some(ret.new_state));
992        let commands = vec![Command::StakeDeposit(StakeDepositInput {
993            operator: ACCOUNT_A,
994            max_amount: 20_000,
995        })];
996        set_tx(&mut state, ACCOUNT_B, 2, &commands);
997        let ret = execute_commands(state, commands);
998        assert_eq!(ret.error, Some(TransitionError::PoolNotExists));
999        println!(
1000            "gas_consumed {}",
1001            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1002        );
1003    }
1004
1005    // Prepare: set maximum number of pools in world state, pool (account a) has the minimum power.
1006    // Prepare: deposits (account b) to pool (account a)
1007    // Commands (account b): Stake Deposit (to increase the power of pool (account a))
1008    #[test]
1009    fn test_stake_deposit_delegated_stakes_nvp_change_key() {
1010        let mut state = create_state(None);
1011        create_full_pools_in_nvp(&mut state, false, false);
1012        let pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1013        assert_eq!(pool.power().unwrap(), 100_000);
1014        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B);
1015        deposit.set_balance(6_300_000);
1016        deposit.set_auto_stake_rewards(false);
1017
1018        let ws = state.ctx.rw_set.commit_to_world_state();
1019
1020        let mut state = create_state(Some(ws));
1021        let commands = vec![Command::StakeDeposit(StakeDepositInput {
1022            operator: ACCOUNT_A,
1023            max_amount: 6_300_000,
1024        })];
1025        set_tx(&mut state, ACCOUNT_B, 0, &commands);
1026        let ret = execute_commands(state, commands);
1027        assert_eq!(
1028            (
1029                &ret.error,
1030                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1031            ),
1032            (&None, &ExitStatus::Success)
1033        );
1034        assert_eq!(
1035            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1036            6_300_000_u64.to_le_bytes().to_vec()
1037        );
1038        println!(
1039            "gas_consumed {}",
1040            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1041        );
1042
1043        let mut state = create_state(Some(ret.new_state));
1044        let pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1045        assert_eq!(pool.power().unwrap(), 6_400_000);
1046        assert_eq!(
1047            NetworkAccount::nvp(&mut state).length(),
1048            TEST_MAX_VALIDATOR_SET_SIZE as u32
1049        );
1050        assert_eq!(
1051            NetworkAccount::nvp(&mut state).get(0).unwrap().operator,
1052            [
1053                2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1054                1, 1, 1, 1
1055            ]
1056        );
1057        assert_eq!(
1058            NetworkAccount::nvp(&mut state).get(0).unwrap().power,
1059            200_000
1060        );
1061    }
1062
1063    // Prepare: set maximum number of pools in world state, pool (account b) is not inside nvp.
1064    // Prepare: deposits (account c) to pool (account b)
1065    // Commands (account c): Stake Deposit (to increase the power of pool (account b) to be included in nvp)
1066    #[test]
1067    fn test_stake_deposit_delegated_stakes_nvp_insert() {
1068        let mut state = create_state(None);
1069        create_full_pools_in_nvp(&mut state, false, false);
1070        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_B);
1071        pool.set_operator(ACCOUNT_B);
1072        pool.set_commission_rate(1);
1073        pool.set_power(0);
1074        pool.set_operator_stake(None);
1075        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_B, ACCOUNT_C);
1076        deposit.set_balance(6_500_000);
1077        deposit.set_auto_stake_rewards(false);
1078
1079        let ws = state.ctx.rw_set.commit_to_world_state();
1080
1081        let mut state = create_state(Some(ws));
1082        let commands = vec![Command::StakeDeposit(StakeDepositInput {
1083            operator: ACCOUNT_B,
1084            max_amount: 6_500_000,
1085        })];
1086        set_tx(&mut state, ACCOUNT_C, 0, &commands);
1087        let ret = execute_commands(state, commands);
1088        assert_eq!(
1089            (
1090                &ret.error,
1091                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1092            ),
1093            (&None, &ExitStatus::Success)
1094        );
1095        assert_eq!(
1096            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1097            6_500_000_u64.to_le_bytes().to_vec()
1098        );
1099        println!(
1100            "gas_consumed {}",
1101            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1102        );
1103        let mut state = create_state(Some(ret.new_state));
1104
1105        assert_eq!(
1106            NetworkAccount::nvp(&mut state).length(),
1107            TEST_MAX_VALIDATOR_SET_SIZE as u32
1108        );
1109        assert_eq!(
1110            NetworkAccount::nvp(&mut state).get(0).unwrap().operator,
1111            [
1112                2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1113                1, 1, 1, 1
1114            ]
1115        );
1116        assert_eq!(
1117            NetworkAccount::nvp(&mut state).get(0).unwrap().power,
1118            200_000
1119        );
1120        let pool_in_nvp = NetworkAccount::nvp(&mut state).get_by(&ACCOUNT_B).unwrap();
1121        assert_eq!(
1122            (pool_in_nvp.operator, pool_in_nvp.power),
1123            (ACCOUNT_B, 6_500_000)
1124        );
1125    }
1126
1127    // Prepare: pool (account a), with maximum number of stakes in world state
1128    // Prepare: deposits (account c) to pool (account a)
1129    // Commands (account c): Stake Deposit (to be included in delegated stakes)
1130    // Exception
1131    // - stake is too small to insert
1132    #[test]
1133    fn test_stake_deposit_delegated_stakes_insert() {
1134        let mut state = create_state(None);
1135        create_full_stakes_in_pool(&mut state, ACCOUNT_A);
1136        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_C);
1137        deposit.set_balance(250_000);
1138        deposit.set_auto_stake_rewards(false);
1139
1140        let ws = state.ctx.rw_set.commit_to_world_state();
1141
1142        let mut state = create_state(Some(ws));
1143        let prev_pool_power = NetworkAccount::pools(&mut state, ACCOUNT_A)
1144            .power()
1145            .unwrap();
1146        let commands = vec![Command::StakeDeposit(StakeDepositInput {
1147            operator: ACCOUNT_A,
1148            max_amount: 250_000,
1149        })];
1150        set_tx(&mut state, ACCOUNT_C, 0, &commands);
1151        let ret = execute_commands(state, commands);
1152        assert_eq!(
1153            (
1154                &ret.error,
1155                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1156            ),
1157            (&None, &ExitStatus::Success)
1158        );
1159        assert_eq!(
1160            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1161            250_000_u64.to_le_bytes().to_vec()
1162        );
1163        println!(
1164            "gas_consumed {}",
1165            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1166        );
1167
1168        let mut state = create_state(Some(ret.new_state));
1169        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1170        let cur_pool_power = pool.power().unwrap();
1171        assert_eq!(cur_pool_power, prev_pool_power + 50_000);
1172        let delegated_stakes = pool.delegated_stakes();
1173        assert_eq!(delegated_stakes.get(0).unwrap().power, 250_000);
1174        assert_eq!(delegated_stakes.get(0).unwrap().owner, ACCOUNT_C);
1175
1176        ///// Exceptions: /////
1177
1178        let mut state = create_state(Some(state.ws.to_owned()));
1179        // create deposit first (too low to join deledated stake )
1180        let commands = vec![Command::CreateDeposit(CreateDepositInput {
1181            operator: ACCOUNT_A,
1182            balance: 100_000,
1183            auto_stake_rewards: false,
1184        })];
1185        set_tx(&mut state, ACCOUNT_D, 0, &commands);
1186        let ret = execute_commands(state, commands);
1187        assert_eq!(
1188            (
1189                &ret.error,
1190                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1191            ),
1192            (&None, &ExitStatus::Success)
1193        );
1194        println!(
1195            "gas_consumed {}",
1196            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1197        );
1198        // and then stake deposit
1199        let mut state = create_state(Some(ret.new_state));
1200        let commands = vec![Command::StakeDeposit(StakeDepositInput {
1201            operator: ACCOUNT_A,
1202            max_amount: 100_000,
1203        })];
1204        set_tx(&mut state, ACCOUNT_D, 1, &commands);
1205        let ret = execute_commands(state, commands);
1206        assert_eq!(ret.error, Some(TransitionError::InvalidStakeAmount));
1207        println!(
1208            "gas_consumed {}",
1209            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1210        );
1211    }
1212
1213    // Prepare: pool (account c), with maximum number of stakes in world state, stakes (account b) is the minimum value.
1214    // Prepare: deposits (account b) to pool (account c)
1215    // Commands (account b): Stake Deposit (to be included in delegated stakes, but not the minimum one)
1216    #[test]
1217    fn test_stake_deposit_delegated_stakes_change_key() {
1218        let mut state = create_state(None);
1219        create_full_stakes_in_pool(&mut state, ACCOUNT_C);
1220        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_C, ACCOUNT_B);
1221        deposit.set_balance(310_000);
1222        deposit.set_auto_stake_rewards(false);
1223
1224        let ws = state.ctx.rw_set.commit_to_world_state();
1225
1226        let mut state = create_state(Some(ws));
1227        let prev_pool_power = NetworkAccount::pools(&mut state, ACCOUNT_C)
1228            .power()
1229            .unwrap();
1230        let commands = vec![Command::StakeDeposit(StakeDepositInput {
1231            operator: ACCOUNT_C,
1232            max_amount: 110_000,
1233        })];
1234        set_tx(&mut state, ACCOUNT_B, 0, &commands);
1235        let ret = execute_commands(state, commands);
1236        assert_eq!(
1237            (
1238                &ret.error,
1239                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1240            ),
1241            (&None, &ExitStatus::Success)
1242        );
1243        assert_eq!(
1244            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1245            110_000_u64.to_le_bytes().to_vec()
1246        );
1247        println!(
1248            "gas_consumed {}",
1249            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1250        );
1251        let mut state = create_state(Some(ret.new_state));
1252
1253        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_C);
1254        let cur_pool_power = pool.power().unwrap();
1255        assert_eq!(cur_pool_power, prev_pool_power + 110_000);
1256        let min_stake = pool.delegated_stakes().get(0).unwrap();
1257        assert_eq!(min_stake.power, 300_000);
1258        assert_eq!(
1259            min_stake.owner,
1260            [
1261                3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1262                2, 2, 2, 2
1263            ]
1264        );
1265    }
1266
1267    // Prepare: pool (account a) in world state, with delegated stakes of account b
1268    // Prepare: deposits (account b) to pool (account a)
1269    // Commands (account b): Stake Deposit (to increase the stake in the delegated stakes)
1270    #[test]
1271    fn test_stake_deposit_delegated_stakes_existing() {
1272        let mut state = create_state(None);
1273        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1274        pool.set_operator(ACCOUNT_A);
1275        pool.set_power(100_000);
1276        pool.set_commission_rate(1);
1277        pool.set_operator_stake(None);
1278        pool.delegated_stakes()
1279            .insert(StakeValue::new(Stake {
1280                owner: ACCOUNT_B,
1281                power: 50_000,
1282            }))
1283            .unwrap();
1284        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B);
1285        deposit.set_balance(100_000);
1286        deposit.set_auto_stake_rewards(false);
1287
1288        let ws = state.ctx.rw_set.commit_to_world_state();
1289
1290        let mut state = create_state(Some(ws));
1291        let commands = vec![Command::StakeDeposit(StakeDepositInput {
1292            operator: ACCOUNT_A,
1293            max_amount: 40_000,
1294        })];
1295        set_tx(&mut state, ACCOUNT_B, 0, &commands);
1296        let ret = execute_commands(state, commands);
1297        assert_eq!(
1298            (
1299                &ret.error,
1300                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1301            ),
1302            (&None, &ExitStatus::Success)
1303        );
1304        assert_eq!(
1305            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1306            40_000_u64.to_le_bytes().to_vec()
1307        );
1308        println!(
1309            "gas_consumed {}",
1310            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1311        );
1312
1313        let mut state = create_state(Some(ret.new_state));
1314
1315        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1316        assert_eq!(pool.power().unwrap(), 140_000);
1317        let delegated_stake = pool.delegated_stakes();
1318        let delegated_stake = delegated_stake.get_by(&ACCOUNT_B).unwrap();
1319        assert_eq!(delegated_stake.power, 90_000);
1320    }
1321
1322    // Prepare: pool (account a) in world state
1323    // Prepare: deposits (account a) to pool (account a)
1324    // Commands (account a): Stake Deposit
1325    #[test]
1326    fn test_stake_deposit_same_owner() {
1327        let mut state = create_state(None);
1328        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1329        pool.set_operator(ACCOUNT_A);
1330        pool.set_power(100_000);
1331        pool.set_commission_rate(1);
1332        pool.set_operator_stake(None);
1333        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_A);
1334        deposit.set_balance(150_000);
1335        deposit.set_auto_stake_rewards(false);
1336
1337        let ws = state.ctx.rw_set.commit_to_world_state();
1338
1339        let state = create_state(Some(ws));
1340        let ret = execute_commands(
1341            state,
1342            vec![Command::StakeDeposit(StakeDepositInput {
1343                operator: ACCOUNT_A,
1344                max_amount: 20_000,
1345            })],
1346        );
1347        assert_eq!(
1348            (
1349                &ret.error,
1350                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1351            ),
1352            (&None, &ExitStatus::Success)
1353        );
1354        assert_eq!(
1355            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1356            20_000_u64.to_le_bytes().to_vec()
1357        );
1358        println!(
1359            "gas_consumed {}",
1360            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1361        );
1362
1363        let mut state = create_state(Some(ret.new_state));
1364
1365        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1366        let operator_state = pool.operator_stake().unwrap().unwrap();
1367        assert_eq!(operator_state.power, 20_000);
1368        assert_eq!(pool.power().unwrap(), 120_000);
1369        let delegated_stake = pool.delegated_stakes();
1370        assert_eq!(delegated_stake.length(), 0);
1371    }
1372
1373    // Prepare: set maximum number of pools in world state, pool (account a) has the minimum power.
1374    // Prepare: deposits (account a) to pool (account a)
1375    // Commands (account a): Stake Deposit (to increase the power of pool (account a))
1376    #[test]
1377    fn test_stake_deposit_same_owner_nvp_change_key() {
1378        let mut state = create_state(None);
1379        create_full_pools_in_nvp(&mut state, false, false);
1380        let pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1381        assert_eq!(pool.power().unwrap(), 100_000);
1382        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_A);
1383        deposit.set_balance(210_000);
1384        deposit.set_auto_stake_rewards(false);
1385
1386        let ws = state.ctx.rw_set.commit_to_world_state();
1387
1388        let mut state = create_state(Some(ws));
1389        let commands = vec![Command::StakeDeposit(StakeDepositInput {
1390            operator: ACCOUNT_A,
1391            max_amount: 110_000,
1392        })];
1393        set_tx(&mut state, ACCOUNT_A, 0, &commands);
1394        let ret = execute_commands(state, commands);
1395        assert_eq!(
1396            (
1397                &ret.error,
1398                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1399            ),
1400            (&None, &ExitStatus::Success)
1401        );
1402        assert_eq!(
1403            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1404            110_000_u64.to_le_bytes().to_vec()
1405        );
1406        println!(
1407            "gas_consumed {}",
1408            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1409        );
1410
1411        let mut state = create_state(Some(ret.new_state));
1412
1413        let pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1414        assert_eq!(pool.power().unwrap(), 210_000);
1415        assert_eq!(pool.operator_stake().unwrap().unwrap().power, 210_000);
1416        assert_eq!(
1417            NetworkAccount::nvp(&mut state).length(),
1418            TEST_MAX_VALIDATOR_SET_SIZE as u32
1419        );
1420        assert_eq!(
1421            NetworkAccount::nvp(&mut state).get(0).unwrap().operator,
1422            [
1423                2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1424                1, 1, 1, 1
1425            ]
1426        );
1427        assert_eq!(
1428            NetworkAccount::nvp(&mut state).get(0).unwrap().power,
1429            200_000
1430        );
1431    }
1432
1433    // Prepare: set maximum number of pools in world state, pool (account c) is not inside nvp.
1434    // Prepare: deposits (account c) to pool (account c)
1435    // Commands (account c): Stake Deposit (to increase the power of pool (account c) to be included in nvp)
1436    #[test]
1437    fn test_stake_deposit_same_owner_nvp_insert() {
1438        let mut state = create_state(None);
1439        create_full_pools_in_nvp(&mut state, false, false);
1440        assert!(NetworkAccount::pools(&mut state, ACCOUNT_C)
1441            .operator()
1442            .is_none());
1443        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_C);
1444        pool.set_operator(ACCOUNT_C);
1445        pool.set_commission_rate(1);
1446        pool.set_power(0);
1447        pool.set_operator_stake(None);
1448        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_C, ACCOUNT_C);
1449        deposit.set_balance(150_000);
1450        deposit.set_auto_stake_rewards(false);
1451
1452        let ws = state.ctx.rw_set.commit_to_world_state();
1453
1454        let mut state = create_state(Some(ws));
1455        let commands = vec![Command::StakeDeposit(StakeDepositInput {
1456            operator: ACCOUNT_C,
1457            max_amount: 150_000,
1458        })];
1459        set_tx(&mut state, ACCOUNT_C, 0, &commands);
1460        let ret = execute_commands(state, commands);
1461        assert_eq!(
1462            (
1463                &ret.error,
1464                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1465            ),
1466            (&None, &ExitStatus::Success)
1467        );
1468        assert_eq!(
1469            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1470            150_000_u64.to_le_bytes().to_vec()
1471        );
1472        println!(
1473            "gas_consumed {}",
1474            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1475        );
1476
1477        let mut state = create_state(Some(ret.new_state));
1478
1479        let pool = NetworkAccount::pools(&mut state, ACCOUNT_C);
1480        assert_eq!(pool.power().unwrap(), 150_000);
1481        assert_eq!(pool.operator_stake().unwrap().unwrap().power, 150_000);
1482        assert_eq!(
1483            NetworkAccount::nvp(&mut state).length(),
1484            TEST_MAX_VALIDATOR_SET_SIZE as u32
1485        );
1486        assert_eq!(
1487            NetworkAccount::nvp(&mut state).get(0).unwrap().operator,
1488            ACCOUNT_C
1489        );
1490        assert_eq!(
1491            NetworkAccount::nvp(&mut state).get(0).unwrap().power,
1492            150_000
1493        );
1494    }
1495
1496    // Prepare: pool (account a) in world state, with non-zero value of Operator Stake
1497    // Prepare: deposits (account a) to pool (account a)
1498    // Commands (account a): Stake Deposit
1499    #[test]
1500    fn test_stake_deposit_same_owner_existing() {
1501        let mut state = create_state(None);
1502        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1503        pool.set_operator(ACCOUNT_A);
1504        pool.set_power(100_000);
1505        pool.set_commission_rate(1);
1506        pool.set_operator_stake(Some(Stake {
1507            owner: ACCOUNT_A,
1508            power: 80_000,
1509        }));
1510        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_A);
1511        deposit.set_balance(100_000);
1512        deposit.set_auto_stake_rewards(false);
1513
1514        let ws = state.ctx.rw_set.commit_to_world_state();
1515
1516        let state = create_state(Some(ws));
1517        let ret = execute_commands(
1518            state,
1519            vec![Command::StakeDeposit(StakeDepositInput {
1520                operator: ACCOUNT_A,
1521                max_amount: 10_000,
1522            })],
1523        );
1524        assert_eq!(
1525            (
1526                &ret.error,
1527                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1528            ),
1529            (&None, &ExitStatus::Success)
1530        );
1531        assert_eq!(
1532            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1533            10_000_u64.to_le_bytes().to_vec()
1534        );
1535        println!(
1536            "gas_consumed {}",
1537            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1538        );
1539
1540        let mut state = create_state(Some(ret.new_state));
1541
1542        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1543        let operator_state = pool.operator_stake().unwrap().unwrap();
1544        assert_eq!(operator_state.power, 90_000);
1545        assert_eq!(pool.power().unwrap(), 110_000);
1546        let delegated_stake = pool.delegated_stakes();
1547        assert_eq!(delegated_stake.length(), 0);
1548    }
1549
1550    // Prepare: pool (account a) in world state, with delegated stakes of account b
1551    // Prepare: deposits (account b) to pool (account a)
1552    // Commands (account b): Unstake Deposit
1553    // Exception:
1554    // - Stakes not exists
1555    // - Pool has no delegated stake
1556    // - Pool not exists
1557    #[test]
1558    fn test_unstake_deposit_delegated_stakes() {
1559        let mut state = create_state(None);
1560        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1561        pool.set_operator(ACCOUNT_A);
1562        pool.set_power(100_000);
1563        pool.set_commission_rate(1);
1564        pool.set_operator_stake(None);
1565        pool.delegated_stakes()
1566            .insert(StakeValue::new(Stake {
1567                owner: ACCOUNT_B,
1568                power: 50_000,
1569            }))
1570            .unwrap();
1571        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B);
1572        deposit.set_balance(100_000);
1573        deposit.set_auto_stake_rewards(false);
1574
1575        let ws = state.ctx.rw_set.commit_to_world_state();
1576
1577        let mut state = create_state(Some(ws));
1578        let commands = vec![Command::UnstakeDeposit(UnstakeDepositInput {
1579            operator: ACCOUNT_A,
1580            max_amount: 40_000,
1581        })];
1582        set_tx(&mut state, ACCOUNT_B, 0, &commands);
1583        let ret = execute_commands(state, commands);
1584        assert_eq!(
1585            (
1586                &ret.error,
1587                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1588            ),
1589            (&None, &ExitStatus::Success)
1590        );
1591        assert_eq!(
1592            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1593            40_000_u64.to_le_bytes().to_vec()
1594        );
1595        println!(
1596            "gas_consumed {}",
1597            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1598        );
1599
1600        let mut state = create_state(Some(ret.new_state));
1601
1602        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1603        assert_eq!(pool.power().unwrap(), 60_000);
1604        let delegated_stake = pool.delegated_stakes();
1605        let delegated_stake = delegated_stake.get_by(&ACCOUNT_B).unwrap();
1606        assert_eq!(delegated_stake.power, 10_000);
1607
1608        ///// Exceptions: /////
1609
1610        let mut state = create_state(Some(state.ws.to_owned()));
1611        let commands = vec![Command::UnstakeDeposit(UnstakeDepositInput {
1612            operator: ACCOUNT_C,
1613            max_amount: 40_000,
1614        })];
1615        set_tx(&mut state, ACCOUNT_B, 1, &commands);
1616        let ret = execute_commands(state, commands);
1617        assert_eq!(ret.error, Some(TransitionError::DepositsNotExists));
1618        println!(
1619            "gas_consumed {}",
1620            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1621        );
1622
1623        // create Pool and deposit first
1624        let mut state = create_state(Some(ret.new_state));
1625        let commands = vec![Command::CreatePool(CreatePoolInput { commission_rate: 1 })];
1626        set_tx(&mut state, ACCOUNT_C, 0, &commands);
1627        let ret = execute_commands(state, commands);
1628        assert_eq!(
1629            (
1630                &ret.error,
1631                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1632            ),
1633            (&None, &ExitStatus::Success)
1634        );
1635        println!(
1636            "gas_consumed {}",
1637            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1638        );
1639        let mut state = create_state(Some(ret.new_state));
1640        let commands = vec![Command::CreateDeposit(CreateDepositInput {
1641            operator: ACCOUNT_C,
1642            balance: 10_000,
1643            auto_stake_rewards: false,
1644        })];
1645        set_tx(&mut state, ACCOUNT_B, 2, &commands);
1646        let ret = execute_commands(state, commands);
1647        assert_eq!(
1648            (
1649                &ret.error,
1650                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1651            ),
1652            (&None, &ExitStatus::Success)
1653        );
1654        println!(
1655            "gas_consumed {}",
1656            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1657        );
1658        // and then UnstakeDeposit
1659        let mut state = create_state(Some(ret.new_state));
1660        let commands = vec![Command::UnstakeDeposit(UnstakeDepositInput {
1661            operator: ACCOUNT_C,
1662            max_amount: 10_000,
1663        })];
1664        set_tx(&mut state, ACCOUNT_B, 3, &commands);
1665        let ret = execute_commands(state, commands);
1666        assert_eq!(ret.error, Some(TransitionError::PoolHasNoStakes));
1667        println!(
1668            "gas_consumed {}",
1669            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1670        );
1671
1672        // delete pool first
1673        let state = create_state(Some(ret.new_state));
1674        let ret = execute_commands(state, vec![Command::DeletePool]);
1675        assert_eq!(
1676            (
1677                &ret.error,
1678                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1679            ),
1680            (&None, &ExitStatus::Success)
1681        );
1682        println!(
1683            "gas_consumed {}",
1684            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1685        );
1686        // then UnstakeDeposit
1687        let mut state = create_state(Some(ret.new_state));
1688        let commands = vec![Command::UnstakeDeposit(UnstakeDepositInput {
1689            operator: ACCOUNT_A,
1690            max_amount: 10_000,
1691        })];
1692        set_tx(&mut state, ACCOUNT_B, 4, &commands);
1693        let ret = execute_commands(state, commands);
1694        assert_eq!(ret.error, Some(TransitionError::PoolNotExists));
1695        println!(
1696            "gas_consumed {}",
1697            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1698        );
1699    }
1700
1701    // Prepare: pool (account a) in world state, with delegated stakes of account X, X has the biggest stake
1702    // Prepare: deposits (account X) to pool (account a)
1703    // Commands (account X): Unstake Deposit
1704    #[test]
1705    fn test_unstake_deposit_delegated_stakes_remove() {
1706        let mut state = create_state(None);
1707        create_full_deposits_in_pool(&mut state, ACCOUNT_A, false);
1708        create_full_stakes_in_pool(&mut state, ACCOUNT_A);
1709        let biggest = [
1710            129u8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1711            2, 2, 2, 2,
1712        ];
1713        state.set_balance(biggest, 500_000_000);
1714        let origin_pool_power = NetworkAccount::pools(&mut state, ACCOUNT_A)
1715            .power()
1716            .unwrap();
1717        let stake = NetworkAccount::pools(&mut state, ACCOUNT_A)
1718            .delegated_stakes()
1719            .get_by(&biggest)
1720            .unwrap();
1721
1722        let ws = state.ctx.rw_set.commit_to_world_state();
1723
1724        let mut state = create_state(Some(ws));
1725        let commands = vec![Command::UnstakeDeposit(UnstakeDepositInput {
1726            operator: ACCOUNT_A,
1727            max_amount: stake.power,
1728        })];
1729        set_tx(&mut state, biggest, 0, &commands);
1730        let ret = execute_commands(state, commands);
1731        assert_eq!(
1732            (
1733                &ret.error,
1734                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1735            ),
1736            (&None, &ExitStatus::Success)
1737        );
1738        assert_eq!(
1739            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1740            stake.power.to_le_bytes().to_vec()
1741        );
1742        println!(
1743            "gas_consumed {}",
1744            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1745        );
1746
1747        let mut state = create_state(Some(ret.new_state));
1748
1749        let new_pool_power = NetworkAccount::pools(&mut state, ACCOUNT_A)
1750            .power()
1751            .unwrap();
1752        assert_eq!(origin_pool_power - new_pool_power, stake.power);
1753        let stakers = NetworkAccount::pools(&mut state, ACCOUNT_A)
1754            .delegated_stakes()
1755            .unordered_values();
1756        assert!(!stakers.iter().any(|v| v.owner == biggest));
1757        assert!(NetworkAccount::pools(&mut state, ACCOUNT_A)
1758            .delegated_stakes()
1759            .get_by(&biggest)
1760            .is_none());
1761    }
1762
1763    // Prepare: set maximum number of pools in world state, pool (account t) has power > minimum, with delegated stakes of account b
1764    // Prepare: deposits (account b) to pool (account t)
1765    // Commands (account b): Unstake Deposit (to decrease the power of pool (account t))
1766    #[test]
1767    fn test_unstake_deposit_delegated_stakes_nvp_change_key() {
1768        const ACCOUNT_T: [u8; 32] = [
1769            2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1770            1, 1, 1,
1771        ];
1772        let mut state = create_state(None);
1773        create_full_pools_in_nvp(&mut state, false, false);
1774        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_T);
1775        assert_eq!(pool.power().unwrap(), 200_000);
1776        pool.delegated_stakes()
1777            .insert(StakeValue::new(Stake {
1778                owner: ACCOUNT_B,
1779                power: 150_000,
1780            }))
1781            .unwrap();
1782        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_T, ACCOUNT_B);
1783        deposit.set_balance(200_000);
1784        deposit.set_auto_stake_rewards(false);
1785
1786        let ws = state.ctx.rw_set.commit_to_world_state();
1787
1788        let mut state = create_state(Some(ws));
1789        let commands = vec![
1790            Command::UnstakeDeposit(UnstakeDepositInput {
1791                operator: ACCOUNT_T,
1792                max_amount: 150_000 + 1,
1793            }), // unstake more than staked
1794        ];
1795        set_tx(&mut state, ACCOUNT_B, 0, &commands);
1796        let ret = execute_commands(state, commands);
1797        assert_eq!(
1798            (
1799                &ret.error,
1800                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1801            ),
1802            (&None, &ExitStatus::Success)
1803        );
1804        assert_eq!(
1805            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1806            150_000_u64.to_le_bytes().to_vec()
1807        );
1808        println!(
1809            "gas_consumed {}",
1810            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1811        );
1812
1813        let mut state = create_state(Some(ret.new_state));
1814
1815        let pool = NetworkAccount::pools(&mut state, ACCOUNT_T);
1816        assert_eq!(pool.power().unwrap(), 50_000);
1817        assert_eq!(
1818            NetworkAccount::nvp(&mut state).length(),
1819            TEST_MAX_VALIDATOR_SET_SIZE as u32
1820        );
1821        assert_eq!(
1822            NetworkAccount::nvp(&mut state).get(0).unwrap().operator,
1823            ACCOUNT_T
1824        );
1825        assert_eq!(
1826            NetworkAccount::nvp(&mut state).get(0).unwrap().power,
1827            50_000
1828        );
1829    }
1830
1831    // Prepare: set maximum number of pools in world state, pool (account t) has power > minimum, with delegated stakes of account b
1832    // Prepare: deposits (account b) to pool (account t)
1833    // Commands (account b): Unstake Deposit (to empty the power of pool (account t), and to be kicked out from nvp)
1834    #[test]
1835    fn test_unstake_deposit_delegated_stakes_nvp_remove() {
1836        const ACCOUNT_T: [u8; 32] = [
1837            2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1838            1, 1, 1,
1839        ];
1840        let mut state = create_state(None);
1841        create_full_pools_in_nvp(&mut state, false, false);
1842        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_T);
1843        assert_eq!(pool.power().unwrap(), 200_000);
1844        pool.delegated_stakes()
1845            .insert(StakeValue::new(Stake {
1846                owner: ACCOUNT_B,
1847                power: 200_000,
1848            }))
1849            .unwrap();
1850        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_T, ACCOUNT_B);
1851        deposit.set_balance(200_000);
1852        deposit.set_auto_stake_rewards(false);
1853
1854        let ws = state.ctx.rw_set.commit_to_world_state();
1855
1856        let mut state = create_state(Some(ws));
1857        let commands = vec![Command::UnstakeDeposit(UnstakeDepositInput {
1858            operator: ACCOUNT_T,
1859            max_amount: 200_000,
1860        })];
1861        set_tx(&mut state, ACCOUNT_B, 0, &commands);
1862        let ret = execute_commands(state, commands);
1863        assert_eq!(
1864            (
1865                &ret.error,
1866                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1867            ),
1868            (&None, &ExitStatus::Success)
1869        );
1870        assert_eq!(
1871            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1872            200_000_u64.to_le_bytes().to_vec()
1873        );
1874        println!(
1875            "gas_consumed {}",
1876            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1877        );
1878
1879        let mut state = create_state(Some(ret.new_state));
1880
1881        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_T);
1882        assert_eq!(pool.power().unwrap(), 0);
1883        assert!(pool.delegated_stakes().get_by(&ACCOUNT_B).is_none());
1884        assert_eq!(
1885            NetworkAccount::nvp(&mut state).length(),
1886            TEST_MAX_VALIDATOR_SET_SIZE as u32 - 1
1887        );
1888        assert_ne!(
1889            NetworkAccount::nvp(&mut state).get(0).unwrap().operator,
1890            ACCOUNT_T
1891        );
1892    }
1893
1894    // Prepare: pool (account a) in world state, with non-zero value of Operator Stake
1895    // Prepare: deposits (account a) to pool (account a)
1896    // Commands (account a): Unstake Deposit
1897    // Exception:
1898    // - Pool has no operator stake
1899    #[test]
1900    fn test_unstake_deposit_same_owner() {
1901        let mut state = create_state(None);
1902        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1903        pool.set_operator(ACCOUNT_A);
1904        pool.set_power(100_000);
1905        pool.set_commission_rate(1);
1906        pool.set_operator_stake(Some(Stake {
1907            owner: ACCOUNT_A,
1908            power: 100_000,
1909        }));
1910        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_A);
1911        deposit.set_balance(150_000);
1912        deposit.set_auto_stake_rewards(false);
1913
1914        let ws = state.ctx.rw_set.commit_to_world_state();
1915
1916        let state = create_state(Some(ws));
1917        let ret = execute_commands(
1918            state,
1919            vec![Command::UnstakeDeposit(UnstakeDepositInput {
1920                operator: ACCOUNT_A,
1921                max_amount: 100_000,
1922            })],
1923        );
1924        assert_eq!(
1925            (
1926                &ret.error,
1927                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
1928            ),
1929            (&None, &ExitStatus::Success)
1930        );
1931        assert_eq!(
1932            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
1933            100_000_u64.to_le_bytes().to_vec()
1934        );
1935        println!(
1936            "gas_consumed {}",
1937            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1938        );
1939
1940        let mut state = create_state(Some(ret.new_state));
1941
1942        let pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
1943        assert_eq!(pool.power().unwrap(), 0);
1944        assert!(pool.operator_stake().unwrap().is_none());
1945
1946        ///// Exceptions: /////
1947
1948        let mut state = create_state(Some(state.ws.to_owned()));
1949        state.tx.nonce = 1;
1950        let ret = execute_commands(
1951            state,
1952            vec![Command::UnstakeDeposit(UnstakeDepositInput {
1953                operator: ACCOUNT_A,
1954                max_amount: 50_000,
1955            })],
1956        );
1957        assert_eq!(ret.error, Some(TransitionError::PoolHasNoStakes));
1958        println!(
1959            "gas_consumed {}",
1960            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
1961        );
1962    }
1963
1964    // Prepare: set maximum number of pools in world state, pool (account t) has power > minimum, with non-zero value of Operator Stake
1965    // Prepare: deposits (account t) to pool (account t)
1966    // Commands (account t): Unstake Deposit (to decrease the power of pool (account t))
1967    #[test]
1968    fn test_unstake_deposit_same_owner_nvp_change_key() {
1969        const ACCOUNT_T: [u8; 32] = [
1970            2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1971            1, 1, 1,
1972        ];
1973        let mut state = create_state(None);
1974        create_full_pools_in_nvp(&mut state, false, false);
1975        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_T);
1976        assert_eq!(pool.power().unwrap(), 200_000);
1977        pool.set_operator_stake(Some(Stake {
1978            owner: ACCOUNT_T,
1979            power: 200_000,
1980        }));
1981        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_T, ACCOUNT_T);
1982        deposit.set_balance(200_000);
1983        deposit.set_auto_stake_rewards(false);
1984
1985        state
1986            .ctx
1987            .rw_set
1988            .ws
1989            .cached()
1990            .set_balance(ACCOUNT_T, 500_000_000);
1991        let ws = state.ctx.rw_set.commit_to_world_state();
1992
1993        let mut state = create_state(Some(ws));
1994        let commands = vec![Command::UnstakeDeposit(UnstakeDepositInput {
1995            operator: ACCOUNT_T,
1996            max_amount: 190_000,
1997        })];
1998        set_tx(&mut state, ACCOUNT_T, 0, &commands);
1999        let ret = execute_commands(state, commands);
2000        assert_eq!(
2001            (
2002                &ret.error,
2003                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2004            ),
2005            (&None, &ExitStatus::Success)
2006        );
2007        assert_eq!(
2008            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
2009            190_000_u64.to_le_bytes().to_vec()
2010        );
2011        println!(
2012            "gas_consumed {}",
2013            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
2014        );
2015
2016        let mut state = create_state(Some(ret.new_state));
2017
2018        let pool = NetworkAccount::pools(&mut state, ACCOUNT_T);
2019        assert_eq!(pool.power().unwrap(), 10_000);
2020        assert_eq!(
2021            NetworkAccount::nvp(&mut state).length(),
2022            TEST_MAX_VALIDATOR_SET_SIZE as u32
2023        );
2024        assert_eq!(
2025            NetworkAccount::nvp(&mut state).get(0).unwrap().operator,
2026            ACCOUNT_T
2027        );
2028        assert_eq!(
2029            NetworkAccount::nvp(&mut state).get(0).unwrap().power,
2030            10_000
2031        );
2032    }
2033
2034    // Prepare: set maximum number of pools in world state, pool (account t) has power > minimum, with non-zero value of Operator Stake
2035    // Prepare: deposits (account t) to pool (account t)
2036    // Commands (account t): Unstake Deposit (to empty the power of pool (account t), and to be kicked out from nvp)
2037    #[test]
2038    fn test_unstake_deposit_same_owner_nvp_remove() {
2039        const ACCOUNT_T: [u8; 32] = [
2040            2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2041            1, 1, 1,
2042        ];
2043        let mut state = create_state(None);
2044        create_full_pools_in_nvp(&mut state, false, false);
2045        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_T);
2046        assert_eq!(pool.power().unwrap(), 200_000);
2047        pool.set_operator_stake(Some(Stake {
2048            owner: ACCOUNT_T,
2049            power: 200_000,
2050        }));
2051        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_T, ACCOUNT_T);
2052        deposit.set_balance(200_000);
2053        deposit.set_auto_stake_rewards(false);
2054
2055        state
2056            .ctx
2057            .rw_set
2058            .ws
2059            .cached()
2060            .set_balance(ACCOUNT_T, 500_000_000);
2061        let ws = state.ctx.rw_set.commit_to_world_state();
2062
2063        let mut state = create_state(Some(ws));
2064        let commands = vec![Command::UnstakeDeposit(UnstakeDepositInput {
2065            operator: ACCOUNT_T,
2066            max_amount: 200_000,
2067        })];
2068        set_tx(&mut state, ACCOUNT_T, 0, &commands);
2069        let ret = execute_commands(state, commands);
2070        assert_eq!(
2071            (
2072                &ret.error,
2073                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2074            ),
2075            (&None, &ExitStatus::Success)
2076        );
2077        assert_eq!(
2078            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
2079            200_000_u64.to_le_bytes().to_vec()
2080        );
2081        println!(
2082            "gas_consumed {}",
2083            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
2084        );
2085
2086        let mut state = create_state(Some(ret.new_state));
2087
2088        let pool = NetworkAccount::pools(&mut state, ACCOUNT_T);
2089        assert_eq!(pool.power().unwrap(), 0);
2090        assert!(pool.operator_stake().unwrap().is_none());
2091        assert_eq!(
2092            NetworkAccount::nvp(&mut state).length(),
2093            TEST_MAX_VALIDATOR_SET_SIZE as u32 - 1
2094        );
2095        assert_ne!(
2096            NetworkAccount::nvp(&mut state).get(0).unwrap().operator,
2097            ACCOUNT_T
2098        );
2099    }
2100
2101    // Prepare: pool (account a) in world state, with delegated stakes of account b
2102    // Prepare: deposits (account b) to pool (account a)
2103    // Commands (account b): Withdraw Deposit (to reduce the delegated stakes in pool (account a))
2104    // Exception:
2105    // - Deposit not exist
2106    // - deposit amount = locked stake amount (vp)
2107    // - deposit amount = locked stake amount (pvp)
2108    #[test]
2109    fn test_withdrawal_deposit_delegated_stakes() {
2110        let mut state = create_state(None);
2111        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
2112        pool.set_operator(ACCOUNT_A);
2113        pool.set_power(100_000);
2114        pool.set_commission_rate(1);
2115        pool.set_operator_stake(None);
2116        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B);
2117        deposit.set_balance(100_000);
2118        deposit.set_auto_stake_rewards(false);
2119        NetworkAccount::pools(&mut state, ACCOUNT_A)
2120            .delegated_stakes()
2121            .insert(StakeValue::new(Stake {
2122                owner: ACCOUNT_B,
2123                power: 100_000,
2124            }))
2125            .unwrap();
2126
2127        let ws = state.ctx.rw_set.commit_to_world_state();
2128
2129        let mut state = create_state(Some(ws));
2130        let owner_balance_before = state.ctx.rw_set.ws.balance(ACCOUNT_B);
2131        let commands = vec![Command::WithdrawDeposit(WithdrawDepositInput {
2132            operator: ACCOUNT_A,
2133            max_amount: 40_000,
2134        })];
2135        let tx_base_cost = set_tx(&mut state, ACCOUNT_B, 0, &commands);
2136        let ret = execute_commands(state, commands);
2137        assert_eq!(
2138            (
2139                &ret.error,
2140                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2141            ),
2142            (&None, &ExitStatus::Success)
2143        );
2144        assert_eq!(
2145            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
2146            40_000_u64.to_le_bytes().to_vec()
2147        );
2148        let gas_used = ret
2149            .receipt
2150            .clone()
2151            .unwrap()
2152            .iter()
2153            .map(|g| g.gas_used)
2154            .sum::<u64>();
2155        println!("gas_consumed {}", gas_used);
2156
2157        let mut state = create_state(Some(ret.new_state));
2158        assert_eq!(
2159            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B)
2160                .balance()
2161                .unwrap(),
2162            60_000
2163        );
2164        let stake = NetworkAccount::pools(&mut state, ACCOUNT_A)
2165            .delegated_stakes()
2166            .get_by(&ACCOUNT_B)
2167            .unwrap();
2168        assert_eq!((stake.owner, stake.power), (ACCOUNT_B, 60_000));
2169        assert_eq!(
2170            NetworkAccount::pools(&mut state, ACCOUNT_A)
2171                .power()
2172                .unwrap(),
2173            60_000
2174        );
2175        let owner_balance_after = state.ctx.rw_set.ws.balance(ACCOUNT_B);
2176        assert_eq!(
2177            owner_balance_before,
2178            owner_balance_after + gas_used + tx_base_cost - 40_000
2179        );
2180
2181        ///// Exceptions: /////
2182
2183        let state = create_state(Some(state.ws.to_owned()));
2184        let ret = execute_commands(
2185            state,
2186            vec![Command::WithdrawDeposit(WithdrawDepositInput {
2187                operator: ACCOUNT_A,
2188                max_amount: 40_000,
2189            })],
2190        );
2191        assert_eq!(ret.error, Some(TransitionError::DepositsNotExists));
2192        println!(
2193            "gas_consumed {}",
2194            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
2195        );
2196
2197        // First proceed next epoch
2198        let mut state = create_state(Some(ret.new_state));
2199        state.tx.nonce = 1;
2200        let ret = execute_next_epoch_command(state, vec![Command::NextEpoch]);
2201        assert_eq!(
2202            (
2203                &ret.error,
2204                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2205            ),
2206            (&None, &ExitStatus::Success)
2207        );
2208        println!(
2209            "gas_consumed {}",
2210            ret.receipt
2211                .clone()
2212                .unwrap()
2213                .iter()
2214                .map(|g| g.gas_used)
2215                .sum::<u64>()
2216        );
2217        // Then unstake
2218        let mut state = create_state(Some(ret.new_state));
2219        let commands = vec![
2220            Command::UnstakeDeposit(UnstakeDepositInput {
2221                operator: ACCOUNT_A,
2222                max_amount: 10_000,
2223            }), // 60_000 - 10_000
2224        ];
2225        set_tx(&mut state, ACCOUNT_B, 1, &commands);
2226        let ret = execute_commands(state, commands);
2227        assert_eq!(
2228            (
2229                &ret.error,
2230                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2231            ),
2232            (&None, &ExitStatus::Success)
2233        );
2234        println!(
2235            "gas_consumed {}",
2236            ret.receipt
2237                .clone()
2238                .unwrap()
2239                .iter()
2240                .map(|g| g.gas_used)
2241                .sum::<u64>()
2242        );
2243        // pvp: 0, vp: 60_000, nvp: 50_000, deposit: 60_000, Try withdraw
2244        let mut state = create_state(Some(ret.new_state));
2245        let commands = vec![Command::WithdrawDeposit(WithdrawDepositInput {
2246            operator: ACCOUNT_A,
2247            max_amount: 10_000,
2248        })];
2249        set_tx(&mut state, ACCOUNT_B, 2, &commands);
2250        let ret = execute_commands(state, commands);
2251        assert_eq!(ret.error, Some(TransitionError::InvalidStakeAmount));
2252        println!(
2253            "gas_consumed {}",
2254            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
2255        );
2256
2257        // Proceed next epoch
2258        let mut state = create_state(Some(ret.new_state));
2259        state.tx.nonce = 2;
2260        state.bd.validator_performance = Some(single_node_performance(
2261            ACCOUNT_A,
2262            TEST_MAX_VALIDATOR_SET_SIZE as u32,
2263        ));
2264        let ret = execute_next_epoch_command(state, vec![Command::NextEpoch]);
2265        assert_eq!(
2266            (
2267                &ret.error,
2268                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2269            ),
2270            (&None, &ExitStatus::Success)
2271        );
2272        println!(
2273            "gas_consumed {}",
2274            ret.receipt
2275                .clone()
2276                .unwrap()
2277                .iter()
2278                .map(|g| g.gas_used)
2279                .sum::<u64>()
2280        );
2281        // pvp: 60_000, vp: 50_000, nvp: 50_000, deposit: 60_013, Deduce deposit to 60_000
2282        let mut state = create_state(Some(ret.new_state));
2283        let commands = vec![
2284            Command::WithdrawDeposit(WithdrawDepositInput {
2285                operator: ACCOUNT_A,
2286                max_amount: 13,
2287            }), // reduce deposit to 60_000
2288        ];
2289        set_tx(&mut state, ACCOUNT_B, 3, &commands);
2290        let ret = execute_commands(state, commands);
2291        assert_eq!(
2292            (
2293                &ret.error,
2294                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2295            ),
2296            (&None, &ExitStatus::Success)
2297        );
2298        println!(
2299            "gas_consumed {}",
2300            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
2301        );
2302        // pvp: 60_000, vp: 50_000, nvp: 50_000, deposit: 60_000, Try Withdraw
2303        let mut state = create_state(Some(ret.new_state));
2304        let commands = vec![Command::WithdrawDeposit(WithdrawDepositInput {
2305            operator: ACCOUNT_A,
2306            max_amount: 10_000,
2307        })];
2308        set_tx(&mut state, ACCOUNT_B, 4, &commands);
2309        let ret = execute_commands(state, commands);
2310        assert_eq!(ret.error, Some(TransitionError::InvalidStakeAmount));
2311        println!(
2312            "gas_consumed {}",
2313            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
2314        );
2315    }
2316
2317    // Prepare: set maximum number of pools in world state, pool (account t) has power > minimum, with delegated stakes of account b
2318    // Prepare: deposits (account b) to pool (account t)
2319    // Commands (account b): Withdraw Deposit (to decrease the power of pool (account t))
2320    #[test]
2321    fn test_withdrawal_deposit_delegated_stakes_nvp_change_key() {
2322        const ACCOUNT_T: [u8; 32] = [
2323            2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2324            1, 1, 1,
2325        ];
2326        let mut state = create_state(None);
2327        create_full_pools_in_nvp(&mut state, false, false);
2328        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_T);
2329        assert_eq!(pool.power().unwrap(), 200_000);
2330        pool.set_operator_stake(None);
2331        NetworkAccount::pools(&mut state, ACCOUNT_T)
2332            .delegated_stakes()
2333            .insert(StakeValue::new(Stake {
2334                owner: ACCOUNT_B,
2335                power: 150_000,
2336            }))
2337            .unwrap();
2338        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_T, ACCOUNT_B);
2339        deposit.set_balance(200_000);
2340        deposit.set_auto_stake_rewards(false);
2341
2342        let ws = state.ctx.rw_set.commit_to_world_state();
2343
2344        let mut state = create_state(Some(ws));
2345        let owner_balance_before = state.ctx.rw_set.ws.balance(ACCOUNT_B);
2346        let commands = vec![Command::WithdrawDeposit(WithdrawDepositInput {
2347            operator: ACCOUNT_T,
2348            max_amount: 200_000,
2349        })];
2350        let tx_base_cost = set_tx(&mut state, ACCOUNT_B, 0, &commands);
2351        let ret = execute_commands(state, commands);
2352        assert_eq!(
2353            (
2354                &ret.error,
2355                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2356            ),
2357            (&None, &ExitStatus::Success)
2358        );
2359        assert_eq!(
2360            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
2361            200_000_u64.to_le_bytes().to_vec()
2362        );
2363        let gas_used = ret
2364            .receipt
2365            .as_ref()
2366            .unwrap()
2367            .iter()
2368            .map(|g| g.gas_used)
2369            .sum::<u64>();
2370        println!(
2371            "gas_consumed {}",
2372            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
2373        );
2374
2375        let mut state = create_state(Some(ret.new_state));
2376
2377        assert_eq!(
2378            NetworkAccount::deposits(&mut state, ACCOUNT_T, ACCOUNT_B).balance(),
2379            None
2380        );
2381        let stake = NetworkAccount::pools(&mut state, ACCOUNT_T)
2382            .delegated_stakes()
2383            .get_by(&ACCOUNT_B);
2384        assert!(stake.is_none());
2385        assert_eq!(
2386            NetworkAccount::pools(&mut state, ACCOUNT_T)
2387                .power()
2388                .unwrap(),
2389            50_000
2390        );
2391        let owner_balance_after = state.ctx.rw_set.ws.balance(ACCOUNT_B);
2392        assert_eq!(
2393            owner_balance_before,
2394            owner_balance_after + gas_used + tx_base_cost - 200_000
2395        );
2396        assert_eq!(
2397            NetworkAccount::nvp(&mut state).length(),
2398            TEST_MAX_VALIDATOR_SET_SIZE as u32
2399        );
2400        assert_eq!(
2401            NetworkAccount::nvp(&mut state).get(0).unwrap().operator,
2402            ACCOUNT_T
2403        );
2404        assert_eq!(
2405            NetworkAccount::nvp(&mut state).get(0).unwrap().power,
2406            50_000
2407        );
2408    }
2409
2410    // Prepare: set maximum number of pools in world state, pool (account t) has power > minimum, with delegated stakes of account b
2411    // Prepare: deposits (account b) to pool (account t)
2412    // Commands (account b): Withdraw Deposit (to empty the power of pool (account t), and to be kicked out from nvp)
2413    #[test]
2414    fn test_withdrawal_deposit_delegated_stakes_nvp_remove() {
2415        const ACCOUNT_T: [u8; 32] = [
2416            2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2417            1, 1, 1,
2418        ];
2419        let mut state = create_state(None);
2420        create_full_pools_in_nvp(&mut state, false, false);
2421        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_T);
2422        assert_eq!(pool.power().unwrap(), 200_000);
2423        pool.set_operator_stake(None);
2424        NetworkAccount::pools(&mut state, ACCOUNT_T)
2425            .delegated_stakes()
2426            .insert(StakeValue::new(Stake {
2427                owner: ACCOUNT_B,
2428                power: 200_000,
2429            }))
2430            .unwrap();
2431        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_T, ACCOUNT_B);
2432        deposit.set_balance(300_000);
2433        deposit.set_auto_stake_rewards(false);
2434
2435        let ws = state.ctx.rw_set.commit_to_world_state();
2436
2437        let mut state = create_state(Some(ws));
2438        let owner_balance_before = state.ctx.rw_set.ws.balance(ACCOUNT_A);
2439        let commands = vec![Command::WithdrawDeposit(WithdrawDepositInput {
2440            operator: ACCOUNT_T,
2441            max_amount: 300_000,
2442        })];
2443        let tx_base_cost = set_tx(&mut state, ACCOUNT_B, 0, &commands);
2444        let ret = execute_commands(state, commands);
2445        assert_eq!(
2446            (
2447                &ret.error,
2448                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2449            ),
2450            (&None, &ExitStatus::Success)
2451        );
2452        assert_eq!(
2453            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
2454            300_000_u64.to_le_bytes().to_vec()
2455        );
2456        let gas_used = ret
2457            .receipt
2458            .as_ref()
2459            .unwrap()
2460            .iter()
2461            .map(|g| g.gas_used)
2462            .sum::<u64>();
2463        println!(
2464            "gas_consumed {}",
2465            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
2466        );
2467
2468        let mut state = create_state(Some(ret.new_state));
2469
2470        assert_eq!(
2471            NetworkAccount::deposits(&mut state, ACCOUNT_T, ACCOUNT_B).balance(),
2472            None
2473        );
2474        let stake = NetworkAccount::pools(&mut state, ACCOUNT_T)
2475            .delegated_stakes()
2476            .get_by(&ACCOUNT_B);
2477        assert!(stake.is_none());
2478        assert_eq!(
2479            NetworkAccount::pools(&mut state, ACCOUNT_T)
2480                .power()
2481                .unwrap(),
2482            0
2483        );
2484        let owner_balance_after = state.ctx.rw_set.ws.balance(ACCOUNT_B);
2485        assert_eq!(
2486            owner_balance_before,
2487            owner_balance_after + gas_used + tx_base_cost - 300_000
2488        );
2489        assert_eq!(
2490            NetworkAccount::nvp(&mut state).length(),
2491            TEST_MAX_VALIDATOR_SET_SIZE as u32 - 1
2492        );
2493        assert_eq!(
2494            NetworkAccount::nvp(&mut state).get(0).unwrap().operator,
2495            ACCOUNT_A
2496        );
2497        assert_eq!(
2498            NetworkAccount::nvp(&mut state).get(0).unwrap().power,
2499            100_000
2500        );
2501    }
2502
2503    // Prepare: pool (account a) in world state, with non-zero value of Operator Stake
2504    // Prepare: deposits (account a) to pool (account a)
2505    // Commands (account a): Withdraw Deposit (to reduce the operator stake of pool (account a))
2506    #[test]
2507    fn test_withdrawal_deposit_same_owner() {
2508        let mut state = create_state(None);
2509        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
2510        pool.set_operator(ACCOUNT_A);
2511        pool.set_power(100_000);
2512        pool.set_commission_rate(1);
2513        pool.set_operator_stake(Some(Stake {
2514            owner: ACCOUNT_A,
2515            power: 100_000,
2516        }));
2517        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_A);
2518        deposit.set_balance(100_000);
2519        deposit.set_auto_stake_rewards(false);
2520
2521        let ws = state.ctx.rw_set.commit_to_world_state();
2522
2523        let mut state = create_state(Some(ws));
2524        let owner_balance_before = state.ctx.rw_set.ws.balance(ACCOUNT_A);
2525        let commands = vec![Command::WithdrawDeposit(WithdrawDepositInput {
2526            operator: ACCOUNT_A,
2527            max_amount: 45_000,
2528        })];
2529        let tx_base_cost = set_tx(&mut state, ACCOUNT_A, 0, &commands);
2530        let ret = execute_commands(state, commands);
2531        assert_eq!(
2532            (
2533                &ret.error,
2534                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2535            ),
2536            (&None, &ExitStatus::Success)
2537        );
2538        assert_eq!(
2539            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
2540            45_000_u64.to_le_bytes().to_vec()
2541        );
2542        let gas_used = ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>();
2543        println!("gas_consumed {}", gas_used);
2544
2545        let mut state = create_state(Some(ret.new_state));
2546
2547        assert_eq!(
2548            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_A)
2549                .balance()
2550                .unwrap(),
2551            55_000
2552        );
2553        let stake = NetworkAccount::pools(&mut state, ACCOUNT_A)
2554            .operator_stake()
2555            .unwrap()
2556            .unwrap();
2557        assert_eq!((stake.owner, stake.power), (ACCOUNT_A, 55_000));
2558        assert_eq!(
2559            NetworkAccount::pools(&mut state, ACCOUNT_A)
2560                .power()
2561                .unwrap(),
2562            55_000
2563        );
2564        let owner_balance_after = state.ctx.rw_set.ws.balance(ACCOUNT_A);
2565        assert_eq!(
2566            owner_balance_before,
2567            owner_balance_after + gas_used + tx_base_cost - 45_000
2568        );
2569    }
2570
2571    // Prepare: set maximum number of pools in world state, pool (account t) has power > minimum, with non-zero value of Operator Stake
2572    // Prepare: deposits (account t) to pool (account t)
2573    // Commands (account t): Withdraw Deposit (to decrease the power of pool (account t))
2574    #[test]
2575    fn test_withdrawal_deposit_same_owner_nvp_change_key() {
2576        const ACCOUNT_T: [u8; 32] = [
2577            2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2578            1, 1, 1,
2579        ];
2580        let mut state = create_state(None);
2581        create_full_pools_in_nvp(&mut state, false, false);
2582        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_T);
2583        assert_eq!(pool.power().unwrap(), 200_000);
2584        pool.set_operator_stake(Some(Stake {
2585            owner: ACCOUNT_T,
2586            power: 150_000,
2587        }));
2588        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_T, ACCOUNT_T);
2589        deposit.set_balance(200_000);
2590        deposit.set_auto_stake_rewards(false);
2591
2592        state
2593            .ctx
2594            .rw_set
2595            .ws
2596            .cached()
2597            .set_balance(ACCOUNT_T, 500_000_000);
2598        let ws = state.ctx.rw_set.commit_to_world_state();
2599
2600        let mut state = create_state(Some(ws));
2601        let owner_balance_before = state.ctx.rw_set.ws.balance(ACCOUNT_T);
2602        let commands = vec![Command::WithdrawDeposit(WithdrawDepositInput {
2603            operator: ACCOUNT_T,
2604            max_amount: 200_000,
2605        })];
2606        let tx_base_cost = set_tx(&mut state, ACCOUNT_T, 0, &commands);
2607        let ret = execute_commands(state, commands);
2608        assert_eq!(
2609            (
2610                &ret.error,
2611                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2612            ),
2613            (&None, &ExitStatus::Success)
2614        );
2615        assert_eq!(
2616            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
2617            200_000_u64.to_le_bytes().to_vec()
2618        );
2619        let gas_used = ret
2620            .receipt
2621            .as_ref()
2622            .unwrap()
2623            .iter()
2624            .map(|g| g.gas_used)
2625            .sum::<u64>();
2626        println!(
2627            "gas_consumed {}",
2628            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
2629        );
2630
2631        let mut state = create_state(Some(ret.new_state));
2632
2633        assert_eq!(
2634            NetworkAccount::deposits(&mut state, ACCOUNT_T, ACCOUNT_T).balance(),
2635            None
2636        );
2637        assert!(NetworkAccount::pools(&mut state, ACCOUNT_T)
2638            .operator_stake()
2639            .unwrap()
2640            .is_none());
2641        assert_eq!(
2642            NetworkAccount::pools(&mut state, ACCOUNT_T)
2643                .power()
2644                .unwrap(),
2645            50_000
2646        );
2647        let owner_balance_after = state.ctx.rw_set.ws.balance(ACCOUNT_T);
2648        assert_eq!(
2649            owner_balance_before,
2650            owner_balance_after + gas_used + tx_base_cost - 200_000
2651        );
2652        assert_eq!(
2653            NetworkAccount::nvp(&mut state).length(),
2654            TEST_MAX_VALIDATOR_SET_SIZE as u32
2655        );
2656        assert_eq!(
2657            NetworkAccount::nvp(&mut state).get(0).unwrap().operator,
2658            ACCOUNT_T
2659        );
2660        assert_eq!(
2661            NetworkAccount::nvp(&mut state).get(0).unwrap().power,
2662            50_000
2663        );
2664    }
2665
2666    // Prepare: set maximum number of pools in world state, pool (account t) has power > minimum, with non-zero value of Operator Stake
2667    // Prepare: deposits (account t) to pool (account t)
2668    // Commands (account t): Withdraw Deposit (to empty the power of pool (account t), and to be kicked out from nvp)
2669    #[test]
2670    fn test_withdrawal_deposit_same_owner_nvp_remove() {
2671        const ACCOUNT_T: [u8; 32] = [
2672            2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2673            1, 1, 1,
2674        ];
2675        let mut state = create_state(None);
2676        create_full_pools_in_nvp(&mut state, false, false);
2677        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_T);
2678        assert_eq!(pool.power().unwrap(), 200_000);
2679        pool.set_operator_stake(Some(Stake {
2680            owner: ACCOUNT_T,
2681            power: 200_000,
2682        }));
2683        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_T, ACCOUNT_T);
2684        deposit.set_balance(300_000);
2685        deposit.set_auto_stake_rewards(false);
2686
2687        state
2688            .ctx
2689            .rw_set
2690            .ws
2691            .cached()
2692            .set_balance(ACCOUNT_T, 500_000_000);
2693        let ws = state.ctx.rw_set.commit_to_world_state();
2694
2695        let mut state = create_state(Some(ws));
2696        let owner_balance_before = state.ctx.rw_set.ws.balance(ACCOUNT_A);
2697        let commands = vec![Command::WithdrawDeposit(WithdrawDepositInput {
2698            operator: ACCOUNT_T,
2699            max_amount: 300_000,
2700        })];
2701        let tx_base_cost = set_tx(&mut state, ACCOUNT_T, 0, &commands);
2702        let ret = execute_commands(state, commands);
2703        assert_eq!(
2704            (
2705                &ret.error,
2706                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2707            ),
2708            (&None, &ExitStatus::Success)
2709        );
2710        assert_eq!(
2711            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
2712            300_000_u64.to_le_bytes().to_vec()
2713        );
2714        let gas_used = ret
2715            .receipt
2716            .as_ref()
2717            .unwrap()
2718            .iter()
2719            .map(|g| g.gas_used)
2720            .sum::<u64>();
2721        println!(
2722            "gas_consumed {}",
2723            ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>()
2724        );
2725
2726        let mut state = create_state(Some(ret.new_state));
2727
2728        assert_eq!(
2729            NetworkAccount::deposits(&mut state, ACCOUNT_T, ACCOUNT_T).balance(),
2730            None
2731        );
2732        assert!(NetworkAccount::pools(&mut state, ACCOUNT_T)
2733            .operator_stake()
2734            .unwrap()
2735            .is_none());
2736        let owner_balance_after = state.ctx.rw_set.ws.balance(ACCOUNT_T);
2737        assert_eq!(
2738            owner_balance_before,
2739            owner_balance_after + gas_used + tx_base_cost - 300_000
2740        );
2741        assert_eq!(
2742            NetworkAccount::nvp(&mut state).length(),
2743            TEST_MAX_VALIDATOR_SET_SIZE as u32 - 1
2744        );
2745        assert_eq!(
2746            NetworkAccount::nvp(&mut state).get(0).unwrap().operator,
2747            ACCOUNT_A
2748        );
2749        assert_eq!(
2750            NetworkAccount::nvp(&mut state).get(0).unwrap().power,
2751            100_000
2752        );
2753    }
2754
2755    // Prepare: pool (account a) in world state, with delegated stakes of account b
2756    // Prepare: deposits (account b) to pool (account a)
2757    // Prepare: 0 < pvp.power < vp.power
2758    // Commands (account b): Withdraw Deposit (to reduce the delegated stakes in pool (account a))
2759    #[test]
2760    fn test_withdrawal_deposit_bounded_by_vp() {
2761        let mut state = create_state(None);
2762        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
2763        pool.set_operator(ACCOUNT_A);
2764        pool.set_power(100_000);
2765        pool.set_commission_rate(1);
2766        pool.set_operator_stake(None);
2767        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B);
2768        deposit.set_balance(100_000);
2769        deposit.set_auto_stake_rewards(false);
2770        NetworkAccount::pools(&mut state, ACCOUNT_A)
2771            .delegated_stakes()
2772            .insert(StakeValue::new(Stake {
2773                owner: ACCOUNT_B,
2774                power: 100_000,
2775            }))
2776            .unwrap();
2777        NetworkAccount::pvp(&mut state)
2778            .push(
2779                Pool {
2780                    operator: ACCOUNT_A,
2781                    commission_rate: 1,
2782                    power: 100_000,
2783                    operator_stake: None,
2784                },
2785                vec![StakeValue::new(Stake {
2786                    owner: ACCOUNT_B,
2787                    power: 70_000,
2788                })],
2789            )
2790            .unwrap();
2791        NetworkAccount::vp(&mut state)
2792            .push(
2793                Pool {
2794                    operator: ACCOUNT_A,
2795                    commission_rate: 1,
2796                    power: 100_000,
2797                    operator_stake: None,
2798                },
2799                vec![StakeValue::new(Stake {
2800                    owner: ACCOUNT_B,
2801                    power: 80_000,
2802                })],
2803            )
2804            .unwrap();
2805
2806        let ws = state.ctx.rw_set.commit_to_world_state();
2807
2808        let mut state = create_state(Some(ws));
2809        let owner_balance_before = state.ctx.rw_set.ws.balance(ACCOUNT_B);
2810        let commands = vec![Command::WithdrawDeposit(WithdrawDepositInput {
2811            operator: ACCOUNT_A,
2812            max_amount: 40_000,
2813        })];
2814        let tx_base_cost = set_tx(&mut state, ACCOUNT_B, 0, &commands);
2815        let ret = execute_commands(state, commands);
2816        assert_eq!(
2817            (
2818                &ret.error,
2819                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2820            ),
2821            (&None, &ExitStatus::Success)
2822        );
2823        assert_eq!(
2824            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
2825            20_000_u64.to_le_bytes().to_vec()
2826        );
2827        let gas_used = ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>();
2828        println!("gas_consumed {}", gas_used);
2829
2830        let mut state = create_state(Some(ret.new_state));
2831
2832        assert_eq!(
2833            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B)
2834                .balance()
2835                .unwrap(),
2836            80_000
2837        );
2838        let stake = NetworkAccount::pools(&mut state, ACCOUNT_A)
2839            .delegated_stakes()
2840            .get_by(&ACCOUNT_B)
2841            .unwrap();
2842        assert_eq!((stake.owner, stake.power), (ACCOUNT_B, 80_000));
2843        assert_eq!(
2844            NetworkAccount::pools(&mut state, ACCOUNT_A)
2845                .power()
2846                .unwrap(),
2847            80_000
2848        );
2849        let owner_balance_after = state.ctx.rw_set.ws.balance(ACCOUNT_B);
2850        assert_eq!(
2851            owner_balance_before,
2852            owner_balance_after + gas_used + tx_base_cost - 20_000
2853        );
2854    }
2855
2856    // Prepare: pool (account a) in world state, with delegated stakes of account b
2857    // Prepare: deposits (account b) to pool (account a)
2858    // Prepare: 0 < vp.power < pvp.power
2859    // Commands (account b): Withdraw Deposit (to reduce the delegated stakes in pool (account a))
2860    #[test]
2861    fn test_withdrawal_deposit_bounded_by_pvp() {
2862        let mut state = create_state(None);
2863        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
2864        pool.set_operator(ACCOUNT_A);
2865        pool.set_power(100_000);
2866        pool.set_commission_rate(1);
2867        pool.set_operator_stake(None);
2868        let mut deposit = NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B);
2869        deposit.set_balance(100_000);
2870        deposit.set_auto_stake_rewards(false);
2871        NetworkAccount::pools(&mut state, ACCOUNT_A)
2872            .delegated_stakes()
2873            .insert(StakeValue::new(Stake {
2874                owner: ACCOUNT_B,
2875                power: 100_000,
2876            }))
2877            .unwrap();
2878        NetworkAccount::pvp(&mut state)
2879            .push(
2880                Pool {
2881                    operator: ACCOUNT_A,
2882                    commission_rate: 1,
2883                    power: 100_000,
2884                    operator_stake: None,
2885                },
2886                vec![StakeValue::new(Stake {
2887                    owner: ACCOUNT_B,
2888                    power: 90_000,
2889                })],
2890            )
2891            .unwrap();
2892        NetworkAccount::vp(&mut state)
2893            .push(
2894                Pool {
2895                    operator: ACCOUNT_A,
2896                    commission_rate: 1,
2897                    power: 100_000,
2898                    operator_stake: None,
2899                },
2900                vec![StakeValue::new(Stake {
2901                    owner: ACCOUNT_B,
2902                    power: 80_000,
2903                })],
2904            )
2905            .unwrap();
2906
2907        let ws = state.ctx.rw_set.commit_to_world_state();
2908
2909        let mut state = create_state(Some(ws));
2910        let owner_balance_before = state.ctx.rw_set.ws.balance(ACCOUNT_B);
2911        let commands = vec![Command::WithdrawDeposit(WithdrawDepositInput {
2912            operator: ACCOUNT_A,
2913            max_amount: 40_000,
2914        })];
2915        let tx_base_cost = set_tx(&mut state, ACCOUNT_B, 0, &commands);
2916        let ret = execute_commands(state, commands);
2917        assert_eq!(
2918            (
2919                &ret.error,
2920                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
2921            ),
2922            (&None, &ExitStatus::Success)
2923        );
2924        assert_eq!(
2925            ret.receipt.as_ref().unwrap().last().unwrap().return_values,
2926            10_000_u64.to_le_bytes().to_vec()
2927        );
2928        let gas_used = ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>();
2929        println!("gas_consumed {}", gas_used);
2930
2931        let mut state = create_state(Some(ret.new_state));
2932
2933        assert_eq!(
2934            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B)
2935                .balance()
2936                .unwrap(),
2937            90_000
2938        );
2939        let stake = NetworkAccount::pools(&mut state, ACCOUNT_A)
2940            .delegated_stakes()
2941            .get_by(&ACCOUNT_B)
2942            .unwrap();
2943        assert_eq!((stake.owner, stake.power), (ACCOUNT_B, 90_000));
2944        assert_eq!(
2945            NetworkAccount::pools(&mut state, ACCOUNT_A)
2946                .power()
2947                .unwrap(),
2948            90_000
2949        );
2950        let owner_balance_after = state.ctx.rw_set.ws.balance(ACCOUNT_B);
2951        assert_eq!(
2952            owner_balance_before,
2953            owner_balance_after + gas_used + tx_base_cost - 10_000
2954        );
2955    }
2956
2957    // Prepare: no pool in world state
2958    // Prepare: empty pvp and vp.
2959    // Commands (account a): Next Epoch
2960    #[test]
2961    fn test_next_epoch_no_pool() {
2962        let mut state = create_state(None);
2963        NetworkAccount::new(&mut state).set_current_epoch(0);
2964        let ws = state.ctx.rw_set.commit_to_world_state();
2965        let state = create_state(Some(ws));
2966        let mut state = execute_next_epoch(state);
2967        assert_eq!(NetworkAccount::new(&mut state).current_epoch(), 1);
2968    }
2969
2970    // Prepare: pool (account a) in world state, included in nvp.
2971    //              with delegated stakes of account b, auto_stake_reward = false
2972    //              with non-zero value of Operator Stake, auto_stake_reward = false
2973    // Prepare: empty pvp and vp.
2974    // Commands (account a): Next Epoch
2975    #[test]
2976    fn test_next_epoch_single_pool() {
2977        let ws = prepare_single_pool(false, false);
2978        let state = create_state(Some(ws));
2979        let mut state = execute_next_epoch(state);
2980
2981        // PVP should be empty
2982        assert_eq!(NetworkAccount::pvp(&mut state).length(), 0);
2983        // VP is copied by nvp (nvp is not changed as auto_stake_rewards = false)
2984        let mut vp = NetworkAccount::vp(&mut state);
2985        assert_eq!(vp.length(), 1);
2986        let pool_in_vp: Pool = vp.pool_at(0).unwrap().try_into().unwrap();
2987        let stakes_in_vp = vp
2988            .pool(ACCOUNT_A)
2989            .unwrap()
2990            .delegated_stakes()
2991            .get(0)
2992            .unwrap();
2993        // No rewards at first epoch
2994        assert_eq!(
2995            (
2996                pool_in_vp.operator,
2997                pool_in_vp.commission_rate,
2998                pool_in_vp.power,
2999                pool_in_vp.operator_stake
3000            ),
3001            (
3002                ACCOUNT_A,
3003                1,
3004                100_000,
3005                Some(Stake {
3006                    owner: ACCOUNT_A,
3007                    power: 10_000
3008                })
3009            )
3010        );
3011        assert_eq!(
3012            (stakes_in_vp.owner, stakes_in_vp.power),
3013            (ACCOUNT_B, 90_000)
3014        );
3015        // NVP unchanged
3016        let nvp = NetworkAccount::nvp(&mut state);
3017        assert_eq!(nvp.length(), 1);
3018        let pool_in_nvp = nvp.get(0).unwrap();
3019        assert_eq!(
3020            (pool_in_nvp.operator, pool_in_nvp.power),
3021            (ACCOUNT_A, 100_000)
3022        );
3023        // pool unchanged
3024        let mut pool = NetworkAccount::pools(&mut state, ACCOUNT_A);
3025        assert_eq!(
3026            (
3027                pool.operator().unwrap(),
3028                pool.commission_rate().unwrap(),
3029                pool.power().unwrap(),
3030                pool.operator_stake().unwrap()
3031            ),
3032            (
3033                ACCOUNT_A,
3034                1,
3035                100_000,
3036                Some(Stake {
3037                    owner: ACCOUNT_A,
3038                    power: 10_000
3039                })
3040            )
3041        );
3042        let delegated_stakes = pool.delegated_stakes();
3043        let delegated_stake = delegated_stakes.get(0).unwrap();
3044        assert_eq!(
3045            (delegated_stake.owner, delegated_stake.power),
3046            (ACCOUNT_B, 90_000)
3047        );
3048        // deposits unchanged
3049        assert_eq!(
3050            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_A)
3051                .balance()
3052                .unwrap(),
3053            10_000
3054        );
3055        assert_eq!(
3056            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B)
3057                .balance()
3058                .unwrap(),
3059            90_000
3060        );
3061
3062        // Epoch increased by 1
3063        assert_eq!(NetworkAccount::new(&mut state).current_epoch(), 1);
3064    }
3065
3066    // Prepare: pool (account a) in world state, included in nvp.
3067    //              with delegated stakes of account b, auto_stake_reward = false
3068    //              with non-zero value of Operator Stake, auto_stake_reward = false
3069    // Prepare: empty pvp. valid vp with pool (account a) and stakes (account b).
3070    // Commands (account a): Next Epoch, Next Epoch
3071    #[test]
3072    fn test_next_epoch_single_pool_with_vp() {
3073        let ws = prepare_single_pool(false, false);
3074        let mut state = create_state(Some(ws));
3075        state.bd.validator_performance = Some(single_node_performance(ACCOUNT_A, 1));
3076        // prepare data by executing first epoch, assume test result is correct from test_next_epoch_single_pool
3077        let mut state = execute_next_epoch(state);
3078        state.bd.validator_performance = Some(single_node_performance(ACCOUNT_A, 1));
3079        // second epoch
3080        state.tx.nonce = 1;
3081        let mut state = execute_next_epoch(state);
3082
3083        // PVP is copied by VP
3084        let mut pvp = NetworkAccount::pvp(&mut state);
3085        assert_eq!(pvp.length(), 1);
3086        let pool_in_pvp: Pool = pvp.pool_at(0).unwrap().try_into().unwrap();
3087        let stakes_in_pvp = pvp
3088            .pool(ACCOUNT_A)
3089            .unwrap()
3090            .delegated_stakes()
3091            .get(0)
3092            .unwrap();
3093        assert_eq!(
3094            (
3095                pool_in_pvp.operator,
3096                pool_in_pvp.commission_rate,
3097                pool_in_pvp.power,
3098                pool_in_pvp.operator_stake
3099            ),
3100            (
3101                ACCOUNT_A,
3102                1,
3103                100_000,
3104                Some(Stake {
3105                    owner: ACCOUNT_A,
3106                    power: 10_000
3107                })
3108            )
3109        );
3110        assert_eq!(
3111            (stakes_in_pvp.owner, stakes_in_pvp.power),
3112            (ACCOUNT_B, 90_000)
3113        );
3114        // VP is copied by nvp (nvp is not changed as auto_stake_rewards = false)
3115        let mut vp = NetworkAccount::pvp(&mut state);
3116        assert_eq!(vp.length(), 1);
3117        let pool_in_vp: Pool = vp.pool_at(0).unwrap().try_into().unwrap();
3118        let stakes_in_vp = vp
3119            .pool(ACCOUNT_A)
3120            .unwrap()
3121            .delegated_stakes()
3122            .get(0)
3123            .unwrap();
3124        assert_eq!(
3125            (
3126                pool_in_vp.operator,
3127                pool_in_vp.commission_rate,
3128                pool_in_vp.power,
3129                pool_in_vp.operator_stake
3130            ),
3131            (
3132                ACCOUNT_A,
3133                1,
3134                100_000,
3135                Some(Stake {
3136                    owner: ACCOUNT_A,
3137                    power: 10_000
3138                })
3139            )
3140        );
3141        assert_eq!(
3142            (stakes_in_vp.owner, stakes_in_vp.power),
3143            (ACCOUNT_B, 90_000)
3144        );
3145
3146        // deposits are rewarded, assume 64 blocks per epoch (test setup)
3147        // pool rewards = (100_000 * 8.346 / 100) / 365 = 22
3148        // reward for b = 22 * 9 / 10 = 19
3149        // reward for a = 22 * 1 / 10 = 2
3150        // commission fee from b = 19 * 1% = 0
3151        // reward for b after commission fee = 19 - 0 = 19
3152        // reward for a after commission fee = 2 + 0 = 2
3153
3154        // NVP unchanged (auto stakes reward = false)
3155        let nvp = NetworkAccount::nvp(&mut state);
3156        assert_eq!(nvp.length(), 1);
3157        let pool_in_nvp = nvp.get(0).unwrap();
3158        assert_eq!(
3159            (pool_in_nvp.operator, pool_in_nvp.power),
3160            (ACCOUNT_A, 100_000)
3161        );
3162        assert_eq!(
3163            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_A)
3164                .balance()
3165                .unwrap(),
3166            10_002
3167        );
3168        assert_eq!(
3169            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B)
3170                .balance()
3171                .unwrap(),
3172            90_019
3173        );
3174
3175        // Epoch increased by 1
3176        assert_eq!(NetworkAccount::new(&mut state).current_epoch(), 2);
3177    }
3178
3179    // Prepare: pool (account a) in world state, included in nvp.
3180    //              with delegated stakes of account b, auto_stake_reward = true
3181    //              with non-zero value of Operator Stake, auto_stake_reward = true
3182    // Prepare: empty pvp and vp.
3183    // Commands (account a): Next Epoch, Next Epoch
3184    #[test]
3185    fn test_next_epoch_single_pool_auto_stake() {
3186        let ws = prepare_single_pool(true, true);
3187        let mut state = create_state(Some(ws));
3188        state.bd.validator_performance = Some(single_node_performance(ACCOUNT_A, 1));
3189        // prepare data by executing first epoch, assume test result is correct from test_next_epoch_single_pool
3190        let mut state = execute_next_epoch(state);
3191        state.bd.validator_performance = Some(single_node_performance(ACCOUNT_A, 1));
3192        // second epoch
3193        state.tx.nonce = 1;
3194        let mut state = execute_next_epoch(state);
3195
3196        // PVP is copied by VP
3197        let mut pvp = NetworkAccount::pvp(&mut state);
3198        assert_eq!(pvp.length(), 1);
3199        let pool_in_pvp: Pool = pvp.pool_at(0).unwrap().try_into().unwrap();
3200        let stakes_in_pvp = pvp
3201            .pool(ACCOUNT_A)
3202            .unwrap()
3203            .delegated_stakes()
3204            .get(0)
3205            .unwrap();
3206        assert_eq!(
3207            (
3208                pool_in_pvp.operator,
3209                pool_in_pvp.commission_rate,
3210                pool_in_pvp.power,
3211                pool_in_pvp.operator_stake
3212            ),
3213            (
3214                ACCOUNT_A,
3215                1,
3216                100_000,
3217                Some(Stake {
3218                    owner: ACCOUNT_A,
3219                    power: 10_000
3220                })
3221            )
3222        );
3223        assert_eq!(
3224            (stakes_in_pvp.owner, stakes_in_pvp.power),
3225            (ACCOUNT_B, 90_000)
3226        );
3227        // VP is copied by nvp (nvp is not changed as auto_stake_rewards = false)
3228        let mut vp = NetworkAccount::pvp(&mut state);
3229        assert_eq!(vp.length(), 1);
3230        let pool_in_vp: Pool = vp.pool_at(0).unwrap().try_into().unwrap();
3231        let stakes_in_vp = vp
3232            .pool(ACCOUNT_A)
3233            .unwrap()
3234            .delegated_stakes()
3235            .get(0)
3236            .unwrap();
3237        assert_eq!(
3238            (
3239                pool_in_vp.operator,
3240                pool_in_vp.commission_rate,
3241                pool_in_vp.power,
3242                pool_in_vp.operator_stake
3243            ),
3244            (
3245                ACCOUNT_A,
3246                1,
3247                100_000,
3248                Some(Stake {
3249                    owner: ACCOUNT_A,
3250                    power: 10_000
3251                })
3252            )
3253        );
3254        assert_eq!(
3255            (stakes_in_vp.owner, stakes_in_vp.power),
3256            (ACCOUNT_B, 90_000)
3257        );
3258        // deposits are rewarded, assume 64 blocks per epoch (test setup)
3259        // pool rewards = (100_000 * 8.346 / 100) / 365 = 22
3260        // reward for b = 22 * 9 / 10 = 19
3261        // reward for a = 22 * 1 / 10 = 2
3262        // commission fee from b = 19 * 1% = 0
3263        // reward for b after commission fee = 19 - 0 = 19
3264        // reward for a after commission fee = 2 + 0 = 2
3265
3266        // NVP changed (auto stakes reward = false)
3267        let nvp = NetworkAccount::nvp(&mut state);
3268        assert_eq!(nvp.length(), 1);
3269        let pool_in_nvp = nvp.get(0).unwrap();
3270        assert_eq!(
3271            (pool_in_nvp.operator, pool_in_nvp.power),
3272            (ACCOUNT_A, 100_021) // + pool increase in pool power = 19 + 2 = 21
3273        );
3274        assert_eq!(
3275            NetworkAccount::pools(&mut state, ACCOUNT_A)
3276                .operator_stake()
3277                .unwrap()
3278                .unwrap()
3279                .power,
3280            10_002
3281        );
3282        assert_eq!(
3283            NetworkAccount::pools(&mut state, ACCOUNT_A)
3284                .delegated_stakes()
3285                .get_by(&ACCOUNT_B)
3286                .unwrap()
3287                .power,
3288            90_019
3289        );
3290        assert_eq!(
3291            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_A)
3292                .balance()
3293                .unwrap(),
3294            10_002
3295        );
3296        assert_eq!(
3297            NetworkAccount::deposits(&mut state, ACCOUNT_A, ACCOUNT_B)
3298                .balance()
3299                .unwrap(),
3300            90_019
3301        );
3302    }
3303
3304    // Prepare: add max. number of pools in world state, included in nvp.
3305    //              with max. number of delegated stakes of accounts, auto_stake_reward = false
3306    //              with non-zero value of Operator Stake, auto_stake_reward = false
3307    // Prepare: empty pvp and vp.
3308    // Commands (account a): Next Epoch, Next Epoch
3309    #[test]
3310    fn test_next_epoch_multiple_pools_and_stakes() {
3311        let mut state = create_state(None);
3312        prepare_accounts_balance(&mut state.ctx.rw_set.ws);
3313        create_full_nvp_pool_stakes_deposits(&mut state, false, false, false);
3314        let ws = state.ctx.rw_set.commit_to_world_state();
3315        let mut state = create_state(Some(ws));
3316
3317        // First Epoch
3318        state.bd.validator_performance = Some(all_nodes_performance());
3319        let t = std::time::Instant::now();
3320        let mut state = execute_next_epoch(state);
3321        println!("next epoch 1 exec time: {}", t.elapsed().as_millis());
3322
3323        assert_eq!(NetworkAccount::pvp(&mut state).length(), 0);
3324        assert_eq!(
3325            NetworkAccount::vp(&mut state).length(),
3326            TEST_MAX_VALIDATOR_SET_SIZE as u32
3327        );
3328        assert_eq!(
3329            NetworkAccount::nvp(&mut state).length(),
3330            TEST_MAX_VALIDATOR_SET_SIZE as u32
3331        );
3332
3333        {
3334            // open account storage state for speed up read operations
3335            let acc_state = state
3336                .ws
3337                .account_storage_state(constants::NETWORK_ADDRESS)
3338                .unwrap();
3339            let mut state = super::protocol::NetworkAccountWorldState::new(&mut state, acc_state);
3340
3341            // Pool power of vp and nvp are equal
3342            let l = NetworkAccount::vp(&mut state).length();
3343            for i in 0..l {
3344                let vp: Pool = NetworkAccount::vp(&mut state)
3345                    .pool_at(i)
3346                    .unwrap()
3347                    .try_into()
3348                    .unwrap();
3349                let nvp = NetworkAccount::nvp(&mut state)
3350                    .get_by(&vp.operator)
3351                    .unwrap();
3352                assert_eq!(vp.power, nvp.power);
3353            }
3354
3355            // Stakes in VP and Deposits are not rewarded
3356            let mut pool_operator_stakes = HashMap::new();
3357            for i in 0..l {
3358                let mut vp_dict = NetworkAccount::vp(&mut state);
3359                let vp = vp_dict.pool_at(i).unwrap();
3360                let vp_operator = vp.operator().unwrap();
3361                let vp_power = vp.power().unwrap();
3362                let vp_operator_stake_power = vp.operator_stake().unwrap().unwrap().power;
3363                let mut sum = 0;
3364                for j in 0..TEST_MAX_STAKES_PER_POOL {
3365                    let (address, power) = init_setup_stake_of_owner(j);
3366                    let stake = NetworkAccount::vp(&mut state)
3367                        .pool(vp_operator)
3368                        .unwrap()
3369                        .delegated_stakes()
3370                        .get_by(&address)
3371                        .unwrap();
3372                    assert_eq!(stake.power, power);
3373                    sum += stake.power;
3374                    let deposit = NetworkAccount::deposits(&mut state, vp_operator, address)
3375                        .balance()
3376                        .unwrap();
3377                    assert_eq!(deposit, power);
3378                }
3379                pool_operator_stakes.insert(vp_operator, vp_operator_stake_power);
3380                sum += vp_operator_stake_power;
3381                assert_eq!(sum, vp_power);
3382            }
3383            // Operator Stakes and Deposits are not rewarded
3384            for i in 1..TEST_MAX_VALIDATOR_SET_SIZE + 1 {
3385                let (operator, power, _) = init_setup_pool_power(i);
3386                assert_eq!(pool_operator_stakes.get(&operator).unwrap(), &power);
3387                assert!(NetworkAccount::deposits(&mut state, operator, operator)
3388                    .balance()
3389                    .is_none());
3390            }
3391        }
3392
3393        // Second Epoch
3394        let mut state = create_state(Some(state.ws.to_owned()));
3395        state.bd.validator_performance = Some(all_nodes_performance());
3396        state.tx.nonce = 1;
3397        let t = std::time::Instant::now();
3398        let mut state = execute_next_epoch(state);
3399        println!("next epoch 2 exec time: {}", t.elapsed().as_millis());
3400
3401        assert_eq!(
3402            NetworkAccount::pvp(&mut state).length(),
3403            TEST_MAX_VALIDATOR_SET_SIZE as u32
3404        );
3405        assert_eq!(
3406            NetworkAccount::vp(&mut state).length(),
3407            TEST_MAX_VALIDATOR_SET_SIZE as u32
3408        );
3409        assert_eq!(
3410            NetworkAccount::nvp(&mut state).length(),
3411            TEST_MAX_VALIDATOR_SET_SIZE as u32
3412        );
3413
3414        {
3415            // open account storage state for speed up read operations
3416            let acc_state = state
3417                .ws
3418                .account_storage_state(constants::NETWORK_ADDRESS)
3419                .unwrap();
3420            let mut state = super::protocol::NetworkAccountWorldState::new(&mut state, acc_state);
3421
3422            // Pool power of pvp, vp and nvp are equal
3423            let l = NetworkAccount::vp(&mut state).length();
3424            for i in 0..l {
3425                let pvp: Pool = NetworkAccount::pvp(&mut state)
3426                    .pool_at(i)
3427                    .unwrap()
3428                    .try_into()
3429                    .unwrap();
3430                let nvp = NetworkAccount::nvp(&mut state)
3431                    .get_by(&pvp.operator)
3432                    .unwrap();
3433                assert_eq!(pvp.power, nvp.power);
3434
3435                let vp: Pool = NetworkAccount::vp(&mut state)
3436                    .pool_at(i)
3437                    .unwrap()
3438                    .try_into()
3439                    .unwrap();
3440                let nvp = NetworkAccount::nvp(&mut state)
3441                    .get_by(&vp.operator)
3442                    .unwrap();
3443                assert_eq!(vp.power, nvp.power);
3444            }
3445
3446            // Stakes are not rewarded, Desposits are rewarded
3447            let mut pool_operator_stakes = HashMap::new();
3448            for i in 0..l {
3449                let mut vp_dict = NetworkAccount::vp(&mut state);
3450                let vp = vp_dict.pool_at(i).unwrap();
3451                let vp_operator = vp.operator().unwrap();
3452                let vp_power = vp.power().unwrap();
3453                let vp_operator_stake_power = vp.operator_stake().unwrap().unwrap().power;
3454                let mut sum = 0;
3455                for j in 0..TEST_MAX_STAKES_PER_POOL {
3456                    let (address, power) = init_setup_stake_of_owner(j);
3457                    let stake = NetworkAccount::vp(&mut state)
3458                        .pool(vp_operator)
3459                        .unwrap()
3460                        .delegated_stakes()
3461                        .get_by(&address)
3462                        .unwrap();
3463                    sum += stake.power;
3464                    assert_eq!(stake.power, power);
3465                    let deposit = NetworkAccount::deposits(&mut state, vp_operator, address)
3466                        .balance()
3467                        .unwrap();
3468                    assert!(deposit > power);
3469                }
3470                pool_operator_stakes.insert(vp_operator, vp_operator_stake_power);
3471                sum += vp_operator_stake_power;
3472                assert_eq!(sum, vp_power);
3473            }
3474            // Operator Stakes are not reward, Deposits are rewarded
3475            for i in 1..TEST_MAX_VALIDATOR_SET_SIZE + 1 {
3476                let (operator, power, _) = init_setup_pool_power(i);
3477                assert_eq!(pool_operator_stakes.get(&operator).unwrap(), &power);
3478                assert!(
3479                    NetworkAccount::deposits(&mut state, operator, operator).balance() > Some(0)
3480                );
3481            }
3482        }
3483    }
3484
3485    // Prepare: add max. number of pools in world state, included in nvp.
3486    //              with max. number of delegated stakes of accounts, auto_stake_reward = true
3487    //              with non-zero value of Operator Stake, auto_stake_reward = true
3488    // Prepare: empty pvp and vp.
3489    // Commands (account a): Next Epoch, Next Epoch
3490    #[test]
3491    fn test_next_epoch_multiple_pools_and_stakes_auto_stake() {
3492        let mut state = create_state(None);
3493        prepare_accounts_balance(&mut state.ctx.rw_set.ws);
3494        create_full_nvp_pool_stakes_deposits(&mut state, true, true, true);
3495        let ws = state.ctx.rw_set.commit_to_world_state();
3496        let mut state = create_state(Some(ws));
3497
3498        // First Epoch
3499        state.bd.validator_performance = Some(all_nodes_performance());
3500        let t = std::time::Instant::now();
3501        let mut state = execute_next_epoch(state);
3502        println!("next epoch 1 exec time: {}", t.elapsed().as_millis());
3503
3504        assert_eq!(NetworkAccount::pvp(&mut state).length(), 0);
3505        assert_eq!(
3506            NetworkAccount::vp(&mut state).length(),
3507            TEST_MAX_VALIDATOR_SET_SIZE as u32
3508        );
3509        assert_eq!(
3510            NetworkAccount::nvp(&mut state).length(),
3511            TEST_MAX_VALIDATOR_SET_SIZE as u32
3512        );
3513
3514        {
3515            // open account storage state for speed up read operations
3516            let acc_state = state
3517                .ws
3518                .account_storage_state(constants::NETWORK_ADDRESS)
3519                .unwrap();
3520            let mut state = super::protocol::NetworkAccountWorldState::new(&mut state, acc_state);
3521
3522            // Pool power of vp and nvp are equal
3523            let l = NetworkAccount::vp(&mut state).length();
3524            for i in 0..l {
3525                let vp: Pool = NetworkAccount::vp(&mut state)
3526                    .pool_at(i)
3527                    .unwrap()
3528                    .try_into()
3529                    .unwrap();
3530                let nvp = NetworkAccount::nvp(&mut state)
3531                    .get_by(&vp.operator)
3532                    .unwrap();
3533                assert_eq!(vp.power, nvp.power);
3534            }
3535
3536            // Stakes in VP and Deposits are not rewarded
3537            let mut pool_operator_stakes = HashMap::new();
3538            for i in 0..l {
3539                let mut vp_dict = NetworkAccount::vp(&mut state);
3540                let vp = vp_dict.pool_at(i).unwrap();
3541                let vp_operator = vp.operator().unwrap();
3542                let vp_power = vp.power().unwrap();
3543                let vp_operator_stake_power = vp.operator_stake().unwrap().unwrap().power;
3544                let mut sum = 0;
3545                for j in 0..TEST_MAX_STAKES_PER_POOL {
3546                    let (address, power) = init_setup_stake_of_owner(j);
3547                    let stake = NetworkAccount::vp(&mut state)
3548                        .pool(vp_operator)
3549                        .unwrap()
3550                        .delegated_stakes()
3551                        .get_by(&address)
3552                        .unwrap();
3553                    assert_eq!(stake.power, power);
3554                    sum += stake.power;
3555                    let deposit = NetworkAccount::deposits(&mut state, vp_operator, address)
3556                        .balance()
3557                        .unwrap();
3558                    assert_eq!(deposit, power);
3559                }
3560                pool_operator_stakes.insert(vp_operator, vp_operator_stake_power);
3561                sum += vp_operator_stake_power;
3562                assert_eq!(sum, vp_power);
3563            }
3564            // Operator Stakes and Deposits are not rewarded
3565            for i in 1..TEST_MAX_VALIDATOR_SET_SIZE + 1 {
3566                let (operator, power, _) = init_setup_pool_power(i);
3567                assert_eq!(pool_operator_stakes.get(&operator).unwrap(), &power);
3568                assert_eq!(
3569                    NetworkAccount::deposits(&mut state, operator, operator).balance(),
3570                    Some(power)
3571                );
3572            }
3573        }
3574
3575        // Second Epoch
3576        let mut state = create_state(Some(state.ws.to_owned()));
3577        state.bd.validator_performance = Some(all_nodes_performance());
3578        state.tx.nonce = 1;
3579        let t = std::time::Instant::now();
3580        let mut state = execute_next_epoch(state);
3581        println!("next epoch 2 exec time: {}", t.elapsed().as_millis());
3582
3583        assert_eq!(
3584            NetworkAccount::pvp(&mut state).length(),
3585            TEST_MAX_VALIDATOR_SET_SIZE as u32
3586        );
3587        assert_eq!(
3588            NetworkAccount::vp(&mut state).length(),
3589            TEST_MAX_VALIDATOR_SET_SIZE as u32
3590        );
3591        assert_eq!(
3592            NetworkAccount::nvp(&mut state).length(),
3593            TEST_MAX_VALIDATOR_SET_SIZE as u32
3594        );
3595
3596        {
3597            // open account storage state for speed up read operations
3598            let acc_state = state
3599                .ws
3600                .account_storage_state(constants::NETWORK_ADDRESS)
3601                .unwrap();
3602            let mut state = super::protocol::NetworkAccountWorldState::new(&mut state, acc_state);
3603
3604            // Pool power of vp and nvp are equal and greater than pool power of pvp
3605            let l = NetworkAccount::vp(&mut state).length();
3606            for i in 0..l {
3607                let pvp: Pool = NetworkAccount::pvp(&mut state)
3608                    .pool_at(i)
3609                    .unwrap()
3610                    .try_into()
3611                    .unwrap();
3612                let nvp = NetworkAccount::nvp(&mut state)
3613                    .get_by(&pvp.operator)
3614                    .unwrap();
3615                assert!(pvp.power < nvp.power);
3616
3617                let vp: Pool = NetworkAccount::vp(&mut state)
3618                    .pool_at(i)
3619                    .unwrap()
3620                    .try_into()
3621                    .unwrap();
3622                let nvp = NetworkAccount::nvp(&mut state)
3623                    .get_by(&vp.operator)
3624                    .unwrap();
3625                assert_eq!(vp.power, nvp.power);
3626            }
3627
3628            // Stakes and Desposits are rewarded
3629            let mut pool_operator_stakes = HashMap::new();
3630            for i in 0..l {
3631                let mut vp_dict = NetworkAccount::vp(&mut state);
3632                let vp = vp_dict.pool_at(i).unwrap();
3633                let vp_operator = vp.operator().unwrap();
3634                let vp_power = vp.power().unwrap();
3635                let vp_operator_stake_power = vp.operator_stake().unwrap().unwrap().power;
3636                let mut sum = 0;
3637                for j in 0..TEST_MAX_STAKES_PER_POOL {
3638                    let (address, power) = init_setup_stake_of_owner(j);
3639                    let stake = NetworkAccount::vp(&mut state)
3640                        .pool(vp_operator)
3641                        .unwrap()
3642                        .delegated_stakes()
3643                        .get_by(&address)
3644                        .unwrap();
3645                    sum += stake.power;
3646                    assert!(stake.power > power);
3647                    let deposit = NetworkAccount::deposits(&mut state, vp_operator, address)
3648                        .balance()
3649                        .unwrap();
3650                    assert_eq!(deposit, stake.power);
3651                }
3652                pool_operator_stakes.insert(vp_operator, vp_operator_stake_power);
3653                sum += vp_operator_stake_power;
3654                assert_eq!(sum, vp_power);
3655            }
3656            // Operator Stakes and Deposits are rewarded (As Operator enable auto-stake-reward)
3657            for i in 1..TEST_MAX_VALIDATOR_SET_SIZE + 1 {
3658                let (operator, power, _) = init_setup_pool_power(i);
3659                assert!(pool_operator_stakes.get(&operator).unwrap() > &power);
3660                assert_eq!(
3661                    pool_operator_stakes.get(&operator).unwrap(),
3662                    &NetworkAccount::deposits(&mut state, operator, operator)
3663                        .balance()
3664                        .unwrap()
3665                );
3666            }
3667        }
3668    }
3669
3670    // Prepare: add max. number of pools in world state, included in nvp.
3671    // Prepare: empty pvp and vp.
3672    // Commands: Next Epoch, Delete Pool (account a), Next Epoch, Create Pool (account b), Next Epoch
3673    #[test]
3674    fn test_change_of_validators() {
3675        let mut state = create_state(None);
3676        create_full_pools_in_nvp(&mut state, false, false);
3677        let ws = state.ctx.rw_set.commit_to_world_state();
3678        let state = create_state(Some(ws));
3679        let mut state = execute_next_epoch(state);
3680
3681        state.tx.nonce = 1;
3682        let ret = execute_commands(state, vec![Command::DeletePool]);
3683        assert_eq!(
3684            (
3685                &ret.error,
3686                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
3687            ),
3688            (&None, &ExitStatus::Success)
3689        );
3690        let gas_used = ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>();
3691        println!("gas_consumed {}", gas_used);
3692        let mut state = create_state(Some(ret.new_state));
3693
3694        state.tx.nonce = 2;
3695        let state = execute_next_epoch(state);
3696
3697        let mut state = create_state(Some(state.ctx.rw_set.ws));
3698        state.tx.signer = ACCOUNT_B;
3699        state.tx.nonce = 0;
3700        let ret = execute_commands(
3701            state,
3702            vec![Command::CreatePool(CreatePoolInput { commission_rate: 1 })],
3703        );
3704        assert_eq!(
3705            (
3706                &ret.error,
3707                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
3708            ),
3709            (&None, &ExitStatus::Success)
3710        );
3711        let gas_used = ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>();
3712        println!("gas_consumed {}", gas_used);
3713        let mut state = create_state(Some(ret.new_state));
3714
3715        state.tx.nonce = 3;
3716        execute_next_epoch(state);
3717    }
3718
3719    fn create_state(init_ws: Option<WorldState<SimpleStore>>) -> ExecutionState<SimpleStore> {
3720        let ws = match init_ws {
3721            Some(ws) => ws,
3722            None => {
3723                let mut ws = WorldState::initialize(SimpleStore {
3724                    inner: HashMap::new(),
3725                });
3726                ws.with_commit().set_balance(ACCOUNT_A, 500_000_000);
3727                ws.with_commit().set_balance(ACCOUNT_B, 500_000_000);
3728                ws.with_commit().set_balance(ACCOUNT_C, 500_000_000);
3729                ws.with_commit().set_balance(ACCOUNT_D, 500_000_000);
3730                ws
3731            }
3732        };
3733        let ctx = TransitionContext::new(ws);
3734        let tx = create_tx(ACCOUNT_A);
3735        let base_tx = BaseTx::from(&tx);
3736        ExecutionState {
3737            bd: create_bd(),
3738            tx_size: tx.serialize().len(),
3739            commands_len: 0,
3740            tx: base_tx,
3741            ctx,
3742        }
3743    }
3744
3745    fn set_tx(
3746        state: &mut ExecutionState<SimpleStore>,
3747        signer: PublicAddress,
3748        nonce: u64,
3749        commands: &Vec<Command>,
3750    ) -> u64 {
3751        let mut tx = create_tx(signer);
3752        tx.nonce = nonce;
3753        state.tx_size = tx.serialize().len();
3754        state.tx = BaseTx::from(&tx);
3755        state.commands_len = commands.len();
3756        gas::tx_inclusion_cost(state.tx_size, state.commands_len)
3757    }
3758
3759    fn create_tx(signer: PublicAddress) -> Transaction {
3760        Transaction {
3761            signer,
3762            gas_limit: 10_000_000,
3763            priority_fee_per_gas: 0,
3764            max_base_fee_per_gas: MIN_BASE_FEE,
3765            nonce: 0,
3766            hash: [0u8; 32],
3767            signature: [0u8; 64],
3768            commands: Vec::new(),
3769        }
3770    }
3771
3772    fn create_bd() -> BlockchainParams {
3773        let mut validator_performance = ValidatorPerformance::default();
3774        validator_performance.blocks_per_epoch = TEST_MAX_VALIDATOR_SET_SIZE as u32;
3775        for i in 1..TEST_MAX_VALIDATOR_SET_SIZE + 1 {
3776            let mut address = [1u8; 32];
3777            address[0] = i as u8;
3778            validator_performance
3779                .stats
3780                .insert(address, BlockProposalStats::new(1));
3781        }
3782        BlockchainParams {
3783            this_block_number: 1,
3784            prev_block_hash: [3u8; 32],
3785            this_base_fee: 1,
3786            timestamp: 1665370157,
3787            random_bytes: [255u8; 32],
3788            proposer_address: [99u8; 32],
3789            treasury_address: [100u8; 32],
3790            cur_view: 1234,
3791            validator_performance: Some(validator_performance),
3792        }
3793    }
3794
3795    fn single_node_performance(address: PublicAddress, num_of_blocks: u32) -> ValidatorPerformance {
3796        let mut validator_performance = ValidatorPerformance::default();
3797        validator_performance.blocks_per_epoch = num_of_blocks;
3798        validator_performance
3799            .stats
3800            .insert(address, BlockProposalStats::new(num_of_blocks));
3801        validator_performance
3802    }
3803
3804    fn all_nodes_performance() -> ValidatorPerformance {
3805        let mut validator_performance = ValidatorPerformance::default();
3806        validator_performance.blocks_per_epoch = TEST_MAX_STAKES_PER_POOL as u32;
3807
3808        for i in 0..TEST_MAX_STAKES_PER_POOL {
3809            let mut address = [1u8; 32];
3810            address[0] = i as u8;
3811            validator_performance
3812                .stats
3813                .insert(address, BlockProposalStats::new(1));
3814        }
3815        validator_performance
3816    }
3817
3818    /// Account address range from \[X, X, X, X, ... , 2\] where X starts with u32(\[2,2,2,2\]). Number of Accounts = MAX_STAKES_PER_POOL
3819    /// all balance = 500_000_000
3820    fn prepare_accounts_balance(ws: &mut WorldState<SimpleStore>) {
3821        let start = u32::from_le_bytes([2u8, 2, 2, 2]);
3822        for i in 0..TEST_MAX_STAKES_PER_POOL {
3823            let mut address = [2u8; 32];
3824            address[0..4].copy_from_slice(&(start + i as u32).to_le_bytes().to_vec());
3825            ws.cached().set_balance(address, 500_000_000);
3826        }
3827        ws.commit();
3828    }
3829
3830    /// Pools address range from \[X, 1, 1, 1, ... , 1\] where X \in \[1, TEST_MAX_VALIDATOR_SET_SIZE\]
3831    /// Pool powers = 100_000, 200_000, ... , 6_400_000
3832    fn create_full_pools_in_nvp(
3833        ws: &mut ExecutionState<SimpleStore>,
3834        add_operators_deposit: bool,
3835        operators_auto_stake_rewards: bool,
3836    ) {
3837        NetworkAccount::nvp(ws).clear();
3838        for i in 1..TEST_MAX_VALIDATOR_SET_SIZE + 1 {
3839            let (address, power, rate) = init_setup_pool_power(i);
3840            let mut pool = NetworkAccount::pools(ws, address);
3841            pool.set_operator(address);
3842            pool.set_power(power);
3843            pool.set_commission_rate(rate);
3844            pool.set_operator_stake(Some(Stake {
3845                owner: address,
3846                power,
3847            }));
3848            NetworkAccount::nvp(ws)
3849                .insert(PoolKey {
3850                    operator: address,
3851                    power,
3852                })
3853                .unwrap();
3854            if add_operators_deposit {
3855                NetworkAccount::deposits(ws, address, address).set_balance(power);
3856                NetworkAccount::deposits(ws, address, address)
3857                    .set_auto_stake_rewards(operators_auto_stake_rewards);
3858            }
3859        }
3860        assert_eq!(
3861            NetworkAccount::nvp(ws).length(),
3862            TEST_MAX_VALIDATOR_SET_SIZE as u32
3863        );
3864    }
3865
3866    /// Stake address = [i, 1, 1, 1, 1, 1, 1, 1, ...]
3867    /// Pool powers = 100_000 * (i)
3868    /// Commission_rate = i % 100
3869    fn init_setup_pool_power(i: u16) -> (PublicAddress, u64, u8) {
3870        let mut address = [1u8; 32];
3871        address[0] = i as u8;
3872        let power = 100_000 * i as u64;
3873        (address, power, i as u8 % 100)
3874    }
3875
3876    /// Staker address range from \[X, X, X, X, ... , 2\] where X starts with u32(\[2,2,2,2\]). Number of stakers = TEST_MAX_STAKES_PER_POOL
3877    /// Stake powers = 200_000, 300_000, ...
3878    fn create_full_stakes_in_pool(ws: &mut ExecutionState<SimpleStore>, operator: PublicAddress) {
3879        NetworkAccount::pools(ws, operator)
3880            .delegated_stakes()
3881            .clear();
3882        let mut sum = 0;
3883        let mut vs = vec![];
3884        for i in 0..TEST_MAX_STAKES_PER_POOL {
3885            let (address, power) = init_setup_stake_of_owner(i);
3886            sum += power;
3887            let stake = StakeValue::new(Stake {
3888                owner: address,
3889                power,
3890            });
3891            vs.push(stake);
3892        }
3893        NetworkAccount::pools(ws, operator)
3894            .delegated_stakes()
3895            .reset(vs)
3896            .unwrap();
3897        let operator_stake = NetworkAccount::pools(ws, operator)
3898            .operator_stake()
3899            .map_or(0, |p| p.map_or(0, |v| v.power));
3900        NetworkAccount::pools(ws, operator).set_operator(operator);
3901        NetworkAccount::pools(ws, operator).set_power(sum + operator_stake);
3902        NetworkAccount::nvp(ws).change_key(PoolKey {
3903            operator,
3904            power: sum + operator_stake,
3905        });
3906        assert_eq!(
3907            NetworkAccount::pools(ws, operator)
3908                .delegated_stakes()
3909                .length(),
3910            TEST_MAX_STAKES_PER_POOL as u32
3911        );
3912    }
3913
3914    /// Stake address = [X, X, X, X, 2, 2, 2, 2, ...] where X,X,X,X is i as LE bytes
3915    /// Stake powers = 100_000 * (i+2)
3916    fn init_setup_stake_of_owner(i: u16) -> (PublicAddress, u64) {
3917        let start = u32::from_le_bytes([2u8, 2, 2, 2]);
3918        let mut address = [2u8; 32];
3919        address[0..4].copy_from_slice(&(start + i as u32).to_le_bytes().to_vec());
3920        (address, 100_000 * (i + 2) as u64)
3921    }
3922
3923    /// Staker address range from \[X, X, X, X, ... , 2\] where X starts with u32(\[2,2,2,2\]). Number of stakers = TEST_MAX_STAKES_PER_POOL
3924    /// Deposits = 200_000, 300_000, ...
3925    fn create_full_deposits_in_pool(
3926        ws: &mut ExecutionState<SimpleStore>,
3927        operator: PublicAddress,
3928        auto_stake_rewards: bool,
3929    ) {
3930        for i in 0..TEST_MAX_STAKES_PER_POOL {
3931            let (address, balance) = init_setup_stake_of_owner(i);
3932            NetworkAccount::deposits(ws, operator, address).set_balance(balance);
3933            NetworkAccount::deposits(ws, operator, address)
3934                .set_auto_stake_rewards(auto_stake_rewards);
3935        }
3936    }
3937    fn create_full_nvp_pool_stakes_deposits(
3938        ws: &mut ExecutionState<SimpleStore>,
3939        auto_stake_rewards: bool,
3940        add_operators_deposit: bool,
3941        operators_auto_stake_rewards: bool,
3942    ) {
3943        create_full_pools_in_nvp(ws, add_operators_deposit, operators_auto_stake_rewards);
3944        let mut nvps = vec![];
3945        for i in 0..TEST_MAX_VALIDATOR_SET_SIZE {
3946            let p = NetworkAccount::nvp(ws).get(i as u32).unwrap();
3947            nvps.push(p);
3948        }
3949        for p in nvps {
3950            create_full_stakes_in_pool(ws, p.operator);
3951            create_full_deposits_in_pool(ws, p.operator, auto_stake_rewards);
3952        }
3953    }
3954
3955    // pool (account a) in world state, included in nvp.
3956    //      with delegated stakes of account b, auto_stake_reward = false
3957    //      with non-zero value of Operator Stake, auto_stake_reward = false
3958    // pool[A].power = 100_000
3959    // pool[A].operator_stake = 10_000
3960    // pool[A].delegated_stakes[B] = 90_000
3961    // deposits[A, A] = 10_000
3962    // deposits[A, B] = 90_000
3963    fn prepare_single_pool(
3964        auto_stake_rewards_a: bool,
3965        auto_stake_rewards_b: bool,
3966    ) -> WorldState<SimpleStore> {
3967        let mut state = create_state(None);
3968        setup_pool(
3969            &mut state,
3970            ACCOUNT_A,
3971            10_000,
3972            ACCOUNT_B,
3973            90_000,
3974            auto_stake_rewards_a,
3975            auto_stake_rewards_b,
3976        );
3977        let ws = state.ctx.rw_set.commit_to_world_state();
3978        ws
3979    }
3980
3981    // pool[A].power = 100_000
3982    // pool[A].operator_stake = 10_000
3983    // pool[A].delegated_stakes[B] = 90_000
3984    // deposits[A, A] = 10_000
3985    // deposits[A, B] = 90_000
3986    fn setup_pool(
3987        state: &mut ExecutionState<SimpleStore>,
3988        operator: PublicAddress,
3989        operator_power: u64,
3990        owner: PublicAddress,
3991        owner_power: u64,
3992        auto_stake_rewards_a: bool,
3993        auto_stake_rewards_b: bool,
3994    ) {
3995        let mut pool = NetworkAccount::pools(state, operator);
3996        pool.set_operator(operator);
3997        pool.set_power(operator_power + owner_power);
3998        pool.set_commission_rate(1);
3999        pool.set_operator_stake(Some(Stake {
4000            owner: operator,
4001            power: operator_power,
4002        }));
4003        NetworkAccount::pools(state, operator)
4004            .delegated_stakes()
4005            .insert(StakeValue::new(Stake {
4006                owner: owner,
4007                power: owner_power,
4008            }))
4009            .unwrap();
4010        let mut deposit = NetworkAccount::deposits(state, operator, operator);
4011        deposit.set_balance(operator_power);
4012        deposit.set_auto_stake_rewards(auto_stake_rewards_a);
4013        let mut deposit = NetworkAccount::deposits(state, operator, owner);
4014        deposit.set_balance(owner_power);
4015        deposit.set_auto_stake_rewards(auto_stake_rewards_b);
4016        NetworkAccount::nvp(state)
4017            .insert(PoolKey {
4018                operator,
4019                power: operator_power + owner_power,
4020            })
4021            .unwrap();
4022    }
4023
4024    fn execute_next_epoch(state: ExecutionState<SimpleStore>) -> ExecutionState<SimpleStore> {
4025        let ret = execute_next_epoch_command(state, vec![Command::NextEpoch]);
4026        assert_eq!(
4027            (
4028                &ret.error,
4029                &ret.receipt.as_ref().unwrap().last().unwrap().exit_status
4030            ),
4031            (&None, &ExitStatus::Success)
4032        );
4033        let gas_used = ret.receipt.unwrap().iter().map(|g| g.gas_used).sum::<u64>();
4034        println!("gas_consumed {}", gas_used);
4035        println!(
4036            "new validators {}",
4037            ret.validator_changes
4038                .as_ref()
4039                .unwrap()
4040                .new_validator_set
4041                .len()
4042        );
4043        println!(
4044            "remove validators {}",
4045            ret.validator_changes
4046                .as_ref()
4047                .unwrap()
4048                .remove_validator_set
4049                .len()
4050        );
4051        create_state(Some(ret.new_state))
4052    }
4053}