Skip to content

Commit

Permalink
Merge pull request #3143 from planetarium/feat/migrate-undelegated
Browse files Browse the repository at this point in the history
Soft migration via Stake action for skipped agents
  • Loading branch information
OnedgeLee authored Jan 22, 2025
2 parents f74ffa7 + ad056b2 commit c9f098f
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 8 deletions.
11 changes: 6 additions & 5 deletions .Lib9c.Tests/Action/Guild/ClaimUnbonded_ValidatorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public void Execute_SlashedValidator()
[InlineData(793705868)]
[InlineData(559431555)]
[InlineData(1133637517)]
[InlineData(52169708)]
public void Execute_Fact_WithStaticSeed(int randomSeed)
{
var fixture = new RandomFixture(randomSeed);
Expand Down Expand Up @@ -162,12 +163,12 @@ private void ExecuteWithFixture(IClaimUnbondedFixture fixture)

// Check ncg after unstaking
var amountGG = validatorSlashedGG - expectedStakedGG;
const long minimumStakeAmount = 50;
if (amountGG.MajorUnit >= minimumStakeAmount)
var minimumStakeAmount = NCG * 50;
var ncg = GGToNCG(amountGG);
var majorUnit = ncg.MinorUnit > 0 ? ncg.MajorUnit + 1 : ncg.MajorUnit;
var amount = new FungibleAssetValue(NCG, majorUnit, 0);
if (amount >= minimumStakeAmount && amount <= validatorSlashedNCG)
{
var ncg = GGToNCG(amountGG);
var majorUnit = ncg.MinorUnit > 0 ? ncg.MajorUnit + 1 : ncg.MajorUnit;
var amount = new FungibleAssetValue(NCG, majorUnit, 0);
var expectedNCG1 = NCG * 0;
var expectedNCG2 = validatorSlashedNCG - amount;
var actualNCG1 = world.GetBalance(validatorKey.Address, NCG);
Expand Down
94 changes: 94 additions & 0 deletions .Lib9c.Tests/Action/StakeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,100 @@ public void Execute_Success_When_Validator_Slashed()
Assert.Equal(_ncg * 90, actualNCG);
}

[Fact]
public void Execute_Success_Exceptional_Unmigrated()
{
var world = _initialState;
var height = 0L;
var promoteAmount = 50;
var validatorKey = new PrivateKey();
var validatorAddress = validatorKey.PublicKey.Address;
var guildMasterKey = new PrivateKey();
var guildMasterAddress = new GuildAddress(guildMasterKey.Address);
world = DelegationUtil.EnsureValidatorPromotionReady(
world, validatorKey.PublicKey, promoteAmount, height++);
world = DelegationUtil.MakeGuild(
world, guildMasterAddress, validatorAddress, height++, out var guildAddress);
world = DelegationUtil.JoinGuild(world, _agentAddr, guildAddress, height++);
world = DelegationUtil.MintNCG(world, _agentAddr, 100, height++);
var stakeStateAddr = LegacyStakeState.DeriveAddress(_agentAddr);
var stakeState = new LegacyStakeState(
address: stakeStateAddr,
startedBlockIndex: height++);
world = world.TransferAsset(
new ActionContext { },
_agentAddr,
stakeStateAddr,
world.GetGoldCurrency() * 100);
world = world.SetLegacyState(stakeStateAddr, stakeState.Serialize());

Assert.True(world.TryGetStakeState(_agentAddr, out var stakeStateV2));
Assert.Equal(2, stakeStateV2.StateVersion);
Assert.Equal(Currencies.GuildGold * 0, world.GetBalance(stakeStateAddr, Currencies.GuildGold));
var repo = new GuildRepository(world, new ActionContext { });
var share = repo.GetBond(repo.GetDelegatee(validatorAddress), _agentAddr).Share;
Assert.Equal((Currencies.GuildGold * 0).RawValue, share);

if (!StakeStateUtils.TryMigrateV2ToV3(
new ActionContext { },
world,
stakeStateAddr,
stakeStateV2,
out var result))
{
throw new InvalidOperationException("Failed to migration. Unexpected situation.");
}

world = result.Value.world;
Assert.True(world.TryGetStakeState(_agentAddr, out var stakeStateV3));
Assert.Equal(3, stakeStateV3.StateVersion);
Assert.Equal(Currencies.GuildGold * 100, world.GetBalance(stakeStateAddr, Currencies.GuildGold));
repo.UpdateWorld(world);
share = repo.GetBond(repo.GetDelegatee(validatorAddress), _agentAddr).Share;
Assert.Equal((Currencies.GuildGold * 0).RawValue, share);

world = DelegationUtil.Stake(world, _agentAddr, _avatarAddr, 100, height++);
Assert.Equal(Currencies.GuildGold * 0, world.GetBalance(stakeStateAddr, Currencies.GuildGold));
repo.UpdateWorld(world);
share = repo.GetBond(repo.GetDelegatee(validatorAddress), _agentAddr).Share;
Assert.Equal((Currencies.GuildGold * 100).RawValue, share);
}

[Fact]
public void Execute_Success_Unmigrated()
{
var world = _initialState;
var height = 0L;
var promoteAmount = 50;
var validatorKey = new PrivateKey();
var validatorAddress = validatorKey.PublicKey.Address;
var guildMasterKey = new PrivateKey();
var guildMasterAddress = new GuildAddress(guildMasterKey.Address);
world = DelegationUtil.EnsureValidatorPromotionReady(
world, validatorKey.PublicKey, promoteAmount, height++);
world = DelegationUtil.MakeGuild(
world, guildMasterAddress, validatorAddress, height++, out var guildAddress);
world = DelegationUtil.JoinGuild(world, _agentAddr, guildAddress, height++);
world = DelegationUtil.MintNCG(world, _agentAddr, 100, height++);
var stakeStateAddr = LegacyStakeState.DeriveAddress(_agentAddr);
var stakeState = new LegacyStakeState(
address: stakeStateAddr,
startedBlockIndex: height++);
world = world.TransferAsset(
new ActionContext { },
_agentAddr,
stakeStateAddr,
world.GetGoldCurrency() * 100);
world = world.SetLegacyState(stakeStateAddr, stakeState.Serialize());
var repo = new GuildRepository(world, new ActionContext { });
var share = repo.GetBond(repo.GetDelegatee(validatorAddress), _agentAddr).Share;
Assert.Equal((Currencies.GuildGold * 0).RawValue, share);
world = DelegationUtil.Stake(world, _agentAddr, _avatarAddr, 100, height++);
repo.UpdateWorld(world);
share = repo.GetBond(repo.GetDelegatee(validatorAddress), _agentAddr).Share;
Assert.Equal((Currencies.GuildGold * 100).RawValue, share);
}

private IWorld Execute(
long blockIndex,
IWorld previousState,
Expand Down
3 changes: 0 additions & 3 deletions .Lib9c.Tests/Delegation/DelegateeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@ namespace Lib9c.Tests.Delegation
{
using System;
using System.Numerics;
using Bencodex;
using Libplanet.Crypto;
using Libplanet.Types.Assets;
using Nekoyume;
using Nekoyume.Delegation;
using Xunit;

public class DelegateeTest
{
private readonly DelegationFixture _fixture;
private readonly Codec _codec = new Codec();

public DelegateeTest()
{
Expand Down
13 changes: 13 additions & 0 deletions Lib9c/Action/Stake.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,19 @@ public override IWorld Execute(IActionContext context)
states = result.Value.world;
}

// NOTE: Exceptional case for late-migration due to the re-pledge.
var ggBalance = states.GetBalance(stakeStateAddress, Currencies.GuildGold);
if (ggBalance.Sign > 0)
{
var guildRepository = new GuildRepository(states, context);
if (guildRepository.TryGetGuildParticipant(new AgentAddress(context.Signer), out var guildParticipant))
{
var guild = guildRepository.GetGuild(guildParticipant.GuildAddress);
guildParticipant.Delegate(guild, ggBalance, context.BlockIndex);
states = guildRepository.World;
}
}

// NOTE: Contract a new staking.
states = ContractNewStake(
context,
Expand Down

0 comments on commit c9f098f

Please sign in to comment.