From 85b33a211a8980647a6045c9e59382066632a7a5 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 28 Mar 2024 07:34:11 +0900 Subject: [PATCH 1/9] Moved GetBalance from IWorldState to external --- Libplanet.Action/State/IWorldExtensions.cs | 32 ++++++++++++++++++++++ Libplanet.Action/State/IWorldState.cs | 11 -------- Libplanet.Action/State/World.cs | 21 ++++---------- Libplanet.Action/State/WorldBaseState.cs | 10 ------- Libplanet.Mocks/MockWorldState.cs | 6 ---- 5 files changed, 37 insertions(+), 43 deletions(-) create mode 100644 Libplanet.Action/State/IWorldExtensions.cs diff --git a/Libplanet.Action/State/IWorldExtensions.cs b/Libplanet.Action/State/IWorldExtensions.cs new file mode 100644 index 00000000000..f7a21dce35c --- /dev/null +++ b/Libplanet.Action/State/IWorldExtensions.cs @@ -0,0 +1,32 @@ +using System.Diagnostics.Contracts; +using Bencodex.Types; +using Libplanet.Crypto; +using Libplanet.Types.Assets; +using static Libplanet.Action.State.KeyConverters; + +namespace Libplanet.Action.State +{ + public static class IWorldExtensions + { + /// + /// Queries 's balance of the . + /// + /// The owner address to query. + /// The currency type to query. + /// + /// The 's balance of the . + /// + [Pure] + public static FungibleAssetValue GetBalance( + this IWorldState worldState, + Address address, + Currency currency) + { + IAccountState account = worldState.GetAccountState(ReservedAddresses.LegacyAccount); + IValue? value = account.Trie.Get(ToFungibleAssetKey(address, currency)); + return value is Integer i + ? FungibleAssetValue.FromRawValue(currency, i) + : currency * 0; + } + } +} diff --git a/Libplanet.Action/State/IWorldState.cs b/Libplanet.Action/State/IWorldState.cs index a0231404f7b..0475e7917b2 100644 --- a/Libplanet.Action/State/IWorldState.cs +++ b/Libplanet.Action/State/IWorldState.cs @@ -52,17 +52,6 @@ public interface IWorldState [Pure] IAccountState GetAccountState(Address address); - /// - /// Queries 's balance of the . - /// - /// The owner address to query. - /// The currency type to query. - /// - /// The 's balance of the . - /// - [Pure] - FungibleAssetValue GetBalance(Address address, Currency currency); - /// /// Returns the total supply of a . /// diff --git a/Libplanet.Action/State/World.cs b/Libplanet.Action/State/World.cs index d87916a3613..52c7305320d 100644 --- a/Libplanet.Action/State/World.cs +++ b/Libplanet.Action/State/World.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Immutable; using System.Diagnostics.Contracts; using System.Numerics; using Bencodex.Types; @@ -68,16 +67,6 @@ public IWorld SetAccount(Address address, IAccount account) return new World(_baseState, Delta.SetAccount(address, account)); } - /// - public FungibleAssetValue GetBalance(Address address, Currency currency) - { - IAccountState account = GetAccountState(ReservedAddresses.LegacyAccount); - IValue? value = account.Trie.Get(ToFungibleAssetKey(address, currency)); - return value is Integer i - ? FungibleAssetValue.FromRawValue(currency, i) - : currency * 0; - } - /// public FungibleAssetValue GetTotalSupply(Currency currency) { @@ -124,7 +113,7 @@ public IWorld MintAsset(IActionContext context, Address recipient, FungibleAsset ); } - FungibleAssetValue balance = GetBalance(recipient, currency); + FungibleAssetValue balance = this.GetBalance(recipient, currency); BigInteger rawBalance = (balance + value).RawValue; if (currency.TotalSupplyTrackable) @@ -170,7 +159,7 @@ public IWorld BurnAsset(IActionContext context, Address owner, FungibleAssetValu throw new CurrencyPermissionException(msg, context.Signer, currency); } - FungibleAssetValue balance = GetBalance(owner, currency); + FungibleAssetValue balance = this.GetBalance(owner, currency); if (balance < value) { @@ -251,8 +240,8 @@ private IWorld TransferAssetV0( } Currency currency = value.Currency; - FungibleAssetValue senderBalance = GetBalance(sender, currency); - FungibleAssetValue recipientBalance = GetBalance(recipient, currency); + FungibleAssetValue senderBalance = this.GetBalance(sender, currency); + FungibleAssetValue recipientBalance = this.GetBalance(recipient, currency); if (!allowNegativeBalance && senderBalance < value) { @@ -281,7 +270,7 @@ private IWorld TransferAssetV1( } Currency currency = value.Currency; - FungibleAssetValue senderBalance = GetBalance(sender, currency); + FungibleAssetValue senderBalance = this.GetBalance(sender, currency); if (!allowNegativeBalance && senderBalance < value) { diff --git a/Libplanet.Action/State/WorldBaseState.cs b/Libplanet.Action/State/WorldBaseState.cs index ace4de4c8f3..053f96d0600 100644 --- a/Libplanet.Action/State/WorldBaseState.cs +++ b/Libplanet.Action/State/WorldBaseState.cs @@ -49,16 +49,6 @@ public IAccountState GetAccountState(Address address) } } - /// - public FungibleAssetValue GetBalance(Address address, Currency currency) - { - IAccountState account = GetAccountState(ReservedAddresses.LegacyAccount); - IValue? value = account.Trie.Get(ToFungibleAssetKey(address, currency)); - return value is Integer i - ? FungibleAssetValue.FromRawValue(currency, i) - : currency * 0; - } - /// public FungibleAssetValue GetTotalSupply(Currency currency) { diff --git a/Libplanet.Mocks/MockWorldState.cs b/Libplanet.Mocks/MockWorldState.cs index 301e281cdef..34b5706236b 100644 --- a/Libplanet.Mocks/MockWorldState.cs +++ b/Libplanet.Mocks/MockWorldState.cs @@ -97,12 +97,6 @@ public IAccountState GetAccountState(Address address) => ? _stateStore.GetStateRoot(new HashDigest(stateRootNotNull)) : _stateStore.GetStateRoot(null)); - public FungibleAssetValue GetBalance(Address address, Currency currency) => - GetAccountState(ReservedAddresses.LegacyAccount).Trie - .Get(ToFungibleAssetKey(address, currency)) is Integer i - ? FungibleAssetValue.FromRawValue(currency, i) - : currency * 0; - public FungibleAssetValue GetTotalSupply(Currency currency) => GetAccountState(ReservedAddresses.LegacyAccount).Trie .Get(ToTotalSupplyKey(currency)) is Integer i From 51a2e72b64c1c34a8ae2206fa4eb93377dff3616 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 28 Mar 2024 07:38:15 +0900 Subject: [PATCH 2/9] Moved GetTotalSupply from IWorldState to external --- Libplanet.Action/State/IWorldExtensions.cs | 26 ++++++++++++++++++++++ Libplanet.Action/State/IWorldState.cs | 12 ---------- Libplanet.Action/State/World.cs | 19 ++-------------- Libplanet.Action/State/WorldBaseState.cs | 15 ------------- Libplanet.Mocks/MockWorldState.cs | 6 ----- 5 files changed, 28 insertions(+), 50 deletions(-) diff --git a/Libplanet.Action/State/IWorldExtensions.cs b/Libplanet.Action/State/IWorldExtensions.cs index f7a21dce35c..e8b8018d6c3 100644 --- a/Libplanet.Action/State/IWorldExtensions.cs +++ b/Libplanet.Action/State/IWorldExtensions.cs @@ -28,5 +28,31 @@ public static FungibleAssetValue GetBalance( ? FungibleAssetValue.FromRawValue(currency, i) : currency * 0; } + + /// + /// Returns the total supply of a . + /// + /// The currency type to query. + /// The total supply of the . + /// + /// Thrown when the total supply of the + /// given is not trackable. + /// + [Pure] + public static FungibleAssetValue GetTotalSupply( + this IWorldState worldState, + Currency currency) + { + if (!currency.TotalSupplyTrackable) + { + throw TotalSupplyNotTrackableException.WithDefaultMessage(currency); + } + + IAccountState account = worldState.GetAccountState(ReservedAddresses.LegacyAccount); + IValue? value = account.Trie.Get(ToTotalSupplyKey(currency)); + return value is Integer i + ? FungibleAssetValue.FromRawValue(currency, i) + : currency * 0; + } } } diff --git a/Libplanet.Action/State/IWorldState.cs b/Libplanet.Action/State/IWorldState.cs index 0475e7917b2..e9589499e7e 100644 --- a/Libplanet.Action/State/IWorldState.cs +++ b/Libplanet.Action/State/IWorldState.cs @@ -52,18 +52,6 @@ public interface IWorldState [Pure] IAccountState GetAccountState(Address address); - /// - /// Returns the total supply of a . - /// - /// The currency type to query. - /// The total supply of the . - /// - /// Thrown when the total supply of the - /// given is not trackable. - /// - [Pure] - FungibleAssetValue GetTotalSupply(Currency currency); - /// /// Returns the validator set. /// diff --git a/Libplanet.Action/State/World.cs b/Libplanet.Action/State/World.cs index 52c7305320d..9ac3061cff0 100644 --- a/Libplanet.Action/State/World.cs +++ b/Libplanet.Action/State/World.cs @@ -67,21 +67,6 @@ public IWorld SetAccount(Address address, IAccount account) return new World(_baseState, Delta.SetAccount(address, account)); } - /// - public FungibleAssetValue GetTotalSupply(Currency currency) - { - if (!currency.TotalSupplyTrackable) - { - throw TotalSupplyNotTrackableException.WithDefaultMessage(currency); - } - - IAccountState account = GetAccountState(ReservedAddresses.LegacyAccount); - IValue? value = account.Trie.Get(ToTotalSupplyKey(currency)); - return value is Integer i - ? FungibleAssetValue.FromRawValue(currency, i) - : currency * 0; - } - /// public ValidatorSet GetValidatorSet() { @@ -118,7 +103,7 @@ public IWorld MintAsset(IActionContext context, Address recipient, FungibleAsset if (currency.TotalSupplyTrackable) { - var currentTotalSupply = GetTotalSupply(currency); + var currentTotalSupply = this.GetTotalSupply(currency); if (currency.MaximumSupply < currentTotalSupply + value) { var msg = $"The amount {value} attempted to be minted added to the current" @@ -171,7 +156,7 @@ public IWorld BurnAsset(IActionContext context, Address owner, FungibleAssetValu BigInteger rawBalance = (balance - value).RawValue; if (currency.TotalSupplyTrackable) { - var currentTotalSupply = GetTotalSupply(currency); + var currentTotalSupply = this.GetTotalSupply(currency); return UpdateFungibleAssets( owner, currency, diff --git a/Libplanet.Action/State/WorldBaseState.cs b/Libplanet.Action/State/WorldBaseState.cs index 053f96d0600..32d33a9fcb1 100644 --- a/Libplanet.Action/State/WorldBaseState.cs +++ b/Libplanet.Action/State/WorldBaseState.cs @@ -49,21 +49,6 @@ public IAccountState GetAccountState(Address address) } } - /// - public FungibleAssetValue GetTotalSupply(Currency currency) - { - if (!currency.TotalSupplyTrackable) - { - throw TotalSupplyNotTrackableException.WithDefaultMessage(currency); - } - - IAccountState account = GetAccountState(ReservedAddresses.LegacyAccount); - IValue? value = account.Trie.Get(ToTotalSupplyKey(currency)); - return value is Integer i - ? FungibleAssetValue.FromRawValue(currency, i) - : currency * 0; - } - /// public ValidatorSet GetValidatorSet() { diff --git a/Libplanet.Mocks/MockWorldState.cs b/Libplanet.Mocks/MockWorldState.cs index 34b5706236b..2cd342c6c5b 100644 --- a/Libplanet.Mocks/MockWorldState.cs +++ b/Libplanet.Mocks/MockWorldState.cs @@ -97,12 +97,6 @@ public IAccountState GetAccountState(Address address) => ? _stateStore.GetStateRoot(new HashDigest(stateRootNotNull)) : _stateStore.GetStateRoot(null)); - public FungibleAssetValue GetTotalSupply(Currency currency) => - GetAccountState(ReservedAddresses.LegacyAccount).Trie - .Get(ToTotalSupplyKey(currency)) is Integer i - ? FungibleAssetValue.FromRawValue(currency, i) - : currency * 0; - public ValidatorSet GetValidatorSet() => GetAccountState(ReservedAddresses.LegacyAccount).Trie .Get(ValidatorSetKey) is List l From 91d3a1359eb078526264a52f50d7657b603f222b Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 28 Mar 2024 07:59:57 +0900 Subject: [PATCH 3/9] Moved GetValidatorSet from IWorldState to external --- Libplanet.Action/State/IWorldExtensions.cs | 16 ++++++++++++++++ Libplanet.Action/State/IWorldState.cs | 8 -------- Libplanet.Action/State/World.cs | 12 +----------- Libplanet.Action/State/WorldBaseState.cs | 10 ---------- Libplanet.Mocks/MockWorldState.cs | 6 ------ 5 files changed, 17 insertions(+), 35 deletions(-) diff --git a/Libplanet.Action/State/IWorldExtensions.cs b/Libplanet.Action/State/IWorldExtensions.cs index e8b8018d6c3..4fb465ae496 100644 --- a/Libplanet.Action/State/IWorldExtensions.cs +++ b/Libplanet.Action/State/IWorldExtensions.cs @@ -2,6 +2,7 @@ using Bencodex.Types; using Libplanet.Crypto; using Libplanet.Types.Assets; +using Libplanet.Types.Consensus; using static Libplanet.Action.State.KeyConverters; namespace Libplanet.Action.State @@ -54,5 +55,20 @@ public static FungibleAssetValue GetTotalSupply( ? FungibleAssetValue.FromRawValue(currency, i) : currency * 0; } + + /// + /// Returns the validator set. + /// + /// The validator set of type . + /// + [Pure] + public static ValidatorSet GetValidatorSet(this IWorldState worldState) + { + IAccountState account = worldState.GetAccountState(ReservedAddresses.LegacyAccount); + IValue? value = account.Trie.Get(ValidatorSetKey); + return value is List list + ? new ValidatorSet(list) + : new ValidatorSet(); + } } } diff --git a/Libplanet.Action/State/IWorldState.cs b/Libplanet.Action/State/IWorldState.cs index e9589499e7e..05b5be32004 100644 --- a/Libplanet.Action/State/IWorldState.cs +++ b/Libplanet.Action/State/IWorldState.cs @@ -51,13 +51,5 @@ public interface IWorldState /// instead. [Pure] IAccountState GetAccountState(Address address); - - /// - /// Returns the validator set. - /// - /// The validator set of type . - /// - [Pure] - ValidatorSet GetValidatorSet(); } } diff --git a/Libplanet.Action/State/World.cs b/Libplanet.Action/State/World.cs index 9ac3061cff0..e1e7e3a109b 100644 --- a/Libplanet.Action/State/World.cs +++ b/Libplanet.Action/State/World.cs @@ -67,16 +67,6 @@ public IWorld SetAccount(Address address, IAccount account) return new World(_baseState, Delta.SetAccount(address, account)); } - /// - public ValidatorSet GetValidatorSet() - { - IAccountState account = GetAccountState(ReservedAddresses.LegacyAccount); - IValue? value = account.Trie.Get(ValidatorSetKey); - return value is List list - ? new ValidatorSet(list) - : new ValidatorSet(); - } - /// public IWorld MintAsset(IActionContext context, Address recipient, FungibleAssetValue value) { @@ -181,7 +171,7 @@ public IWorld TransferAsset( /// public IWorld SetValidator(Validator validator) => - UpdateValidatorSet(GetValidatorSet().Update(validator)); + UpdateValidatorSet(this.GetValidatorSet().Update(validator)); private IWorld UpdateFungibleAssets( Address address, diff --git a/Libplanet.Action/State/WorldBaseState.cs b/Libplanet.Action/State/WorldBaseState.cs index 32d33a9fcb1..4f920cefd7e 100644 --- a/Libplanet.Action/State/WorldBaseState.cs +++ b/Libplanet.Action/State/WorldBaseState.cs @@ -48,15 +48,5 @@ public IAccountState GetAccountState(Address address) : new AccountState(_stateStore.GetStateRoot(null)); } } - - /// - public ValidatorSet GetValidatorSet() - { - IAccountState account = GetAccountState(ReservedAddresses.LegacyAccount); - IValue? value = account.Trie.Get(ValidatorSetKey); - return value is List list - ? new ValidatorSet(list) - : new ValidatorSet(); - } } } diff --git a/Libplanet.Mocks/MockWorldState.cs b/Libplanet.Mocks/MockWorldState.cs index 2cd342c6c5b..753bcaba738 100644 --- a/Libplanet.Mocks/MockWorldState.cs +++ b/Libplanet.Mocks/MockWorldState.cs @@ -97,12 +97,6 @@ public IAccountState GetAccountState(Address address) => ? _stateStore.GetStateRoot(new HashDigest(stateRootNotNull)) : _stateStore.GetStateRoot(null)); - public ValidatorSet GetValidatorSet() => - GetAccountState(ReservedAddresses.LegacyAccount).Trie - .Get(ValidatorSetKey) is List l - ? new ValidatorSet(l) - : new ValidatorSet(); - /// /// Converts to "modern" if /// is . Otherwise, does nothing. From c51263cfea1f6e8ef9e93affc4578a91ec6dfee3 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 28 Mar 2024 10:45:58 +0900 Subject: [PATCH 4/9] Moved MintAsset from IWorld to external --- Libplanet.Action/State/IWorld.cs | 22 ------ Libplanet.Action/State/IWorldExtensions.cs | 92 ++++++++++++++++++++++ Libplanet.Action/State/World.cs | 47 ----------- 3 files changed, 92 insertions(+), 69 deletions(-) diff --git a/Libplanet.Action/State/IWorld.cs b/Libplanet.Action/State/IWorld.cs index 5746689f099..b54036cf1fc 100644 --- a/Libplanet.Action/State/IWorld.cs +++ b/Libplanet.Action/State/IWorld.cs @@ -77,28 +77,6 @@ public interface IWorld : IWorldState [Pure] IWorld SetAccount(Address address, IAccount account); - /// - /// Mints the fungible asset (i.e., in-game monetary), - /// and give it to the . - /// - /// The of the - /// executing this method. - /// The address who receives the minted asset. - /// The asset value to mint. - /// A new instance that the given is added to 's balance. - /// Thrown when the - /// is less than or equal to 0. - /// Thrown when a transaction signer - /// (or a miner in case of block actions) is not a member of the 's . - /// Thrown when the sum of the - /// to be minted and the current total supply amount of the - /// exceeds the - /// . - [Pure] - IWorld MintAsset(IActionContext context, Address recipient, FungibleAssetValue value); - /// /// Burns the fungible asset (i.e., in-game monetary) from /// 's balance. diff --git a/Libplanet.Action/State/IWorldExtensions.cs b/Libplanet.Action/State/IWorldExtensions.cs index 4fb465ae496..058ba349b81 100644 --- a/Libplanet.Action/State/IWorldExtensions.cs +++ b/Libplanet.Action/State/IWorldExtensions.cs @@ -1,4 +1,6 @@ +using System; using System.Diagnostics.Contracts; +using System.Numerics; using Bencodex.Types; using Libplanet.Crypto; using Libplanet.Types.Assets; @@ -30,6 +32,77 @@ public static FungibleAssetValue GetBalance( : currency * 0; } + /// + /// Mints the fungible asset (i.e., in-game monetary), + /// and give it to the . + /// + /// The of the + /// executing this method. + /// The address who receives the minted asset. + /// The asset value to mint. + /// A new instance that the given is added to 's balance. + /// Thrown when the + /// is less than or equal to 0. + /// Thrown when a transaction signer + /// (or a miner in case of block actions) is not a member of the 's . + /// Thrown when the sum of the + /// to be minted and the current total supply amount of the + /// exceeds the + /// . + [Pure] + public static IWorld MintAsset( + this IWorld world, + IActionContext context, + Address recipient, + FungibleAssetValue value) + { + if (value.Sign <= 0) + { + throw new ArgumentOutOfRangeException( + nameof(value), + "The value to mint has to be greater than zero." + ); + } + + Currency currency = value.Currency; + if (!currency.AllowsToMint(context.Signer)) + { + throw new CurrencyPermissionException( + $"The account {context.Signer} has no permission to mint currency {currency}.", + context.Signer, + currency + ); + } + + FungibleAssetValue balance = GetBalance(world, recipient, currency); + BigInteger rawBalance = (balance + value).RawValue; + + if (currency.TotalSupplyTrackable) + { + var currentTotalSupply = GetTotalSupply(world, currency); + if (currency.MaximumSupply < currentTotalSupply + value) + { + var msg = $"The amount {value} attempted to be minted added to the current" + + $" total supply of {currentTotalSupply} exceeds the" + + $" maximum allowed supply of {currency.MaximumSupply}."; + throw new SupplyOverflowException(msg, value); + } + + return UpdateFungibleAssets( + world, + recipient, + currency, + rawBalance, + (currentTotalSupply + value).RawValue); + } + else + { + return UpdateFungibleAssets(world, recipient, currency, rawBalance); + } + } + /// /// Returns the total supply of a . /// @@ -70,5 +143,24 @@ public static ValidatorSet GetValidatorSet(this IWorldState worldState) ? new ValidatorSet(list) : new ValidatorSet(); } + + private static IWorld UpdateFungibleAssets( + IWorld world, + Address address, + Currency currency, + BigInteger amount, + BigInteger? supplyAmount = null) + { + IAccount account = supplyAmount is { } sa + ? new Account(new AccountState( + world.GetAccount(ReservedAddresses.LegacyAccount).Trie + .Set(ToFungibleAssetKey(address, currency), new Integer(amount)) + .Set(ToTotalSupplyKey(currency), new Integer(sa)))) + : new Account(new AccountState( + world.GetAccount(ReservedAddresses.LegacyAccount).Trie + .Set(ToFungibleAssetKey(address, currency), new Integer(amount)))); + + return world.SetAccount(ReservedAddresses.LegacyAccount, account); + } } } diff --git a/Libplanet.Action/State/World.cs b/Libplanet.Action/State/World.cs index e1e7e3a109b..ca8c320be5f 100644 --- a/Libplanet.Action/State/World.cs +++ b/Libplanet.Action/State/World.cs @@ -67,53 +67,6 @@ public IWorld SetAccount(Address address, IAccount account) return new World(_baseState, Delta.SetAccount(address, account)); } - /// - public IWorld MintAsset(IActionContext context, Address recipient, FungibleAssetValue value) - { - if (value.Sign <= 0) - { - throw new ArgumentOutOfRangeException( - nameof(value), - "The value to mint has to be greater than zero." - ); - } - - Currency currency = value.Currency; - if (!currency.AllowsToMint(context.Signer)) - { - throw new CurrencyPermissionException( - $"The account {context.Signer} has no permission to mint currency {currency}.", - context.Signer, - currency - ); - } - - FungibleAssetValue balance = this.GetBalance(recipient, currency); - BigInteger rawBalance = (balance + value).RawValue; - - if (currency.TotalSupplyTrackable) - { - var currentTotalSupply = this.GetTotalSupply(currency); - if (currency.MaximumSupply < currentTotalSupply + value) - { - var msg = $"The amount {value} attempted to be minted added to the current" - + $" total supply of {currentTotalSupply} exceeds the" - + $" maximum allowed supply of {currency.MaximumSupply}."; - throw new SupplyOverflowException(msg, value); - } - - return UpdateFungibleAssets( - recipient, - currency, - rawBalance, - (currentTotalSupply + value).RawValue); - } - else - { - return UpdateFungibleAssets(recipient, currency, rawBalance); - } - } - /// public IWorld BurnAsset(IActionContext context, Address owner, FungibleAssetValue value) { From fa9a10860972b47e94c7d74d1f9c87ebb9956f2a Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 28 Mar 2024 10:48:58 +0900 Subject: [PATCH 5/9] Moved BurnAsset from IWorld to external --- Libplanet.Action/State/IWorld.cs | 20 ------- Libplanet.Action/State/IWorldExtensions.cs | 67 ++++++++++++++++++++++ Libplanet.Action/State/World.cs | 45 --------------- 3 files changed, 67 insertions(+), 65 deletions(-) diff --git a/Libplanet.Action/State/IWorld.cs b/Libplanet.Action/State/IWorld.cs index b54036cf1fc..ed15156ea2c 100644 --- a/Libplanet.Action/State/IWorld.cs +++ b/Libplanet.Action/State/IWorld.cs @@ -77,26 +77,6 @@ public interface IWorld : IWorldState [Pure] IWorld SetAccount(Address address, IAccount account); - /// - /// Burns the fungible asset (i.e., in-game monetary) from - /// 's balance. - /// - /// The of the - /// executing this method. - /// The address who owns the fungible asset to burn. - /// The fungible asset to burn. - /// A new instance that the given is subtracted from 's balance. - /// Thrown when the - /// is less than or equal to zero. - /// Thrown when a transaction signer - /// (or a miner in case of block actions) is not a member of the 's . - /// Thrown when the - /// has insufficient balance than to burn. - [Pure] - IWorld BurnAsset(IActionContext context, Address owner, FungibleAssetValue value); - /// /// Transfers the fungible asset (i.e., in-game monetary) /// from the to the . diff --git a/Libplanet.Action/State/IWorldExtensions.cs b/Libplanet.Action/State/IWorldExtensions.cs index 058ba349b81..3f6f94ea53a 100644 --- a/Libplanet.Action/State/IWorldExtensions.cs +++ b/Libplanet.Action/State/IWorldExtensions.cs @@ -103,6 +103,73 @@ public static IWorld MintAsset( } } + /// + /// Burns the fungible asset (i.e., in-game monetary) from + /// 's balance. + /// + /// The of the + /// executing this method. + /// The address who owns the fungible asset to burn. + /// The fungible asset to burn. + /// A new instance that the given is subtracted from 's balance. + /// Thrown when the + /// is less than or equal to zero. + /// Thrown when a transaction signer + /// (or a miner in case of block actions) is not a member of the 's . + /// Thrown when the + /// has insufficient balance than to burn. + [Pure] + public static IWorld BurnAsset( + this IWorld world, + IActionContext context, + Address owner, + FungibleAssetValue value) + { + string msg; + if (value.Sign <= 0) + { + throw new ArgumentOutOfRangeException( + nameof(value), + "The value to burn has to be greater than zero." + ); + } + + Currency currency = value.Currency; + if (!currency.AllowsToMint(context.Signer)) + { + msg = $"The account {context.Signer} has no permission to burn assets of " + + $"the currency {currency}."; + throw new CurrencyPermissionException(msg, context.Signer, currency); + } + + FungibleAssetValue balance = world.GetBalance(owner, currency); + + if (balance < value) + { + msg = $"The account {owner}'s balance of {currency} is insufficient to burn: " + + $"{balance} < {value}."; + throw new InsufficientBalanceException(msg, owner, balance); + } + + BigInteger rawBalance = (balance - value).RawValue; + if (currency.TotalSupplyTrackable) + { + var currentTotalSupply = world.GetTotalSupply(currency); + return UpdateFungibleAssets( + world, + owner, + currency, + rawBalance, + (currentTotalSupply - value).RawValue); + } + else + { + return UpdateFungibleAssets(world, owner, currency, rawBalance); + } + } + /// /// Returns the total supply of a . /// diff --git a/Libplanet.Action/State/World.cs b/Libplanet.Action/State/World.cs index ca8c320be5f..a4bf5d3c725 100644 --- a/Libplanet.Action/State/World.cs +++ b/Libplanet.Action/State/World.cs @@ -67,51 +67,6 @@ public IWorld SetAccount(Address address, IAccount account) return new World(_baseState, Delta.SetAccount(address, account)); } - /// - public IWorld BurnAsset(IActionContext context, Address owner, FungibleAssetValue value) - { - string msg; - if (value.Sign <= 0) - { - throw new ArgumentOutOfRangeException( - nameof(value), - "The value to burn has to be greater than zero." - ); - } - - Currency currency = value.Currency; - if (!currency.AllowsToMint(context.Signer)) - { - msg = $"The account {context.Signer} has no permission to burn assets of " + - $"the currency {currency}."; - throw new CurrencyPermissionException(msg, context.Signer, currency); - } - - FungibleAssetValue balance = this.GetBalance(owner, currency); - - if (balance < value) - { - msg = $"The account {owner}'s balance of {currency} is insufficient to burn: " + - $"{balance} < {value}."; - throw new InsufficientBalanceException(msg, owner, balance); - } - - BigInteger rawBalance = (balance - value).RawValue; - if (currency.TotalSupplyTrackable) - { - var currentTotalSupply = this.GetTotalSupply(currency); - return UpdateFungibleAssets( - owner, - currency, - rawBalance, - (currentTotalSupply - value).RawValue); - } - else - { - return UpdateFungibleAssets(owner, currency, rawBalance); - } - } - /// public IWorld TransferAsset( IActionContext context, From 9788ca9c6fdaac1fd46b36c1aea551ee645b684c Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 28 Mar 2024 11:19:06 +0900 Subject: [PATCH 6/9] Moved TransferAsset from IWorld to external --- Libplanet.Action/State/IWorld.cs | 37 -------- Libplanet.Action/State/IWorldExtensions.cs | 104 +++++++++++++++++++++ Libplanet.Action/State/IWorldState.cs | 2 - Libplanet.Action/State/World.cs | 91 ------------------ Libplanet.Action/State/WorldBaseState.cs | 2 - 5 files changed, 104 insertions(+), 132 deletions(-) diff --git a/Libplanet.Action/State/IWorld.cs b/Libplanet.Action/State/IWorld.cs index ed15156ea2c..633376f4597 100644 --- a/Libplanet.Action/State/IWorld.cs +++ b/Libplanet.Action/State/IWorld.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics.Contracts; using Libplanet.Crypto; -using Libplanet.Types.Assets; using Libplanet.Types.Consensus; namespace Libplanet.Action.State @@ -77,41 +75,6 @@ public interface IWorld : IWorldState [Pure] IWorld SetAccount(Address address, IAccount account); - /// - /// Transfers the fungible asset (i.e., in-game monetary) - /// from the to the . - /// - /// The of the - /// executing this method. - /// The address who sends the fungible asset to - /// the . - /// The address who receives the fungible asset from - /// the . - /// The asset value to transfer. - /// Turn on to allow 's balance - /// less than zero. Turned off by default. - /// A new instance that the given is subtracted from 's balance and added to - /// 's balance. - /// Thrown when the - /// is less than or equal to zero. - /// Thrown when the - /// has insufficient balance than to transfer and - /// the option is turned off. - /// - /// The behavior is different depending on 's - /// . There is a bug for version 0 - /// where this may not act as intended. Such behavior is left intact for backward - /// compatibility. - /// - [Pure] - IWorld TransferAsset( - IActionContext context, - Address sender, - Address recipient, - FungibleAssetValue value, - bool allowNegativeBalance = false); - /// /// Sets to the stored . /// If 0 is given as its power, removes the validator from the . diff --git a/Libplanet.Action/State/IWorldExtensions.cs b/Libplanet.Action/State/IWorldExtensions.cs index 3f6f94ea53a..d116d6c337d 100644 --- a/Libplanet.Action/State/IWorldExtensions.cs +++ b/Libplanet.Action/State/IWorldExtensions.cs @@ -170,6 +170,44 @@ public static IWorld BurnAsset( } } + /// + /// Transfers the fungible asset (i.e., in-game monetary) + /// from the to the . + /// + /// The of the + /// executing this method. + /// The address who sends the fungible asset to + /// the . + /// The address who receives the fungible asset from + /// the . + /// The asset value to transfer. + /// Turn on to allow 's balance + /// less than zero. Turned off by default. + /// A new instance that the given is subtracted from 's balance and added to + /// 's balance. + /// Thrown when the + /// is less than or equal to zero. + /// Thrown when the + /// has insufficient balance than to transfer and + /// the option is turned off. + /// + /// The behavior is different depending on 's + /// . There is a bug for version 0 + /// where this may not act as intended. Such behavior is left intact for backward + /// compatibility. + /// + [Pure] + public static IWorld TransferAsset( + this IWorld world, + IActionContext context, + Address sender, + Address recipient, + FungibleAssetValue value, + bool allowNegativeBalance = false) => context.BlockProtocolVersion > 0 + ? TransferAssetV1(world, sender, recipient, value, allowNegativeBalance) + : TransferAssetV0(world, sender, recipient, value, allowNegativeBalance); + /// /// Returns the total supply of a . /// @@ -229,5 +267,71 @@ private static IWorld UpdateFungibleAssets( return world.SetAccount(ReservedAddresses.LegacyAccount, account); } + + private static IWorld TransferAssetV0( + IWorld world, + Address sender, + Address recipient, + FungibleAssetValue value, + bool allowNegativeBalance = false) + { + if (value.Sign <= 0) + { + throw new ArgumentOutOfRangeException( + nameof(value), + "The value to transfer has to be greater than zero." + ); + } + + Currency currency = value.Currency; + FungibleAssetValue senderBalance = world.GetBalance(sender, currency); + FungibleAssetValue recipientBalance = world.GetBalance(recipient, currency); + + if (!allowNegativeBalance && senderBalance < value) + { + var msg = $"The account {sender}'s balance of {currency} is insufficient to " + + $"transfer: {senderBalance} < {value}."; + throw new InsufficientBalanceException(msg, sender, senderBalance); + } + + IWorld intermediate = UpdateFungibleAssets( + world, sender, currency, (senderBalance - value).RawValue); + return UpdateFungibleAssets( + intermediate, recipient, currency, (recipientBalance + value).RawValue); + } + + [Pure] + private static IWorld TransferAssetV1( + IWorld world, + Address sender, + Address recipient, + FungibleAssetValue value, + bool allowNegativeBalance = false) + { + if (value.Sign <= 0) + { + throw new ArgumentOutOfRangeException( + nameof(value), + "The value to transfer has to be greater than zero." + ); + } + + Currency currency = value.Currency; + FungibleAssetValue senderBalance = world.GetBalance(sender, currency); + + if (!allowNegativeBalance && senderBalance < value) + { + var msg = $"The account {sender}'s balance of {currency} is insufficient to " + + $"transfer: {senderBalance} < {value}."; + throw new InsufficientBalanceException(msg, sender, senderBalance); + } + + BigInteger senderRawBalance = (senderBalance - value).RawValue; + IWorld intermediate = UpdateFungibleAssets(world, sender, currency, senderRawBalance); + FungibleAssetValue recipientBalance = intermediate.GetBalance(recipient, currency); + BigInteger recipientRawBalance = (recipientBalance + value).RawValue; + + return UpdateFungibleAssets(intermediate, recipient, currency, recipientRawBalance); + } } } diff --git a/Libplanet.Action/State/IWorldState.cs b/Libplanet.Action/State/IWorldState.cs index 05b5be32004..2ed9dbce3a4 100644 --- a/Libplanet.Action/State/IWorldState.cs +++ b/Libplanet.Action/State/IWorldState.cs @@ -2,8 +2,6 @@ using System.Diagnostics.Contracts; using Libplanet.Crypto; using Libplanet.Store.Trie; -using Libplanet.Types.Assets; -using Libplanet.Types.Consensus; namespace Libplanet.Action.State { diff --git a/Libplanet.Action/State/World.cs b/Libplanet.Action/State/World.cs index a4bf5d3c725..cdbd51c0803 100644 --- a/Libplanet.Action/State/World.cs +++ b/Libplanet.Action/State/World.cs @@ -67,38 +67,10 @@ public IWorld SetAccount(Address address, IAccount account) return new World(_baseState, Delta.SetAccount(address, account)); } - /// - public IWorld TransferAsset( - IActionContext context, - Address sender, - Address recipient, - FungibleAssetValue value, - bool allowNegativeBalance = false) => context.BlockProtocolVersion > 0 - ? TransferAssetV1(sender, recipient, value, allowNegativeBalance) - : TransferAssetV0(sender, recipient, value, allowNegativeBalance); - /// public IWorld SetValidator(Validator validator) => UpdateValidatorSet(this.GetValidatorSet().Update(validator)); - private IWorld UpdateFungibleAssets( - Address address, - Currency currency, - BigInteger amount, - BigInteger? supplyAmount = null) - { - IAccount account = supplyAmount is { } sa - ? new Account(new AccountState( - GetAccount(ReservedAddresses.LegacyAccount).Trie - .Set(ToFungibleAssetKey(address, currency), new Integer(amount)) - .Set(ToTotalSupplyKey(currency), new Integer(sa)))) - : new Account(new AccountState( - GetAccount(ReservedAddresses.LegacyAccount).Trie - .Set(ToFungibleAssetKey(address, currency), new Integer(amount)))); - - return SetAccount(ReservedAddresses.LegacyAccount, account); - } - private IWorld UpdateValidatorSet(ValidatorSet validatorSet) { IAccount account = GetAccount(ReservedAddresses.LegacyAccount); @@ -107,68 +79,5 @@ private IWorld UpdateValidatorSet(ValidatorSet validatorSet) new Account(new AccountState( account.Trie.Set(ValidatorSetKey, validatorSet.Bencoded)))); } - - private IWorld TransferAssetV0( - Address sender, - Address recipient, - FungibleAssetValue value, - bool allowNegativeBalance = false) - { - if (value.Sign <= 0) - { - throw new ArgumentOutOfRangeException( - nameof(value), - "The value to transfer has to be greater than zero." - ); - } - - Currency currency = value.Currency; - FungibleAssetValue senderBalance = this.GetBalance(sender, currency); - FungibleAssetValue recipientBalance = this.GetBalance(recipient, currency); - - if (!allowNegativeBalance && senderBalance < value) - { - var msg = $"The account {sender}'s balance of {currency} is insufficient to " + - $"transfer: {senderBalance} < {value}."; - throw new InsufficientBalanceException(msg, sender, senderBalance); - } - - return ((World)UpdateFungibleAssets(sender, currency, (senderBalance - value).RawValue)) - .UpdateFungibleAssets(recipient, currency, (recipientBalance + value).RawValue); - } - - [Pure] - private IWorld TransferAssetV1( - Address sender, - Address recipient, - FungibleAssetValue value, - bool allowNegativeBalance = false) - { - if (value.Sign <= 0) - { - throw new ArgumentOutOfRangeException( - nameof(value), - "The value to transfer has to be greater than zero." - ); - } - - Currency currency = value.Currency; - FungibleAssetValue senderBalance = this.GetBalance(sender, currency); - - if (!allowNegativeBalance && senderBalance < value) - { - var msg = $"The account {sender}'s balance of {currency} is insufficient to " + - $"transfer: {senderBalance} < {value}."; - throw new InsufficientBalanceException(msg, sender, senderBalance); - } - - BigInteger senderRawBalance = (senderBalance - value).RawValue; - IWorld intermediate = UpdateFungibleAssets(sender, currency, senderRawBalance); - FungibleAssetValue recipientBalance = intermediate.GetBalance(recipient, currency); - BigInteger recipientRawBalance = (recipientBalance + value).RawValue; - - return ((World)intermediate).UpdateFungibleAssets( - recipient, currency, recipientRawBalance); - } } } diff --git a/Libplanet.Action/State/WorldBaseState.cs b/Libplanet.Action/State/WorldBaseState.cs index 4f920cefd7e..997ac86f4d1 100644 --- a/Libplanet.Action/State/WorldBaseState.cs +++ b/Libplanet.Action/State/WorldBaseState.cs @@ -4,8 +4,6 @@ using Libplanet.Crypto; using Libplanet.Store; using Libplanet.Store.Trie; -using Libplanet.Types.Assets; -using Libplanet.Types.Consensus; using static Libplanet.Action.State.KeyConverters; namespace Libplanet.Action.State From abd22579ecb93ff79c920bd2a9b85ed763ef4b1a Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 28 Mar 2024 11:29:15 +0900 Subject: [PATCH 7/9] Moved SetValidator from IWorld to external --- Libplanet.Action/ActionEvaluator.cs | 6 ++---- Libplanet.Action/State/IWorld.cs | 11 ----------- Libplanet.Action/State/IWorldExtensions.cs | 23 ++++++++++++++++++++++ Libplanet.Action/State/World.cs | 20 +------------------ 4 files changed, 26 insertions(+), 34 deletions(-) diff --git a/Libplanet.Action/ActionEvaluator.cs b/Libplanet.Action/ActionEvaluator.cs index 4bc94099e60..f5fe07d8e00 100644 --- a/Libplanet.Action/ActionEvaluator.cs +++ b/Libplanet.Action/ActionEvaluator.cs @@ -575,8 +575,7 @@ private static IWorld CommitLegacyWorld(IWorld prevWorld, IStateStore stateStore return new World( new WorldBaseState( stateStore.Commit(prevWorld.GetAccount(ReservedAddresses.LegacyAccount).Trie), - stateStore), - new WorldDelta()); + stateStore)); } private static IWorld CommitWorld(IWorld prevWorld, IStateStore stateStore) @@ -590,8 +589,7 @@ private static IWorld CommitWorld(IWorld prevWorld, IStateStore stateStore) } return new World( - new WorldBaseState(stateStore.Commit(worldTrie), stateStore), - new WorldDelta()); + new WorldBaseState(stateStore.Commit(worldTrie), stateStore)); } [Pure] diff --git a/Libplanet.Action/State/IWorld.cs b/Libplanet.Action/State/IWorld.cs index 633376f4597..96d44413f91 100644 --- a/Libplanet.Action/State/IWorld.cs +++ b/Libplanet.Action/State/IWorld.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Diagnostics.Contracts; using Libplanet.Crypto; -using Libplanet.Types.Consensus; namespace Libplanet.Action.State { @@ -74,15 +73,5 @@ public interface IWorld : IWorldState /// [Pure] IWorld SetAccount(Address address, IAccount account); - - /// - /// Sets to the stored . - /// If 0 is given as its power, removes the validator from the . - /// - /// The instance to write. - /// A new instance with - /// set. - [Pure] - IWorld SetValidator(Validator validator); } } diff --git a/Libplanet.Action/State/IWorldExtensions.cs b/Libplanet.Action/State/IWorldExtensions.cs index d116d6c337d..d534d8ba1db 100644 --- a/Libplanet.Action/State/IWorldExtensions.cs +++ b/Libplanet.Action/State/IWorldExtensions.cs @@ -249,6 +249,18 @@ public static ValidatorSet GetValidatorSet(this IWorldState worldState) : new ValidatorSet(); } + /// + /// Sets to the stored . + /// If 0 is given as its power, removes the validator from the . + /// + /// The instance to write. + /// A new instance with + /// set. + [Pure] + public static IWorld SetValidator(this IWorld world, Validator validator) => + UpdateValidatorSet(world, world.GetValidatorSet().Update(validator)); + + [Pure] private static IWorld UpdateFungibleAssets( IWorld world, Address address, @@ -268,6 +280,7 @@ private static IWorld UpdateFungibleAssets( return world.SetAccount(ReservedAddresses.LegacyAccount, account); } + [Pure] private static IWorld TransferAssetV0( IWorld world, Address sender, @@ -333,5 +346,15 @@ private static IWorld TransferAssetV1( return UpdateFungibleAssets(intermediate, recipient, currency, recipientRawBalance); } + + [Pure] + private static IWorld UpdateValidatorSet(IWorld world, ValidatorSet validatorSet) + { + IAccount account = world.GetAccount(ReservedAddresses.LegacyAccount); + return world.SetAccount( + ReservedAddresses.LegacyAccount, + new Account(new AccountState( + account.Trie.Set(ValidatorSetKey, validatorSet.Bencoded)))); + } } } diff --git a/Libplanet.Action/State/World.cs b/Libplanet.Action/State/World.cs index cdbd51c0803..c0c9de8b95f 100644 --- a/Libplanet.Action/State/World.cs +++ b/Libplanet.Action/State/World.cs @@ -1,12 +1,7 @@ using System; using System.Diagnostics.Contracts; -using System.Numerics; -using Bencodex.Types; using Libplanet.Crypto; using Libplanet.Store.Trie; -using Libplanet.Types.Assets; -using Libplanet.Types.Consensus; -using static Libplanet.Action.State.KeyConverters; namespace Libplanet.Action.State { @@ -23,7 +18,7 @@ public World(IWorldState baseState) { } - public World(IWorldState baseState, IWorldDelta delta) + private World(IWorldState baseState, IWorldDelta delta) { _baseState = baseState; Delta = delta; @@ -66,18 +61,5 @@ public IWorld SetAccount(Address address, IAccount account) return new World(_baseState, Delta.SetAccount(address, account)); } - - /// - public IWorld SetValidator(Validator validator) => - UpdateValidatorSet(this.GetValidatorSet().Update(validator)); - - private IWorld UpdateValidatorSet(ValidatorSet validatorSet) - { - IAccount account = GetAccount(ReservedAddresses.LegacyAccount); - return SetAccount( - ReservedAddresses.LegacyAccount, - new Account(new AccountState( - account.Trie.Set(ValidatorSetKey, validatorSet.Bencoded)))); - } } } From 016d6ff62d33254e2146f964b9aa83a2f6d101d4 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 28 Mar 2024 12:10:14 +0900 Subject: [PATCH 8/9] Changelog --- CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 12578d9ba0b..74ab08f6174 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,10 @@ To be released. type `IReadOnlyList?` to `IActionContext`. [[#3713]] - (Libplanet.Action) Removed `TotalFungibleAssets` property from `IWorld`. [[#3714]] + - (Libplanet.Action) Changed `GetBalance()`, `GetTotalSupply()`, and + `GetValidatorSet()` of `IWorldState` to extension methods. [[#3715]] + - (Libplanet.Action) Changed `MintAsset()`, `BurnAsset()`, `TransferAsset()`, + and `SetValidator()` of `IWorld` to extension methods. [[#3715]] ### Backward-incompatible network protocol changes @@ -31,6 +35,7 @@ To be released. [#3713]: https://github.com/planetarium/libplanet/pull/3713 [#3714]: https://github.com/planetarium/libplanet/pull/3714 +[#3715]: https://github.com/planetarium/libplanet/pull/3715 Version 4.2.0 From ba40e76eb90023bf43f5a3391920018083e48ffe Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 28 Mar 2024 16:40:17 +0900 Subject: [PATCH 9/9] Updated docs --- Libplanet.Action/State/IWorldExtensions.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Libplanet.Action/State/IWorldExtensions.cs b/Libplanet.Action/State/IWorldExtensions.cs index d534d8ba1db..8de5fe62253 100644 --- a/Libplanet.Action/State/IWorldExtensions.cs +++ b/Libplanet.Action/State/IWorldExtensions.cs @@ -14,6 +14,7 @@ public static class IWorldExtensions /// /// Queries 's balance of the . /// + /// The to read from. /// The owner address to query. /// The currency type to query. /// @@ -36,6 +37,7 @@ public static FungibleAssetValue GetBalance( /// Mints the fungible asset (i.e., in-game monetary), /// and give it to the . /// + /// The to manipulate. /// The of the /// executing this method. /// The address who receives the minted asset. @@ -107,6 +109,7 @@ public static IWorld MintAsset( /// Burns the fungible asset (i.e., in-game monetary) from /// 's balance. /// + /// The to manipulate. /// The of the /// executing this method. /// The address who owns the fungible asset to burn. @@ -174,6 +177,7 @@ public static IWorld BurnAsset( /// Transfers the fungible asset (i.e., in-game monetary) /// from the to the . /// + /// The to manipulate. /// The of the /// executing this method. /// The address who sends the fungible asset to @@ -211,6 +215,7 @@ public static IWorld TransferAsset( /// /// Returns the total supply of a . /// + /// The to read from. /// The currency type to query. /// The total supply of the . /// @@ -237,6 +242,7 @@ public static FungibleAssetValue GetTotalSupply( /// /// Returns the validator set. /// + /// The to read from. /// The validator set of type . /// [Pure] @@ -253,6 +259,7 @@ public static ValidatorSet GetValidatorSet(this IWorldState worldState) /// Sets to the stored . /// If 0 is given as its power, removes the validator from the . /// + /// The to manipulate. /// The instance to write. /// A new instance with /// set.