disable early unlock of tokens

pull/3605/head
Rongjian Lan 4 years ago
parent 4b704a727c
commit d7b968e579
  1. 8
      hmy/staking.go
  2. 3
      internal/chain/engine.go
  3. 17
      internal/params/config.go
  4. 4
      staking/types/delegation.go
  5. 26
      staking/types/delegation_test.go

@ -139,6 +139,11 @@ func (hmy *Harmony) IsPreStakingEpoch(epoch *big.Int) bool {
return hmy.BlockChain.Config().IsPreStaking(epoch)
}
// IsNoEarlyUnlockEpoch ...
func (hmy *Harmony) IsNoEarlyUnlockEpoch(epoch *big.Int) bool {
return hmy.BlockChain.Config().IsNoEarlyUnlock(epoch)
}
// IsCommitteeSelectionBlock checks if the given block is the committee selection block
func (hmy *Harmony) IsCommitteeSelectionBlock(header *block.Header) bool {
return chain.IsCommitteeSelectionBlock(hmy.BlockChain, header)
@ -547,8 +552,9 @@ func (hmy *Harmony) GetUndelegationPayouts(
if err != nil || wrapper == nil {
continue // Not a validator at this epoch or unable to fetch validator info because of pruned state.
}
noEarlyUnlock := hmy.IsNoEarlyUnlockEpoch(epoch)
for _, delegation := range wrapper.Delegations {
withdraw := delegation.RemoveUnlockedUndelegations(epoch, wrapper.LastEpochInCommittee, lockingPeriod)
withdraw := delegation.RemoveUnlockedUndelegations(epoch, wrapper.LastEpochInCommittee, lockingPeriod, noEarlyUnlock)
if withdraw.Cmp(bigZero) == 1 {
if totalPayout, ok := undelegationPayouts[delegation.DelegatorAddress]; ok {
undelegationPayouts[delegation.DelegatorAddress] = new(big.Int).Add(totalPayout, withdraw)

@ -302,10 +302,11 @@ func payoutUndelegations(
)
}
lockPeriod := GetLockPeriodInEpoch(chain, header.Epoch())
noEarlyUnlock := chain.Config().IsNoEarlyUnlock(header.Epoch())
for i := range wrapper.Delegations {
delegation := &wrapper.Delegations[i]
totalWithdraw := delegation.RemoveUnlockedUndelegations(
header.Epoch(), wrapper.LastEpochInCommittee, lockPeriod,
header.Epoch(), wrapper.LastEpochInCommittee, lockPeriod, noEarlyUnlock,
)
state.AddBalance(delegation.DelegatorAddress, totalWithdraw)
}

@ -49,6 +49,7 @@ var (
TwoSecondsEpoch: big.NewInt(366), // Around Tuesday Dec 8th 2020, 8AM PST
SixtyPercentEpoch: EpochTBD,
RedelegationEpoch: big.NewInt(290),
NoEarlyUnlockEpoch: EpochTBD,
EIP155Epoch: big.NewInt(28),
S3Epoch: big.NewInt(28),
IstanbulEpoch: big.NewInt(314),
@ -70,6 +71,7 @@ var (
TwoSecondsEpoch: big.NewInt(73000),
SixtyPercentEpoch: big.NewInt(73282),
RedelegationEpoch: big.NewInt(36500),
NoEarlyUnlockEpoch: big.NewInt(73580),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(43800),
@ -92,6 +94,7 @@ var (
TwoSecondsEpoch: big.NewInt(0),
SixtyPercentEpoch: big.NewInt(0),
RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
@ -114,6 +117,7 @@ var (
TwoSecondsEpoch: big.NewInt(0),
SixtyPercentEpoch: big.NewInt(0),
RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
@ -136,6 +140,7 @@ var (
TwoSecondsEpoch: big.NewInt(0),
SixtyPercentEpoch: big.NewInt(10),
RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
@ -157,6 +162,7 @@ var (
TwoSecondsEpoch: big.NewInt(3),
SixtyPercentEpoch: EpochTBD, // Never enable it for localnet as localnet has no external validator setup
RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
@ -180,6 +186,7 @@ var (
big.NewInt(0), // TwoSecondsEpoch
big.NewInt(0), // SixtyPercentEpoch
big.NewInt(0), // RedelegationEpoch
big.NewInt(0), // NoEarlyUnlockEpoch
big.NewInt(0), // EIP155Epoch
big.NewInt(0), // S3Epoch
big.NewInt(0), // IstanbulEpoch
@ -203,6 +210,7 @@ var (
big.NewInt(0), // TwoSecondsEpoch
big.NewInt(0), // SixtyPercentEpoch
big.NewInt(0), // RedelegationEpoch
big.NewInt(0), // NoEarlyUnlockEpoch
big.NewInt(0), // EIP155Epoch
big.NewInt(0), // S3Epoch
big.NewInt(0), // IstanbulEpoch
@ -276,6 +284,10 @@ type ChainConfig struct {
// is restored to 7 epoch
RedelegationEpoch *big.Int `json:"redelegation-epoch,omitempty"`
// NoEarlyUnlockEpoch is the epoch when the early unlock of undelegated token from validators who were elected for
// more than 7 epochs is disabled
NoEarlyUnlockEpoch *big.Int `json:"no-early-unlock-epoch,omitempty"`
// EIP155 hard fork epoch (include EIP158 too)
EIP155Epoch *big.Int `json:"eip155-epoch,omitempty"`
@ -357,6 +369,11 @@ func (c *ChainConfig) IsRedelegation(epoch *big.Int) bool {
return isForked(c.RedelegationEpoch, epoch)
}
// IsNoEarlyUnlock determines whether it is the epoch to stop early unlock
func (c *ChainConfig) IsNoEarlyUnlock(epoch *big.Int) bool {
return isForked(c.NoEarlyUnlockEpoch, epoch)
}
// IsPreStaking determines whether staking transactions are allowed
func (c *ChainConfig) IsPreStaking(epoch *big.Int) bool {
return isForked(c.PreStakingEpoch, epoch)

@ -178,13 +178,13 @@ func (d *Delegation) DeleteEntry(epoch *big.Int) {
// RemoveUnlockedUndelegations removes all fully unlocked
// undelegations and returns the total sum
func (d *Delegation) RemoveUnlockedUndelegations(
curEpoch, lastEpochInCommittee *big.Int, lockPeriod int,
curEpoch, lastEpochInCommittee *big.Int, lockPeriod int, noEarlyUnlock bool,
) *big.Int {
totalWithdraw := big.NewInt(0)
count := 0
for j := range d.Undelegations {
if big.NewInt(0).Sub(curEpoch, d.Undelegations[j].Epoch).Int64() >= int64(lockPeriod) ||
big.NewInt(0).Sub(curEpoch, lastEpochInCommittee).Int64() >= int64(lockPeriod) {
(!noEarlyUnlock && big.NewInt(0).Sub(curEpoch, lastEpochInCommittee).Int64() >= int64(lockPeriod)) {
// need to wait at least 7 epochs to withdraw; or the validator has been out of committee for 7 epochs
totalWithdraw.Add(totalWithdraw, d.Undelegations[j].Amount)
count++

@ -75,7 +75,7 @@ func TestUnlockedLastEpochInCommittee(t *testing.T) {
amount4 := big.NewInt(4000)
delegation.Undelegate(epoch4, amount4)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 7)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 7, false)
if result.Cmp(big.NewInt(8000)) != 0 {
t.Errorf("removing an unlocked undelegation fails")
}
@ -90,7 +90,7 @@ func TestUnlockedLastEpochInCommitteeFail(t *testing.T) {
amount4 := big.NewInt(4000)
delegation.Undelegate(epoch4, amount4)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 7)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 7, false)
if result.Cmp(big.NewInt(0)) != 0 {
t.Errorf("premature delegation shouldn't be unlocked")
}
@ -104,7 +104,7 @@ func TestUnlockedFullPeriod(t *testing.T) {
amount5 := big.NewInt(4000)
delegation.Undelegate(epoch5, amount5)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 7)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 7, false)
if result.Cmp(big.NewInt(4000)) != 0 {
t.Errorf("removing an unlocked undelegation fails")
}
@ -118,7 +118,7 @@ func TestQuickUnlock(t *testing.T) {
amount7 := big.NewInt(4000)
delegation.Undelegate(epoch7, amount7)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 0)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 0, false)
if result.Cmp(big.NewInt(4000)) != 0 {
t.Errorf("removing an unlocked undelegation fails")
}
@ -133,7 +133,7 @@ func TestUnlockedFullPeriodFail(t *testing.T) {
amount5 := big.NewInt(4000)
delegation.Undelegate(epoch5, amount5)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 7)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 7, false)
if result.Cmp(big.NewInt(0)) != 0 {
t.Errorf("premature delegation shouldn't be unlocked")
}
@ -147,8 +147,22 @@ func TestUnlockedPremature(t *testing.T) {
amount6 := big.NewInt(4000)
delegation.Undelegate(epoch6, amount6)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 7)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 7, false)
if result.Cmp(big.NewInt(0)) != 0 {
t.Errorf("premature delegation shouldn't be unlocked")
}
}
func TestNoEarlyUnlock(t *testing.T) {
lastEpochInCommittee := big.NewInt(17)
curEpoch := big.NewInt(24)
epoch4 := big.NewInt(21)
amount4 := big.NewInt(4000)
delegation.Undelegate(epoch4, amount4)
result := delegation.RemoveUnlockedUndelegations(curEpoch, lastEpochInCommittee, 7, false)
if result.Cmp(big.NewInt(0)) != 0 {
t.Errorf("should not allow early unlock")
}
}

Loading…
Cancel
Save