From e6ce217d7462ea47ac6af82af59fe7b460d08e0c Mon Sep 17 00:00:00 2001 From: ilgyu Date: Mon, 25 Sep 2023 09:58:33 +0900 Subject: [PATCH] test: Update tests Co-authored-by: Chanhyuck Ko Co-authored-by: Lee, Suho (cherry picked from commit 9ab368f1b8a524c29bf8e6d03020c4a2efde28ea) --- Libplanet.Action.Tests/ActionContextTest.cs | 10 +- .../ActionEvaluationExtensions.cs | 12 +- .../ActionEvaluationTest.cs | 13 +- Libplanet.Action.Tests/Common/Attack.cs | 10 +- Libplanet.Action.Tests/Common/BaseAction.cs | 2 +- Libplanet.Action.Tests/Common/DelayAction.cs | 7 +- .../Common/DetectRehearsal.cs | 15 +- Libplanet.Action.Tests/Common/DumbAction.cs | 23 +- .../Common/DumbModernAction.cs | 321 ++++++++++++++++++ Libplanet.Action.Tests/Common/MinerReward.cs | 14 +- Libplanet.Action.Tests/Common/RandomAction.cs | 12 +- .../Common/SetStatesAtBlock.cs | 14 +- Libplanet.Action.Tests/Common/SetValidator.cs | 7 +- Libplanet.Action.Tests/Common/Sleep.cs | 2 +- .../Common/ThrowException.cs | 2 +- .../Loader/TypedActionLoaderTest.cs | 6 +- .../Mocks/MockAccountState.cs | 21 +- .../Mocks/MockWorldState.cs | 42 +++ Libplanet.Action.Tests/Sys/InitializeTest.cs | 33 +- Libplanet.Action.Tests/Sys/RegistryTest.cs | 21 +- Libplanet.Action.Tests/TestUtils.cs | 60 +++- Libplanet.Action/State/IBlockChainStates.cs | 12 + .../ActionAnalyzerTest.cs | 4 +- .../GeneratedBlockChainFixture.cs | 3 +- .../Queries/StateQueryTest.cs | 215 ++++++++---- .../Queries/TransactionQueryTest.cs | 10 +- Libplanet.Explorer.Tests/SimpleAction.cs | 4 +- Libplanet.Explorer/Queries/StateQuery.cs | 6 +- Libplanet.Net.Tests/SwarmTest.Preload.cs | 10 +- Libplanet.Net.Tests/SwarmTest.cs | 29 +- Libplanet.Tests/Action/AccountDiffTest.cs | 11 +- Libplanet.Tests/Action/AccountV0Test.cs | 14 +- Libplanet.Tests/Action/AccountV1Test.cs | 15 +- Libplanet.Tests/Action/ActionEvaluatorTest.cs | 2 +- .../Blockchain/BlockChainTest.Append.cs | 98 ++++-- .../Blockchain/BlockChainTest.ProposeBlock.cs | 62 ++-- .../BlockChainTest.ValidateNextBlock.cs | 2 +- Libplanet.Tests/Blockchain/BlockChainTest.cs | 105 ++++-- .../Renderers/AnonymousActionRendererTest.cs | 12 +- .../Renderers/LoggedActionRendererTest.cs | 8 +- .../Blocks/PreEvaluationBlockTest.cs | 19 +- Libplanet.Tests/Fixtures/Arithmetic.cs | 11 +- .../Fixtures/BlockContentFixture.cs | 3 +- Libplanet.Tests/Fixtures/IntegerSet.cs | 14 +- Libplanet.Tests/Store/StoreTest.cs | 2 +- Libplanet.Tests/TestUtils.cs | 3 +- Libplanet.Tests/Tx/TransactionTest.cs | 27 +- Libplanet/Blockchain/BlockChain.cs | 6 +- 48 files changed, 1056 insertions(+), 298 deletions(-) create mode 100644 Libplanet.Action.Tests/Common/DumbModernAction.cs create mode 100644 Libplanet.Action.Tests/Mocks/MockWorldState.cs diff --git a/Libplanet.Action.Tests/ActionContextTest.cs b/Libplanet.Action.Tests/ActionContextTest.cs index 4044de57780..58344f4fe63 100644 --- a/Libplanet.Action.Tests/ActionContextTest.cs +++ b/Libplanet.Action.Tests/ActionContextTest.cs @@ -36,7 +36,7 @@ public void RandomShouldBeDeterministic() miner: _address, blockIndex: 1, blockProtocolVersion: Block.CurrentProtocolVersion, - previousState: new Account(MockAccountState.Empty), + previousState: World.Create(new MockWorldState()), randomSeed: seed, gasLimit: 0 ); @@ -54,7 +54,7 @@ public void GuidShouldBeDeterministic() miner: _address, blockIndex: 1, blockProtocolVersion: Block.CurrentProtocolVersion, - previousState: new Account(MockAccountState.Empty), + previousState: World.Create(new MockWorldState()), randomSeed: 0, gasLimit: 0 ); @@ -65,7 +65,7 @@ public void GuidShouldBeDeterministic() miner: _address, blockIndex: 1, blockProtocolVersion: Block.CurrentProtocolVersion, - previousState: new Account(MockAccountState.Empty), + previousState: World.Create(new MockWorldState()), randomSeed: 0, gasLimit: 0 ); @@ -76,7 +76,7 @@ public void GuidShouldBeDeterministic() miner: _address, blockIndex: 1, blockProtocolVersion: Block.CurrentProtocolVersion, - previousState: new Account(MockAccountState.Empty), + previousState: World.Create(new MockWorldState()), randomSeed: 1, gasLimit: 0 ); @@ -115,7 +115,7 @@ public void GuidVersionAndVariant() miner: _address, blockIndex: 1, blockProtocolVersion: Block.CurrentProtocolVersion, - previousState: new Account(MockAccountState.Empty), + previousState: World.Create(new MockWorldState()), randomSeed: i, gasLimit: 0 ); diff --git a/Libplanet.Action.Tests/ActionEvaluationExtensions.cs b/Libplanet.Action.Tests/ActionEvaluationExtensions.cs index e158dafbaea..7fd1b273ab4 100644 --- a/Libplanet.Action.Tests/ActionEvaluationExtensions.cs +++ b/Libplanet.Action.Tests/ActionEvaluationExtensions.cs @@ -13,7 +13,9 @@ this IEnumerable evaluations ) => evaluations.Aggregate( ImmutableDictionary.Empty, - (dirty, ev) => dirty.SetItems(ev.OutputState.GetUpdatedStates()) + (dirty, ev) => dirty.SetItems( + ev.OutputState.GetAccount( + ReservedAddresses.LegacyAccount).GetUpdatedStates()) ); public static IImmutableDictionary<(Address, Currency), FungibleAssetValue> @@ -22,14 +24,18 @@ this IEnumerable evaluations ) => evaluations.Aggregate( ImmutableDictionary<(Address, Currency), FungibleAssetValue>.Empty, - (dirty, ev) => dirty.SetItems(ev.OutputState.GetUpdatedBalances()) + (dirty, ev) => dirty.SetItems( + ev.OutputState.GetAccount( + ReservedAddresses.LegacyAccount).GetUpdatedBalances()) ); public static IImmutableDictionary GetDirtyTotalSupplies(this IEnumerable evaluations) => evaluations.Aggregate( ImmutableDictionary.Empty, - (dirty, ev) => dirty.SetItems(ev.OutputState.GetUpdatedTotalSupplies()) + (dirty, ev) => dirty.SetItems( + ev.OutputState.GetAccount( + ReservedAddresses.LegacyAccount).GetUpdatedTotalSupplies()) ); } } diff --git a/Libplanet.Action.Tests/ActionEvaluationTest.cs b/Libplanet.Action.Tests/ActionEvaluationTest.cs index e71f5af1457..663b2740a5f 100644 --- a/Libplanet.Action.Tests/ActionEvaluationTest.cs +++ b/Libplanet.Action.Tests/ActionEvaluationTest.cs @@ -37,11 +37,15 @@ public void Constructor() address, 1, Block.CurrentProtocolVersion, - new Account(MockAccountState.Empty), + World.Create(new MockWorldState()), 123, 0, false), - new Account(MockAccountState.Empty.SetState(address, (Text)"item"))); + World.Create( + new MockWorldState().SetAccount( + ReservedAddresses.LegacyAccount, + new Account(MockAccountState.Empty.SetState(address, (Text)"item")))) + ); var action = (DumbAction)evaluation.Action; Assert.Equal(address, action.TargetAddress); @@ -51,11 +55,12 @@ public void Constructor() Assert.Equal(address, evaluation.InputContext.Miner); Assert.Equal(1, evaluation.InputContext.BlockIndex); Assert.Null( - evaluation.InputContext.PreviousState.GetState(address) + evaluation.InputContext.PreviousState.GetAccount( + ReservedAddresses.LegacyAccount).GetState(address) ); Assert.Equal( (Text)"item", - evaluation.OutputState.GetState(address) + evaluation.OutputState.GetAccount(ReservedAddresses.LegacyAccount).GetState(address) ); } } diff --git a/Libplanet.Action.Tests/Common/Attack.cs b/Libplanet.Action.Tests/Common/Attack.cs index 679a319e46f..62b3ad40bcc 100644 --- a/Libplanet.Action.Tests/Common/Attack.cs +++ b/Libplanet.Action.Tests/Common/Attack.cs @@ -29,13 +29,14 @@ public override void LoadPlainValue(IValue plainValue) TargetAddress = new Address(values["target_address"]); } - public override IAccount Execute(IActionContext context) + public override IWorld Execute(IActionContext context) { IImmutableSet usedWeapons = ImmutableHashSet.Empty; IImmutableSet targets = ImmutableHashSet.Empty; - IAccount previousState = context.PreviousState; + IWorld previousState = context.PreviousState; + IAccount legacyAccount = previousState.GetAccount(ReservedAddresses.LegacyAccount); - object value = previousState.GetState(TargetAddress); + object value = legacyAccount.GetState(TargetAddress); if (!ReferenceEquals(value, null)) { var previousResult = BattleResult.FromBencodex((Bencodex.Types.Dictionary)value); @@ -46,8 +47,9 @@ public override IAccount Execute(IActionContext context) usedWeapons = usedWeapons.Add(Weapon); targets = targets.Add(Target); var result = new BattleResult(usedWeapons, targets); + legacyAccount = legacyAccount.SetState(TargetAddress, result.ToBencodex()); - return previousState.SetState(TargetAddress, result.ToBencodex()); + return previousState.SetAccount(ReservedAddresses.LegacyAccount, legacyAccount); } } } diff --git a/Libplanet.Action.Tests/Common/BaseAction.cs b/Libplanet.Action.Tests/Common/BaseAction.cs index c36fb8f99e9..d7578d12a8c 100644 --- a/Libplanet.Action.Tests/Common/BaseAction.cs +++ b/Libplanet.Action.Tests/Common/BaseAction.cs @@ -15,7 +15,7 @@ public abstract class BaseAction : IAction public abstract IValue PlainValue { get; } - public abstract IAccount Execute(IActionContext context); + public abstract IWorld Execute(IActionContext context); public abstract void LoadPlainValue(IValue plainValue); diff --git a/Libplanet.Action.Tests/Common/DelayAction.cs b/Libplanet.Action.Tests/Common/DelayAction.cs index a39bb5c75dc..bac1f8f75a1 100644 --- a/Libplanet.Action.Tests/Common/DelayAction.cs +++ b/Libplanet.Action.Tests/Common/DelayAction.cs @@ -31,7 +31,7 @@ public IValue PlainValue } } - public IAccount Execute(IActionContext context) + public IWorld Execute(IActionContext context) { var state = context.PreviousState; var started = DateTimeOffset.UtcNow; @@ -41,7 +41,10 @@ public IAccount Execute(IActionContext context) MilliSecond); Thread.Sleep(MilliSecond); var ended = DateTimeOffset.UtcNow; - state = state.SetState(TrivialUpdatedAddress, new Bencodex.Types.Integer(MilliSecond)); + var delayAccount = state + .GetAccount(ReservedAddresses.LegacyAccount) + .SetState(TrivialUpdatedAddress, new Bencodex.Types.Integer(MilliSecond)); + state = state.SetAccount(ReservedAddresses.LegacyAccount, delayAccount); Log.Debug( "{MethodName} Total Executed Time: {Elapsed}. Delay target: {MilliSecond}", nameof(DelayAction), diff --git a/Libplanet.Action.Tests/Common/DetectRehearsal.cs b/Libplanet.Action.Tests/Common/DetectRehearsal.cs index cd0b2c86aea..a0c7fc948ef 100644 --- a/Libplanet.Action.Tests/Common/DetectRehearsal.cs +++ b/Libplanet.Action.Tests/Common/DetectRehearsal.cs @@ -22,14 +22,17 @@ public override void LoadPlainValue(IValue plainValue) TargetAddress = new Address(values["target_address"]); } - public override IAccount Execute(IActionContext context) + public override IWorld Execute(IActionContext context) { - IAccount previousState = context.PreviousState; + IWorld previousState = context.PreviousState; + IAccount legacyAccount = previousState.GetAccount(ReservedAddresses.LegacyAccount); ResultState = context.Rehearsal; - return previousState.SetState( - TargetAddress, - new Bencodex.Types.Boolean(context.Rehearsal) - ); + return previousState.SetAccount( + ReservedAddresses.LegacyAccount, + legacyAccount.SetState( + TargetAddress, + new Bencodex.Types.Boolean(context.Rehearsal) + )); } } } diff --git a/Libplanet.Action.Tests/Common/DumbAction.cs b/Libplanet.Action.Tests/Common/DumbAction.cs index cb2f6a1c439..b58a03d7d8b 100644 --- a/Libplanet.Action.Tests/Common/DumbAction.cs +++ b/Libplanet.Action.Tests/Common/DumbAction.cs @@ -131,7 +131,7 @@ public IValue PlainValue } } - public IAccount Execute(IActionContext context) + public IWorld Execute(IActionContext context) { if (RehearsalRecords.Value is null) { @@ -144,13 +144,14 @@ public IAccount Execute(IActionContext context) RehearsalRecords.Value.Add((TargetAddress, Item)); } - IAccount states = context.PreviousState; + IWorld world = context.PreviousState; if (Item is null) { - return states; + return world; } - string items = (Text?)states.GetState(TargetAddress); + IAccount account = world.GetAccount(ReservedAddresses.LegacyAccount); + string items = (Text?)account.GetState(TargetAddress); string item = RecordRehearsal ? $"{Item}:{context.Rehearsal}" : Item; @@ -176,7 +177,7 @@ public IAccount Execute(IActionContext context) if (RecordRandom) { - states = states.SetState( + account = account.SetState( RandomRecordsAddress, (Integer)context.GetRandom().Next() ); @@ -187,11 +188,11 @@ public IAccount Execute(IActionContext context) Item = Item.ToUpperInvariant(); } - IAccount nextState = states.SetState(TargetAddress, (Text)items); + account = account.SetState(TargetAddress, (Text)items); if (!(Transfer is null)) { - nextState = nextState.TransferAsset( + account = account.TransferAsset( context, sender: Transfer.Item1, recipient: Transfer.Item2, @@ -202,8 +203,8 @@ public IAccount Execute(IActionContext context) if (!(Validators is null)) { - nextState = Validators.Aggregate( - nextState, + account = Validators.Aggregate( + account, (current, validator) => current.SetValidator(new Validator(validator, BigInteger.One))); } @@ -216,11 +217,11 @@ public IAccount Execute(IActionContext context) ExecuteRecords.Value = ExecuteRecords.Value.Add(new ExecuteRecord() { Action = this, - NextState = nextState, + NextState = account, Rehearsal = context.Rehearsal, }); - return nextState; + return world.SetAccount(ReservedAddresses.LegacyAccount, account); } public void LoadPlainValue(IValue plainValue) diff --git a/Libplanet.Action.Tests/Common/DumbModernAction.cs b/Libplanet.Action.Tests/Common/DumbModernAction.cs new file mode 100644 index 00000000000..9e3b2852688 --- /dev/null +++ b/Libplanet.Action.Tests/Common/DumbModernAction.cs @@ -0,0 +1,321 @@ +using System.Collections.Immutable; +using System.Globalization; +using System.Numerics; +using Bencodex.Types; +using Libplanet.Action.State; +using Libplanet.Crypto; +using Libplanet.Types.Assets; +using Libplanet.Types.Consensus; +using Boolean = Bencodex.Types.Boolean; + +namespace Libplanet.Action.Tests.Common +{ + public sealed class DumbModernAction : IAction, IEquatable + { + public static readonly Address DumbModernAddress = + new Address("0123456789abcdef0123456789abcdef12345678"); + + public static readonly Address RandomRecordsAddress = + new Address("7811C3fAa0f9Cc41F7971c3d9b031B1095b20AB2"); + + public static readonly Currency DumbCurrency = + Currency.Uncapped("DUMB", 0, null); + + public DumbModernAction() + { + } + + public DumbModernAction(IEnumerable validators) + { + Validators = validators; + } + + public DumbModernAction( + Address targetAddress, + string item, + bool recordRehearsal = false, + bool recordRandom = false, + bool idempotent = false, + Tuple transfer = null) + { + Idempotent = idempotent; + TargetAddress = targetAddress; + Item = item; + RecordRehearsal = recordRehearsal; + RecordRandom = recordRandom; + Transfer = transfer; + } + + public DumbModernAction( + Address targetAddress, + string item, + Address transferFrom, + Address transferTo, + BigInteger transferAmount, + bool recordRehearsal = false, + bool recordRandom = false, + bool idempotent = false + ) + : this( + targetAddress, + item, + recordRehearsal, + recordRandom, + idempotent, + Tuple.Create(transferFrom, transferTo, transferAmount) + ) + { + } + + public static AsyncLocal> + ExecuteRecords + { get; } = new AsyncLocal>(); + + public static AsyncLocal> + RehearsalRecords + { get; } = + new AsyncLocal>(); + + public Address TargetAddress { get; private set; } + + public string Item { get; private set; } + + public bool RecordRehearsal { get; private set; } + + public bool RecordRandom { get; private set; } + + public bool Idempotent { get; private set; } + + public Tuple Transfer { get; private set; } + + public IEnumerable Validators { get; private set; } + + public IValue PlainValue + { + get + { + var plainValue = Bencodex.Types.Dictionary.Empty; + if (!(Item is null)) + { + plainValue = new Bencodex.Types.Dictionary( + new Dictionary + { + ["item"] = (Text)Item, + ["target_address"] = new Binary(TargetAddress.ByteArray), + ["record_rehearsal"] = new Bencodex.Types.Boolean(RecordRehearsal), + }); + } + + if (RecordRandom) + { + // In order to avoid changing tx signatures in many test + // fixtures, adds field only if RecordRandom = true. + plainValue = plainValue.Add("record_random", true); + } + + if (Idempotent) + { + plainValue = plainValue.Add("idempotent", Idempotent); + } + + if (!(Transfer is null)) + { + plainValue = plainValue + .Add("transfer_from", Transfer.Item1.ByteArray) + .Add("transfer_to", Transfer.Item2.ByteArray) + .Add("transfer_amount", Transfer.Item3); + } + + if (!(Validators is null)) + { + plainValue = plainValue + .Add("validators", new List(Validators.Select(p => p.Format(false)))); + } + + return plainValue; + } + } + + public IWorld Execute(IActionContext context) + { + if (RehearsalRecords.Value is null) + { + RehearsalRecords.Value = ImmutableList<(Address, string)>.Empty; + } + + if (context.Rehearsal) + { + RehearsalRecords.Value = + RehearsalRecords.Value.Add((TargetAddress, Item)); + } + + IWorld world = context.PreviousState; + if (Item is null) + { + return world; + } + + IAccount account = world.GetAccount(DumbModernAddress); + string items = (Text?)account.GetState(TargetAddress); + string item = RecordRehearsal + ? $"{Item}:{context.Rehearsal}" + : Item; + + if (Idempotent) + { + var splitItems = items is null ? new[] { item } : (items + "," + item).Split(','); + items = string.Join( + ",", + splitItems.OrderBy(x => + float.Parse( + x.Substring(4), + NumberStyles.Float, + CultureInfo.InvariantCulture + ) + ) + ); + } + else + { + items = items is null ? item : $"{items},{item}"; + } + + if (RecordRandom) + { + account = account.SetState( + RandomRecordsAddress, + (Integer)context.GetRandom().Next() + ); + } + + if (Item.Equals("D") && !context.Rehearsal) + { + Item = Item.ToUpperInvariant(); + } + + account = account.SetState(TargetAddress, (Text)items); + + if (!(Transfer is null)) + { + account = account.TransferAsset( + context, + sender: Transfer.Item1, + recipient: Transfer.Item2, + value: FungibleAssetValue.FromRawValue(DumbCurrency, Transfer.Item3), + allowNegativeBalance: true + ); + } + + if (!(Validators is null)) + { + account = Validators.Aggregate( + account, + (current, validator) => + current.SetValidator(new Validator(validator, BigInteger.One))); + } + + if (ExecuteRecords.Value is null) + { + ExecuteRecords.Value = ImmutableList.Empty; + } + + ExecuteRecords.Value = ExecuteRecords.Value.Add(new ExecuteRecord() + { + Action = this, + NextState = account, + Rehearsal = context.Rehearsal, + }); + + world = world.SetAccount(DumbModernAddress, account); + return world; + } + + public void LoadPlainValue(IValue plainValue) + { + LoadPlainValue((Bencodex.Types.Dictionary)plainValue); + } + + public void LoadPlainValue(Dictionary plainValue) + { + Item = plainValue.GetValue("item"); + TargetAddress = new Address(plainValue.GetValue("target_address")); + RecordRehearsal = plainValue.GetValue("record_rehearsal").Value; + RecordRandom = + plainValue.ContainsKey((IKey)(Text)"record_random") && + plainValue["record_random"] is Boolean r && + r.Value; + + if (plainValue.ContainsKey((IKey)(Text)"idempotent")) + { + Idempotent = plainValue.GetValue("idempotent"); + } + + if (plainValue.TryGetValue((Text)"transfer_from", out IValue from) && + plainValue.TryGetValue((Text)"transfer_to", out IValue to) && + plainValue.TryGetValue((Text)"transfer_amount", out IValue a) && + a is Integer amount) + { + Transfer = Tuple.Create(new Address(from), new Address(to), amount.Value); + } + + if (plainValue.ContainsKey((IKey)(Text)"validators")) + { + Validators = plainValue.GetValue("validators") + .Select(value => new PublicKey(((Binary)value).ByteArray)); + } + } + + public bool Equals(DumbModernAction other) + { + return !(other is null) && ( + ReferenceEquals(this, other) || ( + TargetAddress.Equals(other.TargetAddress) && + string.Equals(Item, other.Item) && + RecordRehearsal == other.RecordRehearsal + ) + ); + } + + public override bool Equals(object obj) + { + return !(obj is null) && ( + ReferenceEquals(this, obj) || + (obj is DumbModernAction other && Equals(other)) + ); + } + + public override int GetHashCode() + { + unchecked + { + int hashCode = TargetAddress.GetHashCode(); + hashCode = (hashCode * 397) ^ + (Item != null ? Item.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ RecordRehearsal.GetHashCode(); + return hashCode; + } + } + + public override string ToString() + { + const string T = "true", F = "false"; + string transfer = Transfer is Tuple t + ? $"({t.Item1}, {t.Item2}, {t.Item3})" + : "null"; + string validators = Validators is null + ? "none" + : Validators + .Aggregate(string.Empty, (s, key) => s + key.Format(false) + ", ") + .TrimEnd(',', ' '); + return $"{nameof(DumbModernAction)} {{ " + + $"{nameof(TargetAddress)} = {TargetAddress}, " + + $"{nameof(Item)} = {Item ?? string.Empty}, " + + $"{nameof(RecordRehearsal)} = {(RecordRehearsal ? T : F)}, " + + $"{nameof(RecordRandom)} = {(RecordRandom ? T : F)}, " + + $"{nameof(Idempotent)} = {(Idempotent ? T : F)}, " + + $"{nameof(Transfer)} = {transfer} " + + $"{nameof(Validators)} = {validators} " + + "}"; + } + } +} diff --git a/Libplanet.Action.Tests/Common/MinerReward.cs b/Libplanet.Action.Tests/Common/MinerReward.cs index 1a5ca0bb348..1572a3c220f 100644 --- a/Libplanet.Action.Tests/Common/MinerReward.cs +++ b/Libplanet.Action.Tests/Common/MinerReward.cs @@ -36,23 +36,25 @@ public void LoadPlainValue(Dictionary plainValue) Reward = plainValue.GetValue("reward"); } - public IAccount Execute(IActionContext ctx) + public IWorld Execute(IActionContext ctx) { - IAccount states = ctx.PreviousState; + IWorld states = ctx.PreviousState; + IAccount legacyAccount = states.GetAccount(ReservedAddresses.LegacyAccount); - string rewardRecord = (Text?)states.GetState(RewardRecordAddress); + string rewardRecord = (Text?)legacyAccount.GetState(RewardRecordAddress); rewardRecord = rewardRecord is null ? ctx.Miner.ToString() : $"{rewardRecord},{ctx.Miner}"; - states = states.SetState(RewardRecordAddress, (Text)rewardRecord); + legacyAccount = legacyAccount.SetState(RewardRecordAddress, (Text)rewardRecord); - IValue tempQualifier1 = states?.GetState(ctx.Miner); + IValue tempQualifier1 = legacyAccount.GetState(ctx.Miner); int previousReward = tempQualifier1 is Integer i ? (int)i.Value : 0; int reward = previousReward + Reward; - return states.SetState(ctx.Miner, (Integer)reward); + legacyAccount = legacyAccount.SetState(ctx.Miner, (Integer)reward); + return states.SetAccount(ReservedAddresses.LegacyAccount, legacyAccount); } } } diff --git a/Libplanet.Action.Tests/Common/RandomAction.cs b/Libplanet.Action.Tests/Common/RandomAction.cs index 6c71de6b1e2..40463566a75 100644 --- a/Libplanet.Action.Tests/Common/RandomAction.cs +++ b/Libplanet.Action.Tests/Common/RandomAction.cs @@ -28,15 +28,19 @@ public void LoadPlainValue(IValue plainValue) Address = new Address((string)dictionary.GetValue("address")); } - public IAccount Execute(IActionContext context) + public IWorld Execute(IActionContext context) { - IAccount states = context.PreviousState; + IWorld states = context.PreviousState; + IAccount legacyAccount = states.GetAccount(ReservedAddresses.LegacyAccount); if (context.Rehearsal) { - return states.SetState(Address, Null.Value); + return states.SetAccount( + ReservedAddresses.LegacyAccount, + legacyAccount.SetState(Address, Null.Value)); } - return states.SetState(Address, (Integer)context.GetRandom().Next()); + legacyAccount = legacyAccount.SetState(Address, (Integer)context.GetRandom().Next()); + return states.SetAccount(ReservedAddresses.LegacyAccount, legacyAccount); } } } diff --git a/Libplanet.Action.Tests/Common/SetStatesAtBlock.cs b/Libplanet.Action.Tests/Common/SetStatesAtBlock.cs index befaa787cb7..b32d386eef3 100644 --- a/Libplanet.Action.Tests/Common/SetStatesAtBlock.cs +++ b/Libplanet.Action.Tests/Common/SetStatesAtBlock.cs @@ -8,22 +8,26 @@ public class SetStatesAtBlock : IAction { private Address _address; private IValue _value = Null.Value; + private Address _accountAddress; private long _blockIndex; public SetStatesAtBlock() { } - public SetStatesAtBlock(Address address, IValue value, long blockIndex) + public SetStatesAtBlock( + Address address, IValue value, Address accountAddress, long blockIndex) { _address = address; _blockIndex = blockIndex; + _accountAddress = accountAddress; _value = value; } public IValue PlainValue => Bencodex.Types.Dictionary.Empty .Add("address", _address.ByteArray) .Add("value", _value) + .Add("account_address", _accountAddress.ByteArray) .Add("block_index", _blockIndex); public void LoadPlainValue(IValue plainValue) @@ -31,15 +35,17 @@ public void LoadPlainValue(IValue plainValue) var dict = (Bencodex.Types.Dictionary)plainValue; _address = new Address(dict.GetValue("address")); _value = dict["value"]; + _accountAddress = new Address(dict.GetValue("account_address")); _blockIndex = dict.GetValue("block_index"); } - public IAccount Execute(IActionContext context) + public IWorld Execute(IActionContext context) { - IAccount states = context.PreviousState; + IWorld states = context.PreviousState; + IAccount account = states.GetAccount(_accountAddress); if (context.BlockIndex == _blockIndex) { - states = states.SetState(_address, _value); + states = states.SetAccount(_accountAddress, account.SetState(_address, _value)); } return states; diff --git a/Libplanet.Action.Tests/Common/SetValidator.cs b/Libplanet.Action.Tests/Common/SetValidator.cs index 9b915c91108..a6e7e1d2755 100644 --- a/Libplanet.Action.Tests/Common/SetValidator.cs +++ b/Libplanet.Action.Tests/Common/SetValidator.cs @@ -37,9 +37,12 @@ public void LoadPlainValue(IValue plainValue) } /// - public IAccount Execute(IActionContext context) + public IWorld Execute(IActionContext context) { - return context.PreviousState.SetValidator(Validator); + IWorld states = context.PreviousState; + IAccount legacyAccount = states.GetAccount(ReservedAddresses.LegacyAccount); + return states.SetAccount( + ReservedAddresses.LegacyAccount, legacyAccount.SetValidator(Validator)); } /// diff --git a/Libplanet.Action.Tests/Common/Sleep.cs b/Libplanet.Action.Tests/Common/Sleep.cs index cdee4b20f46..98f8b2fd836 100644 --- a/Libplanet.Action.Tests/Common/Sleep.cs +++ b/Libplanet.Action.Tests/Common/Sleep.cs @@ -13,7 +13,7 @@ public class Sleep : BaseAction .Add("values", Dictionary.Empty .Add("zone_id", ZoneId)); - public override IAccount Execute(IActionContext context) + public override IWorld Execute(IActionContext context) { // No-op. return context.PreviousState; diff --git a/Libplanet.Action.Tests/Common/ThrowException.cs b/Libplanet.Action.Tests/Common/ThrowException.cs index 0be3689f1b7..322ae04dde3 100644 --- a/Libplanet.Action.Tests/Common/ThrowException.cs +++ b/Libplanet.Action.Tests/Common/ThrowException.cs @@ -36,7 +36,7 @@ public void LoadPlainValue(Dictionary plainValue) Deterministic = plainValue.GetValue("deterministic"); } - public IAccount Execute(IActionContext context) + public IWorld Execute(IActionContext context) { if (context.Rehearsal ? ThrowOnRehearsal : ThrowOnExecution) { diff --git a/Libplanet.Action.Tests/Loader/TypedActionLoaderTest.cs b/Libplanet.Action.Tests/Loader/TypedActionLoaderTest.cs index 688d300d057..c386f58ee21 100644 --- a/Libplanet.Action.Tests/Loader/TypedActionLoaderTest.cs +++ b/Libplanet.Action.Tests/Loader/TypedActionLoaderTest.cs @@ -1,5 +1,6 @@ using Bencodex.Types; using Libplanet.Action.Loader; +using Libplanet.Action.State; using Libplanet.Action.Sys; using Libplanet.Action.Tests.Common; using Libplanet.Crypto; @@ -47,7 +48,10 @@ public void LoadAction() new ValidatorSet( new List() { new Validator(new PrivateKey().PublicKey, 1) }).Bencoded, - Dictionary.Empty.Add(default(Address).ToByteArray(), "initial value"))); + Dictionary.Empty.Add( + ReservedAddresses.LegacyAccount.ToByteArray(), + Dictionary.Empty.Add( + default(Address).ToByteArray(), "initial value")))); var action = new Initialize(); action.LoadPlainValue(plainValue); diff --git a/Libplanet.Action.Tests/Mocks/MockAccountState.cs b/Libplanet.Action.Tests/Mocks/MockAccountState.cs index 71b8df3cc96..78544f3de9e 100644 --- a/Libplanet.Action.Tests/Mocks/MockAccountState.cs +++ b/Libplanet.Action.Tests/Mocks/MockAccountState.cs @@ -5,6 +5,7 @@ using Libplanet.Store; using Libplanet.Store.Trie; using Libplanet.Types.Assets; +using Libplanet.Types.Blocks; using Libplanet.Types.Consensus; namespace Libplanet.Action.Tests.Mocks @@ -60,8 +61,12 @@ private MockAccountState(ITrie trie) public static MockAccountState Empty => _empty; + public Address Address { get; } + public ITrie Trie { get; } + public BlockHash? BlockHash { get; } + public IValue GetState(Address address) => Trie.Get(KeyConverters.ToStateKey(address)); @@ -95,7 +100,8 @@ public ValidatorSet GetValidatorSet() => : new ValidatorSet(); public MockAccountState SetState(Address address, IValue state) => - new MockAccountState(Trie.Set(KeyConverters.ToStateKey(address), state)); + new MockAccountState( + Trie.Set(KeyConverters.ToStateKey(address), state)); public MockAccountState SetBalance( Address address, FungibleAssetValue amount) => @@ -107,9 +113,10 @@ public MockAccountState SetBalance( public MockAccountState SetBalance( (Address Address, Currency Currency) pair, BigInteger rawAmount) => - new MockAccountState(Trie.Set( - KeyConverters.ToFungibleAssetKey(pair.Address, pair.Currency), - new Integer(rawAmount))); + new MockAccountState( + Trie.Set( + KeyConverters.ToFungibleAssetKey(pair.Address, pair.Currency), + new Integer(rawAmount))); public MockAccountState AddBalance(Address address, FungibleAssetValue amount) => AddBalance((address, amount.Currency), amount.RawValue); @@ -182,8 +189,8 @@ public MockAccountState SubtractTotalSupply(Currency currency, BigInteger rawAmo Integer amount ? amount : 0) - rawAmount); public MockAccountState SetValidator(Validator validator) => - new MockAccountState(Trie.Set( - KeyConverters.ValidatorSetKey, - GetValidatorSet().Update(validator).Bencoded)); + new MockAccountState( + Trie.Set( + KeyConverters.ValidatorSetKey, GetValidatorSet().Update(validator).Bencoded)); } } diff --git a/Libplanet.Action.Tests/Mocks/MockWorldState.cs b/Libplanet.Action.Tests/Mocks/MockWorldState.cs new file mode 100644 index 00000000000..5c4f259c528 --- /dev/null +++ b/Libplanet.Action.Tests/Mocks/MockWorldState.cs @@ -0,0 +1,42 @@ +using System.Collections.Immutable; +using Libplanet.Action.State; +using Libplanet.Crypto; +using Libplanet.Store; +using Libplanet.Store.Trie; + +namespace Libplanet.Action.Tests.Mocks +{ + public class MockWorldState : IWorldState + { + private readonly IImmutableDictionary _accounts; + + public MockWorldState() + : this(ImmutableDictionary.Empty) + { + } + + public MockWorldState(IImmutableDictionary accounts) + : this(new TrieStateStore(new MemoryKeyValueStore()).GetStateRoot(null), accounts) + { + } + + public MockWorldState(ITrie trie, IImmutableDictionary accounts) + { + Trie = trie; + Legacy = true; + _accounts = accounts; + } + + public ITrie Trie { get; } + + public bool Legacy { get; private set; } + + public IAccount GetAccount(Address address) + => _accounts.TryGetValue(address, out IAccount account) + ? account + : new Account(new MockAccountState()); + + public IWorldState SetAccount(Address address, IAccount account) => + new MockWorldState(_accounts.SetItem(address, account)); + } +} diff --git a/Libplanet.Action.Tests/Sys/InitializeTest.cs b/Libplanet.Action.Tests/Sys/InitializeTest.cs index 5c6bea6328c..4bba35ae0ed 100644 --- a/Libplanet.Action.Tests/Sys/InitializeTest.cs +++ b/Libplanet.Action.Tests/Sys/InitializeTest.cs @@ -20,10 +20,15 @@ public class InitializeTest } ); - private static readonly ImmutableDictionary _states = - new Dictionary + private static readonly IImmutableDictionary> + _states = + new Dictionary> { - [default] = (Text)"initial value", + [default] = + new Dictionary + { + [default] = (Text)"initial value", + }.ToImmutableDictionary(), }.ToImmutableDictionary(); [Fact] @@ -42,7 +47,7 @@ public void Execute() { var random = new System.Random(); Address signer = random.NextAddress(); - var prevState = new Account(MockAccountState.Empty); + var prevState = World.Create(new MockWorldState()); BlockHash genesisHash = random.NextBlockHash(); var context = new ActionContext( signer: signer, @@ -61,8 +66,12 @@ public void Execute() var nextState = initialize.Execute(context); - Assert.Equal(_validatorSet, nextState.GetValidatorSet()); - Assert.Equal(_states[default], nextState.GetState(default)); + Assert.Equal( + _validatorSet, + nextState.GetAccount(ReservedAddresses.LegacyAccount).GetValidatorSet()); + Assert.Equal( + _states[default][default], + nextState.GetAccount(default).GetState(default)); } [Fact] @@ -70,7 +79,7 @@ public void ExecuteInNonGenesis() { var random = new System.Random(); Address signer = random.NextAddress(); - var prevState = new Account(MockAccountState.Empty); + var prevState = World.Create(new MockWorldState()); BlockHash genesisHash = random.NextBlockHash(); var context = new ActionContext( signer: signer, @@ -106,7 +115,10 @@ public void Serialize() "values", new List( _validatorSet.Bencoded, - Dictionary.Empty.Add(default(Address).ToByteArray(), "initial value"))), + Dictionary.Empty.Add( + default(Address).ToByteArray(), + Dictionary.Empty.Add(default(Address).ToByteArray(), "initial value" + )))), action.PlainValue); } @@ -119,7 +131,10 @@ public void Deserialize() "values", new List( _validatorSet.Bencoded, - Dictionary.Empty.Add(default(Address).ToByteArray(), "initial value"))); + Dictionary.Empty.Add( + default(Address).ToByteArray(), + Dictionary.Empty.Add(default(Address).ToByteArray(), "initial value" + )))); var action = new Initialize(); action.LoadPlainValue(encoded); diff --git a/Libplanet.Action.Tests/Sys/RegistryTest.cs b/Libplanet.Action.Tests/Sys/RegistryTest.cs index c209d59f8a5..489372d5461 100644 --- a/Libplanet.Action.Tests/Sys/RegistryTest.cs +++ b/Libplanet.Action.Tests/Sys/RegistryTest.cs @@ -19,10 +19,15 @@ public class RegistryTest } ); - private static readonly ImmutableDictionary _states = - new Dictionary + private static readonly IImmutableDictionary> + _states = + new Dictionary> { - [default] = (Text)"initial value", + [default] = + new Dictionary + { + [default] = (Text)"initial value", + }.ToImmutableDictionary(), }.ToImmutableDictionary(); private static readonly Currency FooCurrency = Currency.Uncapped("FOO", 2, null); @@ -36,7 +41,10 @@ public void Deserialize() "values", new List( _validatorSet.Bencoded, - Dictionary.Empty.Add(default(Address).ToByteArray(), "initial value"))); + Dictionary.Empty.Add( + default(Address).ToByteArray(), + Dictionary.Empty.Add(default(Address).ToByteArray(), "initial value" + )))); IAction action = Registry.Deserialize(value); var initialize = Assert.IsType(action); Assert.Equal(_validatorSet, initialize.ValidatorSet); @@ -82,7 +90,10 @@ public void Serialize() "values", new List( _validatorSet.Bencoded, - Dictionary.Empty.Add(default(Address).ToByteArray(), "initial value"))); + Dictionary.Empty.Add( + default(Address).ToByteArray(), + Dictionary.Empty.Add(default(Address).ToByteArray(), "initial value" + )))); TestUtils.AssertBencodexEqual(expected, actual); } diff --git a/Libplanet.Action.Tests/TestUtils.cs b/Libplanet.Action.Tests/TestUtils.cs index 192b0274b71..5f2e4be7a20 100644 --- a/Libplanet.Action.Tests/TestUtils.cs +++ b/Libplanet.Action.Tests/TestUtils.cs @@ -1,11 +1,14 @@ +using System.Collections.Immutable; using Bencodex.Types; using DiffPlex.DiffBuilder; using DiffPlex.DiffBuilder.Model; +using Libplanet.Action.State; +using Xunit; using Xunit.Sdk; namespace Libplanet.Action.Tests { - internal static class TestUtils + public static class TestUtils { private static readonly System.Random _random = new System.Random(); @@ -46,6 +49,61 @@ public static void AssertBencodexEqual(IValue expected, IValue actual) ); } + public static void AssertAccountEqual(IAccount expected, IAccount actual) + { + if (expected is null && actual is null) + { + return; + } + + if (expected is null || actual is null || + !(expected is Account ea && actual is Account aa)) + { + throw new XunitException("Accounts should be of type Account"); + } + + if (!ea.TotalUpdatedFungibleAssets.SequenceEqual(aa.TotalUpdatedFungibleAssets) || + !DictionaryEquals(ea.TotalUpdatedFungibles, aa.TotalUpdatedFungibles)) + { + Assert.Equal(expected, actual); + } + + if (!DictionaryEquals(ea.Delta.ToRawDelta(), aa.Delta.ToRawDelta())) + { + Assert.Equal(ea.Delta, aa.Delta); + } + } + + public static bool DictionaryEquals( + IImmutableDictionary expected, + IImmutableDictionary actual) + { + if (expected is null && actual is null) + { + return true; + } + + if (expected is null || actual is null) + { + return false; + } + + if (expected.Count != actual.Count) + { + return false; + } + + foreach (KeyValuePair pair in expected) + { + if (!actual.TryGetValue(pair.Key, out T2 value) || !pair.Value.Equals(value)) + { + return false; + } + } + + return true; + } + public static byte[] GetRandomBytes(int size) { var bytes = new byte[size]; diff --git a/Libplanet.Action/State/IBlockChainStates.cs b/Libplanet.Action/State/IBlockChainStates.cs index 3676c912997..7030423f53c 100644 --- a/Libplanet.Action/State/IBlockChainStates.cs +++ b/Libplanet.Action/State/IBlockChainStates.cs @@ -215,5 +215,17 @@ FungibleAssetValue GetTotalSupply( /// /// IAccountState GetAccountState(Address address, BlockHash? offset); + + /// + /// Returns the in the + /// of root hash . + /// + /// The of the root hash + /// for which to create an . + /// + /// The of state root hash . + /// + /// + IAccountState GetAccountState(HashDigest? stateRootHash); } } diff --git a/Libplanet.Analyzers.Tests/ActionAnalyzerTest.cs b/Libplanet.Analyzers.Tests/ActionAnalyzerTest.cs index 52eb38179d9..824a7349e05 100644 --- a/Libplanet.Analyzers.Tests/ActionAnalyzerTest.cs +++ b/Libplanet.Analyzers.Tests/ActionAnalyzerTest.cs @@ -31,7 +31,7 @@ public class SampleAction : IAction { public SampleAction() {} public IValue PlainValue => Null.Value; public void LoadPlainValue(IValue plainValue) {} - public IAccount Execute(IActionContext context) { + public IWorld Execute(IActionContext context) { new Random().Next(); return context.PreviousState; } @@ -130,7 +130,7 @@ public class SampleAction : IAction { public SampleAction() {} public IValue PlainValue => Null.Value; public void LoadPlainValue(IValue plainValue) {} - public IAccount Execute(IActionContext context) { + public IWorld Execute(IActionContext context) { // Following code should all fail: var v = " + expr + @"; ConsumeEnumerable(v); diff --git a/Libplanet.Explorer.Tests/GeneratedBlockChainFixture.cs b/Libplanet.Explorer.Tests/GeneratedBlockChainFixture.cs index 8f35c9797cd..1f17ba483fe 100644 --- a/Libplanet.Explorer.Tests/GeneratedBlockChainFixture.cs +++ b/Libplanet.Explorer.Tests/GeneratedBlockChainFixture.cs @@ -102,7 +102,8 @@ public GeneratedBlockChainFixture( new ValidatorSet( ImmutableList.Empty.Add( new Validator(pk.PublicKey, 1)).ToList()), - ImmutableDictionary.Empty), + ImmutableDictionary.Create< + Address, IImmutableDictionary>()) }.ToPlainValues())) .ToImmutableList()); Chain = BlockChain.Create( diff --git a/Libplanet.Explorer.Tests/Queries/StateQueryTest.cs b/Libplanet.Explorer.Tests/Queries/StateQueryTest.cs index f2aa3674e5b..dc51ea04159 100644 --- a/Libplanet.Explorer.Tests/Queries/StateQueryTest.cs +++ b/Libplanet.Explorer.Tests/Queries/StateQueryTest.cs @@ -2,6 +2,7 @@ using System.Collections.Immutable; using System.Linq; using System.Numerics; +using System.Security.Cryptography; using System.Threading.Tasks; using Bencodex.Types; using GraphQL; @@ -9,25 +10,79 @@ using Libplanet.Action; using Libplanet.Action.State; using Libplanet.Blockchain.Policies; +using Libplanet.Common; using Libplanet.Crypto; +using Libplanet.Explorer.Queries; +using Libplanet.Store; +using Libplanet.Store.Trie; using Libplanet.Types.Assets; using Libplanet.Types.Blocks; using Libplanet.Types.Consensus; -using Libplanet.Explorer.Queries; -using Libplanet.Store.Trie; using Xunit; using static Libplanet.Explorer.Tests.GraphQLTestUtils; -using Libplanet.Common; -using System.Security.Cryptography; namespace Libplanet.Explorer.Tests.Queries; public class StateQueryTest { + [Fact] + public async Task WorldStates() + { + (IBlockChainStates, IBlockPolicy) source = ( + new MockChainStates(), new BlockPolicy() + ); + ExecutionResult result = await ExecuteQueryAsync(@" + { + worldState( + offsetBlockHash: + ""01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"" + ) + { + stateRootHash + legacy + } + } + ", source: source); + Assert.Null(result.Errors); + ExecutionNode resultData = Assert.IsAssignableFrom(result.Data); + IDictionary resultDict = + Assert.IsAssignableFrom>(resultData!.ToValue()); + IDictionary states = + Assert.IsAssignableFrom>(resultDict["worldState"]); + Assert.NotNull(states["stateRootHash"]); + Assert.True((bool)states["legacy"]); + } + + [Fact] + public async Task AccountStates() + { + (IBlockChainStates, IBlockPolicy) source = ( + new MockChainStates(), new BlockPolicy() + ); + ExecutionResult result = await ExecuteQueryAsync(@" + { + accountState( + accountAddress: ""0x40837BFebC1b192600023a431400557EA5FDE51a"", + offsetBlockHash: + ""01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"" + ) + { + stateRootHash + } + } + ", source: source); + Assert.Null(result.Errors); + ExecutionNode resultData = Assert.IsAssignableFrom(result.Data); + IDictionary resultDict = + Assert.IsAssignableFrom>(resultData!.ToValue()); + IDictionary states = + Assert.IsAssignableFrom>(resultDict["accountState"]); + Assert.NotNull(states["stateRootHash"]); + } + [Fact] public async Task States() { - var currency = Currency.Uncapped("ABC", 2, minters: null); (IBlockChainStates, IBlockPolicy) source = ( new MockChainStates(), new BlockPolicy() ); @@ -35,6 +90,7 @@ public async Task States() { states( addresses: [""0x5003712B63baAB98094aD678EA2B24BcE445D076"", ""0x0000000000000000000000000000000000000000""], + accountAddress: ""0x40837BFebC1b192600023a431400557EA5FDE51a"" offsetBlockHash: ""01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"" ) @@ -93,12 +149,12 @@ public async Task Balance() [Fact] public async Task TotalSupply() { - var currency = Currency.Uncapped("ABC", 2, minters: null); + var currency = Currency.Uncapped("ABC", 2, minters: null); #pragma warning disable CS0618 // Legacy, which is obsolete, is the only way to test this: - var legacyToken = Currency.Legacy("LEG", 0, null); + var legacyToken = Currency.Legacy("LEG", 0, null); #pragma warning restore CS0618 - (IBlockChainStates, IBlockPolicy) source = ( - new MockChainStates(), new BlockPolicy()); + (IBlockChainStates, IBlockPolicy) source = ( + new MockChainStates(), new BlockPolicy()); ExecutionResult result = await ExecuteQueryAsync(@" { totalSupply( @@ -149,10 +205,10 @@ public async Task TotalSupply() [Fact] public async Task Validators() { - (IBlockChainStates, IBlockPolicy) source = ( - new MockChainStates(), - new BlockPolicy() - ); + (IBlockChainStates, IBlockPolicy) source = ( + new MockChainStates(), + new BlockPolicy() + ); ExecutionResult result = await ExecuteQueryAsync(@" { validators( @@ -349,37 +405,38 @@ public async Task ValidatorsBySrh() private class MockChainStates : IBlockChainStates { - public IValue GetState(Address address, Address accountAddress, BlockHash? offset) => - GetAccountState(accountAddress, offset).GetState(address); - public IReadOnlyList GetStates( - IReadOnlyList
addresses, Address accountAddress, BlockHash? offset) => - GetAccountState(accountAddress, offset).GetStates(addresses); + IReadOnlyList
addresses, + HashDigest? stateRootHash) + { + throw new System.NotImplementedException(); + } public FungibleAssetValue GetBalance( - Address address, - Currency currency, - BlockHash? offset) => - GetAccountState(ReservedAddresses.LegacyAccount, offset).GetBalance(address, currency); + Address address, Currency currency, BlockHash? offset) => + new MockAccount().GetBalance(address, currency); public FungibleAssetValue GetTotalSupply(Currency currency, BlockHash? offset) => - GetAccountState(ReservedAddresses.LegacyAccount, offset).GetTotalSupply(currency); + new MockAccount().GetTotalSupply(currency); public ValidatorSet GetValidatorSet(BlockHash? offset) => - GetAccountState(ReservedAddresses.LegacyAccount, offset).GetValidatorSet(); + new MockAccount().GetValidatorSet(); + + public IValue GetState(Address address, Address accountAddress, BlockHash? offset) + => new MockAccount().GetState(address); public IWorldState GetWorldState(BlockHash? offset) { throw new System.NotImplementedException(); } - public IAccountState GetAccountState(Address address, BlockHash? offset) => - new MockAccount(address, null); + public IReadOnlyList GetStates(IReadOnlyList
addresses, Address accountAddress, BlockHash? offset) + => new MockAccount().GetStates(addresses); - public IAccountState GetAccountState(HashDigest? hash) => - new MockAccount(null, hash); + public IAccountState GetAccountState(Address address, BlockHash? blockHash) + => new MockAccount(); - public ITrie GetTrie(BlockHash? offset) + public ITrie GetBlockTrie(BlockHash? offset) { throw new System.NotImplementedException(); } @@ -388,27 +445,75 @@ public ITrie GetTrie(HashDigest? hash) { throw new System.NotImplementedException(); } + + public IWorldState GetBlockWorldState(BlockHash? offset) + => new MockWorld(); + + public IWorldState GetWorldState(HashDigest? hash) + => new MockWorld(); + + public IAccountState GetAccountState(HashDigest? hash) + => new MockAccount(); } - private class MockAccount : IAccount + private class MockWorld : IWorld { - public MockAccount(Address? address, HashDigest? stateRootHash) + public MockWorld() + { + Trie = new TrieStateStore(new MemoryKeyValueStore()).GetStateRoot(null); + } + public ITrie Trie { get; } + + public bool Legacy => true; + + public IWorldDelta Delta => throw new System.NotImplementedException(); + + public IAccount GetAccount(Address address) + => new MockAccount(); + + public IWorld SetAccount(Address address, IAccount account) { - Address = address ?? default; - StateRootHash = stateRootHash ?? default; + throw new System.NotImplementedException(); } + } - public Address Address { get; } + private class MockAccount : IAccount + { + public MockAccount() + { + Trie = new TrieStateStore(new MemoryKeyValueStore()).GetStateRoot(null); + } public ITrie Trie { get; } - public IAccountDelta Delta { get; } + public IAccountDelta Delta => throw new System.NotImplementedException(); + + public IImmutableSet<(Address, Currency)> TotalUpdatedFungibleAssets => throw new System.NotImplementedException(); + + public IValue GetState(Address address) => GetStates(new[] { address }).First(); + + public IReadOnlyList GetStates(IReadOnlyList
addresses) => + addresses.Select(address => address.ToString() switch + { + "0x5003712B63baAB98094aD678EA2B24BcE445D076" => (IValue)Null.Value, + _ => null, + }).ToImmutableList(); + + public FungibleAssetValue GetBalance(Address address, Currency currency) => + currency * 123; - public BlockHash BlockHash { get; } + public FungibleAssetValue GetTotalSupply(Currency currency) => + currency * 10000; - public HashDigest StateRootHash { get; } + public ValidatorSet GetValidatorSet() => + new ValidatorSet(new List + { + new( + PublicKey.FromHex( + "032038e153d344773986c039ba5dbff12ae70cfdf6ea8beb7c5ea9b361a72a9233"), + new BigInteger(1)), + }); - public IImmutableSet<(Address, Currency)> TotalUpdatedFungibleAssets { get; } public IAccount SetState(Address address, IValue state) { throw new System.NotImplementedException(); @@ -419,8 +524,7 @@ public IAccount MintAsset(IActionContext context, Address recipient, FungibleAss throw new System.NotImplementedException(); } - public IAccount TransferAsset(IActionContext context, Address sender, Address recipient, - FungibleAssetValue value, bool allowNegativeBalance = false) + public IAccount TransferAsset(IActionContext context, Address sender, Address recipient, FungibleAssetValue value, bool allowNegativeBalance = false) { throw new System.NotImplementedException(); } @@ -434,36 +538,5 @@ public IAccount SetValidator(Validator validator) { throw new System.NotImplementedException(); } - - - public IValue GetState(Address address) => GetStates(new[] { address }).First(); - - public IReadOnlyList GetStates(IReadOnlyList
addresses) => - addresses.Select(address => address.ToString() switch - { - "0x5003712B63baAB98094aD678EA2B24BcE445D076" => (IValue)Null.Value, - _ => null, - }).ToImmutableList(); - - public FungibleAssetValue GetBalance(Address address, Currency currency) => - BlockHash is { } && StateRootHash is { } - ? currency * 123 - : currency * 0; - - public FungibleAssetValue GetTotalSupply(Currency currency) => - BlockHash is { } && StateRootHash is { } - ? currency * 10000 - : currency * 0; - - public ValidatorSet GetValidatorSet() => - BlockHash is { } && StateRootHash is { } - ? new ValidatorSet(new List - { - new( - PublicKey.FromHex( - "032038e153d344773986c039ba5dbff12ae70cfdf6ea8beb7c5ea9b361a72a9233"), - new BigInteger(1)), - }) - : new ValidatorSet(); } } diff --git a/Libplanet.Explorer.Tests/Queries/TransactionQueryTest.cs b/Libplanet.Explorer.Tests/Queries/TransactionQueryTest.cs index 3a0bb11ba1e..7eff5eba2d6 100644 --- a/Libplanet.Explorer.Tests/Queries/TransactionQueryTest.cs +++ b/Libplanet.Explorer.Tests/Queries/TransactionQueryTest.cs @@ -75,8 +75,14 @@ public async Task BindSignatureWithSystemAction() var action = new Initialize( new ValidatorSet(new List() { new Validator(new PrivateKey().PublicKey, 1 )}), - new Dictionary - { [default] = (Text)"initial value" }.ToImmutableDictionary()); + new Dictionary> + { + [default] = + new Dictionary + { + [default] = (Text)"initial value", + }.ToImmutableDictionary(), + }.ToImmutableDictionary()); var tx = Transaction.Create( 0L, new PrivateKey(), diff --git a/Libplanet.Explorer.Tests/SimpleAction.cs b/Libplanet.Explorer.Tests/SimpleAction.cs index e75e6c45cf5..be15e6b2775 100644 --- a/Libplanet.Explorer.Tests/SimpleAction.cs +++ b/Libplanet.Explorer.Tests/SimpleAction.cs @@ -23,7 +23,7 @@ public void LoadPlainValue(IValue plainValue) { } - public virtual IAccount Execute(IActionContext context) => context.PreviousState; + public virtual IWorld Execute(IActionContext context) => context.PreviousState; public static SimpleAction GetAction(int seed) => (seed % 10) switch @@ -90,6 +90,6 @@ public class SimpleAction8 : SimpleAction [ActionType(nameof(SimpleAction0Fail))] public class SimpleAction0Fail : SimpleAction { - public override IAccount Execute(IActionContext context) => + public override IWorld Execute(IActionContext context) => throw new CurrencyPermissionException("test message", context.Signer, default); } diff --git a/Libplanet.Explorer/Queries/StateQuery.cs b/Libplanet.Explorer/Queries/StateQuery.cs index 2b8a1c48ab8..c967a5a198a 100644 --- a/Libplanet.Explorer/Queries/StateQuery.cs +++ b/Libplanet.Explorer/Queries/StateQuery.cs @@ -200,9 +200,9 @@ private static object ResolveBalance( } case (_, srh: not null): - return context.Source.ChainStates.GetAccountState( - offsetStateRootHash - ).GetBalance(owner, currency); + return context.Source.ChainStates.GetWorldState(offsetStateRootHash) + .GetAccount(ReservedAddresses.LegacyAccount) + .GetBalance(owner, currency); } } diff --git a/Libplanet.Net.Tests/SwarmTest.Preload.cs b/Libplanet.Net.Tests/SwarmTest.Preload.cs index bc9db0d1c18..e2b11a8cd48 100644 --- a/Libplanet.Net.Tests/SwarmTest.Preload.cs +++ b/Libplanet.Net.Tests/SwarmTest.Preload.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Bencodex.Types; using Libplanet.Action; +using Libplanet.Action.State; using Libplanet.Action.Tests.Common; using Libplanet.Blockchain; using Libplanet.Blockchain.Policies; @@ -105,7 +106,8 @@ public async Task InitialBlockDownloadStates() await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer }, null); await receiverSwarm.PreloadAsync(); - var state = receiverChain.GetState(address1); + var state = receiverChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address1); Assert.Equal((Text)"foo,bar,baz", state); Assert.Equal(minerChain.BlockHashes, receiverChain.BlockHashes); @@ -743,7 +745,8 @@ public async Task PreloadAsyncCancellation(int cancelAfter) Assert.Equal(blockArray[0], receiverChain.Tip); Assert.Equal( (Text)string.Join(",", Enumerable.Range(0, 5).Select(j => $"Item0.{j}")), - receiverChain.GetState(address) + receiverChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address) ); } else @@ -756,7 +759,8 @@ public async Task PreloadAsyncCancellation(int cancelAfter) string.Join(",", Enumerable.Range(0, 5).Select(j => $"Item{i}.{j}")) ) ), - receiverChain.GetState(address) + receiverChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address) ); } diff --git a/Libplanet.Net.Tests/SwarmTest.cs b/Libplanet.Net.Tests/SwarmTest.cs index 419f35f00ba..5f4ecb5920a 100644 --- a/Libplanet.Net.Tests/SwarmTest.cs +++ b/Libplanet.Net.Tests/SwarmTest.cs @@ -1055,8 +1055,10 @@ public async void RestageTransactionsOnceLocallyMinedAfterReorg(bool restage) keyB, CreateBlockCommit(minerB.BlockChain.Tip)); minerB.BlockChain.Append(blockC, TestUtils.CreateBlockCommit(blockC)); - Assert.Equal((Text)dumbItem, minerA.BlockChain.GetState(targetAddress1)); - Assert.Equal((Text)dumbItem, minerB.BlockChain.GetState(targetAddress2)); + Assert.Equal((Text)dumbItem, minerA.BlockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(targetAddress1)); + Assert.Equal((Text)dumbItem, minerB.BlockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(targetAddress2)); await StartAsync(minerA); await StartAsync(minerB); @@ -1071,8 +1073,10 @@ public async void RestageTransactionsOnceLocallyMinedAfterReorg(bool restage) Assert.Equal(3, minerA.BlockChain.Count); Assert.Equal( restage ? null : (Text?)dumbItem, - minerA.BlockChain.GetState(targetAddress1)); - Assert.Equal((Text)dumbItem, minerA.BlockChain.GetState(targetAddress2)); + minerA.BlockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(targetAddress1)); + Assert.Equal((Text)dumbItem, minerA.BlockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(targetAddress2)); Log.Debug("Check if txs in unrendered blocks staged again"); Assert.Equal( @@ -1086,8 +1090,10 @@ public async void RestageTransactionsOnceLocallyMinedAfterReorg(bool restage) await minerB.BlockAppended.WaitAsync(); Assert.Equal(minerA.BlockChain.Tip, minerB.BlockChain.Tip); - Assert.Equal((Text)dumbItem, minerA.BlockChain.GetState(targetAddress1)); - Assert.Equal((Text)dumbItem, minerA.BlockChain.GetState(targetAddress2)); + Assert.Equal((Text)dumbItem, minerA.BlockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(targetAddress1)); + Assert.Equal((Text)dumbItem, minerA.BlockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(targetAddress2)); } finally { @@ -1395,9 +1401,12 @@ public async Task DoNotReceiveBlockFromNodeHavingDifferenceGenesisBlock() Assert.Equal(1, genesisChainB.Count); Assert.Equal(2, genesisChainC.Count); - Assert.Equal("1", (Text)genesisChainA.GetState(signerAddress)); - Assert.Equal("2", (Text)genesisChainB.GetState(signerAddress)); - Assert.Equal("1", (Text)genesisChainC.GetState(signerAddress)); + Assert.Equal("1", (Text)genesisChainA.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(signerAddress)); + Assert.Equal("2", (Text)genesisChainB.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(signerAddress)); + Assert.Equal("1", (Text)genesisChainC.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(signerAddress)); } finally { @@ -2017,7 +2026,7 @@ private class Sleep : IAction { public IValue PlainValue => Null.Value; - public IAccount Execute(IActionContext context) + public IWorld Execute(IActionContext context) { Thread.Sleep(10); return context.PreviousState; diff --git a/Libplanet.Tests/Action/AccountDiffTest.cs b/Libplanet.Tests/Action/AccountDiffTest.cs index 16c902ad210..a47fdec6bb6 100644 --- a/Libplanet.Tests/Action/AccountDiffTest.cs +++ b/Libplanet.Tests/Action/AccountDiffTest.cs @@ -40,7 +40,7 @@ public void EmptyAccountStateSource() Assert.Empty(diff.TotalSupplyDiffs); Assert.Null(diff.ValidatorSetDiff); - IAccount targetAccount = new Account(new AccountState(targetTrie)); + IAccount targetAccount = new Account(new AccountBaseState(targetTrie)); PrivateKey signer = new PrivateKey(); IActionContext context = CreateActionContext(signer.ToAddress(), targetTrie); targetAccount = targetAccount.MintAsset( @@ -73,7 +73,7 @@ public void Diff() Assert.Empty(diff.TotalSupplyDiffs); Assert.Null(diff.ValidatorSetDiff); - IAccount targetAccount = new Account(new AccountState(targetTrie)); + IAccount targetAccount = new Account(new AccountBaseState(targetTrie)); PrivateKey signer = new PrivateKey(); IActionContext context = CreateActionContext(signer.ToAddress(), targetTrie); targetAccount = targetAccount.SetState(addr1, new Text("One")); @@ -84,7 +84,7 @@ public void Diff() targetTrie = Commit(stateStore, targetTrie, targetAccount.Delta); sourceTrie = targetTrie; - IAccount sourceAccount = new Account(new AccountState(sourceTrie)); + IAccount sourceAccount = new Account(new AccountBaseState(sourceTrie)); sourceAccount = sourceAccount.SetState(addr2, new Text("Two_")); sourceAccount = sourceAccount.SetState(addr3, new Text("Three")); sourceAccount = sourceAccount.MintAsset( @@ -148,7 +148,10 @@ public IActionContext CreateActionContext(Address signer, ITrie trie) => signer, 0, Block.CurrentProtocolVersion, - new Account(new AccountState(trie)), + new World( + new WorldBaseState( + trie, + new TrieStateStore(new MemoryKeyValueStore()))), 0, 0, false); diff --git a/Libplanet.Tests/Action/AccountV0Test.cs b/Libplanet.Tests/Action/AccountV0Test.cs index b17714c7fce..d7f12211aee 100644 --- a/Libplanet.Tests/Action/AccountV0Test.cs +++ b/Libplanet.Tests/Action/AccountV0Test.cs @@ -1,6 +1,7 @@ using Libplanet.Action; using Libplanet.Action.State; using Libplanet.Action.Tests.Common; +using Libplanet.Action.Tests.Mocks; using Libplanet.Blockchain; using Libplanet.Crypto; using Libplanet.Types.Blocks; @@ -12,6 +13,9 @@ namespace Libplanet.Tests.Action { public class AccountV0Test : AccountTest { + private readonly Address _accountAddress + = new Address("2000000000000000000000000000000000000000"); + public AccountV0Test(ITestOutputHelper output) : base(output) { @@ -20,16 +24,20 @@ public AccountV0Test(ITestOutputHelper output) public override int ProtocolVersion { get; } = 0; public override IActionContext CreateContext( - IAccount delta, Address signer) => - new ActionContext( + IAccount delta, Address signer) + { + IWorld world = World.Create(new MockWorldState()); + world = world.SetAccount(_accountAddress, delta); + return new ActionContext( signer, null, signer, 0, ProtocolVersion, - delta, + world, 0, 0); + } [Fact] public override void TransferAsset() diff --git a/Libplanet.Tests/Action/AccountV1Test.cs b/Libplanet.Tests/Action/AccountV1Test.cs index c646dcb7f51..126e2ecc8ca 100644 --- a/Libplanet.Tests/Action/AccountV1Test.cs +++ b/Libplanet.Tests/Action/AccountV1Test.cs @@ -3,6 +3,7 @@ using Libplanet.Action; using Libplanet.Action.State; using Libplanet.Action.Tests.Common; +using Libplanet.Action.Tests.Mocks; using Libplanet.Blockchain; using Libplanet.Crypto; using Libplanet.Types.Assets; @@ -15,6 +16,9 @@ namespace Libplanet.Tests.Action { public class AccountV1Test : AccountTest { + private readonly Address _accountAddress + = new Address("2000000000000000000000000000000000000000"); + public AccountV1Test(ITestOutputHelper output) : base(output) { @@ -22,17 +26,20 @@ public AccountV1Test(ITestOutputHelper output) public override int ProtocolVersion { get; } = Block.CurrentProtocolVersion; - public override IActionContext CreateContext( - IAccount delta, Address signer) => - new ActionContext( + public override IActionContext CreateContext(IAccount delta, Address signer) + { + IWorld world = World.Create(new MockWorldState()); + world = world.SetAccount(_accountAddress, delta); + return new ActionContext( signer, null, signer, 0, ProtocolVersion, - delta, + world, 0, 0); + } [Fact] public override void TransferAsset() diff --git a/Libplanet.Tests/Action/ActionEvaluatorTest.cs b/Libplanet.Tests/Action/ActionEvaluatorTest.cs index ca5f9d2eb08..cfaec006c99 100644 --- a/Libplanet.Tests/Action/ActionEvaluatorTest.cs +++ b/Libplanet.Tests/Action/ActionEvaluatorTest.cs @@ -1465,4 +1465,4 @@ public IEnumerator GetEnumerator() IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } #pragma warning restore SA1402 -} +} \ No newline at end of file diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs index e4ace3c7e92..57af325e63e 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs @@ -81,47 +81,62 @@ Func getTxExecution Assert.Equal( new IValue[] { null, null, null, null, (Integer)1 }, addresses.Select( - _blockChain.GetAccountState(renders[0].Context.PreviousState).GetState) + _blockChain.GetWorldState(renders[0].Context.PreviousState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState) ); Assert.Equal( new IValue[] { (Text)"foo", null, null, null, (Integer)1 }, - addresses.Select(_blockChain.GetAccountState(renders[0].NextState).GetState) + addresses.Select( + _blockChain.GetWorldState(renders[0].NextState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState) ); Assert.Equal("bar", actions[1].Item); Assert.Equal(2, renders[1].Context.BlockIndex); Assert.Equal( - addresses.Select(_blockChain.GetAccountState(renders[0].NextState).GetState), - addresses.Select( - _blockChain.GetAccountState(renders[1].Context.PreviousState).GetState) + addresses.Select(_blockChain.GetWorldState(renders[0].NextState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState), + addresses.Select(_blockChain.GetWorldState(renders[1].Context.PreviousState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState) ); Assert.Equal( new IValue[] { (Text)"foo", (Text)"bar", null, null, (Integer)1 }, - addresses.Select(_blockChain.GetAccountState(renders[1].NextState).GetState) + addresses.Select( + _blockChain.GetWorldState(renders[1].NextState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState) ); Assert.Equal("baz", actions[2].Item); Assert.Equal(2, renders[2].Context.BlockIndex); Assert.Equal( - addresses.Select(_blockChain.GetAccountState(renders[1].NextState).GetState), addresses.Select( - _blockChain.GetAccountState(renders[2].Context.PreviousState).GetState) + _blockChain.GetWorldState(renders[1].NextState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState), + addresses.Select( + _blockChain.GetWorldState(renders[2].Context.PreviousState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState) ); Assert.Equal( new IValue[] { (Text)"foo", (Text)"bar", (Text)"baz", null, (Integer)1 }, - addresses.Select(_blockChain.GetAccountState(renders[2].NextState).GetState) + addresses.Select( + _blockChain.GetWorldState(renders[2].NextState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState) ); Assert.Equal("qux", actions[3].Item); Assert.Equal(2, renders[3].Context.BlockIndex); Assert.Equal( - addresses.Select(_blockChain.GetAccountState(renders[2].NextState).GetState), addresses.Select( - _blockChain.GetAccountState(renders[3].Context.PreviousState).GetState) + _blockChain.GetWorldState(renders[2].NextState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState), + addresses.Select( + _blockChain.GetWorldState(renders[3].Context.PreviousState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState) ); Assert.Equal( new IValue[] { (Text)"foo", (Text)"bar", (Text)"baz", (Text)"qux", (Integer)1, }, - _blockChain.GetAccountState(renders[3].NextState).GetStates(addresses) + _blockChain.GetWorldState(renders[3].NextState) + .GetAccount(ReservedAddresses.LegacyAccount).GetStates(addresses) ); Address minerAddress = addresses[4]; @@ -129,7 +144,8 @@ Func getTxExecution .Where(r => TestUtils.IsMinerReward(r.Action)) .ToArray(); - Assert.Equal((Integer)2, (Integer)_blockChain.GetState(minerAddress)); + Assert.Equal((Integer)2, (Integer)_blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(minerAddress)); Assert.Equal(2, blockRenders.Length); Assert.True(blockRenders.All(r => r.Render)); Assert.Equal(1, blockRenders[0].Context.BlockIndex); @@ -137,18 +153,18 @@ Func getTxExecution Assert.Equal( (Integer)1, - (Integer)_blockChain.GetAccountState( - blockRenders[0].NextState).GetState(minerAddress) + (Integer)_blockChain.GetWorldState(blockRenders[0].NextState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState(minerAddress) ); Assert.Equal( (Integer)1, - (Integer)_blockChain.GetAccountState(blockRenders[1].Context.PreviousState) - .GetState(minerAddress) + (Integer)_blockChain.GetWorldState(blockRenders[1].Context.PreviousState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState(minerAddress) ); Assert.Equal( (Integer)2, - (Integer)_blockChain.GetAccountState( - blockRenders[1].NextState).GetState(minerAddress) + (Integer)_blockChain.GetWorldState(blockRenders[1].NextState) + .GetAccount(ReservedAddresses.LegacyAccount).GetState(minerAddress) ); foreach (Transaction tx in txs) @@ -161,9 +177,11 @@ Func getTxExecution Assert.Equal(block2.Hash, e.BlockHash); Assert.Equal(tx.Id, e.TxId); var inputAccount = - _blockChain.GetAccountState(Assert.IsType>(e.InputState)); + _blockChain.GetWorldState(Assert.IsType>(e.InputState)) + .GetAccount(ReservedAddresses.LegacyAccount); var outputAccount = - _blockChain.GetAccountState(Assert.IsType>(e.OutputState)); + _blockChain.GetWorldState(Assert.IsType>(e.OutputState)) + .GetAccount(ReservedAddresses.LegacyAccount); var accountDiff = AccountDiff.Create(inputAccount, outputAccount); Assert.Empty(accountDiff.FungibleAssetValueDiffs); } @@ -256,6 +274,44 @@ Func getTxExecution outputAccount3.GetBalance(addresses[1], DumbAction.DumbCurrency)); } + [SkippableFact] + public void AppendModern() + { + _blockChain = TestUtils.MakeBlockChain( + new NullBlockPolicy(), + new MemoryStore(), + new TrieStateStore(new MemoryKeyValueStore())); + var genesis = _blockChain.Genesis; + var address1 = new Address(TestUtils.GetRandomBytes(20)); + var address2 = new Address(TestUtils.GetRandomBytes(20)); + var miner = new PrivateKey(); + var action1 = new DumbModernAction(address1, "foo"); + var action2 = new DumbModernAction(address2, "bar"); + var tx1 = Transaction.Create(0, miner, genesis.Hash, new[] { action1 }.ToPlainValues()); + var tx2 = Transaction.Create(1, miner, genesis.Hash, new[] { action2 }.ToPlainValues()); + var block1 = _blockChain.ProposeBlock( + miner, + new[] { tx1 }.ToImmutableList(), + TestUtils.CreateBlockCommit(_blockChain.Tip)); + var commit1 = TestUtils.CreateBlockCommit(block1); + _blockChain.Append(block1, commit1); + Assert.Equal( + (Text)"foo", + _blockChain.GetWorldState() + .GetAccount(DumbModernAction.DumbModernAddress) + .GetState(address1)); + var block2 = _blockChain.ProposeBlock( + miner, + new[] { tx2 }.ToImmutableList(), + commit1); + _blockChain.Append(block2, TestUtils.CreateBlockCommit(block2)); + Assert.Equal( + (Text)"bar", + _blockChain.GetWorldState() + .GetAccount(DumbModernAction.DumbModernAddress) + .GetState(address2)); + } + [SkippableFact] public void AppendFailDueToInvalidBytesLength() { diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.ProposeBlock.cs b/Libplanet.Tests/Blockchain/BlockChainTest.ProposeBlock.cs index 03aa45dbc77..74b907f42d7 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.ProposeBlock.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.ProposeBlock.cs @@ -5,6 +5,7 @@ using Bencodex.Types; using Libplanet.Action; using Libplanet.Action.Loader; +using Libplanet.Action.State; using Libplanet.Action.Tests.Common; using Libplanet.Blockchain; using Libplanet.Blockchain.Policies; @@ -28,7 +29,8 @@ public void ProposeBlock() Assert.Equal(1, _blockChain.Count); AssertBencodexEqual( (Text)$"{GenesisProposer.ToAddress()}", - _blockChain.GetState(default)); + _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(default)); var proposerA = new PrivateKey(); Block block = _blockChain.ProposeBlock(proposerA); @@ -39,7 +41,8 @@ public void ProposeBlock() block.MarshalBlock().EncodingLength <= getMaxTransactionsBytes(block.Index)); AssertBencodexEqual( (Text)$"{GenesisProposer.ToAddress()},{proposerA.ToAddress()}", - _blockChain.GetState(default) + _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(default) ); var proposerB = new PrivateKey(); @@ -56,7 +59,8 @@ public void ProposeBlock() $"{GenesisProposer.ToAddress()},{proposerA.ToAddress()},{proposerB.ToAddress()}"); AssertBencodexEqual( expected, - _blockChain.GetState(default) + _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(default) ); Block block3 = _blockChain.ProposeBlock( @@ -70,7 +74,8 @@ public void ProposeBlock() $"{GenesisProposer.ToAddress()},{proposerA.ToAddress()},{proposerB.ToAddress()}"); AssertBencodexEqual( expected, - _blockChain.GetState(default) + _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(default) ); // Tests if ProposeBlock() method automatically fits the number of transactions @@ -113,7 +118,8 @@ public void ProposeBlock() $"{GenesisProposer.ToAddress()},{proposerA.ToAddress()},{proposerB.ToAddress()}"); AssertBencodexEqual( expected, - _blockChain.GetState(default) + _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(default) ); } @@ -270,11 +276,16 @@ public void ProposeBlockWithPendingTxs() StageTransactions(txs); - Assert.Null(_blockChain.GetState(addrA)); - Assert.Null(_blockChain.GetState(addrB)); - Assert.Null(_blockChain.GetState(addrC)); - Assert.Null(_blockChain.GetState(addrD)); - Assert.Null(_blockChain.GetState(addrE)); + Assert.Null(_blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(addrA)); + Assert.Null(_blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(addrB)); + Assert.Null(_blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(addrC)); + Assert.Null(_blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(addrD)); + Assert.Null(_blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(addrE)); foreach (Transaction tx in txs) { @@ -295,15 +306,22 @@ public void ProposeBlockWithPendingTxs() Assert.Contains(txs[2].Id, txIds); Assert.Contains(txs[3].Id, txIds); - Assert.Equal(new Integer(1), _blockChain.GetState(addrA)); - Assert.Equal(new Text("1b"), _blockChain.GetState(addrB)); - Assert.Equal(new Text("2a"), _blockChain.GetState(addrC)); - Assert.IsType(_blockChain.GetState(addrD)); + Assert.Equal(new Integer(1), _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(addrA)); + Assert.Equal(new Text("1b"), _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(addrB)); + Assert.Equal(new Text("2a"), _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(addrC)); + Assert.IsType(_blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(addrD)); Assert.Equal( new HashSet { "2b", "5a" }, - ((string)(Text)_blockChain.GetState(addrD)).Split(new[] { ',' }).ToHashSet() + ((string)(Text)_blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(addrD)).Split(new[] { ',' }) + .ToHashSet() ); - Assert.Equal(new Text("5b"), _blockChain.GetState(addrE)); + Assert.Equal(new Text("5b"), _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(addrE)); foreach (Transaction tx in new[] { txs[0], txs[1], txs[4] }) { @@ -464,8 +482,10 @@ public void ProposeBlockWithBlockAction() var block = blockChain.ProposeBlock(privateKey1, CreateBlockCommit(_blockChain.Tip)); blockChain.Append(block, CreateBlockCommit(block)); - var state1 = blockChain.GetState(address1); - var state2 = blockChain.GetState(address2); + var state1 = blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address1); + var state2 = blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address2); Assert.Equal(0, blockChain.GetNextTxNonce(address1)); Assert.Equal(1, blockChain.GetNextTxNonce(address2)); @@ -476,8 +496,10 @@ public void ProposeBlockWithBlockAction() block = blockChain.ProposeBlock(privateKey1, CreateBlockCommit(_blockChain.Tip)); blockChain.Append(block, CreateBlockCommit(block)); - state1 = blockChain.GetState(address1); - state2 = blockChain.GetState(address2); + state1 = blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address1); + state2 = blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address2); Assert.Equal(1, blockChain.GetNextTxNonce(address1)); Assert.Equal(1, blockChain.GetNextTxNonce(address2)); diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs index a2aa00fa8f6..35159affd0a 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs @@ -213,7 +213,7 @@ public void ValidateNextBlockInvalidStateRootHash() TestUtils.GenesisProposer); var policyWithBlockAction = new BlockPolicy( - new SetStatesAtBlock(default, (Text)"foo", 1), + new SetStatesAtBlock(default, (Text)"foo", default, 1), policy.BlockInterval ); var chain2 = new BlockChain( diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index 83a6e56ce8a..10c1e05e0b7 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -193,7 +193,8 @@ public void ProcessActions() { new Initialize( validatorSet: TestUtils.ValidatorSet, - states: ImmutableDictionary.Create()), + states: ImmutableDictionary.Create + >()), }.ToPlainValues(), timestamp: DateTimeOffset.UtcNow)) .OrderBy(tx => tx.Id) @@ -239,7 +240,8 @@ public void ProcessActions() chain.StageTransaction(tx1); Block block1 = chain.ProposeBlock(new PrivateKey()); chain.Append(block1, CreateBlockCommit(block1)); - IValue state = chain.GetState(_fx.Address1); + IValue state = chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(_fx.Address1); Assert.NotNull(state); var result = BattleResult.FromBencodex((Bencodex.Types.Dictionary)state); @@ -269,7 +271,8 @@ public void ProcessActions() new PrivateKey(), CreateBlockCommit(chain.Tip)); chain.Append(block2, CreateBlockCommit(block2)); - state = chain.GetState(_fx.Address1); + state = chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(_fx.Address1); result = BattleResult.FromBencodex((Bencodex.Types.Dictionary)state); Assert.Contains("bow", result.UsedWeapons); @@ -291,7 +294,8 @@ public void ProcessActions() new PrivateKey(), CreateBlockCommit(chain.Tip)); chain.StageTransaction(tx3); chain.Append(block3, CreateBlockCommit(block3)); - state = chain.GetState(_fx.Address1); + state = chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(_fx.Address1); Assert.NotNull(state); } @@ -568,16 +572,19 @@ public void StateAfterForkingAndAddingExistingBlock() var b2 = _blockChain.ProposeBlock( miner, lastCommit: CreateBlockCommit(_blockChain.Tip)); _blockChain.Append(b2, CreateBlockCommit(b2)); - var state = _blockChain.GetState(address); + var state = _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address); Assert.Equal((Text)"foo,bar", state); var forked = _blockChain.Fork(b1.Hash); - state = forked.GetState(address); + state = forked.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address); Assert.Equal((Text)"foo", state); forked.Append(b2, CreateBlockCommit(b2)); - state = forked.GetState(address); + state = forked.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address); Assert.Equal((Text)"foo,bar", state); } @@ -911,7 +918,8 @@ public void Swap(bool render) // except genesis block. Assert.Equal( (Integer)(totalBlockCount - 1), - (Integer)_blockChain.GetState(minerAddress) + (Integer)_blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(minerAddress) ); Assert.Single(blockActionRenders); // #1 -> #2' Assert.True(blockActionRenders.All(r => r.Render)); @@ -1142,7 +1150,10 @@ public void GetStateOnlyDrillsDownUntilRequestedAddressesAreFound() Math.Min(10, addresses.Length - testingDepth - 1) ).Select(i => addresses[i]).ToArray(); - Assert.All(chain.GetStates(targetAddresses), Assert.NotNull); + Assert.All( + chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetStates(targetAddresses), + Assert.NotNull); var callCount = tracker.Logs.Where( trackLog => trackLog.Method == "GetBlockStates" @@ -1175,7 +1186,8 @@ public void GetStateReturnsEarlyForNonexistentAccount() tracker.ClearLogs(); Address nonexistent = new PrivateKey().ToAddress(); - IValue result = chain.GetState(nonexistent); + IValue result = chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(nonexistent); Assert.Null(result); var callCount = tracker.Logs.Where( trackLog => trackLog.Method == "GetBlockStates" @@ -1198,7 +1210,8 @@ public void GetStateReturnsValidStateAfterFork() store, stateStore, new[] { new DumbAction(_fx.Address1, "item0.0", idempotent: true) }); - Assert.Equal("item0.0", (Text)chain.GetState(_fx.Address1)); + Assert.Equal("item0.0", (Text)chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(_fx.Address1)); chain.MakeTransaction( privateKey, @@ -1209,17 +1222,21 @@ public void GetStateReturnsValidStateAfterFork() chain.Append(block, CreateBlockCommit(block)); Assert.Equal( new IValue[] { (Text)"item0.0,item1.0" }, - chain.GetStates(new[] { _fx.Address1 }) + chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetStates(new[] { _fx.Address1 }) ); - Assert.Equal("item0.0,item1.0", (Text)chain.GetState(_fx.Address1)); + Assert.Equal("item0.0,item1.0", (Text)chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(_fx.Address1)); var forked = chain.Fork(chain.Tip.Hash); Assert.Equal(2, forked.Count); Assert.Equal( new IValue[] { (Text)"item0.0,item1.0" }, - forked.GetStates(new[] { _fx.Address1 }) + forked.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetStates(new[] { _fx.Address1 }) ); - Assert.Equal("item0.0,item1.0", (Text)forked.GetState(_fx.Address1)); + Assert.Equal("item0.0,item1.0", (Text)forked.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(_fx.Address1)); } [SkippableFact] @@ -1239,10 +1256,14 @@ public void GetStateReturnsLatestStatesWhenMultipleAddresses() _fx.StateStore, new SingleActionLoader(typeof(DumbAction)))); - Assert.All(chain.GetStates(addresses), Assert.Null); + Assert.All( + chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetStates(addresses), + Assert.Null); foreach (var address in addresses) { - Assert.Null(chain.GetState(address)); + Assert.Null(chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address)); } var privateKeysAndAddresses10 = privateKeys.Zip(addresses, (k, a) => (k, a)); @@ -1256,19 +1277,25 @@ public void GetStateReturnsLatestStatesWhenMultipleAddresses() chain.Append(block1, CreateBlockCommit(block1)); - Assert.All(chain.GetStates(addresses), v => Assert.Equal((Text)"1", v)); + Assert.All( + chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetStates(addresses), + v => Assert.Equal((Text)"1", v)); foreach (var address in addresses) { - Assert.Equal((Text)"1", chain.GetState(address)); + Assert.Equal((Text)"1", chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address)); } chain.MakeTransaction(privateKeys[0], new[] { new DumbAction(addresses[0], "2") }); Block block2 = chain.ProposeBlock( privateKeys[0], lastCommit: CreateBlockCommit(chain.Tip)); chain.Append(block2, CreateBlockCommit(block2)); - Assert.Equal((Text)"1,2", chain.GetState(addresses[0])); + Assert.Equal((Text)"1,2", chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(addresses[0])); Assert.All( - chain.GetStates(addresses.Skip(1).ToArray()), + chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetStates(addresses.Skip(1).ToArray()), v => Assert.Equal((Text)"1", v) ); } @@ -1508,8 +1535,14 @@ public void MakeTransactionWithSystemAction() var action = new Initialize( new ValidatorSet( new List() { new Validator(new PrivateKey().PublicKey, 1) }), - new Dictionary - { [default] = (Text)"initial value" }.ToImmutableDictionary()); + new Dictionary> + { + [default] = + new Dictionary + { + [default] = (Text)"initial value", + }.ToImmutableDictionary(), + }.ToImmutableDictionary()); _blockChain.MakeTransaction(privateKey, actions: new IAction[] { action }); _blockChain.MakeTransaction(privateKey, actions: new IAction[] { action }); @@ -1605,9 +1638,12 @@ public void BlockActionWithMultipleAddress() miner2, lastCommit: CreateBlockCommit(_blockChain.Tip)); _blockChain.Append(block3, CreateBlockCommit(block3)); - IValue miner1state = _blockChain.GetState(miner1.ToAddress()); - IValue miner2state = _blockChain.GetState(miner2.ToAddress()); - IValue rewardState = _blockChain.GetState(rewardRecordAddress); + IValue miner1state = _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(miner1.ToAddress()); + IValue miner2state = _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(miner2.ToAddress()); + IValue rewardState = _blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(rewardRecordAddress); AssertBencodexEqual((Integer)2, miner1state); AssertBencodexEqual((Integer)1, miner2state); @@ -1695,7 +1731,7 @@ void BuildIndex(Guid id, Block block) // Build a store with incomplete states Block b = chain.Genesis; - IAccount previousState = actionEvaluator.PrepareInitialDelta(null); + IWorld previousState = actionEvaluator.PrepareInitialDelta(null); ActionEvaluation[] evals = actionEvaluator.EvaluateBlock(b, previousState).ToArray(); IImmutableDictionary dirty = evals.GetDirtyStates(); @@ -1852,7 +1888,8 @@ private void CreateWithGenesisBlock() var systemActions = new IAction[] { new Initialize( - states: ImmutableDictionary.Create(), + states: ImmutableDictionary.Create< + Address, IImmutableDictionary>(), validatorSet: new ValidatorSet( new List { @@ -1909,7 +1946,8 @@ private void CreateWithGenesisBlock() tx => !(tx.Actions is null) && tx.Actions.All(a => !Registry.IsSystemAction(a))).UpdatedAddresses); - var states = addresses.Select(address => blockChain.GetState(address)) + var states = addresses.Select(address => blockChain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(address)) .ToArray(); for (int i = 0; i < states.Length; ++i) { @@ -1991,8 +2029,10 @@ private void CheckIfTxPolicyExceptionHasInnerException() { // ReSharper disable AccessToModifiedClosure // The following method calls should not throw any exceptions: - x?.GetStates(new[] { default(Address) }); - x?.GetState(default); + x?.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetStates(new[] { default(Address) }); + x?.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(default); // ReSharper restore AccessToModifiedClosure }); IStore store = new MemoryStore(); @@ -2053,7 +2093,8 @@ private void ValidateNextBlockCommitOnValidatorSetChange() { new Initialize( validatorSet: initialValidatorSet, - states: ImmutableDictionary.Create() + states: ImmutableDictionary.Create< + Address, IImmutableDictionary>() ), }; var privateKey = new PrivateKey(); diff --git a/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs index 1966eb0cf09..06dd9aa4770 100644 --- a/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs @@ -16,7 +16,7 @@ public class AnonymousActionRendererTest { private static IValue _action = new DumbAction().PlainValue; - private static IAccount _account = new Account(MockAccountState.Empty); + private static IWorld _world = World.Create(new MockWorldState()); private static ICommittedActionContext _actionContext = new CommittedActionContext(new ActionContext( @@ -25,7 +25,7 @@ public class AnonymousActionRendererTest default, Block.CurrentProtocolVersion, default, - _account, + _world, default, 0)); @@ -55,11 +55,11 @@ record = (action, context, nextState), renderer.RenderBlock(_genesis, _blockA); Assert.Null(record); - renderer.RenderAction(_action, _actionContext, _account.Trie.Hash); + renderer.RenderAction(_action, _actionContext, _world.Trie.Hash); Assert.NotNull(record); Assert.Same(_action, record?.Item1); Assert.Same(_actionContext, record?.Item2); - Assert.Equal(_account.Trie.Hash, record?.Item3); + Assert.Equal(_world.Trie.Hash, record?.Item3); } [Fact] @@ -72,7 +72,7 @@ public void ActionErrorRenderer() record = (action, context, exception), }; - renderer.RenderAction(_action, _actionContext, _account.Trie.Hash); + renderer.RenderAction(_action, _actionContext, _world.Trie.Hash); Assert.Null(record); renderer.RenderBlock(_genesis, _blockA); Assert.Null(record); @@ -93,7 +93,7 @@ public void BlockRenderer() BlockRenderer = (oldTip, newTip) => record = (oldTip, newTip), }; - renderer.RenderAction(_action, _actionContext, _account.Trie.Hash); + renderer.RenderAction(_action, _actionContext, _world.Trie.Hash); Assert.Null(record); renderer.RenderActionError(_action, _actionContext, _exception); Assert.Null(record); diff --git a/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs b/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs index 4c8220d8616..1af3c2c745a 100644 --- a/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs +++ b/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs @@ -23,7 +23,7 @@ public class LoggedActionRendererTest : IDisposable { private static IValue _action = new DumbAction().PlainValue; - private static IAccount _account = new Account(MockAccountState.Empty); + private static IWorld _world = World.Create(new MockWorldState()); private static Block _genesis = TestUtils.ProposeGenesisBlock(TestUtils.GenesisProposer); @@ -75,7 +75,7 @@ public void ActionRenderings(bool error, bool rehearsal, bool exception) default, Block.CurrentProtocolVersion, 123, - _account, + _world, default, 0, rehearsal)); @@ -112,7 +112,7 @@ public void ActionRenderings(bool error, bool rehearsal, bool exception) firstLog = logs[0]; Assert.Same(_action, action); Assert.Same(actionContext, cxt); - Assert.Equal(_account.Trie.Hash, next); + Assert.Equal(_world.Trie.Hash, next); called = true; if (exception) { @@ -147,7 +147,7 @@ public void ActionRenderings(bool error, bool rehearsal, bool exception) } else { - actionRenderer.RenderAction(_action, actionContext, _account.Trie.Hash); + actionRenderer.RenderAction(_action, actionContext, _world.Trie.Hash); } } catch (ThrowException.SomeException e) diff --git a/Libplanet.Tests/Blocks/PreEvaluationBlockTest.cs b/Libplanet.Tests/Blocks/PreEvaluationBlockTest.cs index ccde686aa6f..55316b4dd6b 100644 --- a/Libplanet.Tests/Blocks/PreEvaluationBlockTest.cs +++ b/Libplanet.Tests/Blocks/PreEvaluationBlockTest.cs @@ -2,6 +2,7 @@ using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Action.Loader; +using Libplanet.Action.State; using Libplanet.Action.Tests.Common; using Libplanet.Blockchain; using Libplanet.Blockchain.Policies; @@ -30,7 +31,8 @@ public PreEvaluationBlockTest(ITestOutputHelper output) public void Evaluate() { Address address = _contents.Block1Tx0.Signer; - var blockAction = new SetStatesAtBlock(address, (Bencodex.Types.Integer)123, 0); + var blockAction = new SetStatesAtBlock( + address, (Bencodex.Types.Integer)123, ReservedAddresses.LegacyAccount, 0); var policy = new BlockPolicy( blockAction: blockAction, blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000)); @@ -59,7 +61,8 @@ public void Evaluate() fx.StateStore, genesis, actionEvaluator); - AssertBencodexEqual((Bencodex.Types.Integer)123, blockChain.GetState(address)); + AssertBencodexEqual((Bencodex.Types.Integer)123, blockChain.GetWorldState() + .GetAccount(ReservedAddresses.LegacyAccount).GetState(address)); HashDigest identicalGenesisStateRootHash = blockChain.DetermineBlockStateRootHash(preEvalGenesis, out _); @@ -86,7 +89,8 @@ public void Evaluate() AssertBytesEqual(block1.StateRootHash, identicalBlock1StateRootHash); blockChain.Append(block1, TestUtils.CreateBlockCommit(block1)); - AssertBencodexEqual((Bencodex.Types.Integer)158, blockChain.GetState(address)); + AssertBencodexEqual((Bencodex.Types.Integer)158, blockChain.GetWorldState() + .GetAccount(ReservedAddresses.LegacyAccount).GetState(address)); } } @@ -94,7 +98,8 @@ public void Evaluate() public void DetermineStateRootHash() { Address address = _contents.Block1Tx0.Signer; - var blockAction = new SetStatesAtBlock(address, (Bencodex.Types.Integer)123, 0); + var blockAction = new SetStatesAtBlock( + address, (Bencodex.Types.Integer)123, ReservedAddresses.LegacyAccount, 0); var policy = new BlockPolicy( blockAction: blockAction, blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000)); @@ -123,7 +128,8 @@ public void DetermineStateRootHash() fx.StateStore, genesis, actionEvaluator); - AssertBencodexEqual((Bencodex.Types.Integer)123, blockChain.GetState(address)); + AssertBencodexEqual((Bencodex.Types.Integer)123, blockChain.GetWorldState() + .GetAccount(ReservedAddresses.LegacyAccount).GetState(address)); HashDigest identicalGenesisStateRootHash = blockChain.DetermineBlockStateRootHash(preEvalGenesis, out _); @@ -148,7 +154,8 @@ public void DetermineStateRootHash() _output.WriteLine("#1: {0}", block1); blockChain.Append(block1, TestUtils.CreateBlockCommit(block1)); - AssertBencodexEqual((Bencodex.Types.Integer)158, blockChain.GetState(address)); + AssertBencodexEqual((Bencodex.Types.Integer)158, blockChain.GetWorldState() + .GetAccount(ReservedAddresses.LegacyAccount).GetState(address)); } } } diff --git a/Libplanet.Tests/Fixtures/Arithmetic.cs b/Libplanet.Tests/Fixtures/Arithmetic.cs index 1d6b47d1e91..fda0c7cc0f9 100644 --- a/Libplanet.Tests/Fixtures/Arithmetic.cs +++ b/Libplanet.Tests/Fixtures/Arithmetic.cs @@ -107,14 +107,15 @@ public void LoadPlainValue(IValue plainValue) Error = null; } - public IAccount Execute(IActionContext context) + public IWorld Execute(IActionContext context) { if (Error != null) { throw new InvalidOperationException(Error); } - IValue v = context.PreviousState.GetState(context.Signer) ?? (Bencodex.Types.Integer)0; + IValue v = context.PreviousState.GetAccount(ReservedAddresses.LegacyAccount) + .GetState(context.Signer) ?? (Bencodex.Types.Integer)0; if (!(v is Bencodex.Types.Integer value)) { throw new InvalidOperationException( @@ -124,7 +125,11 @@ public IAccount Execute(IActionContext context) Func func = Operator.ToFunc(); BigInteger result = func(value, Operand); - return context.PreviousState.SetState(context.Signer, (Bencodex.Types.Integer)result); + return context.PreviousState.SetAccount( + ReservedAddresses.LegacyAccount, + context.PreviousState.GetAccount( + ReservedAddresses.LegacyAccount).SetState( + context.Signer, (Bencodex.Types.Integer)result)); } public bool Equals(Arithmetic other) diff --git a/Libplanet.Tests/Fixtures/BlockContentFixture.cs b/Libplanet.Tests/Fixtures/BlockContentFixture.cs index 2af59e76ca0..8cc1096bd54 100644 --- a/Libplanet.Tests/Fixtures/BlockContentFixture.cs +++ b/Libplanet.Tests/Fixtures/BlockContentFixture.cs @@ -48,7 +48,8 @@ public BlockContentFixture() { new Initialize( validatorSet: TestUtils.ValidatorSet, - states: ImmutableDictionary.Create()), + states: ImmutableDictionary.Create< + Address, IImmutableDictionary>()), }.ToPlainValues(), timestamp: DateTimeOffset.MinValue ); diff --git a/Libplanet.Tests/Fixtures/IntegerSet.cs b/Libplanet.Tests/Fixtures/IntegerSet.cs index 89bdc2592e1..03e3a2e8b10 100644 --- a/Libplanet.Tests/Fixtures/IntegerSet.cs +++ b/Libplanet.Tests/Fixtures/IntegerSet.cs @@ -112,9 +112,10 @@ public TxWithContext Sign(PrivateKey signer, params Arithmetic[] actions) long nonce = Chain.GetNextTxNonce(signerAddress); Transaction tx = Transaction.Create(nonce, signer, Genesis.Hash, actions.ToPlainValues()); - BigInteger prevState = Chain.GetState(signerAddress) is Bencodex.Types.Integer i - ? i.Value - : 0; + BigInteger prevState = Chain.GetWorldState().GetAccount( + ReservedAddresses.LegacyAccount).GetState(signerAddress) is Bencodex.Types.Integer i + ? i.Value + : 0; HashDigest prevStateRootHash = Chain.Tip.StateRootHash; ITrie prevTrie = GetTrie(Chain.Tip.Hash); (BigInteger, HashDigest) prevPair = (prevState, prevStateRootHash); @@ -178,11 +179,8 @@ public Block Propose() => Chain.ProposeBlock( public void Append(Block block) => Chain.Append(block, TestUtils.CreateBlockCommit(block)); - public IAccount CreateAccount(Address signer, BlockHash? offset = null) - => new Account(Chain.GetAccountState(offset)); - - public IAccount CreateAccount(int signerIndex, BlockHash? offset = null) - => CreateAccount(Addresses[signerIndex], offset); + public IWorld CreateWorld(BlockHash? offset = null) + => World.Create(Chain.GetWorldState(offset ?? Tip.Hash)); public ITrie GetTrie(BlockHash? blockHash) { diff --git a/Libplanet.Tests/Store/StoreTest.cs b/Libplanet.Tests/Store/StoreTest.cs index 380b207ec1e..958d81ab234 100644 --- a/Libplanet.Tests/Store/StoreTest.cs +++ b/Libplanet.Tests/Store/StoreTest.cs @@ -1266,7 +1266,7 @@ public void LoadPlainValue(Dictionary plainValue) Md5Digest = plainValue.GetValue("md5").ByteArray; } - public IAccount Execute(IActionContext context) + public IWorld Execute(IActionContext context) { return context.PreviousState; } diff --git a/Libplanet.Tests/TestUtils.cs b/Libplanet.Tests/TestUtils.cs index 303f2e34921..fac9a5d7d49 100644 --- a/Libplanet.Tests/TestUtils.cs +++ b/Libplanet.Tests/TestUtils.cs @@ -427,7 +427,8 @@ public static PreEvaluationBlock ProposeGenesis( { new Initialize( validatorSet: validatorSet, - states: ImmutableDictionary.Create()), + states: ImmutableDictionary.Create< + Address, IImmutableDictionary>()), }.Select(x => x.PlainValue), timestamp: DateTimeOffset.MinValue))); txs = txs.OrderBy(tx => tx.Id).ToList(); diff --git a/Libplanet.Tests/Tx/TransactionTest.cs b/Libplanet.Tests/Tx/TransactionTest.cs index ef937792dd1..17131b724f9 100644 --- a/Libplanet.Tests/Tx/TransactionTest.cs +++ b/Libplanet.Tests/Tx/TransactionTest.cs @@ -4,6 +4,7 @@ using System.Linq; using Bencodex.Types; using Libplanet.Action; +using Libplanet.Action.State; using Libplanet.Action.Sys; using Libplanet.Action.Tests.Common; using Libplanet.Common; @@ -71,8 +72,14 @@ public void CreateWithSystemAction() var action = new Initialize( new ValidatorSet(new List() { new Validator(privateKey.PublicKey, 1) }), - new Dictionary - { [default] = (Text)"initial value" }.ToImmutableDictionary()); + new Dictionary> + { + [ReservedAddresses.LegacyAccount] = + new Dictionary + { + [default] = (Text)"initial value", + }.ToImmutableDictionary(), + }.ToImmutableDictionary()); Transaction tx = Transaction.Create( 0, privateKey, @@ -88,18 +95,18 @@ public void CreateWithSystemAction() AssertBytesEqual( new byte[] { - 0x30, 0x44, 0x02, 0x20, 0x60, 0x8a, 0xbf, 0x3d, 0xdf, 0x50, - 0xf2, 0x00, 0x27, 0x56, 0xbb, 0x84, 0xc5, 0x65, 0x7c, 0xd9, - 0x4f, 0xbc, 0x33, 0x81, 0xe1, 0x0d, 0xc1, 0x5b, 0x23, 0x11, - 0xc4, 0x97, 0x61, 0x3e, 0xa0, 0xff, 0x02, 0x20, 0x44, 0x08, - 0xf8, 0x71, 0x43, 0x8c, 0x51, 0xd6, 0xa8, 0x22, 0x7d, 0x8c, - 0x7d, 0xb2, 0xc5, 0x97, 0x5b, 0xef, 0x72, 0x07, 0xfe, 0x4f, - 0x9d, 0x4c, 0x25, 0xc6, 0xb2, 0x1a, 0x89, 0xc7, 0xad, 0x10, + 0x30, 0x45, 0x02, 0x21, 0x00, 0xc8, 0x26, 0x79, 0x07, 0x90, + 0x38, 0x3d, 0x16, 0x7e, 0x2d, 0x44, 0x2a, 0x5e, 0xda, 0xbb, + 0xc3, 0xb2, 0xb1, 0x47, 0x7f, 0xe0, 0x69, 0x02, 0xb7, 0x39, + 0xd9, 0xed, 0x36, 0xb1, 0xd6, 0x8e, 0x5a, 0x02, 0x20, 0x4c, + 0x2a, 0x41, 0x12, 0x0b, 0x62, 0x96, 0x33, 0x67, 0xcb, 0xe2, + 0x84, 0x6d, 0xa4, 0xaf, 0x31, 0xf4, 0x96, 0xf8, 0x4c, 0xf2, + 0xc8, 0x62, 0x02, 0x3f, 0x20, 0x9a, 0x99, 0x52, 0x2b, 0x9c, 0x0d, }, tx.Signature ); AssertBytesEqual( - TxId.FromHex("eff61a6ee0faa2705b3dbd23abefbf18b4c864fa6b344c4fc3846cbb71a0e294"), + TxId.FromHex("34305c1d3e9f1026b64ae0021e2913b53130a87294d5adabd7b3e63a72ddcb6b"), tx.Id ); } diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index a96f12a461e..4515b1cdf51 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -515,7 +515,7 @@ public IReadOnlyList GetStates( GetAccountState(accountAddress, offset).GetStates(addresses); #pragma warning disable MEN002 - /// + /// #pragma warning restore MEN002 public IReadOnlyList GetStates( IReadOnlyList
addresses, @@ -566,6 +566,10 @@ public ValidatorSet GetValidatorSet(BlockHash? offset) => public IAccountState GetAccountState(Address address, BlockHash? offset) => GetWorldState(offset).GetAccount(address); + /// + public IAccountState GetAccountState(HashDigest? stateRootHash) => + new AccountBaseState(GetTrie(stateRootHash)); + public IWorldState GetWorldState() => GetWorldState(Tip.Hash); ///