1use 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
58pub(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 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 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 let ret = account::try_execute(state, &command)
98 .or_else(|state| staking::try_execute(actor, state, &command))
99 .unwrap();
100
101 state = match ret {
103 Ok(mut state_of_success_execution) => {
105 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 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 Err(StateChangesResult {
123 state: mut state_of_abort_result,
124 error,
125 }) => {
126 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(state, None).finalize(command_task_results.command_receipts())
139}
140
141pub(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 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
167pub(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 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 let (mut state, new_vs) = protocol::next_epoch(state);
195
196 let nonce = state.ws.nonce(signer).saturating_add(1);
199 state.ws.with_commit().set_nonce(signer, nonce);
200
201 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#[derive(Debug)]
213pub(crate) struct CommandTasks(Vec<CommandTask>);
214
215impl CommandTasks {
216 fn new() -> Self {
217 Self(Vec::new())
218 }
219
220 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 fn next_task(&mut self) -> Option<CommandTask> {
237 self.0.pop()
238 }
239}
240
241#[derive(Debug)]
245pub(crate) struct CommandTask {
246 task_id: TaskID,
247 command: CommandTaskItem,
248}
249
250#[derive(Debug)]
252pub(crate) enum CommandTaskItem {
253 TransactionCommmand(Command),
255 DeferredCommand(DeferredCommand),
257}
258
259pub(crate) struct CommandTaskResults(Vec<CommandTaskResult>);
261
262impl CommandTaskResults {
263 fn new() -> Self {
264 Self(Vec::new())
265 }
266
267 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
287pub(crate) struct CommandTaskResult {
293 task_id: TaskID,
294 command_receipt: CommandReceipt,
295}
296
297impl CommandTaskResult {
298 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
309pub(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 #[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 #[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 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 #[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 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 #[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 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 #[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 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 #[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 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 }), ];
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 #[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 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 #[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 }), ];
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 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 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 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 #[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 #[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 #[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 let mut state = create_state(Some(state.ws.to_owned()));
1179 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 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 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 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 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 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 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 #[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 #[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 }), ];
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 #[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 #[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 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 #[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 #[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 #[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 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 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 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 }), ];
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 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 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 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 }), ];
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 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 assert_eq!(NetworkAccount::pvp(&mut state).length(), 0);
2983 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 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 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 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 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 assert_eq!(NetworkAccount::new(&mut state).current_epoch(), 1);
3064 }
3065
3066 #[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 let mut state = execute_next_epoch(state);
3078 state.bd.validator_performance = Some(single_node_performance(ACCOUNT_A, 1));
3079 state.tx.nonce = 1;
3081 let mut state = execute_next_epoch(state);
3082
3083 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 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 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 assert_eq!(NetworkAccount::new(&mut state).current_epoch(), 2);
3177 }
3178
3179 #[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 let mut state = execute_next_epoch(state);
3191 state.bd.validator_performance = Some(single_node_performance(ACCOUNT_A, 1));
3192 state.tx.nonce = 1;
3194 let mut state = execute_next_epoch(state);
3195
3196 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 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 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) );
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 #[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 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 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 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 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 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 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 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 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 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 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 #[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 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 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 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 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 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 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 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 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 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 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 #[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 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 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 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 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 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 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 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 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}