Skip to content

Commit

Permalink
Merge pull request #3416 from greymistcube/refactor/remove-account-tr…
Browse files Browse the repository at this point in the history
…ie-get-set

Remove trie mutation from Account
  • Loading branch information
greymistcube authored Sep 7, 2023
2 parents 8ef2487 + 0cd7ebc commit 8c345e9
Show file tree
Hide file tree
Showing 15 changed files with 230 additions and 86 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ To be released.
- Removed `IBlockState` interface. [[#3413]]
- Removed `IBlockChainState.GetBlockState()` interface method. [[#3413]]
- Added `IBlockChainState.GetAccountState()` interface method. [[#3413]]
- Added `IAccountState` interface. [[#3416]]
- Added `AccountState` class. [[#3416]]

### Backward-incompatible network protocol changes

Expand Down Expand Up @@ -79,6 +81,7 @@ To be released.
[#3407]: https://github.com/planetarium/libplanet/pull/3407
[#3410]: https://github.com/planetarium/libplanet/pull/3410
[#3413]: https://github.com/planetarium/libplanet/pull/3413
[#3416]: https://github.com/planetarium/libplanet/pull/3416
[RocksDB Read Only]: https://github.com/facebook/rocksdb/wiki/Read-only-and-Secondary-instances


Expand Down
12 changes: 6 additions & 6 deletions Libplanet.Action.Tests/ActionContextTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void RandomShouldBeDeterministic()
miner: _address,
blockIndex: 1,
blockProtocolVersion: Block.CurrentProtocolVersion,
previousState: new Account(MockAccountState.Empty.Trie),
previousState: new Account(MockAccountState.Empty),
randomSeed: seed,
gasLimit: 0
);
Expand All @@ -54,7 +54,7 @@ public void GuidShouldBeDeterministic()
miner: _address,
blockIndex: 1,
blockProtocolVersion: Block.CurrentProtocolVersion,
previousState: new Account(MockAccountState.Empty.Trie),
previousState: new Account(MockAccountState.Empty),
randomSeed: 0,
gasLimit: 0
);
Expand All @@ -65,7 +65,7 @@ public void GuidShouldBeDeterministic()
miner: _address,
blockIndex: 1,
blockProtocolVersion: Block.CurrentProtocolVersion,
previousState: new Account(MockAccountState.Empty.Trie),
previousState: new Account(MockAccountState.Empty),
randomSeed: 0,
gasLimit: 0
);
Expand All @@ -76,7 +76,7 @@ public void GuidShouldBeDeterministic()
miner: _address,
blockIndex: 1,
blockProtocolVersion: Block.CurrentProtocolVersion,
previousState: new Account(MockAccountState.Empty.Trie),
previousState: new Account(MockAccountState.Empty),
randomSeed: 1,
gasLimit: 0
);
Expand Down Expand Up @@ -112,7 +112,7 @@ public void GuidVersionAndVariant()
miner: _address,
blockIndex: 1,
blockProtocolVersion: Block.CurrentProtocolVersion,
previousState: new Account(MockAccountState.Empty.Trie),
previousState: new Account(MockAccountState.Empty),
randomSeed: i,
gasLimit: 0
);
Expand All @@ -132,7 +132,7 @@ public void GetUnconsumedContext()
miner: _address,
blockIndex: 1,
blockProtocolVersion: Block.CurrentProtocolVersion,
previousState: new Account(MockAccountState.Empty.Trie),
previousState: new Account(MockAccountState.Empty),
randomSeed: _random.Next(),
gasLimit: 0);

Expand Down
4 changes: 2 additions & 2 deletions Libplanet.Action.Tests/ActionEvaluationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ public void Constructor()
address,
1,
Block.CurrentProtocolVersion,
new Account(MockAccountState.Empty.Trie),
new Account(MockAccountState.Empty),
123,
0,
false),
new Account(MockAccountState.Empty.SetState(address, (Text)"item").Trie));
new Account(MockAccountState.Empty.SetState(address, (Text)"item")));
var action = (DumbAction)evaluation.Action;

Assert.Equal(address, action.TargetAddress);
Expand Down
4 changes: 2 additions & 2 deletions Libplanet.Action.Tests/Sys/InitializeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void Execute()
{
var random = new System.Random();
Address signer = random.NextAddress();
var prevState = new Account(MockAccountState.Empty.Trie);
var prevState = new Account(MockAccountState.Empty);
BlockHash genesisHash = random.NextBlockHash();
var context = new ActionContext(
signer: signer,
Expand Down Expand Up @@ -70,7 +70,7 @@ public void ExecuteInNonGenesis()
{
var random = new System.Random();
Address signer = random.NextAddress();
var prevState = new Account(MockAccountState.Empty.Trie);
var prevState = new Account(MockAccountState.Empty);
BlockHash genesisHash = random.NextBlockHash();
var context = new ActionContext(
signer: signer,
Expand Down
2 changes: 1 addition & 1 deletion Libplanet.Action/ActionEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ internal ActionEvaluation EvaluatePolicyBlockAction(
/// </returns>
internal IAccount PrepareInitialDelta(IPreEvaluationBlock block)
{
return new Account(_blockChainStates.GetAccountState(block.PreviousHash).Trie);
return new Account(_blockChainStates.GetAccountState(block.PreviousHash));
}

[Pure]
Expand Down
73 changes: 29 additions & 44 deletions Libplanet.Action/State/Account.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,30 @@ namespace Libplanet.Action.State
[Pure]
public class Account : IAccount
{
public Account(ITrie trie)
: this(trie, new AccountDelta())
private readonly IAccountState _baseState;

public Account(IAccountState baseState)
: this(baseState, new AccountDelta())
{
}

private Account(ITrie trie, IAccountDelta delta)
: this(trie, delta, ImmutableDictionary<(Address, Currency), BigInteger>.Empty)
public Account(IAccountState baseState, IAccountDelta delta)
: this(baseState, delta, ImmutableDictionary<(Address, Currency), BigInteger>.Empty)
{
}

private Account(
ITrie trie,
IAccountState baseState,
IAccountDelta delta,
IImmutableDictionary<(Address, Currency), BigInteger> totalUpdatedFungibles)
{
Trie = trie;
_baseState = baseState;
Delta = delta;
TotalUpdatedFungibles = totalUpdatedFungibles;
}

/// <inheritdoc cref="IAccountState.Trie"/>
public ITrie Trie { get; }
public ITrie Trie => _baseState.Trie;

/// <inheritdoc/>
public IAccountDelta Delta { get; }
Expand All @@ -57,9 +59,11 @@ private Account(
{
AccountMetrics.GetStateTimer.Value?.Start();
AccountMetrics.GetStateCount.Value += 1;
IValue? state = GetStates(new[] { address })[0];
IValue? value = Delta.States.TryGetValue(address, out IValue? updatedValue)
? updatedValue
: _baseState.GetState(address);
AccountMetrics.GetStateTimer.Value?.Stop();
return state;
return value;
}

/// <inheritdoc cref="IAccountState.GetStates(IReadOnlyList{Address})"/>
Expand All @@ -69,12 +73,7 @@ private Account(
AccountMetrics.GetStateTimer.Value?.Start();
int length = addresses.Count;
AccountMetrics.GetStateCount.Value += length;
var values =
Trie.Get(
addresses
.Select(KeyConverters.ToStateKey)
.ToArray());

List<IValue?> values = addresses.Select(address => GetState(address)).ToList();
AccountMetrics.GetStateTimer.Value?.Stop();
return values;
}
Expand All @@ -85,14 +84,10 @@ private Account(

/// <inheritdoc/>
[Pure]
public FungibleAssetValue GetBalance(Address address, Currency currency)
{
KeyBytes key = KeyConverters.ToFungibleAssetKey(address, currency);
IValue? rawValue = Trie.Get(key);
return rawValue is Integer i
? FungibleAssetValue.FromRawValue(currency, i)
: currency * 0;
}
public FungibleAssetValue GetBalance(Address address, Currency currency) =>
Delta.Fungibles.TryGetValue((address, currency), out BigInteger balance)
? FungibleAssetValue.FromRawValue(currency, balance)
: _baseState.GetBalance(address, currency);

/// <inheritdoc/>
[Pure]
Expand All @@ -103,23 +98,16 @@ public FungibleAssetValue GetTotalSupply(Currency currency)
throw TotalSupplyNotTrackableException.WithDefaultMessage(currency);
}

KeyBytes[] keys = new[] { KeyConverters.ToTotalSupplyKey(currency) };
IReadOnlyList<IValue?> rawValues = Trie.Get(keys);
return rawValues.Count > 0 && rawValues[0] is Bencodex.Types.Integer i
? FungibleAssetValue.FromRawValue(currency, i)
: currency * 0;
// Return dirty state if it exists.
return Delta.TotalSupplies.TryGetValue(currency, out BigInteger totalSupplyValue)
? FungibleAssetValue.FromRawValue(currency, totalSupplyValue)
: _baseState.GetTotalSupply(currency);
}

/// <inheritdoc/>
[Pure]
public ValidatorSet GetValidatorSet()
{
KeyBytes[] keys = new[] { KeyConverters.ValidatorSetKey };
IReadOnlyList<IValue?> rawValues = Trie.Get(keys);
return rawValues.Count > 0 && rawValues[0] is List list
? new ValidatorSet(list)
: new ValidatorSet();
}
public ValidatorSet GetValidatorSet() =>
Delta.ValidatorSet ?? _baseState.GetValidatorSet();

/// <inheritdoc/>
[Pure]
Expand Down Expand Up @@ -250,7 +238,7 @@ public IAccount SetValidator(Validator validator) =>
/// </remarks>
internal static IAccount Flush(IAccount account) =>
account is Account impl
? new Account(impl.Trie, new AccountDelta(), impl.TotalUpdatedFungibles)
? new Account(impl, new AccountDelta(), impl.TotalUpdatedFungibles)
: throw new ArgumentException(
$"Unknown type for {nameof(account)}: {account.GetType()}");

Expand All @@ -259,7 +247,7 @@ private Account UpdateState(
Address address,
IValue value) =>
new Account(
Trie.Set(KeyConverters.ToStateKey(address), value),
_baseState,
new AccountDelta(
Delta.States.SetItem(address, value),
Delta.Fungibles,
Expand All @@ -274,18 +262,15 @@ private Account UpdateFungibleAssets(
BigInteger amount,
BigInteger? supplyAmount = null) => supplyAmount is { } sa
? new Account(
Trie
.Set(KeyConverters.ToFungibleAssetKey(address, currency), new Integer(amount))
.Set(KeyConverters.ToTotalSupplyKey(currency), new Integer(sa)),
_baseState,
new AccountDelta(
Delta.States,
Delta.Fungibles.SetItem((address, currency), amount),
Delta.TotalSupplies.SetItem(currency, sa),
Delta.ValidatorSet),
TotalUpdatedFungibles.SetItem((address, currency), amount))
: new Account(
Trie
.Set(KeyConverters.ToFungibleAssetKey(address, currency), new Integer(amount)),
_baseState,
new AccountDelta(
Delta.States,
Delta.Fungibles.SetItem((address, currency), amount),
Expand All @@ -296,7 +281,7 @@ private Account UpdateFungibleAssets(
[Pure]
private Account UpdateValidatorSet(ValidatorSet validatorSet) =>
new Account(
Trie.Set(KeyConverters.ValidatorSetKey, validatorSet.Bencoded),
_baseState,
new AccountDelta(
Delta.States,
Delta.Fungibles,
Expand Down
83 changes: 83 additions & 0 deletions Libplanet.Action/State/AccountState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System.Collections.Generic;
using System.Linq;
using Bencodex.Types;
using Libplanet.Crypto;
using Libplanet.Store.Trie;
using Libplanet.Types.Assets;
using Libplanet.Types.Consensus;
using static Libplanet.Action.State.KeyConverters;

namespace Libplanet.Action.State
{
/// <summary>
/// A default implementation of <see cref="IAccountState"/> interface.
/// </summary>
public class AccountState : IAccountState
{
private ITrie _trie;
private AccountStateCache _cache;

public AccountState(ITrie trie)
{
_trie = trie;
_cache = new AccountStateCache();
}

/// <inheritdoc cref="IAccountState.Trie"/>
public ITrie Trie => _trie;

/// <inheritdoc cref="IAccountState.GetState"/>
public IValue? GetState(Address address)
{
if (_cache.TryGetValue(address, out IValue? cachedValue))
{
return cachedValue;
}
else
{
IValue? fetched = Trie.Get(ToStateKey(address));
_cache.AddOrUpdate(address, fetched);
return fetched;
}
}

/// <inheritdoc cref="IAccountState.GetStates"/>
public IReadOnlyList<IValue?> GetStates(IReadOnlyList<Address> addresses) =>
addresses.Select(address => GetState(address)).ToList();

/// <inheritdoc cref="IAccountState.GetBalance"/>
public FungibleAssetValue GetBalance(Address address, Currency currency)
{
KeyBytes[] keys = new[] { ToFungibleAssetKey(address, currency) };
IReadOnlyList<IValue?> rawValues = Trie.Get(keys);
return rawValues.Count > 0 && rawValues[0] is Bencodex.Types.Integer i
? FungibleAssetValue.FromRawValue(currency, i)
: currency * 0;
}

/// <inheritdoc cref="IAccountState.GetTotalSupply"/>
public FungibleAssetValue GetTotalSupply(Currency currency)
{
if (!currency.TotalSupplyTrackable)
{
throw TotalSupplyNotTrackableException.WithDefaultMessage(currency);
}

KeyBytes[] keys = new[] { ToTotalSupplyKey(currency) };
IReadOnlyList<IValue?> rawValues = Trie.Get(keys);
return rawValues.Count > 0 && rawValues[0] is Bencodex.Types.Integer i
? FungibleAssetValue.FromRawValue(currency, i)
: currency * 0;
}

/// <inheritdoc cref="IAccountState.GetValidatorSet"/>
public ValidatorSet GetValidatorSet()
{
KeyBytes[] keys = new[] { ValidatorSetKey };
IReadOnlyList<IValue?> rawValues = Trie.Get(keys);
return rawValues.Count > 0 && rawValues[0] is List list
? new ValidatorSet(list)
: new ValidatorSet();
}
}
}
Loading

0 comments on commit 8c345e9

Please sign in to comment.