diff --git a/Lib9c b/Lib9c index d6f420a0e..b7ee4f385 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit d6f420a0ea2c714e3546a4fc346d8bf1cddd8f5f +Subproject commit b7ee4f385a8dd71e7caf1bf841325637de42df52 diff --git a/NineChronicles.Headless.AccessControlCenter/AccessControlService/IMutableAccessControlService.cs b/NineChronicles.Headless.AccessControlCenter/AccessControlService/IMutableAccessControlService.cs index 716fa8fe2..b5d52f697 100644 --- a/NineChronicles.Headless.AccessControlCenter/AccessControlService/IMutableAccessControlService.cs +++ b/NineChronicles.Headless.AccessControlCenter/AccessControlService/IMutableAccessControlService.cs @@ -1,6 +1,6 @@ using Libplanet.Crypto; using System.Collections.Generic; -using NineChronicles.Headless.AccessControlService; +using Nekoyume.Blockchain; namespace NineChronicles.Headless.AccessControlCenter.AccessControlService { diff --git a/NineChronicles.Headless.Tests/Policies/StagePolicyTest.cs b/NineChronicles.Headless.Tests/Policies/StagePolicyTest.cs deleted file mode 100644 index e291e7f27..000000000 --- a/NineChronicles.Headless.Tests/Policies/StagePolicyTest.cs +++ /dev/null @@ -1,324 +0,0 @@ -namespace NineChronicles.Headless.Tests.Policies -{ - using System; - using System.Collections.Generic; - using System.Collections.Immutable; - using System.Linq; - using System.Threading.Tasks; - using Lib9c.Renderers; - using Libplanet.Action; - using Libplanet.Blockchain; - using Libplanet.Blockchain.Policies; - using Libplanet.Crypto; - using Libplanet.Store; - using Libplanet.Store.Trie; - using Libplanet.Types.Blocks; - using Libplanet.Types.Tx; - using Nekoyume; - using Nekoyume.Action; - using Nekoyume.Action.Loader; - using Nekoyume.Blockchain.Policy; - using Nekoyume.Model; - using Nekoyume.Model.State; - using NineChronicles.Headless.Policies; - using Xunit; - - public class StagePolicyTest - { - private readonly PrivateKey[] _accounts; - - private readonly Dictionary _txs; - - public StagePolicyTest() - { - _accounts = new[] - { - new PrivateKey(), - new PrivateKey(), - new PrivateKey(), - new PrivateKey(), - }; - _txs = _accounts.ToDictionary( - acc => acc.ToAddress(), - acc => Enumerable - .Range(0, 10) - .Select( - n => Transaction.Create( - n, - acc, - default, - new ActionBase[0].ToPlainValues() - ) - ) - .ToArray() - ); - } - - [Fact] - public void Stage() - { - NCStagePolicy stagePolicy = new NCStagePolicy(TimeSpan.FromHours(1), 2); - BlockChain chain = MakeChainWithStagePolicy(stagePolicy); - - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][0]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][1]); - stagePolicy.Stage(chain, _txs[_accounts[1].ToAddress()][0]); - stagePolicy.Stage(chain, _txs[_accounts[2].ToAddress()][0]); - - AssertTxs( - chain, - stagePolicy, - _txs[_accounts[0].ToAddress()][0], - _txs[_accounts[0].ToAddress()][1], - _txs[_accounts[1].ToAddress()][0], - _txs[_accounts[2].ToAddress()][0] - ); - } - - [Fact] - public void StageOverQuota() - { - NCStagePolicy stagePolicy = new NCStagePolicy(TimeSpan.FromHours(1), 2); - BlockChain chain = MakeChainWithStagePolicy(stagePolicy); - - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][0]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][1]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][2]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][3]); - - AssertTxs( - chain, - stagePolicy, - _txs[_accounts[0].ToAddress()][0], - _txs[_accounts[0].ToAddress()][1] - ); - } - - [Fact] - public void StageOverQuotaInverseOrder() - { - NCStagePolicy stagePolicy = new NCStagePolicy(TimeSpan.FromHours(1), 2); - BlockChain chain = MakeChainWithStagePolicy(stagePolicy); - - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][3]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][2]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][1]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][0]); - - AssertTxs( - chain, - stagePolicy, - _txs[_accounts[0].ToAddress()][0], - _txs[_accounts[0].ToAddress()][1] - ); - } - - [Fact] - public void StageOverQuotaOutOfOrder() - { - NCStagePolicy stagePolicy = new NCStagePolicy(TimeSpan.FromHours(1), 2); - BlockChain chain = MakeChainWithStagePolicy(stagePolicy); - - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][2]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][1]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][3]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][0]); - - AssertTxs( - chain, - stagePolicy, - _txs[_accounts[0].ToAddress()][0], - _txs[_accounts[0].ToAddress()][1] - ); - } - - [Fact] - public void StageSameNonce() - { - NCStagePolicy stagePolicy = new NCStagePolicy(TimeSpan.FromHours(1), 2); - BlockChain chain = MakeChainWithStagePolicy(stagePolicy); - var txA = Transaction.Create(0, _accounts[0], default, new ActionBase[0].ToPlainValues()); - var txB = Transaction.Create(0, _accounts[0], default, new ActionBase[0].ToPlainValues()); - var txC = Transaction.Create(0, _accounts[0], default, new ActionBase[0].ToPlainValues()); - - stagePolicy.Stage(chain, txA); - stagePolicy.Stage(chain, txB); - stagePolicy.Stage(chain, txC); - - AssertTxs(chain, stagePolicy, txA, txB); - } - - [Fact] - public async Task StateFromMultiThread() - { - NCStagePolicy stagePolicy = new NCStagePolicy(TimeSpan.FromHours(1), 2); - BlockChain chain = MakeChainWithStagePolicy(stagePolicy); - - await Task.WhenAll( - Enumerable - .Range(0, 40) - .Select(i => Task.Run(() => - { - stagePolicy.Stage(chain, _txs[_accounts[i / 10].ToAddress()][i % 10]); - })) - ); - AssertTxs( - chain, - stagePolicy, - _txs[_accounts[0].ToAddress()][0], - _txs[_accounts[0].ToAddress()][1], - _txs[_accounts[1].ToAddress()][0], - _txs[_accounts[1].ToAddress()][1], - _txs[_accounts[2].ToAddress()][0], - _txs[_accounts[2].ToAddress()][1], - _txs[_accounts[3].ToAddress()][0], - _txs[_accounts[3].ToAddress()][1] - ); - } - - [Fact] - public void IterateAfterUnstage() - { - NCStagePolicy stagePolicy = new NCStagePolicy(TimeSpan.FromHours(1), 2); - BlockChain chain = MakeChainWithStagePolicy(stagePolicy); - - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][0]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][1]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][2]); - stagePolicy.Stage(chain, _txs[_accounts[0].ToAddress()][3]); - - AssertTxs( - chain, - stagePolicy, - _txs[_accounts[0].ToAddress()][0], - _txs[_accounts[0].ToAddress()][1] - ); - - stagePolicy.Unstage(chain, _txs[_accounts[0].ToAddress()][0].Id); - - AssertTxs( - chain, - stagePolicy, - _txs[_accounts[0].ToAddress()][1], - _txs[_accounts[0].ToAddress()][2] - ); - } - - [Fact] - public void CalculateNextTxNonceCorrectWhenTxOverQuota() - { - NCStagePolicy stagePolicy = new NCStagePolicy(TimeSpan.FromHours(1), 2); - BlockChain chain = MakeChainWithStagePolicy(stagePolicy); - - long nextTxNonce = chain.GetNextTxNonce(_accounts[0].ToAddress()); - Assert.Equal(0, nextTxNonce); - var txA = Transaction.Create(nextTxNonce, _accounts[0], default, new ActionBase[0].ToPlainValues()); - stagePolicy.Stage(chain, txA); - - nextTxNonce = chain.GetNextTxNonce(_accounts[0].ToAddress()); - Assert.Equal(1, nextTxNonce); - var txB = Transaction.Create(nextTxNonce, _accounts[0], default, new ActionBase[0].ToPlainValues()); - stagePolicy.Stage(chain, txB); - - nextTxNonce = chain.GetNextTxNonce(_accounts[0].ToAddress()); - Assert.Equal(2, nextTxNonce); - var txC = Transaction.Create(nextTxNonce, _accounts[0], default, new ActionBase[0].ToPlainValues()); - stagePolicy.Stage(chain, txC); - - nextTxNonce = chain.GetNextTxNonce(_accounts[0].ToAddress()); - Assert.Equal(3, nextTxNonce); - - AssertTxs( - chain, - stagePolicy, - txA, - txB); - } - - private void AssertTxs(BlockChain blockChain, NCStagePolicy policy, params Transaction[] txs) - { - foreach (Transaction tx in txs) - { - Assert.Equal(tx, policy.Get(blockChain, tx.Id, filtered: true)); - } - - Assert.Equal( - txs.ToHashSet(), - policy.Iterate(blockChain, filtered: true).ToHashSet() - ); - } - - private BlockChain MakeChainWithStagePolicy(NCStagePolicy stagePolicy) - { - BlockPolicySource blockPolicySource = new BlockPolicySource(); - IBlockPolicy policy = blockPolicySource.GetPolicy(); - BlockChain chain = - BlockChainHelper.MakeBlockChain( - blockRenderers: new[] { new BlockRenderer() }, - policy: policy, - stagePolicy: stagePolicy); - return chain; - } - - public static class BlockChainHelper - { - public static BlockChain MakeBlockChain( - BlockRenderer[] blockRenderers, - IBlockPolicy policy = null, - IStagePolicy stagePolicy = null, - IStore store = null, - IStateStore stateStore = null) - { - PrivateKey adminPrivateKey = new PrivateKey(); - - policy ??= new BlockPolicy(); - stagePolicy ??= new VolatileStagePolicy(); - store ??= new DefaultStore(null); - stateStore ??= new TrieStateStore(new DefaultKeyValueStore(null)); - Block genesis = MakeGenesisBlock(adminPrivateKey.ToAddress(), ImmutableHashSet
.Empty); - return BlockChain.Create( - policy, - stagePolicy, - store, - stateStore, - genesis, - new ActionEvaluator( - policyBlockActionGetter: _ => policy.BlockAction, - stateStore: stateStore, - actionTypeLoader: new NCActionLoader() - ), - renderers: blockRenderers); - } - - public static Block MakeGenesisBlock( - Address adminAddress, - IImmutableSet
activatedAddresses, - AuthorizedMinersState authorizedMinersState = null, - DateTimeOffset? timestamp = null, - PendingActivationState[] pendingActivations = null - ) - { - PrivateKey privateKey = new PrivateKey(); - if (pendingActivations is null) - { - var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; - (ActivationKey activationKey, PendingActivationState pendingActivation) = - ActivationKey.Create(privateKey, nonce); - pendingActivations = new[] { pendingActivation }; - } - - var sheets = TableSheetsImporter.ImportSheets(); - return BlockHelper.ProposeGenesisBlock( - sheets, - new GoldDistribution[0], - pendingActivations, - new AdminState(adminAddress, 1500000), - activatedAccounts: activatedAddresses, - isActivateAdminAddress: false, - credits: null, - privateKey: privateKey, - timestamp: timestamp ?? DateTimeOffset.MinValue); - } - } - } -} diff --git a/NineChronicles.Headless/AccessControlService/IAccessControlService.cs b/NineChronicles.Headless/AccessControlService/IAccessControlService.cs deleted file mode 100644 index c96e7c64a..000000000 --- a/NineChronicles.Headless/AccessControlService/IAccessControlService.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Libplanet.Crypto; - -namespace NineChronicles.Headless.AccessControlService -{ - public interface IAccessControlService - { - public int? GetTxQuota(Address address); - } -} diff --git a/NineChronicles.Headless/NineChroniclesNodeService.cs b/NineChronicles.Headless/NineChroniclesNodeService.cs index 7a2db6e4f..181f14e6e 100644 --- a/NineChronicles.Headless/NineChroniclesNodeService.cs +++ b/NineChronicles.Headless/NineChroniclesNodeService.cs @@ -18,8 +18,6 @@ using Microsoft.Extensions.Hosting; using Nekoyume.Blockchain; using Nekoyume.Blockchain.Policy; -using NineChronicles.Headless.AccessControlService; -using NineChronicles.Headless.Policies; using NineChronicles.Headless.Properties; using NineChronicles.Headless.Utils; using NineChronicles.Headless.Services; diff --git a/NineChronicles.Headless/Policies/NCStagePolicy.cs b/NineChronicles.Headless/Policies/NCStagePolicy.cs deleted file mode 100644 index f5b17bb00..000000000 --- a/NineChronicles.Headless/Policies/NCStagePolicy.cs +++ /dev/null @@ -1,141 +0,0 @@ -namespace NineChronicles.Headless.Policies -{ - using System; - using System.Collections.Concurrent; - using System.Collections.Generic; - using System.Collections.Immutable; - using System.Linq; - using Libplanet.Blockchain; - using Libplanet.Blockchain.Policies; - using Libplanet.Crypto; - using Libplanet.Types.Tx; - using NineChronicles.Headless.AccessControlService; - - public class NCStagePolicy : IStagePolicy - { - private readonly VolatileStagePolicy _impl; - private readonly ConcurrentDictionary> _txs; - private readonly int _quotaPerSigner; - private IAccessControlService? _accessControlService; - - public NCStagePolicy(TimeSpan txLifeTime, int quotaPerSigner, IAccessControlService? accessControlService = null) - { - if (quotaPerSigner < 1) - { - throw new ArgumentOutOfRangeException( - $"{nameof(quotaPerSigner)} must be positive: ${quotaPerSigner}"); - } - - _txs = new ConcurrentDictionary>(); - _quotaPerSigner = quotaPerSigner; - _impl = (txLifeTime == default) - ? new VolatileStagePolicy() - : new VolatileStagePolicy(txLifeTime); - - _accessControlService = accessControlService; - } - - public Transaction Get(BlockChain blockChain, TxId id, bool filtered = true) - => _impl.Get(blockChain, id, filtered)!; - - public long GetNextTxNonce(BlockChain blockChain, Address address) - => _impl.GetNextTxNonce(blockChain, address); - - public void Ignore(BlockChain blockChain, TxId id) - => _impl.Ignore(blockChain, id); - - public bool Ignores(BlockChain blockChain, TxId id) - => _impl.Ignores(blockChain, id); - - public IEnumerable Iterate(BlockChain blockChain, bool filtered = true) - { - if (filtered) - { - var txsPerSigner = new Dictionary>(); - foreach (Transaction tx in _impl.Iterate(blockChain, filtered)) - { - if (!txsPerSigner.TryGetValue(tx.Signer, out var s)) - { - txsPerSigner[tx.Signer] = s = new SortedSet(new TxComparer()); - } - - s.Add(tx); - int txQuotaPerSigner = _quotaPerSigner; - - // update txQuotaPerSigner if ACS returns a value for the signer. - if (_accessControlService?.GetTxQuota(tx.Signer) is { } acsTxQuota) - { - txQuotaPerSigner = acsTxQuota; - } - - - if (s.Count > txQuotaPerSigner) - { - s.Remove(s.Max!); - } - } - -#pragma warning disable LAA1002 // DictionariesOrSetsShouldBeOrderedToEnumerate - return txsPerSigner.Values.SelectMany(i => i); -#pragma warning restore LAA1002 // DictionariesOrSetsShouldBeOrderedToEnumerate - } - else - { - return _impl.Iterate(blockChain, filtered); - } - } - - public bool Stage(BlockChain blockChain, Transaction transaction) - { - if (_accessControlService?.GetTxQuota(transaction.Signer) is { } acsTxQuota - && acsTxQuota == 0) - { - return false; - } - - var deniedTxs = new[] - { - // CreatePledge Transaction with 50000 addresses - TxId.FromHex("300826da62b595d8cd663dadf04995a7411534d1cdc17dac75ce88754472f774"), - // CreatePledge Transaction with 5000 addresses - TxId.FromHex("210d1374d8f068de657de6b991e63888da9cadbc68e505ac917b35568b5340f8"), - }; - if (deniedTxs.Contains(transaction.Id)) - { - return false; - } - - return _impl.Stage(blockChain, transaction); - } - - public bool Unstage(BlockChain blockChain, TxId id) - => _impl.Unstage(blockChain, id); - - private sealed class TxComparer : IComparer - { - public int Compare(Transaction? x, Transaction? y) - { - if (x!.Nonce < y!.Nonce) - { - return -1; - } - else if (x.Nonce > y.Nonce) - { - return 1; - } - else if (x.Timestamp < y.Timestamp) - { - return -1; - } - else if (x.Timestamp > y.Timestamp) - { - return 1; - } - else - { - return 0; - } - } - } - } -} diff --git a/NineChronicles.Headless/Services/AccessControlServiceFactory.cs b/NineChronicles.Headless/Services/AccessControlServiceFactory.cs index 7ef6a69a2..0ff8e476a 100644 --- a/NineChronicles.Headless/Services/AccessControlServiceFactory.cs +++ b/NineChronicles.Headless/Services/AccessControlServiceFactory.cs @@ -1,5 +1,5 @@ using System; -using NineChronicles.Headless.AccessControlService; +using Nekoyume.Blockchain; namespace NineChronicles.Headless.Services { diff --git a/NineChronicles.Headless/Services/RedisAccessControlService.cs b/NineChronicles.Headless/Services/RedisAccessControlService.cs index e3bf24498..40769292d 100644 --- a/NineChronicles.Headless/Services/RedisAccessControlService.cs +++ b/NineChronicles.Headless/Services/RedisAccessControlService.cs @@ -1,7 +1,7 @@ using System; using StackExchange.Redis; using Libplanet.Crypto; -using NineChronicles.Headless.AccessControlService; +using Nekoyume.Blockchain; using Serilog; namespace NineChronicles.Headless.Services diff --git a/NineChronicles.Headless/Services/SQLiteAccessControlService.cs b/NineChronicles.Headless/Services/SQLiteAccessControlService.cs index 219b7db3c..f3e7263c8 100644 --- a/NineChronicles.Headless/Services/SQLiteAccessControlService.cs +++ b/NineChronicles.Headless/Services/SQLiteAccessControlService.cs @@ -1,7 +1,7 @@ using System; using Microsoft.Data.Sqlite; using Libplanet.Crypto; -using NineChronicles.Headless.AccessControlService; +using Nekoyume.Blockchain; using Serilog; namespace NineChronicles.Headless.Services