Skip to content

Commit 8630d5b

Browse files
runcometgithub-actions[bot]Ank4n
authored
staking-async: include the unlock era in the Unbonded event (#12630)
resolves #12578 --------- Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com>
1 parent e02e990 commit 8630d5b

5 files changed

Lines changed: 99 additions & 36 deletions

File tree

prdoc/pr_12630.prdoc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
title: '`staking-async`: include the unlock era in the Unbonded event'
2+
doc:
3+
- audience: Runtime User
4+
description: |
5+
`Event::Unbonded` gains `era`, the era at which `amount` becomes withdrawable.
6+
Front-ends, wallets and indexers read it from the event instead of `Staking::Ledger(stash)`.
7+
The unbonding duration is dynamic: 2 eras for pure nominators, `BondingDuration` otherwise.
8+
- audience: Runtime Dev
9+
description: |
10+
`Event::Unbonded` gains an `era: EraIndex` field. Metadata-driven tooling picks it up;
11+
hardcoded decoders and `Unbonded` test assertions need the field. No new logic, no
12+
storage migration.
13+
crates:
14+
- name: pallet-staking-async
15+
bump: major

substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ fn pool_lifecycle_e2e() {
113113
assert_eq!(
114114
staking_events_since_last_call(),
115115
vec![
116-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
117-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
116+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 3 },
117+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 3 },
118118
]
119119
);
120120
assert_eq!(
@@ -175,7 +175,7 @@ fn pool_lifecycle_e2e() {
175175
staking_events_since_last_call(),
176176
vec![
177177
StakingEvent::Chilled { stash: POOL1_BONDED },
178-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 },
178+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50, era: 6 },
179179
]
180180
);
181181
assert_eq!(
@@ -323,9 +323,9 @@ fn pool_chill_e2e() {
323323
assert_eq!(
324324
staking_events_since_last_call(),
325325
vec![
326-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
326+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 3 },
327327
StakingEvent::Chilled { stash: POOL1_BONDED },
328-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
328+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 3 },
329329
StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // other member bonding
330330
StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // depositor bond extra
331331
StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },
@@ -391,8 +391,8 @@ fn pool_slash_e2e() {
391391
assert_eq!(
392392
staking_events_since_last_call(),
393393
vec![
394-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
395-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }
394+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 4 },
395+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 4 }
396396
]
397397
);
398398
assert_eq!(
@@ -414,9 +414,9 @@ fn pool_slash_e2e() {
414414
assert_eq!(
415415
staking_events_since_last_call(),
416416
vec![
417-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
418-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
419-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
417+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 5 },
418+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 5 },
419+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 5 },
420420
]
421421
);
422422

@@ -468,7 +468,7 @@ fn pool_slash_e2e() {
468468
);
469469
assert_eq!(
470470
staking_events_since_last_call(),
471-
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }]
471+
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5, era: 6 }]
472472
);
473473
assert_eq!(
474474
pool_events_since_last_call(),
@@ -503,7 +503,7 @@ fn pool_slash_e2e() {
503503

504504
assert_eq!(
505505
staking_events_since_last_call(),
506-
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }]
506+
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 9 }]
507507
);
508508
assert_eq!(
509509
pool_events_since_last_call(),
@@ -629,7 +629,7 @@ fn pool_slash_proportional() {
629629

630630
assert_eq!(
631631
staking_events_since_last_call(),
632-
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },]
632+
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond, era: 127 },]
633633
);
634634
assert_eq!(
635635
pool_events_since_last_call(),
@@ -646,7 +646,7 @@ fn pool_slash_proportional() {
646646
assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, bond));
647647
assert_eq!(
648648
staking_events_since_last_call(),
649-
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },]
649+
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond, era: 128 },]
650650
);
651651
assert_eq!(
652652
pool_events_since_last_call(),
@@ -663,7 +663,7 @@ fn pool_slash_proportional() {
663663
assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, bond));
664664
assert_eq!(
665665
staking_events_since_last_call(),
666-
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },]
666+
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond, era: 129 },]
667667
);
668668
assert_eq!(
669669
pool_events_since_last_call(),
@@ -831,7 +831,7 @@ fn pool_slash_non_proportional_only_bonded_pool() {
831831
assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond));
832832
assert_eq!(
833833
staking_events_since_last_call(),
834-
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }]
834+
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond, era: 127 }]
835835
);
836836
assert_eq!(
837837
pool_events_since_last_call(),
@@ -910,7 +910,7 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() {
910910
assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond));
911911
assert_eq!(
912912
staking_events_since_last_call(),
913-
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }]
913+
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond, era: 127 }]
914914
);
915915
assert_eq!(
916916
pool_events_since_last_call(),
@@ -1022,8 +1022,8 @@ fn pool_migration_e2e() {
10221022
assert_eq!(
10231023
staking_events_since_last_call(),
10241024
vec![
1025-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 },
1026-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
1025+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5, era: 5 },
1026+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 6 },
10271027
]
10281028
);
10291029
assert_eq!(
@@ -1199,7 +1199,7 @@ fn pool_migration_e2e() {
11991199
staking_events_since_last_call(),
12001200
vec![
12011201
StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 },
1202-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 },
1202+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5, era: 9 },
12031203
StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 5 }
12041204
]
12051205
);
@@ -1501,7 +1501,7 @@ fn pool_no_dangling_delegation() {
15011501

15021502
assert_eq!(
15031503
staking_events_since_last_call(),
1504-
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 20 },]
1504+
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 20, era: 4 },]
15051505
);
15061506
assert_eq!(
15071507
pool_events_since_last_call(),
@@ -1517,8 +1517,8 @@ fn pool_no_dangling_delegation() {
15171517
assert_eq!(
15181518
staking_events_since_last_call(),
15191519
vec![
1520-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
1521-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
1520+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 5 },
1521+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 5 },
15221522
]
15231523
);
15241524

@@ -1614,7 +1614,7 @@ fn pool_no_dangling_delegation() {
16141614

16151615
assert_eq!(
16161616
staking_events_since_last_call(),
1617-
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }]
1617+
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5, era: 18 }]
16181618
);
16191619
assert_eq!(
16201620
pool_events_since_last_call(),
@@ -1691,7 +1691,7 @@ fn pool_no_dangling_delegation() {
16911691

16921692
assert_eq!(
16931693
staking_events_since_last_call(),
1694-
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 15 }]
1694+
vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 15, era: 21 }]
16951695
);
16961696
assert_eq!(
16971697
pool_events_since_last_call(),
@@ -1799,7 +1799,7 @@ fn pool_members_unbond_in_one_era_when_nominators_not_slashable() {
17991799
assert_eq!(
18001800
staking_events_since_last_call(),
18011801
vec![
1802-
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 },
1802+
StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10, era: 3 },
18031803
StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 },
18041804
]
18051805
);

substrate/frame/staking-async/src/pallet/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1340,6 +1340,8 @@ pub mod pallet {
13401340
Unbonded {
13411341
stash: T::AccountId,
13421342
amount: BalanceOf<T>,
1343+
/// The era at which `amount` becomes withdrawable.
1344+
era: EraIndex,
13431345
},
13441346
/// An account has called `withdraw_unbonded` and removed unbonding chunks worth `Balance`
13451347
/// from the unlocking queue.
@@ -2027,7 +2029,7 @@ pub mod pallet {
20272029
let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash));
20282030
}
20292031

2030-
Self::deposit_event(Event::<T>::Unbonded { stash, amount: value });
2032+
Self::deposit_event(Event::<T>::Unbonded { stash, amount: value, era });
20312033
}
20322034

20332035
let actual_weight = if let Some(withdraw_weight) = maybe_withdraw_weight {

substrate/frame/staking-async/src/tests/bonding.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ fn unbonding_works() {
359359
Staking::unbond(RuntimeOrigin::signed(11), 500).unwrap();
360360
assert_eq!(
361361
staking_events_since_last_call(),
362-
vec![Event::Unbonded { stash: 11, amount: 500 }]
362+
vec![Event::Unbonded { stash: 11, amount: 500, era: active_era() + 3 }]
363363
);
364364

365365
// then
@@ -455,7 +455,7 @@ fn unbonding_multi_chunk() {
455455
Staking::unbond(RuntimeOrigin::signed(11), 500).unwrap();
456456
assert_eq!(
457457
staking_events_since_last_call(),
458-
vec![Event::Unbonded { stash: 11, amount: 500 }]
458+
vec![Event::Unbonded { stash: 11, amount: 500, era: active_era() + 3 }]
459459
);
460460

461461
// then
@@ -475,7 +475,7 @@ fn unbonding_multi_chunk() {
475475
Staking::unbond(RuntimeOrigin::signed(11), 250).unwrap();
476476
assert_eq!(
477477
staking_events_since_last_call(),
478-
vec![Event::Unbonded { stash: 11, amount: 250 }]
478+
vec![Event::Unbonded { stash: 11, amount: 250, era: active_era() + 3 }]
479479
);
480480

481481
// then
@@ -529,6 +529,34 @@ fn unbonding_multi_chunk() {
529529
});
530530
}
531531

532+
#[test]
533+
fn unbond_same_era_merges_chunk_but_emits_per_unbond_era() {
534+
// Same-era unbonds merge into one chunk; each still emits its own event with that era.
535+
ExtBuilder::default().build_and_execute(|| {
536+
Staking::unbond(RuntimeOrigin::signed(11), 300).unwrap();
537+
Staking::unbond(RuntimeOrigin::signed(11), 200).unwrap();
538+
539+
assert_eq!(
540+
staking_events_since_last_call(),
541+
vec![
542+
Event::Unbonded { stash: 11, amount: 300, era: active_era() + 3 },
543+
Event::Unbonded { stash: 11, amount: 200, era: active_era() + 3 },
544+
]
545+
);
546+
547+
// One merged chunk, same era as the events.
548+
assert_eq!(
549+
Staking::ledger(11.into()).unwrap(),
550+
StakingLedgerInspect {
551+
stash: 11,
552+
total: 1000,
553+
active: 500,
554+
unlocking: bounded_vec![UnlockChunk { value: 500, era: active_era() + 3 }],
555+
},
556+
);
557+
});
558+
}
559+
532560
#[test]
533561
fn full_unbonding_works() {
534562
ExtBuilder::default().build_and_execute(|| {
@@ -537,7 +565,10 @@ fn full_unbonding_works() {
537565
assert_ok!(Staking::unbond(RuntimeOrigin::signed(11), 1000));
538566
assert_eq!(
539567
staking_events_since_last_call(),
540-
vec![Event::Chilled { stash: 11 }, Event::Unbonded { stash: 11, amount: 1000 }]
568+
vec![
569+
Event::Chilled { stash: 11 },
570+
Event::Unbonded { stash: 11, amount: 1000, era: active_era() + 3 }
571+
]
541572
);
542573

543574
// wait 3 eras
@@ -594,7 +625,10 @@ fn unbond_with_chill_works() {
594625

595626
assert_eq!(
596627
staking_events_since_last_call(),
597-
vec![Event::Chilled { stash: 11 }, Event::Unbonded { stash: 11, amount: 1000 }]
628+
vec![
629+
Event::Chilled { stash: 11 },
630+
Event::Unbonded { stash: 11, amount: 1000, era: active_era() + 3 }
631+
]
598632
);
599633

600634
// Validator is removed from the set
@@ -1339,7 +1373,7 @@ mod rebond {
13391373
);
13401374
assert_eq!(
13411375
staking_events_since_last_call(),
1342-
vec![Event::Unbonded { stash: 11, amount: 900 }]
1376+
vec![Event::Unbonded { stash: 11, amount: 900, era: active_era() + 3 }]
13431377
);
13441378

13451379
// Re-bond less than the total

substrate/frame/staking-async/src/tests/nominators_no_slashing.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,11 @@ fn nominators_can_unbond_in_next_era() {
110110
assert_ok!(Staking::unbond(RuntimeOrigin::signed(101), 200));
111111
assert_eq!(
112112
staking_events_since_last_call(),
113-
vec![Event::Unbonded { stash: 101, amount: 200 }]
113+
vec![Event::Unbonded {
114+
stash: 101,
115+
amount: 200,
116+
era: active_era() + NominatorFastUnbondDuration::get()
117+
}]
114118
);
115119

116120
// Unlocking should be set to active_era + NominatorFastUnbondDuration (not active_era +
@@ -180,7 +184,11 @@ fn validators_still_have_full_bonding_duration() {
180184
assert_ok!(Staking::unbond(RuntimeOrigin::signed(11), 200));
181185
assert_eq!(
182186
staking_events_since_last_call(),
183-
vec![Event::Unbonded { stash: 11, amount: 200 }]
187+
vec![Event::Unbonded {
188+
stash: 11,
189+
amount: 200,
190+
era: active_era() + BondingDuration::get()
191+
}]
184192
);
185193

186194
// Unlocking should be set to active_era + BondingDuration (not active_era +
@@ -648,7 +656,11 @@ fn validator_cannot_switch_to_nominator_to_avoid_slashing() {
648656
assert_ok!(Staking::unbond(RuntimeOrigin::signed(alice), 998));
649657
assert_eq!(
650658
staking_events_since_last_call(),
651-
[Event::Unbonded { stash: alice, amount: 998 }]
659+
[Event::Unbonded {
660+
stash: alice,
661+
amount: 998,
662+
era: active_era() + BondingDuration::get()
663+
}]
652664
);
653665

654666
// Alice should still be a nominator

0 commit comments

Comments
 (0)