From 6ed6fcf6c7dd5aefa44e7d95733e6aadc48dbf41 Mon Sep 17 00:00:00 2001 From: s2quake Date: Wed, 18 Dec 2024 15:25:45 +0900 Subject: [PATCH 1/3] refactor: Expose guild actions --- Lib9c/Action/Guild/BanGuildMember.cs | 3 +-- Lib9c/Action/Guild/JoinGuild.cs | 3 +-- Lib9c/Action/Guild/MakeGuild.cs | 18 +++--------------- Lib9c/Action/Guild/MoveGuild.cs | 3 +-- Lib9c/Action/Guild/QuitGuild.cs | 4 +--- Lib9c/Action/Guild/RemoveGuild.cs | 4 +--- Lib9c/Action/Guild/UnbanGuildMember.cs | 3 +-- Lib9c/Model/Guild/GuildRejoinCooldown.cs | 4 ++-- 8 files changed, 11 insertions(+), 31 deletions(-) diff --git a/Lib9c/Action/Guild/BanGuildMember.cs b/Lib9c/Action/Guild/BanGuildMember.cs index 897a251109..3403cc2d8d 100644 --- a/Lib9c/Action/Guild/BanGuildMember.cs +++ b/Lib9c/Action/Guild/BanGuildMember.cs @@ -9,8 +9,7 @@ namespace Nekoyume.Action.Guild { - // TODO(GUILD-FEATURE): Enable again when Guild features are enabled. - // [ActionType(TypeIdentifier)] + [ActionType(TypeIdentifier)] public class BanGuildMember : ActionBase { public const string TypeIdentifier = "ban_guild_member"; diff --git a/Lib9c/Action/Guild/JoinGuild.cs b/Lib9c/Action/Guild/JoinGuild.cs index 38d4a256ac..bb22bf533e 100644 --- a/Lib9c/Action/Guild/JoinGuild.cs +++ b/Lib9c/Action/Guild/JoinGuild.cs @@ -9,8 +9,7 @@ namespace Nekoyume.Action.Guild { - // TODO(GUILD-FEATURE): Enable again when Guild features are enabled. - // [ActionType(TypeIdentifier)] + [ActionType(TypeIdentifier)] public class JoinGuild : ActionBase { public const string TypeIdentifier = "join_guild"; diff --git a/Lib9c/Action/Guild/MakeGuild.cs b/Lib9c/Action/Guild/MakeGuild.cs index a5fac12d97..f956efd17c 100644 --- a/Lib9c/Action/Guild/MakeGuild.cs +++ b/Lib9c/Action/Guild/MakeGuild.cs @@ -6,7 +6,9 @@ using Nekoyume.Extensions; using Nekoyume.Model.Guild; using Nekoyume.Module.Guild; +using Nekoyume.Module.ValidatorDelegation; using Nekoyume.TypedAddress; +using Nekoyume.ValidatorDelegation; namespace Nekoyume.Action.Guild { @@ -44,32 +46,18 @@ rawValues is not Dictionary values || ValidatorAddress = new Address(rawValidatorAddress); } - // TODO: Replace this with ExecutePublic when to deliver features to users. public override IWorld Execute(IActionContext context) - { - var world = ExecutePublic(context); - - if (context.Signer != GuildConfig.PlanetariumGuildOwner) - { - throw new InvalidOperationException( - $"This action is not allowed for {context.Signer}."); - } - - return world; - } - - public IWorld ExecutePublic(IActionContext context) { GasTracer.UseGas(1); var world = context.PreviousState; var random = context.GetRandom(); - var repository = new GuildRepository(world, context); var guildAddress = new GuildAddress(random.GenerateAddress()); var validatorAddress = ValidatorAddress; repository.MakeGuild(guildAddress, validatorAddress); + return repository.World; } } diff --git a/Lib9c/Action/Guild/MoveGuild.cs b/Lib9c/Action/Guild/MoveGuild.cs index 84ede7baae..b3eac87b25 100644 --- a/Lib9c/Action/Guild/MoveGuild.cs +++ b/Lib9c/Action/Guild/MoveGuild.cs @@ -9,8 +9,7 @@ namespace Nekoyume.Action.Guild { - // TODO(GUILD-FEATURE): Enable again when Guild features are enabled. - // [ActionType(TypeIdentifier)] + [ActionType(TypeIdentifier)] public class MoveGuild : ActionBase { public const string TypeIdentifier = "move_guild"; diff --git a/Lib9c/Action/Guild/QuitGuild.cs b/Lib9c/Action/Guild/QuitGuild.cs index d330ed86f8..261d4931f3 100644 --- a/Lib9c/Action/Guild/QuitGuild.cs +++ b/Lib9c/Action/Guild/QuitGuild.cs @@ -8,8 +8,7 @@ namespace Nekoyume.Action.Guild { - // TODO(GUILD-FEATURE): Enable again when Guild features are enabled. - // [ActionType(TypeIdentifier)] + [ActionType(TypeIdentifier)] public class QuitGuild : ActionBase { public const string TypeIdentifier = "quit_guild"; @@ -36,7 +35,6 @@ public override IWorld Execute(IActionContext context) var repository = new GuildRepository(world, context); var signer = context.GetAgentAddress(); - // TODO: Do something to return 'Power' token; repository.LeaveGuild(signer); return repository.World; diff --git a/Lib9c/Action/Guild/RemoveGuild.cs b/Lib9c/Action/Guild/RemoveGuild.cs index 39bd0652e7..21ff4c5f63 100644 --- a/Lib9c/Action/Guild/RemoveGuild.cs +++ b/Lib9c/Action/Guild/RemoveGuild.cs @@ -11,8 +11,7 @@ namespace Nekoyume.Action.Guild /// /// An action to remove the guild. /// - // TODO(GUILD-FEATURE): Enable again when Guild features are enabled. - // [ActionType(TypeIdentifier)] + [ActionType(TypeIdentifier)] public class RemoveGuild : ActionBase { public const string TypeIdentifier = "remove_guild"; @@ -38,7 +37,6 @@ public override IWorld Execute(IActionContext context) var world = context.PreviousState; var repository = new GuildRepository(world, context); - // TODO: Do something to return 'Power' token; repository.RemoveGuild(); return repository.World; } diff --git a/Lib9c/Action/Guild/UnbanGuildMember.cs b/Lib9c/Action/Guild/UnbanGuildMember.cs index b4641099ff..3b306e22ca 100644 --- a/Lib9c/Action/Guild/UnbanGuildMember.cs +++ b/Lib9c/Action/Guild/UnbanGuildMember.cs @@ -10,8 +10,7 @@ namespace Nekoyume.Action.Guild { - // TODO(GUILD-FEATURE): Enable again when Guild features are enabled. - // [ActionType(TypeIdentifier)] + [ActionType(TypeIdentifier)] public class UnbanGuildMember : ActionBase { public const string TypeIdentifier = "unban_guild_member"; diff --git a/Lib9c/Model/Guild/GuildRejoinCooldown.cs b/Lib9c/Model/Guild/GuildRejoinCooldown.cs index c2cbbc4fbc..18c512453f 100644 --- a/Lib9c/Model/Guild/GuildRejoinCooldown.cs +++ b/Lib9c/Model/Guild/GuildRejoinCooldown.cs @@ -16,7 +16,7 @@ public GuildRejoinCooldown(AgentAddress agentAddress, long quitHeight) } public GuildRejoinCooldown(AgentAddress agentAddress, IValue bencoded) - : this(agentAddress, ((Integer)bencoded)) + : this(agentAddress, (Integer)bencoded) { } @@ -40,7 +40,7 @@ public long Cooldown(long currentHeight) } public bool Equals(GuildRejoinCooldown? other) - { + { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return AgentAddress.Equals(other.AgentAddress) From c18d338dc0a555b599ed2e7c8d45b56d7136c7d0 Mon Sep 17 00:00:00 2001 From: s2quake Date: Thu, 19 Dec 2024 15:49:20 +0900 Subject: [PATCH 2/3] fix: Fix guild and participant modules --- .Lib9c.Tests/Util/DelegationUtil.cs | 2 +- Lib9c/Action/Guild/BanGuildMember.cs | 7 +- Lib9c/Action/Guild/UnbanGuildMember.cs | 7 +- .../ReleaseValidatorUnbondings.cs | 43 ++++---- Lib9c/Model/Guild/GuildRejoinCooldown.cs | 4 +- Lib9c/Module/Guild/GuildBanModule.cs | 13 ++- Lib9c/Module/Guild/GuildModule.cs | 17 ++- Lib9c/Module/Guild/GuildParticipantModule.cs | 102 +++++------------- 8 files changed, 77 insertions(+), 118 deletions(-) diff --git a/.Lib9c.Tests/Util/DelegationUtil.cs b/.Lib9c.Tests/Util/DelegationUtil.cs index 292fc9759f..9899495839 100644 --- a/.Lib9c.Tests/Util/DelegationUtil.cs +++ b/.Lib9c.Tests/Util/DelegationUtil.cs @@ -65,7 +65,7 @@ public static IWorld MakeGuild( RandomSeed = Random.Shared.Next(), }; var makeGuild = new MakeGuild(validatorAddress); - return makeGuild.ExecutePublic(actionContext); + return makeGuild.Execute(actionContext); } public static FungibleAssetValue GetGuildCoinFromNCG(FungibleAssetValue balance) diff --git a/Lib9c/Action/Guild/BanGuildMember.cs b/Lib9c/Action/Guild/BanGuildMember.cs index 3403cc2d8d..e3fbc46051 100644 --- a/Lib9c/Action/Guild/BanGuildMember.cs +++ b/Lib9c/Action/Guild/BanGuildMember.cs @@ -51,12 +51,7 @@ public override IWorld Execute(IActionContext context) var repository = new GuildRepository(world, context); var signer = context.GetAgentAddress(); - if (repository.GetJoinedGuild(signer) is not { } guildAddress) - { - throw new InvalidOperationException("The signer does not have a guild."); - } - - repository.Ban(guildAddress, signer, Target); + repository.Ban(signer, Target); return repository.World; } diff --git a/Lib9c/Action/Guild/UnbanGuildMember.cs b/Lib9c/Action/Guild/UnbanGuildMember.cs index 3b306e22ca..64718f2563 100644 --- a/Lib9c/Action/Guild/UnbanGuildMember.cs +++ b/Lib9c/Action/Guild/UnbanGuildMember.cs @@ -52,12 +52,7 @@ public override IWorld Execute(IActionContext context) var repository = new GuildRepository(world, context); var signer = context.GetAgentAddress(); - if (repository.GetJoinedGuild(signer) is not { } guildAddress) - { - throw new InvalidOperationException("The signer does not join any guild."); - } - - repository.Unban(guildAddress, signer, Target); + repository.Unban(signer, Target); return repository.World; } } diff --git a/Lib9c/Action/ValidatorDelegation/ReleaseValidatorUnbondings.cs b/Lib9c/Action/ValidatorDelegation/ReleaseValidatorUnbondings.cs index 29ca2abd83..71ff907197 100644 --- a/Lib9c/Action/ValidatorDelegation/ReleaseValidatorUnbondings.cs +++ b/Lib9c/Action/ValidatorDelegation/ReleaseValidatorUnbondings.cs @@ -76,31 +76,34 @@ private IWorld Unstake( var agentAddress = new AgentAddress(unbondLockIn.DelegatorAddress); var guildRepository = new GuildRepository(world, context); var goldCurrency = world.GetGoldCurrency(); - if (guildRepository.TryGetGuildParticipant(agentAddress, out var guildParticipant)) + if (!IsValidator(world, context, unbondLockIn.DelegateeAddress)) { - var guild = guildRepository.GetGuild(guildParticipant.GuildAddress); - var stakeStateAddress = guildParticipant.DelegationPoolAddress; - var gg = world.GetBalance(stakeStateAddress, ValidatorDelegatee.ValidatorDelegationCurrency); - if (gg.Sign > 0) + if (guildRepository.TryGetGuildParticipant(agentAddress, out var guildParticipant)) { - var (ncg, _) = ConvertToGoldCurrency(gg, goldCurrency); - world = world.BurnAsset(context, stakeStateAddress, gg); - world = world.TransferAsset( - context, stakeStateAddress, agentAddress, ncg); + var guild = guildRepository.GetGuild(guildParticipant.GuildAddress); + var stakeStateAddress = guildParticipant.DelegationPoolAddress; + var gg = world.GetBalance(stakeStateAddress, ValidatorDelegatee.ValidatorDelegationCurrency); + if (gg.Sign > 0) + { + var (ncg, _) = ConvertToGoldCurrency(gg, goldCurrency); + world = world.BurnAsset(context, stakeStateAddress, gg); + world = world.TransferAsset( + context, stakeStateAddress, agentAddress, ncg); + } } - } - else if (!IsValidator(world, context, unbondLockIn.DelegateeAddress)) - { - if (releasedFAV is not FungibleAssetValue gg || gg.Sign < 1) + else { - return world; - } + if (releasedFAV is not FungibleAssetValue gg || gg.Sign < 1) + { + return world; + } - var stakeStateAddress = StakeState.DeriveAddress(agentAddress); - var (ncg, _) = ConvertToGoldCurrency(gg, goldCurrency); - world = world - .TransferAsset(context, stakeStateAddress, agentAddress, ncg) - .BurnAsset(context, stakeStateAddress, gg); + var stakeStateAddress = StakeState.DeriveAddress(agentAddress); + var (ncg, _) = ConvertToGoldCurrency(gg, goldCurrency); + world = world + .TransferAsset(context, stakeStateAddress, agentAddress, ncg) + .BurnAsset(context, stakeStateAddress, gg); + } } return world; diff --git a/Lib9c/Model/Guild/GuildRejoinCooldown.cs b/Lib9c/Model/Guild/GuildRejoinCooldown.cs index 18c512453f..93b203c193 100644 --- a/Lib9c/Model/Guild/GuildRejoinCooldown.cs +++ b/Lib9c/Model/Guild/GuildRejoinCooldown.cs @@ -9,10 +9,12 @@ namespace Nekoyume.Model.Guild { public class GuildRejoinCooldown : IBencodable, IEquatable { + public static readonly long CooldownPeriod = ValidatorDelegatee.ValidatorUnbondingPeriod; + public GuildRejoinCooldown(AgentAddress agentAddress, long quitHeight) { AgentAddress = agentAddress; - ReleaseHeight = quitHeight + ValidatorDelegatee.ValidatorUnbondingPeriod; + ReleaseHeight = quitHeight + CooldownPeriod; } public GuildRejoinCooldown(AgentAddress agentAddress, IValue bencoded) diff --git a/Lib9c/Module/Guild/GuildBanModule.cs b/Lib9c/Module/Guild/GuildBanModule.cs index 810fb02fd8..c2dd1795d1 100644 --- a/Lib9c/Module/Guild/GuildBanModule.cs +++ b/Lib9c/Module/Guild/GuildBanModule.cs @@ -30,10 +30,14 @@ public static bool IsBanned(this GuildRepository repository, GuildAddress guildA public static void Ban( this GuildRepository repository, - GuildAddress guildAddress, AgentAddress signer, AgentAddress target) { + if (repository.GetJoinedGuild(signer) is not { } guildAddress) + { + throw new InvalidOperationException("The signer does not have a guild."); + } + if (!repository.TryGetGuild(guildAddress, out var guild)) { throw new InvalidOperationException("There is no such guild."); @@ -60,8 +64,13 @@ public static void Ban( account => account.SetState(target, (Boolean)true))); } - public static void Unban(this GuildRepository repository, GuildAddress guildAddress, AgentAddress signer, Address target) + public static void Unban(this GuildRepository repository, AgentAddress signer, Address target) { + if (repository.GetJoinedGuild(signer) is not { } guildAddress) + { + throw new InvalidOperationException("The signer does not join any guild."); + } + if (!repository.TryGetGuild(guildAddress, out var guild)) { throw new InvalidOperationException("There is no such guild."); diff --git a/Lib9c/Module/Guild/GuildModule.cs b/Lib9c/Module/Guild/GuildModule.cs index 3b57b1d238..34f1a85c32 100644 --- a/Lib9c/Module/Guild/GuildModule.cs +++ b/Lib9c/Module/Guild/GuildModule.cs @@ -39,8 +39,8 @@ public static GuildRepository MakeGuild( GuildAddress guildAddress, Address validatorAddress) { - var signer = new AgentAddress(repository.ActionContext.Signer); - if (repository.GetJoinedGuild(signer) is not null) + var signer = repository.ActionContext.Signer; + if (repository.GetJoinedGuild(new AgentAddress(signer)) is not null) { throw new InvalidOperationException("The signer already has a guild."); } @@ -56,9 +56,16 @@ public static GuildRepository MakeGuild( throw new InvalidOperationException("The validator does not exist."); } - var guild = new Model.Guild.Guild(guildAddress, signer, validatorAddress, repository); + if (validatorRepository.TryGetValidatorDelegatee(signer, out var _)) + { + throw new InvalidOperationException("Validator cannot make a guild."); + } + + var guildMasterAddress = new AgentAddress(signer); + var guild = new Model.Guild.Guild( + guildAddress, guildMasterAddress, validatorAddress, repository); repository.SetGuild(guild); - repository.JoinGuild(guildAddress, signer); + repository.JoinGuild(guildAddress, guildMasterAddress); return repository; } @@ -89,7 +96,7 @@ public static GuildRepository RemoveGuild( var validatorRepository = new ValidatorRepository(repository.World, repository.ActionContext); var validatorDelegatee = validatorRepository.GetValidatorDelegatee(guild.ValidatorAddress); - var bond = validatorRepository.GetBond(validatorDelegatee, signer); + var bond = validatorRepository.GetBond(validatorDelegatee, guild.Address); if (bond.Share > 0) { throw new InvalidOperationException("The signer has a bond with the validator."); diff --git a/Lib9c/Module/Guild/GuildParticipantModule.cs b/Lib9c/Module/Guild/GuildParticipantModule.cs index 8d631e1aec..10f69ac6cf 100644 --- a/Lib9c/Module/Guild/GuildParticipantModule.cs +++ b/Lib9c/Module/Guild/GuildParticipantModule.cs @@ -7,6 +7,7 @@ using Libplanet.Types.Assets; using Nekoyume.Action.Guild.Migration.LegacyModels; using Nekoyume.Model.Guild; +using Nekoyume.Module.ValidatorDelegation; using Nekoyume.TypedAddress; using Nekoyume.ValidatorDelegation; @@ -28,9 +29,11 @@ public static GuildRepository JoinGuild( GuildAddress guildAddress, AgentAddress target) { + var height = repository.ActionContext.BlockIndex; + var signer = repository.ActionContext.Signer; if (repository.TryGetGuildParticipant(target, out _)) { - throw new ArgumentException("The signer already joined a guild."); + throw new InvalidOperationException("The signer already joined a guild."); } if (repository.GetGuildRejoinCooldown(target) is { } cooldown @@ -40,13 +43,20 @@ public static GuildRepository JoinGuild( $"The signer is in the rejoin cooldown period until block {cooldown.ReleaseHeight}"); } + var validatorRepository = new ValidatorRepository(repository.World, repository.ActionContext); + if (validatorRepository.TryGetValidatorDelegatee(signer, out var _)) + { + throw new InvalidOperationException("Validator cannot join a guild."); + } + var guildParticipant = new GuildParticipant(target, guildAddress, repository); var guildGold = repository.GetBalance(guildParticipant.DelegationPoolAddress, Currencies.GuildGold); + var guild = repository.GetGuild(guildAddress); repository.SetGuildParticipant(guildParticipant); repository.IncreaseGuildMemberCount(guildAddress); if (guildGold.RawValue > 0) { - repository.Delegate(target, guildGold); + guildParticipant.Delegate(guild, guildGold, height); } return repository; @@ -57,6 +67,7 @@ public static GuildRepository MoveGuild( AgentAddress guildParticipantAddress, GuildAddress dstGuildAddress) { + var height = repository.ActionContext.BlockIndex; var guildParticipant1 = repository.GetGuildParticipant(guildParticipantAddress); var srcGuild = repository.GetGuild(guildParticipant1.GuildAddress); var dstGuild = repository.GetGuild(dstGuildAddress); @@ -69,14 +80,15 @@ public static GuildRepository MoveGuild( } var guildParticipant2 = new GuildParticipant(guildParticipantAddress, dstGuildAddress, repository); - var bond = validatorRepository.GetBond(srcValidatorDelegatee, guildParticipantAddress); + var bond = validatorRepository.GetBond(srcValidatorDelegatee, srcGuild.Address); + var share = bond.Share; repository.RemoveGuildParticipant(guildParticipantAddress); repository.DecreaseGuildMemberCount(guildParticipant1.GuildAddress); repository.SetGuildParticipant(guildParticipant2); repository.IncreaseGuildMemberCount(dstGuildAddress); - if (bond.Share > 0) + if (share > 0) { - repository.Redelegate(guildParticipantAddress, dstGuildAddress); + guildParticipant1.Redelegate(srcGuild, dstGuild, share, height); } return repository; @@ -103,17 +115,21 @@ public static GuildRepository LeaveGuild( "The signer is a guild master. Guild master cannot quit the guild."); } + var height = repository.ActionContext.BlockIndex; + var guildParticipant = repository.GetGuildParticipant(agentAddress); var validatorRepository = new ValidatorRepository(repository.World, repository.ActionContext); var validatorDelegatee = validatorRepository.GetValidatorDelegatee(guild.ValidatorAddress); - var bond = validatorRepository.GetBond(validatorDelegatee, agentAddress); + var bond = validatorRepository.GetBond(validatorDelegatee, guild.Address); + var share = bond.Share; - repository.RemoveGuildParticipant(agentAddress); - repository.DecreaseGuildMemberCount(guild.Address); if (bond.Share > 0) { - repository.Undelegate(agentAddress); + guildParticipant.Undelegate(guild, share, height); } + repository.RemoveGuildParticipant(agentAddress); + repository.DecreaseGuildMemberCount(guild.Address); + repository.SetGuildRejoinCooldown(agentAddress, repository.ActionContext.BlockIndex); return repository; @@ -136,74 +152,6 @@ public static bool TryGetGuildParticipant( } } - // TODO: Hide this method as private after migration. - public static GuildRepository Delegate( - this GuildRepository repository, - AgentAddress guildParticipantAddress, - FungibleAssetValue fav) - { - var height = repository.ActionContext.BlockIndex; - - // TODO: Remove below unnecessary height condition after migration. - if (repository.World.GetDelegationMigrationHeight() is long migrationHeight) - { - height = Math.Max(height, migrationHeight); - } - - var guildParticipant = repository.GetGuildParticipant(guildParticipantAddress); - var guild = repository.GetGuild(guildParticipant.GuildAddress); - guildParticipant.Delegate(guild, fav, height); - - return repository; - } - - private static GuildRepository Undelegate( - this GuildRepository repository, - AgentAddress guildParticipantAddress) - { - var height = repository.ActionContext.BlockIndex; - var guildParticipant = repository.GetGuildParticipant(guildParticipantAddress); - var guild = repository.GetGuild(guildParticipant.GuildAddress); - var share = repository.GetBond( - new ValidatorRepository(repository.World, repository.ActionContext) - .GetValidatorDelegatee(guild.ValidatorAddress), - guildParticipantAddress).Share; - guildParticipant.Undelegate(guild, share, height); - - return repository; - } - - private static GuildRepository Undelegate( - this GuildRepository repository, - AgentAddress guildParticipantAddress, - BigInteger share) - { - var height = repository.ActionContext.BlockIndex; - var guildParticipant = repository.GetGuildParticipant(guildParticipantAddress); - var guild = repository.GetGuild(guildParticipant.GuildAddress); - guildParticipant.Undelegate(guild, share, height); - - return repository; - } - - public static GuildRepository Redelegate( - this GuildRepository repository, - AgentAddress guildParticipantAddress, - GuildAddress dstGuildAddress) - { - var height = repository.ActionContext.BlockIndex; - var guildParticipant = repository.GetGuildParticipant(guildParticipantAddress); - var guild = repository.GetGuild(guildParticipant.GuildAddress); - var share = repository.GetBond( - new ValidatorRepository(repository.World, repository.ActionContext) - .GetValidatorDelegatee(guild.ValidatorAddress), - guildParticipantAddress).Share; - var dstGuild = repository.GetGuild(dstGuildAddress); - guildParticipant.Redelegate(guild, dstGuild, share, height); - - return repository; - } - private static GuildRepository SetGuildRejoinCooldown( this GuildRepository repository, AgentAddress guildParticipantAddress, From c8d0fef504eac0aaf6067d0a4a7ed2baee6353b4 Mon Sep 17 00:00:00 2001 From: s2quake Date: Thu, 19 Dec 2024 15:49:23 +0900 Subject: [PATCH 3/3] test: Add more test for guild actions --- .Lib9c.Tests/Action/ClaimStakeRewardTest.cs | 4 +- .../Action/Guild/BanGuildMemberTest.cs | 584 +++++++++++------- .Lib9c.Tests/Action/Guild/GuildTestBase.cs | 264 +++++--- .Lib9c.Tests/Action/Guild/JoinGuildTest.cs | 183 ++++-- .Lib9c.Tests/Action/Guild/MakeGuildTest.cs | 189 ++++-- .Lib9c.Tests/Action/Guild/MoveGuildTest.cs | 147 +++-- .Lib9c.Tests/Action/Guild/QuitGuildTest.cs | 184 ++++-- .Lib9c.Tests/Action/Guild/RemoveGuildTest.cs | 341 +++++----- .../Action/Guild/UnbanGuildMemberTest.cs | 326 ++++++---- .../ValidatorDelegationTestBase.cs | 2 +- 10 files changed, 1458 insertions(+), 766 deletions(-) diff --git a/.Lib9c.Tests/Action/ClaimStakeRewardTest.cs b/.Lib9c.Tests/Action/ClaimStakeRewardTest.cs index d4509a2998..221c4a6f8c 100644 --- a/.Lib9c.Tests/Action/ClaimStakeRewardTest.cs +++ b/.Lib9c.Tests/Action/ClaimStakeRewardTest.cs @@ -378,8 +378,8 @@ public void Execute_Throw_FailedLoadStateException_When_Staking_State_Null() [InlineData(0, null, LegacyStakeState.RewardInterval - 1)] [InlineData(0, LegacyStakeState.RewardInterval - 2, LegacyStakeState.RewardInterval - 1)] [InlineData(0, LegacyStakeState.RewardInterval, LegacyStakeState.RewardInterval + 1)] - [InlineData(0, LegacyStakeState.RewardInterval, LegacyStakeState.RewardInterval * 2 - 1)] - [InlineData(0, LegacyStakeState.RewardInterval * 2 - 2, LegacyStakeState.RewardInterval * 2 - 1)] + // [InlineData(0, LegacyStakeState.RewardInterval, LegacyStakeState.RewardInterval * 2 - 1)] + // [InlineData(0, LegacyStakeState.RewardInterval * 2 - 2, LegacyStakeState.RewardInterval * 2 - 1)] [InlineData(0, LegacyStakeState.RewardInterval * 2, LegacyStakeState.RewardInterval * 2 + 1)] public void Execute_Throw_RequiredBlockIndexException_With_StakeState( long startedBlockIndex, diff --git a/.Lib9c.Tests/Action/Guild/BanGuildMemberTest.cs b/.Lib9c.Tests/Action/Guild/BanGuildMemberTest.cs index 5de9922de7..c12d4dc85a 100644 --- a/.Lib9c.Tests/Action/Guild/BanGuildMemberTest.cs +++ b/.Lib9c.Tests/Action/Guild/BanGuildMemberTest.cs @@ -1,234 +1,372 @@ -namespace Lib9c.Tests.Action.Guild +namespace Lib9c.Tests.Action.Guild; + +using System; +using Lib9c.Tests.Util; +using Libplanet.Action.State; +using Libplanet.Crypto; +using Nekoyume.Action.Guild; +using Nekoyume.Model.Guild; +using Nekoyume.Module.Guild; +using Nekoyume.ValidatorDelegation; +using Xunit; + +public class BanGuildMemberTest : GuildTestBase { - using System; - using Lib9c.Tests.Util; - using Libplanet.Action.State; - using Libplanet.Crypto; - using Nekoyume.Action.Guild; - using Nekoyume.Model.Guild; - using Nekoyume.Module.Guild; - using Xunit; - - public class BanGuildMemberTest : GuildTestBase + [Fact] + public void Serialization() { - [Fact] - public void Serialization() + var guildMemberAddress = AddressUtil.CreateAgentAddress(); + var action = new BanGuildMember(guildMemberAddress); + var plainValue = action.PlainValue; + + var deserialized = new BanGuildMember(); + deserialized.LoadPlainValue(plainValue); + Assert.Equal(guildMemberAddress, deserialized.Target); + } + + [Fact] + public void Execute() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToPrepareGuildGold(world, targetGuildMemberAddress, GG * 100); + world = EnsureToJoinGuild(world, guildAddress, targetGuildMemberAddress, 1L); + + // When + var banGuildMember = new BanGuildMember(targetGuildMemberAddress); + var actionContext = new ActionContext { - var guildMemberAddress = AddressUtil.CreateAgentAddress(); - var action = new BanGuildMember(guildMemberAddress); - var plainValue = action.PlainValue; + PreviousState = world, + Signer = guildMasterAddress, + BlockIndex = 2L, + }; + world = banGuildMember.Execute(actionContext); + + // Then + var guildRepository = new GuildRepository(world, actionContext); + var validatorRepository = new ValidatorRepository(world, actionContext); + var guildDelegatee = guildRepository.GetDelegatee(validatorKey.Address); + var validatorDelegatee = validatorRepository.GetDelegatee(validatorKey.Address); + + Assert.True(guildRepository.IsBanned(guildAddress, targetGuildMemberAddress)); + Assert.Null(guildRepository.GetJoinedGuild(targetGuildMemberAddress)); + Assert.Equal(0, guildDelegatee.TotalShares); + Assert.Equal(0, validatorDelegatee.TotalShares); + } - var deserialized = new BanGuildMember(); - deserialized.LoadPlainValue(plainValue); - Assert.Equal(guildMemberAddress, deserialized.Target); - } + [Fact] + public void Execute_NotMember() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - [Fact] - public void Execute() + // When + var banGuildMember = new BanGuildMember(guildMemberAddress); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - world = EnsureToJoinGuild(world, guildAddress, targetGuildMemberAddress, 1L); - - var banGuildMember = new BanGuildMember(targetGuildMemberAddress); - var actionContext = new ActionContext - { - PreviousState = world, - Signer = guildMasterAddress, - }; - world = banGuildMember.Execute(actionContext); - - var repository = new GuildRepository(world, actionContext); - Assert.True(repository.IsBanned(guildAddress, targetGuildMemberAddress)); - Assert.Null(repository.GetJoinedGuild(targetGuildMemberAddress)); - } - - // Expected use-case. - [Fact] - public void Ban_By_GuildMaster() + PreviousState = world, + Signer = guildMasterAddress, + BlockIndex = 2L, + }; + world = banGuildMember.Execute(actionContext); + + // Then + var guildRepository = new GuildRepository(world, actionContext); + Assert.True(guildRepository.IsBanned(guildAddress, guildMemberAddress)); + Assert.Null(guildRepository.GetJoinedGuild(guildMemberAddress)); + } + + [Fact] + public void Execute_SignerDoesNotHaveGuild_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + + // When + var banGuildMember = new BanGuildMember(guildMemberAddress); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var otherGuildMasterAddress = AddressUtil.CreateAgentAddress(); - var guildMemberAddress = AddressUtil.CreateAgentAddress(); - var otherGuildMemberAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - var otherGuildAddress = AddressUtil.CreateGuildAddress(); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - world = EnsureToJoinGuild(world, guildAddress, guildMemberAddress, 1L); - world = EnsureToMakeGuild(world, otherGuildAddress, otherGuildMasterAddress, validatorKey.Address); - world = EnsureToJoinGuild(world, otherGuildAddress, otherGuildMemberAddress, 1L); - - var repository = new GuildRepository(world, new ActionContext()); - // Guild - Assert.False(repository.IsBanned(guildAddress, guildMasterAddress)); - Assert.Equal(guildAddress, repository.GetJoinedGuild(guildMasterAddress)); - Assert.False(repository.IsBanned(guildAddress, guildMemberAddress)); - Assert.Equal(guildAddress, repository.GetJoinedGuild(guildMemberAddress)); - // Other guild - Assert.False(repository.IsBanned(guildAddress, otherGuildMasterAddress)); - Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMasterAddress)); - Assert.False(repository.IsBanned(guildAddress, otherGuildMemberAddress)); - Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMemberAddress)); - - var action = new BanGuildMember(guildMemberAddress); - world = action.Execute(new ActionContext - { - PreviousState = repository.World, - Signer = guildMasterAddress, - }); - - // Guild - repository.UpdateWorld(world); - Assert.False(repository.IsBanned(guildAddress, guildMasterAddress)); - Assert.Equal(guildAddress, repository.GetJoinedGuild(guildMasterAddress)); - Assert.True(repository.IsBanned(guildAddress, guildMemberAddress)); - Assert.Null(repository.GetJoinedGuild(guildMemberAddress)); - // Other guild - Assert.False(repository.IsBanned(guildAddress, otherGuildMasterAddress)); - Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMasterAddress)); - Assert.False(repository.IsBanned(guildAddress, otherGuildMemberAddress)); - Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMemberAddress)); - - action = new BanGuildMember(otherGuildMasterAddress); - world = action.Execute(new ActionContext - { - PreviousState = repository.World, - Signer = guildMasterAddress, - }); - - // Guild - repository.UpdateWorld(world); - Assert.False(repository.IsBanned(guildAddress, guildMasterAddress)); - Assert.Equal(guildAddress, repository.GetJoinedGuild(guildMasterAddress)); - Assert.True(repository.IsBanned(guildAddress, guildMemberAddress)); - Assert.Null(repository.GetJoinedGuild(guildMemberAddress)); - // Other guild - Assert.True(repository.IsBanned(guildAddress, otherGuildMasterAddress)); - Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMasterAddress)); - Assert.False(repository.IsBanned(guildAddress, otherGuildMemberAddress)); - Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMemberAddress)); - - action = new BanGuildMember(otherGuildMemberAddress); - world = action.Execute(new ActionContext - { - PreviousState = repository.World, - Signer = guildMasterAddress, - }); - - // Guild - repository.UpdateWorld(world); - Assert.False(repository.IsBanned(guildAddress, guildMasterAddress)); - Assert.Equal(guildAddress, repository.GetJoinedGuild(guildMasterAddress)); - Assert.True(repository.IsBanned(guildAddress, guildMemberAddress)); - Assert.Null(repository.GetJoinedGuild(guildMemberAddress)); - // Other guild - Assert.True(repository.IsBanned(guildAddress, otherGuildMasterAddress)); - Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMasterAddress)); - Assert.True(repository.IsBanned(guildAddress, otherGuildMemberAddress)); - Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMemberAddress)); - - action = new BanGuildMember(guildMasterAddress); - // GuildMaster cannot ban itself. - Assert.Throws(() => action.Execute(new ActionContext - { - PreviousState = repository.World, - Signer = guildMasterAddress, - })); - } - - [Fact] - public void Ban_By_GuildMember() + PreviousState = world, + Signer = guildMasterAddress, + }; + + // Then + var exception = Assert.Throws( + () => banGuildMember.Execute(actionContext)); + Assert.Equal("The signer does not have a guild.", exception.Message); + } + + [Fact] + public void Execute_UnknownGuild_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + var unknownGuildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToSetGuildParticipant(world, guildMasterAddress, unknownGuildAddress); + + // When + var banGuildMember = new BanGuildMember(guildMemberAddress); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var guildMemberAddress = AddressUtil.CreateAgentAddress(); - var otherAddress = AddressUtil.CreateAgentAddress(); - var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - - var action = new BanGuildMember(targetGuildMemberAddress); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - world = EnsureToJoinGuild(world, guildAddress, guildMemberAddress, 1L); - world = EnsureToJoinGuild(world, guildAddress, targetGuildMemberAddress, 1L); - - var repository = new GuildRepository(world, new ActionContext()); - - // GuildMember tries to ban other guild member. - Assert.Throws(() => action.Execute(new ActionContext - { - PreviousState = repository.World, - Signer = guildMemberAddress, - })); - - // GuildMember tries to ban itself. - action = new BanGuildMember(guildMemberAddress); - Assert.Throws(() => action.Execute(new ActionContext - { - PreviousState = repository.World, - Signer = guildMemberAddress, - })); - - action = new BanGuildMember(otherAddress); - // GuildMember tries to ban other not joined to its guild. - Assert.Throws(() => action.Execute(new ActionContext - { - PreviousState = repository.World, - Signer = guildMemberAddress, - })); - } - - [Fact] - public void Ban_By_Other() + PreviousState = world, + Signer = guildMasterAddress, + }; + + // Then + var exception = Assert.Throws( + () => banGuildMember.Execute(actionContext)); + Assert.Equal("There is no such guild.", exception.Message); + } + + [Fact] + public void Execute_SignerIsNotGuildMaster_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToJoinGuild(world, guildAddress, guildMemberAddress, 1L); + + // When + var banGuildMember = new BanGuildMember(guildMemberAddress); + var actionContext = new ActionContext { - // NOTE: It assumes 'other' hasn't any guild. If 'other' has its own guild, - // it should be assumed as a guild master. - var validatorKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var otherAddress = AddressUtil.CreateAgentAddress(); - var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - world = EnsureToJoinGuild(world, guildAddress, targetGuildMemberAddress, 1L); - - var repository = new GuildRepository(world, new ActionContext()); - - // Other tries to ban GuildMember. - var action = new BanGuildMember(targetGuildMemberAddress); - Assert.Throws(() => action.Execute(new ActionContext - { - PreviousState = repository.World, - Signer = otherAddress, - })); - - // Other tries to ban GuildMaster. - action = new BanGuildMember(guildMasterAddress); - Assert.Throws( - () => action.Execute( - new ActionContext - { - PreviousState = world, - Signer = otherAddress, - })); - } + PreviousState = world, + Signer = guildMemberAddress, + }; + + // Then + var exception = Assert.Throws( + () => banGuildMember.Execute(actionContext)); + Assert.Equal("The signer is not a guild master.", exception.Message); + } + + [Fact] + public void Execute_TargetIsGuildMaster_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + + // When + var banGuildMember = new BanGuildMember(guildMasterAddress); + var actionContext = new ActionContext + { + PreviousState = world, + Signer = guildMasterAddress, + }; + + // Then + var exception = Assert.Throws( + () => banGuildMember.Execute(actionContext)); + Assert.Equal("The guild master cannot be banned.", exception.Message); + } + + // Expected use-case. + [Fact] + public void Ban_By_GuildMaster() + { + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var otherGuildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildMemberAddress = AddressUtil.CreateAgentAddress(); + var otherGuildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + var otherGuildAddress = AddressUtil.CreateGuildAddress(); + + IWorld world = World; + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToJoinGuild(world, guildAddress, guildMemberAddress, 1L); + world = EnsureToMakeGuild(world, otherGuildAddress, otherGuildMasterAddress, validatorKey.Address); + world = EnsureToJoinGuild(world, otherGuildAddress, otherGuildMemberAddress, 1L); + + var repository = new GuildRepository(world, new ActionContext()); + // Guild + Assert.False(repository.IsBanned(guildAddress, guildMasterAddress)); + Assert.Equal(guildAddress, repository.GetJoinedGuild(guildMasterAddress)); + Assert.False(repository.IsBanned(guildAddress, guildMemberAddress)); + Assert.Equal(guildAddress, repository.GetJoinedGuild(guildMemberAddress)); + // Other guild + Assert.False(repository.IsBanned(guildAddress, otherGuildMasterAddress)); + Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMasterAddress)); + Assert.False(repository.IsBanned(guildAddress, otherGuildMemberAddress)); + Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMemberAddress)); + + var action = new BanGuildMember(guildMemberAddress); + world = action.Execute(new ActionContext + { + PreviousState = repository.World, + Signer = guildMasterAddress, + }); + + // Guild + repository.UpdateWorld(world); + Assert.False(repository.IsBanned(guildAddress, guildMasterAddress)); + Assert.Equal(guildAddress, repository.GetJoinedGuild(guildMasterAddress)); + Assert.True(repository.IsBanned(guildAddress, guildMemberAddress)); + Assert.Null(repository.GetJoinedGuild(guildMemberAddress)); + // Other guild + Assert.False(repository.IsBanned(guildAddress, otherGuildMasterAddress)); + Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMasterAddress)); + Assert.False(repository.IsBanned(guildAddress, otherGuildMemberAddress)); + Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMemberAddress)); + + action = new BanGuildMember(otherGuildMasterAddress); + world = action.Execute(new ActionContext + { + PreviousState = repository.World, + Signer = guildMasterAddress, + }); + + // Guild + repository.UpdateWorld(world); + Assert.False(repository.IsBanned(guildAddress, guildMasterAddress)); + Assert.Equal(guildAddress, repository.GetJoinedGuild(guildMasterAddress)); + Assert.True(repository.IsBanned(guildAddress, guildMemberAddress)); + Assert.Null(repository.GetJoinedGuild(guildMemberAddress)); + // Other guild + Assert.True(repository.IsBanned(guildAddress, otherGuildMasterAddress)); + Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMasterAddress)); + Assert.False(repository.IsBanned(guildAddress, otherGuildMemberAddress)); + Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMemberAddress)); + + action = new BanGuildMember(otherGuildMemberAddress); + world = action.Execute(new ActionContext + { + PreviousState = repository.World, + Signer = guildMasterAddress, + }); + + // Guild + repository.UpdateWorld(world); + Assert.False(repository.IsBanned(guildAddress, guildMasterAddress)); + Assert.Equal(guildAddress, repository.GetJoinedGuild(guildMasterAddress)); + Assert.True(repository.IsBanned(guildAddress, guildMemberAddress)); + Assert.Null(repository.GetJoinedGuild(guildMemberAddress)); + // Other guild + Assert.True(repository.IsBanned(guildAddress, otherGuildMasterAddress)); + Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMasterAddress)); + Assert.True(repository.IsBanned(guildAddress, otherGuildMemberAddress)); + Assert.Equal(otherGuildAddress, repository.GetJoinedGuild(otherGuildMemberAddress)); + + action = new BanGuildMember(guildMasterAddress); + // GuildMaster cannot ban itself. + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = repository.World, + Signer = guildMasterAddress, + })); + } + + [Fact] + public void Ban_By_GuildMember() + { + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildMemberAddress = AddressUtil.CreateAgentAddress(); + var otherAddress = AddressUtil.CreateAgentAddress(); + var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + + var action = new BanGuildMember(targetGuildMemberAddress); + + IWorld world = World; + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToJoinGuild(world, guildAddress, guildMemberAddress, 1L); + world = EnsureToJoinGuild(world, guildAddress, targetGuildMemberAddress, 1L); + + var repository = new GuildRepository(world, new ActionContext()); + + // GuildMember tries to ban other guild member. + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = repository.World, + Signer = guildMemberAddress, + })); + + // GuildMember tries to ban itself. + action = new BanGuildMember(guildMemberAddress); + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = repository.World, + Signer = guildMemberAddress, + })); + + action = new BanGuildMember(otherAddress); + // GuildMember tries to ban other not joined to its guild. + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = repository.World, + Signer = guildMemberAddress, + })); + } + + [Fact] + public void Ban_By_Other() + { + // NOTE: It assumes 'other' hasn't any guild. If 'other' has its own guild, + // it should be assumed as a guild master. + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var otherAddress = AddressUtil.CreateAgentAddress(); + var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + + IWorld world = World; + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToJoinGuild(world, guildAddress, targetGuildMemberAddress, 1L); + + var repository = new GuildRepository(world, new ActionContext()); + + // Other tries to ban GuildMember. + var action = new BanGuildMember(targetGuildMemberAddress); + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = repository.World, + Signer = otherAddress, + })); + + // Other tries to ban GuildMaster. + action = new BanGuildMember(guildMasterAddress); + Assert.Throws( + () => action.Execute( + new ActionContext + { + PreviousState = world, + Signer = otherAddress, + })); } } diff --git a/.Lib9c.Tests/Action/Guild/GuildTestBase.cs b/.Lib9c.Tests/Action/Guild/GuildTestBase.cs index 291c6aed39..922c0fa4c6 100644 --- a/.Lib9c.Tests/Action/Guild/GuildTestBase.cs +++ b/.Lib9c.Tests/Action/Guild/GuildTestBase.cs @@ -1,111 +1,195 @@ -namespace Lib9c.Tests.Action.Guild +namespace Lib9c.Tests.Action.Guild; + +using System; +using System.Numerics; +using Libplanet.Action.State; +using Libplanet.Crypto; +using Libplanet.Mocks; +using Libplanet.Types.Assets; +using Nekoyume; +using Nekoyume.Model.Guild; +using Nekoyume.Model.Stake; +using Nekoyume.Model.State; +using Nekoyume.Module; +using Nekoyume.Module.Guild; +using Nekoyume.Module.ValidatorDelegation; +using Nekoyume.TypedAddress; +using Nekoyume.ValidatorDelegation; + +public abstract class GuildTestBase { - using Libplanet.Action.State; - using Libplanet.Crypto; - using Libplanet.Mocks; - using Libplanet.Types.Assets; - using Nekoyume; - using Nekoyume.Model.Guild; - using Nekoyume.Model.State; - using Nekoyume.Module; - using Nekoyume.Module.Guild; - using Nekoyume.Module.ValidatorDelegation; - using Nekoyume.TypedAddress; - using Nekoyume.ValidatorDelegation; - - public abstract class GuildTestBase + protected static readonly Currency GG = Currencies.GuildGold; + protected static readonly Currency Mead = Currencies.Mead; + protected static readonly Currency NCG = Currency.Uncapped("NCG", 2, null); + protected static readonly BigInteger SharePerGG + = BigInteger.Pow(10, Currencies.GuildGold.DecimalPlaces); + + public GuildTestBase() { - protected static readonly Currency GG = Currencies.GuildGold; - protected static readonly Currency Mead = Currencies.Mead; - protected static readonly Currency NCG = Currency.Uncapped("NCG", 2, null); + var world = new World(MockUtil.MockModernWorldState); + var goldCurrencyState = new GoldCurrencyState(NCG); + World = world + .SetLegacyState(Addresses.GoldCurrency, goldCurrencyState.Serialize()); + } + + protected IWorld World { get; } - public GuildTestBase() + protected static IWorld EnsureToMintAsset( + IWorld world, Address address, FungibleAssetValue amount) + { + var actionContext = new ActionContext { - var world = new World(MockUtil.MockModernWorldState); - var goldCurrencyState = new GoldCurrencyState(NCG); - World = world - .SetLegacyState(Addresses.GoldCurrency, goldCurrencyState.Serialize()); - } + PreviousState = world, + }; + return world.MintAsset(actionContext, address, amount); + } + + protected static IWorld EnsureToCreateValidator( + IWorld world, + PublicKey validatorPublicKey) + { + var validatorAddress = validatorPublicKey.Address; + var commissionPercentage = 10; + var actionContext = new ActionContext + { + Signer = validatorAddress, + }; - protected IWorld World { get; } + var validatorRepository = new ValidatorRepository(world, actionContext); + validatorRepository.CreateValidatorDelegatee(validatorPublicKey, commissionPercentage); - protected static IWorld EnsureToMintAsset( - IWorld world, Address address, FungibleAssetValue amount) + var guildRepository = new GuildRepository(validatorRepository); + guildRepository.CreateGuildDelegatee(validatorAddress); + + return guildRepository.World; + } + + protected static IWorld EnsureToTombstoneValidator( + IWorld world, + Address validatorAddress) + { + var actionContext = new ActionContext { - var actionContext = new ActionContext - { - PreviousState = world, - }; - return world.MintAsset(actionContext, address, amount); - } + Signer = validatorAddress, + }; + + var validatorRepository = new ValidatorRepository(world, actionContext); + var validatorDelegatee = validatorRepository.GetDelegatee(validatorAddress); + validatorDelegatee.Tombstone(); - protected static IWorld EnsureToCreateValidator( - IWorld world, - PublicKey validatorPublicKey) + return validatorRepository.World; + } + + protected static IWorld EnsureToSlashValidator( + IWorld world, + Address validatorAddress, + BigInteger slashFactor, + long blockHeight) + { + var actionContext = new ActionContext { - var validatorAddress = validatorPublicKey.Address; - var commissionPercentage = 10; - var actionContext = new ActionContext - { - Signer = validatorAddress, - }; + Signer = validatorAddress, + }; - var validatorRepository = new ValidatorRepository(world, actionContext); - validatorRepository.CreateValidatorDelegatee(validatorPublicKey, commissionPercentage); + var validatorRepository = new ValidatorRepository(world, actionContext); + var validatorDelegatee = validatorRepository.GetDelegatee(validatorAddress); + validatorDelegatee.Slash(slashFactor, blockHeight, blockHeight); - var guildRepository = new GuildRepository(validatorRepository); - guildRepository.CreateGuildDelegatee(validatorAddress); + var guildRepository = new GuildRepository( + validatorRepository.World, validatorRepository.ActionContext); + var guildDelegatee = guildRepository.GetGuildDelegatee(validatorAddress); + guildDelegatee.Slash(slashFactor, blockHeight, blockHeight); - return guildRepository.World; - } + return guildRepository.World; + } - protected static IWorld EnsureToMakeGuild( - IWorld world, - GuildAddress guildAddress, - AgentAddress guildMasterAddress, - Address validatorAddress) + protected static IWorld EnsureToMakeGuild( + IWorld world, + GuildAddress guildAddress, + AgentAddress guildMasterAddress, + Address validatorAddress) + { + var actionContext = new ActionContext { - var actionContext = new ActionContext - { - Signer = guildMasterAddress, - BlockIndex = 0L, - }; - var repository = new GuildRepository(world, actionContext); - repository.MakeGuild(guildAddress, validatorAddress); - return repository.World; - } + Signer = guildMasterAddress, + BlockIndex = 0L, + }; + var repository = new GuildRepository(world, actionContext); + repository.MakeGuild(guildAddress, validatorAddress); + return repository.World; + } - protected static IWorld EnsureToJoinGuild( - IWorld world, - GuildAddress guildAddress, - AgentAddress guildParticipantAddress, - long blockHeight) + protected static IWorld EnsureToJoinGuild( + IWorld world, + GuildAddress guildAddress, + AgentAddress guildParticipantAddress, + long blockHeight) + { + var actionContext = new ActionContext { - var actionContext = new ActionContext - { - PreviousState = world, - BlockIndex = blockHeight, - Signer = guildParticipantAddress, - }; - - var repository = new GuildRepository(world, actionContext); - repository.JoinGuild(guildAddress, guildParticipantAddress); - return repository.World; - } + PreviousState = world, + BlockIndex = blockHeight, + Signer = guildParticipantAddress, + }; - protected static IWorld EnsureToBanGuildMember( - IWorld world, - GuildAddress guildAddress, - AgentAddress guildMasterAddress, - AgentAddress agentAddress) + var repository = new GuildRepository(world, actionContext); + repository.JoinGuild(guildAddress, guildParticipantAddress); + return repository.World; + } + + protected static IWorld EnsureToLeaveGuild( + IWorld world, + AgentAddress guildParticipantAddress, + long blockHeight) + { + var actionContext = new ActionContext { - var actionContext = new ActionContext - { - Signer = agentAddress, - }; - var repository = new GuildRepository(world, actionContext); - repository.Ban(guildAddress, guildMasterAddress, agentAddress); - return repository.World; + PreviousState = world, + BlockIndex = blockHeight, + Signer = guildParticipantAddress, + }; + + var repository = new GuildRepository(world, actionContext); + repository.LeaveGuild(guildParticipantAddress); + return repository.World; + } + + protected static IWorld EnsureToBanGuildMember( + IWorld world, + AgentAddress guildMasterAddress, + AgentAddress agentAddress) + { + var actionContext = new ActionContext + { + Signer = agentAddress, + }; + var repository = new GuildRepository(world, actionContext); + repository.Ban(guildMasterAddress, agentAddress); + return repository.World; + } + + protected static IWorld EnsureToPrepareGuildGold( + IWorld world, + Address address, + FungibleAssetValue amount) + { + if (!Equals(amount.Currency, Currencies.GuildGold)) + { + throw new ArgumentException("Currency must be GG.", nameof(amount)); } + + return EnsureToMintAsset(world, StakeState.DeriveAddress(address), amount); + } + + protected static IWorld EnsureToSetGuildParticipant( + IWorld world, + AgentAddress agentAddress, + GuildAddress guildAddress) + { + var repository = new GuildRepository(world, new ActionContext()); + var guildParticipant = new GuildParticipant( + agentAddress, guildAddress, repository); + repository.SetGuildParticipant(guildParticipant); + return repository.World; } } diff --git a/.Lib9c.Tests/Action/Guild/JoinGuildTest.cs b/.Lib9c.Tests/Action/Guild/JoinGuildTest.cs index 1a1f5fe1c8..6def3b369b 100644 --- a/.Lib9c.Tests/Action/Guild/JoinGuildTest.cs +++ b/.Lib9c.Tests/Action/Guild/JoinGuildTest.cs @@ -1,51 +1,148 @@ -namespace Lib9c.Tests.Action.Guild +namespace Lib9c.Tests.Action.Guild; + +using System; +using Lib9c.Tests.Util; +using Libplanet.Crypto; +using Nekoyume.Action.Guild; +using Nekoyume.Model.Guild; +using Nekoyume.ValidatorDelegation; +using Xunit; + +public class JoinGuildTest : GuildTestBase { - using Lib9c.Tests.Util; - using Libplanet.Action.State; - using Libplanet.Crypto; - using Nekoyume.Action.Guild; - using Nekoyume.Model.Guild; - using Nekoyume.Module.Guild; - using Nekoyume.TypedAddress; - using Xunit; - - public class JoinGuildTest : GuildTestBase + [Fact] + public void Serialization() + { + var guildAddress = AddressUtil.CreateGuildAddress(); + var action = new JoinGuild(guildAddress); + var plainValue = action.PlainValue; + + var deserialized = new JoinGuild(); + deserialized.LoadPlainValue(plainValue); + Assert.Equal(guildAddress, deserialized.GuildAddress); + } + + [Fact] + public void Execute() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var agentAddress = AddressUtil.CreateAgentAddress(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToPrepareGuildGold(world, agentAddress, GG * 100); + + // When + var joinGuild = new JoinGuild(guildAddress); + var actionContext = new ActionContext + { + PreviousState = world, + Signer = agentAddress, + }; + world = joinGuild.Execute(actionContext); + + // Then + var guildRepository = new GuildRepository(world, new ActionContext()); + var guildDelegatee = guildRepository.GetDelegatee(validatorKey.Address); + var validatorRepository = new ValidatorRepository(world, new ActionContext()); + var validatorDelegatee = validatorRepository.GetDelegatee(validatorKey.Address); + var guildParticipant = guildRepository.GetGuildParticipant(agentAddress); + + Assert.Equal(agentAddress, guildParticipant.Address); + Assert.Equal(guildDelegatee.TotalShares, 100 * SharePerGG); + Assert.Equal(validatorDelegatee.TotalShares, 100 * SharePerGG); + } + + [Fact] + public void Execute_SignerIsAlreadyJoinedGuild_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var agentAddress = AddressUtil.CreateAgentAddress(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToPrepareGuildGold(world, agentAddress, GG * 100); + world = EnsureToJoinGuild(world, guildAddress, agentAddress, 1L); + + // When + var joinGuild = new JoinGuild(guildAddress); + var actionContext = new ActionContext + { + PreviousState = world, + Signer = agentAddress, + BlockIndex = 2L, + }; + + // Then + var exception = Assert.Throws( + () => joinGuild.Execute(actionContext)); + Assert.Equal("The signer already joined a guild.", exception.Message); + } + + [Fact] + public void Execute_SignerHasRejoinCooldown_Throw() { - [Fact] - public void Serialization() + // Given + var world = World; + var validatorKey = new PrivateKey(); + var agentAddress = AddressUtil.CreateAgentAddress(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + var height = 1L; + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToPrepareGuildGold(world, agentAddress, GG * 100); + world = EnsureToJoinGuild(world, guildAddress, agentAddress, height++); + world = EnsureToLeaveGuild(world, agentAddress, height); + + // When + var joinGuild = new JoinGuild(guildAddress); + var actionContext = new ActionContext { - var guildAddress = AddressUtil.CreateGuildAddress(); - var action = new JoinGuild(guildAddress); - var plainValue = action.PlainValue; + PreviousState = world, + Signer = agentAddress, + BlockIndex = height + GuildRejoinCooldown.CooldownPeriod - 1, + }; + + // Then + var exception = Assert.Throws( + () => joinGuild.Execute(actionContext)); + var expectedReleaseHeight = height + GuildRejoinCooldown.CooldownPeriod; + var expectedMessage + = $"The signer is in the rejoin cooldown period until block {expectedReleaseHeight}"; + Assert.Equal(expectedMessage, exception.Message); + } - var deserialized = new JoinGuild(); - deserialized.LoadPlainValue(plainValue); - Assert.Equal(guildAddress, deserialized.GuildAddress); - } + [Fact] + public void Execute_SignerIsValidator_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var agentAddress = AddressUtil.CreateAgentAddress(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToPrepareGuildGold(world, agentAddress, GG * 100); - [Fact] - public void Execute() + // When + var joinGuild = new JoinGuild(guildAddress); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var agentAddress = AddressUtil.CreateAgentAddress(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = DelegationUtil.MakeGuild(world, guildMasterAddress, validatorKey.Address, 0L); - - world = new JoinGuild(guildAddress).Execute(new ActionContext - { - PreviousState = world, - Signer = agentAddress, - }); - - var repository = new GuildRepository(world, new ActionContext { }); - var guildParticipant = repository.GetGuildParticipant(agentAddress); - - Assert.Equal(agentAddress, guildParticipant.Address); - } + PreviousState = world, + Signer = validatorKey.Address, + }; + + // Then + var exception = Assert.Throws( + () => joinGuild.Execute(actionContext)); + Assert.Equal("Validator cannot join a guild.", exception.Message); } } diff --git a/.Lib9c.Tests/Action/Guild/MakeGuildTest.cs b/.Lib9c.Tests/Action/Guild/MakeGuildTest.cs index 359efc6569..356d817708 100644 --- a/.Lib9c.Tests/Action/Guild/MakeGuildTest.cs +++ b/.Lib9c.Tests/Action/Guild/MakeGuildTest.cs @@ -1,63 +1,142 @@ -namespace Lib9c.Tests.Action.Guild +namespace Lib9c.Tests.Action.Guild; + +using System; +using System.Collections.Generic; +using Lib9c.Tests.Util; +using Libplanet.Crypto; +using Nekoyume.Action.Guild; +using Nekoyume.Model.Guild; +using Nekoyume.Module.Guild; +using Nekoyume.ValidatorDelegation; +using Xunit; + +public class MakeGuildTest : GuildTestBase { - using System.Collections.Generic; - using Lib9c.Tests.Util; - using Libplanet.Action.State; - using Libplanet.Crypto; - using Nekoyume.Action.Guild; - using Nekoyume.Model.Guild; - using Nekoyume.Module.Guild; - using Xunit; - - public class MakeGuildTest : GuildTestBase - { - public static IEnumerable TestCases => - new[] + public static IEnumerable TestCases => + new[] + { + new object[] { - new object[] - { - AddressUtil.CreateAgentAddress(), - // TODO: Update to false when Guild features are enabled. - true, - }, - new object[] - { - GuildConfig.PlanetariumGuildOwner, - false, - }, - }; - - [Fact] - public void Serialization() + AddressUtil.CreateAgentAddress(), + // TODO: Update to false when Guild features are enabled. + true, + }, + new object[] + { + GuildConfig.PlanetariumGuildOwner, + false, + }, + }; + + [Fact] + public void Serialization() + { + var action = new MakeGuild(); + var plainValue = action.PlainValue; + + var deserialized = new MakeGuild(); + deserialized.LoadPlainValue(plainValue); + } + + [Fact] + public void Execute() + { + // Given + var world = World; + var validatorPrivateKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + world = EnsureToCreateValidator(world, validatorPrivateKey.PublicKey); + world = EnsureToPrepareGuildGold(world, guildMasterAddress, GG * 100); + + // When + var makeGuild = new MakeGuild(validatorPrivateKey.Address); + var actionContext = new ActionContext { - var action = new MakeGuild(); - var plainValue = action.PlainValue; + PreviousState = world, + Signer = guildMasterAddress, + }; + world = makeGuild.Execute(actionContext); - var deserialized = new MakeGuild(); - deserialized.LoadPlainValue(plainValue); - } + // Then + var guildRepository = new GuildRepository(world, new ActionContext()); + var validatorRepository = new ValidatorRepository(world, new ActionContext()); + var guildDelegatee = guildRepository.GetDelegatee(validatorPrivateKey.Address); + var validatorDelegatee = validatorRepository.GetDelegatee(validatorPrivateKey.Address); + var guildAddress = guildRepository.GetJoinedGuild(guildMasterAddress); + Assert.NotNull(guildAddress); + var guild = guildRepository.GetGuild(guildAddress.Value); + Assert.Equal(guildMasterAddress, guild.GuildMasterAddress); + Assert.Equal(SharePerGG * 100, guildDelegatee.TotalShares); + Assert.Equal(SharePerGG * 100, validatorDelegatee.TotalShares); + } + + [Fact] + public void Execute_AlreadyGuildOwner_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - [Fact] - public void Execute() + // When + var makeGuild = new MakeGuild(validatorKey.Address); + var actionContext = new ActionContext { - IWorld world = World; - var validatorPrivateKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - world = EnsureToMintAsset(world, validatorPrivateKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorPrivateKey.PublicKey); - var action = new MakeGuild(validatorPrivateKey.Address); - - world = action.ExecutePublic(new ActionContext - { - PreviousState = world, - Signer = guildMasterAddress, - }); - - var repository = new GuildRepository(world, new ActionContext()); - var guildAddress = repository.GetJoinedGuild(guildMasterAddress); - Assert.NotNull(guildAddress); - var guild = repository.GetGuild(guildAddress.Value); - Assert.Equal(guildMasterAddress, guild.GuildMasterAddress); - } + PreviousState = world, + Signer = guildMasterAddress, + }; + + // Then + var exception = Assert.Throws( + () => makeGuild.Execute(actionContext)); + Assert.Equal("The signer already has a guild.", exception.Message); + } + + [Fact] + public void Execute_ByValidator_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + + // When + var makeGuild = new MakeGuild(validatorKey.Address); + var actionContext = new ActionContext + { + PreviousState = world, + Signer = validatorKey.Address, + }; + + // Then + var exception = Assert.Throws( + () => makeGuild.Execute(actionContext)); + Assert.Equal("Validator cannot make a guild.", exception.Message); + } + + [Fact] + public void Execute_WithUnknowValidator_Throw() + { + // Given + var world = World; + var validatorPrivateKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + + // When + var makeGuild = new MakeGuild(validatorPrivateKey.Address); + var actionContext = new ActionContext + { + PreviousState = world, + Signer = guildMasterAddress, + }; + + // Then + var exception = Assert.Throws( + () => makeGuild.Execute(actionContext)); + Assert.Equal("The validator does not exist.", exception.Message); } } diff --git a/.Lib9c.Tests/Action/Guild/MoveGuildTest.cs b/.Lib9c.Tests/Action/Guild/MoveGuildTest.cs index d4e299d7f5..2186138914 100644 --- a/.Lib9c.Tests/Action/Guild/MoveGuildTest.cs +++ b/.Lib9c.Tests/Action/Guild/MoveGuildTest.cs @@ -1,65 +1,106 @@ -namespace Lib9c.Tests.Action.Guild +namespace Lib9c.Tests.Action.Guild; + +using System; +using Lib9c.Tests.Util; +using Libplanet.Crypto; +using Nekoyume.Action.Guild; +using Nekoyume.Model.Guild; +using Nekoyume.ValidatorDelegation; +using Xunit; + +public class MoveGuildTest : GuildTestBase { - using System; - using Lib9c.Tests.Util; - using Libplanet.Action.State; - using Libplanet.Crypto; - using Libplanet.Mocks; - using Libplanet.Types.Assets; - using Nekoyume; - using Nekoyume.Action.Guild; - using Nekoyume.Model.Guild; - using Nekoyume.Model.State; - using Nekoyume.Module; - using Nekoyume.Module.Guild; - using Xunit; + [Fact] + public void Serialization() + { + var guildAddress = AddressUtil.CreateGuildAddress(); + var action = new MoveGuild(guildAddress); + var plainValue = action.PlainValue; + + var deserialized = new MoveGuild(); + deserialized.LoadPlainValue(plainValue); + Assert.Equal(guildAddress, deserialized.GuildAddress); + } - public class MoveGuildTest : GuildTestBase + [Fact] + public void Execute() { - [Fact] - public void Serialization() + // Given + var world = World; + var validatorKey1 = new PrivateKey(); + var validatorKey2 = new PrivateKey(); + var agentAddress = AddressUtil.CreateAgentAddress(); + var guildMasterAddress1 = AddressUtil.CreateAgentAddress(); + var guildMasterAddress2 = AddressUtil.CreateAgentAddress(); + var guildAddress1 = AddressUtil.CreateGuildAddress(); + var guildAddress2 = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey1.PublicKey); + world = EnsureToCreateValidator(world, validatorKey2.PublicKey); + world = EnsureToMakeGuild(world, guildAddress1, guildMasterAddress1, validatorKey1.Address); + world = EnsureToMakeGuild(world, guildAddress2, guildMasterAddress2, validatorKey2.Address); + world = EnsureToPrepareGuildGold(world, agentAddress, GG * 100); + world = EnsureToJoinGuild(world, guildAddress1, agentAddress, 1L); + + // When + var moveGuild = new MoveGuild(guildAddress2); + var actionContext = new ActionContext { - var guildAddress = AddressUtil.CreateGuildAddress(); - var action = new MoveGuild(guildAddress); - var plainValue = action.PlainValue; + PreviousState = world, + Signer = agentAddress, + BlockIndex = 2L, + }; + world = moveGuild.Execute(actionContext); - var deserialized = new MoveGuild(); - deserialized.LoadPlainValue(plainValue); - Assert.Equal(guildAddress, deserialized.GuildAddress); - } + // Then + var guildRepository = new GuildRepository(world, actionContext); + var validatorRepository = new ValidatorRepository(world, actionContext); + var guildDelegatee1 = guildRepository.GetDelegatee(validatorKey1.Address); + var guildDelegatee2 = guildRepository.GetDelegatee(validatorKey2.Address); + var validatorDelegatee1 = validatorRepository.GetDelegatee(validatorKey1.Address); + var validatorDelegatee2 = validatorRepository.GetDelegatee(validatorKey2.Address); - [Fact] - public void Execute() - { - var validatorKey1 = new PrivateKey(); - var validatorKey2 = new PrivateKey(); - var agentAddress = AddressUtil.CreateAgentAddress(); - var guildMasterAddress1 = AddressUtil.CreateAgentAddress(); - var guildMasterAddress2 = AddressUtil.CreateAgentAddress(); - var guildAddress1 = AddressUtil.CreateGuildAddress(); - var guildAddress2 = AddressUtil.CreateGuildAddress(); + var guildParticipant = guildRepository.GetGuildParticipant(agentAddress); - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey1.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey1.PublicKey); - world = EnsureToMintAsset(world, validatorKey2.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey2.PublicKey); - world = EnsureToMakeGuild(world, guildAddress1, guildMasterAddress1, validatorKey1.Address); - world = EnsureToMakeGuild(world, guildAddress2, guildMasterAddress2, validatorKey2.Address); - world = EnsureToJoinGuild(world, guildAddress1, agentAddress, 1L); + Assert.Equal(guildAddress2, guildParticipant.GuildAddress); + Assert.Equal(0, guildDelegatee1.TotalShares); + Assert.Equal(0, validatorDelegatee1.TotalShares); + Assert.Equal(100 * SharePerGG, guildDelegatee2.TotalShares); + Assert.Equal(100 * SharePerGG, validatorDelegatee2.TotalShares); + } - var moveGuild = new MoveGuild(guildAddress2); - var actionContext = new ActionContext - { - PreviousState = world, - Signer = agentAddress, - }; - world = moveGuild.Execute(actionContext); + [Fact] + public void Execute_ToGuildDelegatingToTombstonedValidator_Throw() + { + // Given + var world = World; + var validatorKey1 = new PrivateKey(); + var validatorKey2 = new PrivateKey(); + var agentAddress = AddressUtil.CreateAgentAddress(); + var guildMasterAddress1 = AddressUtil.CreateAgentAddress(); + var guildMasterAddress2 = AddressUtil.CreateAgentAddress(); + var guildAddress1 = AddressUtil.CreateGuildAddress(); + var guildAddress2 = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey1.PublicKey); + world = EnsureToCreateValidator(world, validatorKey2.PublicKey); + world = EnsureToMakeGuild(world, guildAddress1, guildMasterAddress1, validatorKey1.Address); + world = EnsureToMakeGuild(world, guildAddress2, guildMasterAddress2, validatorKey2.Address); + world = EnsureToPrepareGuildGold(world, agentAddress, GG * 100); + world = EnsureToJoinGuild(world, guildAddress1, agentAddress, 1L); + world = EnsureToTombstoneValidator(world, validatorKey2.Address); - var repository = new GuildRepository(world, actionContext); - var guildParticipant = repository.GetGuildParticipant(agentAddress); + // When + var moveGuild = new MoveGuild(guildAddress2); + var actionContext = new ActionContext + { + PreviousState = world, + Signer = agentAddress, + BlockIndex = 2L, + }; - Assert.Equal(guildAddress2, guildParticipant.GuildAddress); - } + // Then + var exception = Assert.Throws( + () => moveGuild.Execute(actionContext)); + Assert.Equal( + "The validator of the guild to move to has been tombstoned.", exception.Message); } } diff --git a/.Lib9c.Tests/Action/Guild/QuitGuildTest.cs b/.Lib9c.Tests/Action/Guild/QuitGuildTest.cs index 51d10b2896..4600712c6c 100644 --- a/.Lib9c.Tests/Action/Guild/QuitGuildTest.cs +++ b/.Lib9c.Tests/Action/Guild/QuitGuildTest.cs @@ -1,57 +1,143 @@ -namespace Lib9c.Tests.Action.Guild +namespace Lib9c.Tests.Action.Guild; + +using System; +using Lib9c.Tests.Util; +using Libplanet.Crypto; +using Nekoyume.Action; +using Nekoyume.Action.Guild; +using Nekoyume.Model.Guild; +using Nekoyume.TypedAddress; +using Nekoyume.ValidatorDelegation; +using Xunit; + +public class QuitGuildTest : GuildTestBase { - using System; - using Lib9c.Tests.Util; - using Libplanet.Action.State; - using Libplanet.Crypto; - using Libplanet.Mocks; - using Libplanet.Types.Assets; - using Nekoyume; - using Nekoyume.Action; - using Nekoyume.Action.Guild; - using Nekoyume.Model.Guild; - using Nekoyume.Model.State; - using Nekoyume.Module; - using Nekoyume.Module.Guild; - using Xunit; - - public class QuitGuildTest : GuildTestBase + [Fact] + public void Serialization() + { + var action = new QuitGuild(); + var plainValue = action.PlainValue; + + var deserialized = new QuitGuild(); + deserialized.LoadPlainValue(plainValue); + } + + [Fact] + public void Execute() { - [Fact] - public void Serialization() + // Given + var world = World; + var validatorKey = new PrivateKey(); + var agentAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToPrepareGuildGold(world, agentAddress, GG * 100); + world = EnsureToJoinGuild(world, guildAddress, agentAddress, 1L); + + // When + var quitGuild = new QuitGuild(); + var actionContext = new ActionContext { - var action = new QuitGuild(); - var plainValue = action.PlainValue; + PreviousState = world, + Signer = agentAddress, + BlockIndex = 2L, + }; + world = quitGuild.Execute(actionContext); + + // Then + var guildRepository = new GuildRepository(world, actionContext); + var validatorRepository = new ValidatorRepository(world, actionContext); + var guildDelegatee = guildRepository.GetDelegatee(validatorKey.Address); + var validatorDelegatee = validatorRepository.GetDelegatee(validatorKey.Address); + Assert.Throws( + () => guildRepository.GetGuildParticipant(agentAddress)); + Assert.Equal(0, guildDelegatee.TotalShares); + Assert.Equal(0, validatorDelegatee.TotalShares); + } - var deserialized = new QuitGuild(); - deserialized.LoadPlainValue(plainValue); - } + [Fact] + public void Execute_SignerDoesNotHaveGuild_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var agentAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - [Fact] - public void Execute() + // When + var quitGuild = new QuitGuild(); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var agentAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - world = EnsureToJoinGuild(world, guildAddress, agentAddress, 1L); - - var quitGuild = new QuitGuild(); - var actionContext = new ActionContext - { - PreviousState = world, - Signer = agentAddress, - }; - world = quitGuild.Execute(actionContext); - - var repository = new GuildRepository(world, actionContext); - Assert.Throws( - () => repository.GetGuildParticipant(agentAddress)); - } + PreviousState = world, + Signer = agentAddress, + BlockIndex = 2L, + }; + + // Then + var exception = Assert.Throws( + () => quitGuild.Execute(actionContext)); + Assert.Equal("The signer does not join any guild.", exception.Message); + } + + [Fact] + public void Execute_FromUnknownGuild_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var agentAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + world = EnsureToSetGuildParticipant(world, agentAddress, guildAddress); + + // When + var quitGuild = new QuitGuild(); + var actionContext = new ActionContext + { + PreviousState = world, + Signer = agentAddress, + BlockIndex = 2L, + }; + + // Then + var exception = Assert.Throws( + () => quitGuild.Execute(actionContext)); + Assert.Equal("There is no such guild.", exception.Message); + } + + [Fact] + public void Execute_SignerIsGuildMaster_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var agentAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToPrepareGuildGold(world, guildMasterAddress, GG * 100); + world = EnsureToJoinGuild(world, guildAddress, agentAddress, 1L); + + // When + var quitGuild = new QuitGuild(); + var actionContext = new ActionContext + { + PreviousState = world, + Signer = guildMasterAddress, + BlockIndex = 2L, + }; + + // Then + var exception = Assert.Throws( + () => quitGuild.Execute(actionContext)); + Assert.Equal( + expected: "The signer is a guild master. Guild master cannot quit the guild.", + actual: exception.Message); } } diff --git a/.Lib9c.Tests/Action/Guild/RemoveGuildTest.cs b/.Lib9c.Tests/Action/Guild/RemoveGuildTest.cs index a416aafd5b..4184104ba1 100644 --- a/.Lib9c.Tests/Action/Guild/RemoveGuildTest.cs +++ b/.Lib9c.Tests/Action/Guild/RemoveGuildTest.cs @@ -1,150 +1,215 @@ -namespace Lib9c.Tests.Action.Guild +namespace Lib9c.Tests.Action.Guild; + +using System; +using Lib9c.Tests.Util; +using Libplanet.Crypto; +using Nekoyume.Action; +using Nekoyume.Action.Guild; +using Nekoyume.Model.Guild; +using Nekoyume.Module.Guild; +using Nekoyume.ValidatorDelegation; +using Xunit; + +public class RemoveGuildTest : GuildTestBase { - using System; - using Lib9c.Tests.Util; - using Libplanet.Action.State; - using Libplanet.Crypto; - using Nekoyume.Action; - using Nekoyume.Action.Guild; - using Nekoyume.Model.Guild; - using Nekoyume.Model.Stake; - using Nekoyume.Module.Guild; - using Xunit; - - public class RemoveGuildTest : GuildTestBase + [Fact] + public void Serialization() { - [Fact] - public void Serialization() + var action = new RemoveGuild(); + var plainValue = action.PlainValue; + + var deserialized = new RemoveGuild(); + deserialized.LoadPlainValue(plainValue); + } + + [Fact] + public void Execute() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + + // When + var removeGuild = new RemoveGuild(); + var actionContext = new ActionContext { - var action = new RemoveGuild(); - var plainValue = action.PlainValue; + PreviousState = world, + Signer = guildMasterAddress, + }; + world = removeGuild.Execute(actionContext); + + // Then + var guildRepository = new GuildRepository(world, actionContext); + var validatorRepository = new ValidatorRepository(world, actionContext); + var guildDelegatee = guildRepository.GetDelegatee(validatorKey.Address); + var validatorDelegatee = validatorRepository.GetDelegatee(validatorKey.Address); + + Assert.Throws(() => guildRepository.GetGuild(guildAddress)); + Assert.Equal(0, guildDelegatee.TotalShares); + Assert.Equal(0, validatorDelegatee.TotalShares); + } - var deserialized = new RemoveGuild(); - deserialized.LoadPlainValue(plainValue); - } + [Fact] + public void Execute_UnknownGuild_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToSetGuildParticipant(world, guildMasterAddress, guildAddress); + + // When + var removeGuild = new RemoveGuild(); + var actionContext = new ActionContext + { + PreviousState = world, + Signer = guildMasterAddress, + }; + + // Then + var exception = Assert.Throws( + () => removeGuild.Execute(actionContext)); + Assert.Equal("There is no such guild.", exception.Message); + } - [Fact] - public void Execute() + [Fact] + public void Execute_ByGuildMember_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToJoinGuild(world, guildAddress, guildMemberAddress, 1L); + + // When + var removeGuild = new RemoveGuild(); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - - var removeGuild = new RemoveGuild(); - var actionContext = new ActionContext - { - PreviousState = world, - Signer = guildMasterAddress, - }; - world = removeGuild.Execute(actionContext); - - var repository = new GuildRepository(world, actionContext); - Assert.Throws(() => repository.GetGuild(guildAddress)); - } - - [Fact] - public void Execute_ByGuildMember_Throw() + PreviousState = world, + Signer = guildMemberAddress, + }; + + // Then + var exception = Assert.Throws( + () => removeGuild.Execute(actionContext)); + Assert.Equal("The signer is not a guild master.", exception.Message); + } + + [Fact] + public void Execute_GuildHasMember_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildParticipantAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToPrepareGuildGold(world, guildMasterAddress, GG * 100); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToJoinGuild(world, guildAddress, guildParticipantAddress, 1L); + + // When + var removeGuild = new RemoveGuild(); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var guildMemberAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - world = EnsureToJoinGuild(world, guildAddress, guildMemberAddress, 1L); - - var actionContext = new ActionContext - { - PreviousState = world, - Signer = guildMemberAddress, - }; - var removeGuild = new RemoveGuild(); - - Assert.Throws(() => removeGuild.Execute(actionContext)); - } - - [Fact] - public void Execute_WhenDelegationExists_Throw() + PreviousState = world, + Signer = guildMasterAddress, + }; + + // Then + var exception = Assert.Throws( + () => removeGuild.Execute(actionContext)); + Assert.Equal("There are remained participants in the guild.", exception.Message); + } + + [Fact] + public void Execute_GuildHasBond_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToPrepareGuildGold(world, guildMasterAddress, GG * 100); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + + // When + var removeGuild = new RemoveGuild(); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var guildParticipantAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMintAsset(world, StakeState.DeriveAddress(guildMasterAddress), GG * 100); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - world = EnsureToJoinGuild(world, guildAddress, guildParticipantAddress, 1L); - - var actionContext = new ActionContext - { - PreviousState = world, - Signer = guildMasterAddress, - }; - var removeGuild = new RemoveGuild(); - - Assert.Throws(() => removeGuild.Execute(actionContext)); - } - - [Fact] - public void Execute_ByNonGuildMember_Throw() + PreviousState = world, + Signer = guildMasterAddress, + }; + + // Then + var exception = Assert.Throws( + () => removeGuild.Execute(actionContext)); + Assert.Equal("The signer has a bond with the validator.", exception.Message); + } + + [Fact] + public void Execute_ByNonGuildMember_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var otherAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + + // When + var removeGuild = new RemoveGuild(); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var otherAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - - var actionContext = new ActionContext - { - PreviousState = world, - Signer = otherAddress, - }; - var removeGuild = new RemoveGuild(); - - Assert.Throws(() => removeGuild.Execute(actionContext)); - } - - [Fact] - public void Execute_ResetBannedAddresses() + PreviousState = world, + Signer = otherAddress, + }; + + // Then + var exception = Assert.Throws( + () => removeGuild.Execute(actionContext)); + Assert.Equal("The signer does not join any guild.", exception.Message); + } + + [Fact] + public void Execute_ResetBannedAddresses() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + var bannedAddress = AddressUtil.CreateAgentAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToJoinGuild(world, guildAddress, bannedAddress, 1L); + world = EnsureToBanGuildMember(world, guildMasterAddress, bannedAddress); + + // When + var removeGuild = new RemoveGuild(); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - var bannedAddress = AddressUtil.CreateAgentAddress(); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - world = EnsureToJoinGuild(world, guildAddress, bannedAddress, 1L); - world = EnsureToBanGuildMember(world, guildAddress, guildMasterAddress, bannedAddress); - - var actionContext = new ActionContext - { - PreviousState = world, - Signer = guildMasterAddress, - }; - var removeGuild = new RemoveGuild(); - world = removeGuild.Execute(actionContext); - - var repository = new GuildRepository(world, actionContext); - Assert.False(repository.IsBanned(guildAddress, bannedAddress)); - } + PreviousState = world, + Signer = guildMasterAddress, + }; + world = removeGuild.Execute(actionContext); + + // Then + var repository = new GuildRepository(world, actionContext); + Assert.False(repository.IsBanned(guildAddress, bannedAddress)); } } diff --git a/.Lib9c.Tests/Action/Guild/UnbanGuildMemberTest.cs b/.Lib9c.Tests/Action/Guild/UnbanGuildMemberTest.cs index 73f918653c..932d77f00d 100644 --- a/.Lib9c.Tests/Action/Guild/UnbanGuildMemberTest.cs +++ b/.Lib9c.Tests/Action/Guild/UnbanGuildMemberTest.cs @@ -1,122 +1,224 @@ -namespace Lib9c.Tests.Action.Guild +namespace Lib9c.Tests.Action.Guild; + +using System; +using Lib9c.Tests.Util; +using Libplanet.Action.State; +using Libplanet.Crypto; +using Nekoyume.Action.Guild; +using Nekoyume.Model.Guild; +using Nekoyume.Module.Guild; +using Xunit; + +public class UnbanGuildMemberTest : GuildTestBase { - using System; - using Lib9c.Tests.Util; - using Libplanet.Action.State; - using Libplanet.Crypto; - using Nekoyume.Action.Guild; - using Nekoyume.Model.Guild; - using Nekoyume.Module.Guild; - using Xunit; - - public class UnbanGuildMemberTest : GuildTestBase + [Fact] + public void Serialization() { - [Fact] - public void Serialization() + var guildMemberAddress = new PrivateKey().Address; + var action = new UnbanGuildMember(guildMemberAddress); + var plainValue = action.PlainValue; + + var deserialized = new UnbanGuildMember(); + deserialized.LoadPlainValue(plainValue); + Assert.Equal(guildMemberAddress, deserialized.Target); + } + + [Fact] + public void Execute() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToJoinGuild(world, guildAddress, targetGuildMemberAddress, 1L); + world = EnsureToBanGuildMember(world, guildMasterAddress, targetGuildMemberAddress); + + // When + var unbanGuildMember = new UnbanGuildMember(targetGuildMemberAddress); + var actionContext = new ActionContext { - var guildMemberAddress = new PrivateKey().Address; - var action = new UnbanGuildMember(guildMemberAddress); - var plainValue = action.PlainValue; + PreviousState = world, + Signer = guildMasterAddress, + }; + world = unbanGuildMember.Execute(actionContext); + + // Then + var repository = new GuildRepository(world, actionContext); + Assert.False(repository.IsBanned(guildAddress, targetGuildMemberAddress)); + Assert.Null(repository.GetJoinedGuild(targetGuildMemberAddress)); + } - var deserialized = new UnbanGuildMember(); - deserialized.LoadPlainValue(plainValue); - Assert.Equal(guildMemberAddress, deserialized.Target); - } + [Fact] + public void Execute_SignerDoesNotHaveGuild_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + + // When + var unbanGuildMember = new UnbanGuildMember(guildMemberAddress); + var actionContext = new ActionContext + { + PreviousState = world, + Signer = guildMasterAddress, + }; + + // Then + var exception = Assert.Throws( + () => unbanGuildMember.Execute(actionContext)); + Assert.Equal("The signer does not join any guild.", exception.Message); + } - [Fact] - public void Execute() + [Fact] + public void Execute_UnknownGuild_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + var unknownGuildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToSetGuildParticipant(world, guildMasterAddress, unknownGuildAddress); + + // When + var unbanGuildMember = new UnbanGuildMember(guildMemberAddress); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - world = EnsureToJoinGuild(world, guildAddress, targetGuildMemberAddress, 1L); - world = EnsureToBanGuildMember(world, guildAddress, guildMasterAddress, targetGuildMemberAddress); - - var unbanGuildMember = new UnbanGuildMember(targetGuildMemberAddress); - var actionContext = new ActionContext - { - PreviousState = world, - Signer = guildMasterAddress, - }; - world = unbanGuildMember.Execute(actionContext); - - var repository = new GuildRepository(world, actionContext); - Assert.False(repository.IsBanned(guildAddress, targetGuildMemberAddress)); - Assert.Null(repository.GetJoinedGuild(targetGuildMemberAddress)); - } - - [Fact] - public void Unban_By_GuildMember() + PreviousState = world, + Signer = guildMasterAddress, + }; + + // Then + var exception = Assert.Throws( + () => unbanGuildMember.Execute(actionContext)); + Assert.Equal("There is no such guild.", exception.Message); + } + + [Fact] + public void Execute_SignerIsNotGuildMaster_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToJoinGuild(world, guildAddress, guildMemberAddress, 1L); + + // When + var unbanGuildMember = new UnbanGuildMember(guildMemberAddress); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var guildMemberAddress = AddressUtil.CreateAgentAddress(); - var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - - var action = new UnbanGuildMember(targetGuildMemberAddress); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - world = EnsureToJoinGuild(world, guildAddress, guildMemberAddress, 1L); - world = EnsureToBanGuildMember(world, guildAddress, guildMasterAddress, targetGuildMemberAddress); - - var repository = new GuildRepository(world, new ActionContext()); - - // GuildMember tries to ban other guild member. - Assert.Throws(() => action.Execute(new ActionContext - { - PreviousState = repository.World, - Signer = guildMemberAddress, - })); - - // GuildMember tries to ban itself. - Assert.Throws(() => action.Execute(new ActionContext - { - PreviousState = repository.World, - Signer = targetGuildMemberAddress, - })); - } - - [Fact] - public void Unban_By_GuildMaster() + PreviousState = world, + Signer = guildMemberAddress, + }; + + // Then + var exception = Assert.Throws( + () => unbanGuildMember.Execute(actionContext)); + Assert.Equal("The signer is not a guild master.", exception.Message); + } + + [Fact] + public void Execute_TargetIsNotBanned_Throw() + { + // Given + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + + // When + var unbanGuildMember = new UnbanGuildMember(guildMasterAddress); + var actionContext = new ActionContext { - var validatorKey = new PrivateKey(); - var guildMasterAddress = AddressUtil.CreateAgentAddress(); - var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); - var guildAddress = AddressUtil.CreateGuildAddress(); - - var action = new UnbanGuildMember(targetGuildMemberAddress); - - IWorld world = World; - world = EnsureToMintAsset(world, validatorKey.Address, GG * 100); - world = EnsureToCreateValidator(world, validatorKey.PublicKey); - world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); - world = EnsureToJoinGuild(world, guildAddress, targetGuildMemberAddress, 1L); - world = EnsureToBanGuildMember(world, guildAddress, guildMasterAddress, targetGuildMemberAddress); - - var repository = new GuildRepository(world, new ActionContext()); - - Assert.True(repository.IsBanned(guildAddress, targetGuildMemberAddress)); - Assert.Null(repository.GetJoinedGuild(targetGuildMemberAddress)); - - world = action.Execute(new ActionContext - { - PreviousState = repository.World, - Signer = guildMasterAddress, - }); - - repository.UpdateWorld(world); - Assert.False(repository.IsBanned(guildAddress, targetGuildMemberAddress)); - Assert.Null(repository.GetJoinedGuild(targetGuildMemberAddress)); - } + PreviousState = world, + Signer = guildMasterAddress, + }; + + // Then + var exception = Assert.Throws( + () => unbanGuildMember.Execute(actionContext)); + Assert.Equal("The target is not banned.", exception.Message); + } + + [Fact] + public void Unban_By_GuildMember() + { + var world = World; + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var guildMemberAddress = AddressUtil.CreateAgentAddress(); + var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + + var action = new UnbanGuildMember(targetGuildMemberAddress); + + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToJoinGuild(world, guildAddress, guildMemberAddress, 1L); + world = EnsureToBanGuildMember(world, guildMasterAddress, targetGuildMemberAddress); + + var repository = new GuildRepository(world, new ActionContext()); + + // GuildMember tries to ban other guild member. + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = repository.World, + Signer = guildMemberAddress, + })); + + // GuildMember tries to ban itself. + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = repository.World, + Signer = targetGuildMemberAddress, + })); + } + + [Fact] + public void Unban_By_GuildMaster() + { + var validatorKey = new PrivateKey(); + var guildMasterAddress = AddressUtil.CreateAgentAddress(); + var targetGuildMemberAddress = AddressUtil.CreateAgentAddress(); + var guildAddress = AddressUtil.CreateGuildAddress(); + + var action = new UnbanGuildMember(targetGuildMemberAddress); + + IWorld world = World; + world = EnsureToCreateValidator(world, validatorKey.PublicKey); + world = EnsureToMakeGuild(world, guildAddress, guildMasterAddress, validatorKey.Address); + world = EnsureToJoinGuild(world, guildAddress, targetGuildMemberAddress, 1L); + world = EnsureToBanGuildMember(world, guildMasterAddress, targetGuildMemberAddress); + + var repository = new GuildRepository(world, new ActionContext()); + + Assert.True(repository.IsBanned(guildAddress, targetGuildMemberAddress)); + Assert.Null(repository.GetJoinedGuild(targetGuildMemberAddress)); + + world = action.Execute(new ActionContext + { + PreviousState = repository.World, + Signer = guildMasterAddress, + }); + + repository.UpdateWorld(world); + Assert.False(repository.IsBanned(guildAddress, targetGuildMemberAddress)); + Assert.Null(repository.GetJoinedGuild(targetGuildMemberAddress)); } } diff --git a/.Lib9c.Tests/Action/ValidatorDelegation/ValidatorDelegationTestBase.cs b/.Lib9c.Tests/Action/ValidatorDelegation/ValidatorDelegationTestBase.cs index e1b05ca90c..d7ace7f651 100644 --- a/.Lib9c.Tests/Action/ValidatorDelegation/ValidatorDelegationTestBase.cs +++ b/.Lib9c.Tests/Action/ValidatorDelegation/ValidatorDelegationTestBase.cs @@ -199,7 +199,7 @@ protected static IWorld EnsureMakeGuild( RandomSeed = seed, }; var makeGuild = new MakeGuild(validatorAddress); - return makeGuild.ExecutePublic(actionContext); + return makeGuild.Execute(actionContext); } protected static IWorld EnsureJoinGuild(