From 234350dbaf724628ef22226c2db7b9d23cb3a9b9 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Thu, 28 Jan 2021 18:37:33 +0800 Subject: [PATCH] Remove currentSnapshot (#2273) --- src/neo/Ledger/Blockchain.cs | 71 ++++++------ src/neo/Ledger/MemoryPool.cs | 14 +-- .../Network/P2P/RemoteNode.ProtocolHandler.cs | 58 +++++----- src/neo/Network/P2P/RemoteNode.cs | 3 +- src/neo/Network/P2P/TaskManager.cs | 28 ++--- src/neo/SmartContract/ApplicationEngine.cs | 11 +- .../ContractParametersContext.cs | 13 +-- src/neo/Wallets/AssetDescriptor.cs | 2 +- src/neo/Wallets/Wallet.cs | 101 +++++++++--------- tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 12 --- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 2 - 11 files changed, 139 insertions(+), 176 deletions(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index e7bb4bcfba..8a3ac9c6d4 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -65,14 +65,15 @@ public class RelayResult { public IInventory Inventory; public VerifyResult Resu private readonly ConcurrentDictionary block_cache = new ConcurrentDictionary(); private readonly Dictionary block_cache_unverified = new Dictionary(); internal readonly RelayCache RelayCache = new RelayCache(100); - private SnapshotCache currentSnapshot; private ImmutableHashSet extensibleWitnessWhiteList; public IStore Store { get; } + /// + /// A readonly view of the blockchain store. + /// Note: It doesn't need to be disposed because the inside it is null. + /// public DataCache View => new SnapshotCache(Store); public MemoryPool MemPool { get; } - public uint Height => NativeContract.Ledger.CurrentIndex(currentSnapshot); - public UInt256 CurrentBlockHash => NativeContract.Ledger.CurrentHash(currentSnapshot); private static Blockchain singleton; public static Blockchain Singleton @@ -110,14 +111,14 @@ public Blockchain(NeoSystem system, IStore store) { if (singleton != null) throw new InvalidOperationException(); - if (!NativeContract.Ledger.Initialized(View)) + DataCache snapshot = View; + if (!NativeContract.Ledger.Initialized(snapshot)) { Persist(GenesisBlock); } else { - UpdateCurrentSnapshot(); - MemPool.LoadPolicy(currentSnapshot); + UpdateExtensibleWitnessWhiteList(snapshot); } singleton = this; } @@ -136,14 +137,16 @@ public SnapshotCache GetSnapshot() private void OnImport(IEnumerable blocks, bool verify) { + uint currentHeight = NativeContract.Ledger.CurrentIndex(View); foreach (Block block in blocks) { - if (block.Index <= Height) continue; - if (block.Index != Height + 1) + if (block.Index <= currentHeight) continue; + if (block.Index != currentHeight + 1) throw new InvalidOperationException(); - if (verify && !block.Verify(currentSnapshot)) + if (verify && !block.Verify(View)) throw new InvalidOperationException(); Persist(block); + ++currentHeight; } Sender.Tell(new ImportCompleted()); } @@ -182,15 +185,17 @@ private void OnFillMemoryPool(IEnumerable transactions) // Invalidate all the transactions in the memory pool, to avoid any failures when adding new transactions. MemPool.InvalidateAllTransactions(); + DataCache snapshot = View; + // Add the transactions to the memory pool foreach (var tx in transactions) { - if (NativeContract.Ledger.ContainsTransaction(View, tx.Hash)) + if (NativeContract.Ledger.ContainsTransaction(snapshot, tx.Hash)) continue; // First remove the tx if it is unverified in the pool. MemPool.TryRemoveUnVerified(tx.Hash, out _); // Add to the memory pool - MemPool.TryAdd(tx, currentSnapshot); + MemPool.TryAdd(tx, snapshot); } // Transactions originally in the pool will automatically be reverified based on their priority. @@ -214,35 +219,37 @@ private void OnInventory(IInventory inventory, bool relay = true) private VerifyResult OnNewBlock(Block block) { - if (block.Index <= Height) + DataCache snapshot = View; + uint currentHeight = NativeContract.Ledger.CurrentIndex(snapshot); + if (block.Index <= currentHeight) return VerifyResult.AlreadyExists; - if (block.Index - 1 > Height) + if (block.Index - 1 > currentHeight) { AddUnverifiedBlockToCache(block); return VerifyResult.UnableToVerify; } - if (block.Index == Height + 1) + if (block.Index == currentHeight + 1) { - if (!block.Verify(currentSnapshot)) + if (!block.Verify(snapshot)) return VerifyResult.Invalid; block_cache.TryAdd(block.Hash, block); block_cache_unverified.Remove(block.Index); Persist(block); - if (block_cache_unverified.TryGetValue(Height + 1, out var unverifiedBlocks)) + if (block_cache_unverified.TryGetValue(block.Index + 1, out var unverifiedBlocks)) { foreach (var unverifiedBlock in unverifiedBlocks.Blocks) Self.Tell(unverifiedBlock, ActorRefs.NoSender); - block_cache_unverified.Remove(Height + 1); + block_cache_unverified.Remove(block.Index + 1); } // We can store the new block in block_cache and tell the new height to other nodes after Persist(). - system.LocalNode.Tell(Message.Create(MessageCommand.Ping, PingPayload.Create(Singleton.Height))); + system.LocalNode.Tell(Message.Create(MessageCommand.Ping, PingPayload.Create(block.Index))); } return VerifyResult.Succeed; } private VerifyResult OnNewInventory(IInventory inventory) { - if (!inventory.Verify(currentSnapshot)) return VerifyResult.Invalid; + if (!inventory.Verify(View)) return VerifyResult.Invalid; RelayCache.Add(inventory); return VerifyResult.Succeed; } @@ -250,7 +257,7 @@ private VerifyResult OnNewInventory(IInventory inventory) private VerifyResult OnNewTransaction(Transaction transaction) { if (ContainsTransaction(transaction.Hash)) return VerifyResult.AlreadyExists; - return MemPool.TryAdd(transaction, currentSnapshot); + return MemPool.TryAdd(transaction, View); } private void OnPreverifyCompleted(PreverifyCompleted task) @@ -284,7 +291,7 @@ protected override void OnReceive(object message) OnPreverifyCompleted(task); break; case Idle _: - if (MemPool.ReVerifyTopUnverifiedTransactionsIfNeeded(MaxTxToReverifyPerIdle, currentSnapshot)) + if (MemPool.ReVerifyTopUnverifiedTransactionsIfNeeded(MaxTxToReverifyPerIdle, View)) Self.Tell(Idle.Instance, ActorRefs.NoSender); break; } @@ -361,19 +368,13 @@ private void Persist(Block block) } } if (commitExceptions != null) throw new AggregateException(commitExceptions); + UpdateExtensibleWitnessWhiteList(snapshot); + MemPool.UpdatePoolForBlockPersisted(block, snapshot); } - UpdateCurrentSnapshot(); block_cache.TryRemove(block.PrevHash, out _); - MemPool.UpdatePoolForBlockPersisted(block, currentSnapshot); Context.System.EventStream.Publish(new PersistCompleted { Block = block }); } - protected override void PostStop() - { - base.PostStop(); - currentSnapshot?.Dispose(); - } - public static Props Props(NeoSystem system, IStore store) { return Akka.Actor.Props.Create(() => new Blockchain(system, store)).WithMailbox("blockchain-mailbox"); @@ -390,21 +391,21 @@ private void SendRelayResult(IInventory inventory, VerifyResult result) Context.System.EventStream.Publish(rr); } - private void UpdateCurrentSnapshot() + private void UpdateExtensibleWitnessWhiteList(DataCache snapshot) { - Interlocked.Exchange(ref currentSnapshot, GetSnapshot())?.Dispose(); + uint currentHeight = NativeContract.Ledger.CurrentIndex(snapshot); var builder = ImmutableHashSet.CreateBuilder(); - builder.Add(NativeContract.NEO.GetCommitteeAddress(currentSnapshot)); - var validators = NativeContract.NEO.GetNextBlockValidators(currentSnapshot); + builder.Add(NativeContract.NEO.GetCommitteeAddress(snapshot)); + var validators = NativeContract.NEO.GetNextBlockValidators(snapshot); builder.Add(Contract.GetBFTAddress(validators)); builder.UnionWith(validators.Select(u => Contract.CreateSignatureRedeemScript(u).ToScriptHash())); - var oracles = NativeContract.RoleManagement.GetDesignatedByRole(currentSnapshot, Role.Oracle, Height); + var oracles = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.Oracle, currentHeight); if (oracles.Length > 0) { builder.Add(Contract.GetBFTAddress(oracles)); builder.UnionWith(oracles.Select(u => Contract.CreateSignatureRedeemScript(u).ToScriptHash())); } - var stateValidators = NativeContract.RoleManagement.GetDesignatedByRole(currentSnapshot, Role.StateValidator, Height); + var stateValidators = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.StateValidator, currentHeight); if (stateValidators.Length > 0) { builder.Add(Contract.GetBFTAddress(stateValidators)); diff --git a/src/neo/Ledger/MemoryPool.cs b/src/neo/Ledger/MemoryPool.cs index bc15638fef..be505878b6 100644 --- a/src/neo/Ledger/MemoryPool.cs +++ b/src/neo/Ledger/MemoryPool.cs @@ -59,8 +59,6 @@ public class MemoryPool : IReadOnlyCollection internal int SortedTxCount => _sortedTransactions.Count; internal int UnverifiedSortedTxCount => _unverifiedSortedTransactions.Count; - private int _maxTxPerBlock; - /// /// Total maximum capacity of transactions the pool can hold. /// @@ -103,11 +101,6 @@ public MemoryPool(NeoSystem system, int capacity) Capacity = capacity; } - internal void LoadPolicy(DataCache snapshot) - { - _maxTxPerBlock = (int)NativeContract.Policy.GetMaxTransactionsPerBlock(snapshot); - } - /// /// Determine whether the pool is holding this transaction and has at some point verified it. /// Note: The pool may not have verified it since the last block was persisted. To get only the @@ -350,8 +343,6 @@ internal void InvalidateVerifiedTransactions() // Note: this must only be called from a single thread (the Blockchain actor) internal void UpdatePoolForBlockPersisted(Block block, DataCache snapshot) { - LoadPolicy(snapshot); - _txRwLock.EnterWriteLock(); try { @@ -370,8 +361,8 @@ internal void UpdatePoolForBlockPersisted(Block block, DataCache snapshot) _txRwLock.ExitWriteLock(); } - ReverifyTransactions(_sortedTransactions, _unverifiedSortedTransactions, - _maxTxPerBlock, MaxMillisecondsToReverifyTx, snapshot); + uint _maxTxPerBlock = NativeContract.Policy.GetMaxTransactionsPerBlock(snapshot); + ReverifyTransactions(_sortedTransactions, _unverifiedSortedTransactions, (int)_maxTxPerBlock, MaxMillisecondsToReverifyTx, snapshot); } internal void InvalidateAllTransactions() @@ -468,6 +459,7 @@ internal bool ReVerifyTopUnverifiedTransactionsIfNeeded(int maxToVerify, DataCac { if (_unverifiedSortedTransactions.Count > 0) { + uint _maxTxPerBlock = NativeContract.Policy.GetMaxTransactionsPerBlock(snapshot); int verifyCount = _sortedTransactions.Count > _maxTxPerBlock ? 1 : maxToVerify; ReverifyTransactions(_sortedTransactions, _unverifiedSortedTransactions, verifyCount, MaxMillisecondsToReverifyTxPerIdle, snapshot); diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index 0cb6b1afcb..fb9fd5cc5b 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -170,23 +170,22 @@ private void OnGetAddrMessageReceived() /// A GetBlocksPayload including start block Hash and number of blocks requested. private void OnGetBlocksMessageReceived(GetBlocksPayload payload) { + // The default value of payload.Count is -1 + int count = payload.Count < 0 || payload.Count > InvPayload.MaxHashesCount ? InvPayload.MaxHashesCount : payload.Count; + DataCache snapshot = Blockchain.Singleton.View; + UInt256 hash = payload.HashStart; + TrimmedBlock state = NativeContract.Ledger.GetTrimmedBlock(snapshot, hash); + if (state == null) return; + uint currentHeight = NativeContract.Ledger.CurrentIndex(snapshot); List hashes = new List(); - using (SnapshotCache snapshot = Blockchain.Singleton.GetSnapshot()) + for (uint i = 1; i <= count; i++) { - UInt256 hash = payload.HashStart; - // The default value of payload.Count is -1 - int count = payload.Count < 0 || payload.Count > InvPayload.MaxHashesCount ? InvPayload.MaxHashesCount : payload.Count; - TrimmedBlock state = NativeContract.Ledger.GetTrimmedBlock(snapshot, hash); - if (state == null) return; - for (uint i = 1; i <= count; i++) - { - uint index = state.Index + i; - if (index > Blockchain.Singleton.Height) - break; - hash = NativeContract.Ledger.GetBlockHash(snapshot, index); - if (hash == null) break; - hashes.Add(hash); - } + uint index = state.Index + i; + if (index > currentHeight) + break; + hash = NativeContract.Ledger.GetBlockHash(snapshot, index); + if (hash == null) break; + hashes.Add(hash); } if (hashes.Count == 0) return; EnqueueMessage(Message.Create(MessageCommand.Inv, InvPayload.Create(InventoryType.Block, hashes.ToArray()))); @@ -273,18 +272,15 @@ private void OnGetDataMessageReceived(InvPayload payload) /// A GetBlocksPayload including start block index and number of blocks' headers requested. private void OnGetHeadersMessageReceived(GetBlockByIndexPayload payload) { - uint index = payload.IndexStart; - if (index > Blockchain.Singleton.Height) return; + DataCache snapshot = Blockchain.Singleton.View; + if (payload.IndexStart > NativeContract.Ledger.CurrentIndex(snapshot)) return; List
headers = new List
(); - using (SnapshotCache snapshot = Blockchain.Singleton.GetSnapshot()) + uint count = payload.Count == -1 ? HeadersPayload.MaxHeadersCount : (uint)payload.Count; + for (uint i = 0; i < count; i++) { - uint count = payload.Count == -1 ? HeadersPayload.MaxHeadersCount : (uint)payload.Count; - for (uint i = 0; i < count; i++) - { - var header = NativeContract.Ledger.GetHeader(snapshot, index + i); - if (header == null) break; - headers.Add(header); - } + var header = NativeContract.Ledger.GetHeader(snapshot, payload.IndexStart + i); + if (header == null) break; + headers.Add(header); } if (headers.Count == 0) return; EnqueueMessage(Message.Create(MessageCommand.Headers, HeadersPayload.Create(headers.ToArray()))); @@ -295,7 +291,7 @@ private void OnInventoryReceived(IInventory inventory) pendingKnownHashes.Remove(inventory.Hash); if (inventory is Block block) { - if (block.Index > Blockchain.Singleton.Height + InvPayload.MaxHashesCount) return; + if (block.Index > NativeContract.Ledger.CurrentIndex(Blockchain.Singleton.View) + InvPayload.MaxHashesCount) return; UpdateLastBlockIndex(block.Index, false); } knownHashes.Add(inventory.Hash); @@ -310,12 +306,16 @@ private void OnInvMessageReceived(InvPayload payload) switch (payload.Type) { case InventoryType.Block: - using (SnapshotCache snapshot = Blockchain.Singleton.GetSnapshot()) + { + DataCache snapshot = Blockchain.Singleton.View; hashes = hashes.Where(p => !NativeContract.Ledger.ContainsBlock(snapshot, p)).ToArray(); + } break; case InventoryType.TX: - using (SnapshotCache snapshot = Blockchain.Singleton.GetSnapshot()) + { + DataCache snapshot = Blockchain.Singleton.View; hashes = hashes.Where(p => !NativeContract.Ledger.ContainsTransaction(snapshot, p)).ToArray(); + } break; } if (hashes.Length == 0) return; @@ -333,7 +333,7 @@ private void OnMemPoolMessageReceived() private void OnPingMessageReceived(PingPayload payload) { UpdateLastBlockIndex(payload.LastBlockIndex, true); - EnqueueMessage(Message.Create(MessageCommand.Pong, PingPayload.Create(Blockchain.Singleton.Height, payload.Nonce))); + EnqueueMessage(Message.Create(MessageCommand.Pong, PingPayload.Create(NativeContract.Ledger.CurrentIndex(Blockchain.Singleton.View), payload.Nonce))); } private void OnPongMessageReceived(PingPayload payload) diff --git a/src/neo/Network/P2P/RemoteNode.cs b/src/neo/Network/P2P/RemoteNode.cs index 5fdc088b92..a417e4115e 100644 --- a/src/neo/Network/P2P/RemoteNode.cs +++ b/src/neo/Network/P2P/RemoteNode.cs @@ -7,6 +7,7 @@ using Neo.Ledger; using Neo.Network.P2P.Capabilities; using Neo.Network.P2P.Payloads; +using Neo.SmartContract.Native; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -173,7 +174,7 @@ private void OnStartProtocol() { var capabilities = new List { - new FullNodeCapability(Blockchain.Singleton.Height) + new FullNodeCapability(NativeContract.Ledger.CurrentIndex(Blockchain.Singleton.View)) }; if (LocalNode.Singleton.ListenerTcpPort > 0) capabilities.Add(new ServerCapability(NodeCapabilityType.TcpServer, (ushort)LocalNode.Singleton.ListenerTcpPort)); diff --git a/src/neo/Network/P2P/TaskManager.cs b/src/neo/Network/P2P/TaskManager.cs index 1e11baf4e0..52aa7013a5 100644 --- a/src/neo/Network/P2P/TaskManager.cs +++ b/src/neo/Network/P2P/TaskManager.cs @@ -46,14 +46,14 @@ public TaskManager(NeoSystem system) { this.system = system; this.knownHashes = new HashSetCache(Blockchain.Singleton.MemPool.Capacity * 2 / 5); - this.lastTaskIndex = Blockchain.Singleton.Height; + this.lastTaskIndex = NativeContract.Ledger.CurrentIndex(Blockchain.Singleton.View); Context.System.EventStream.Subscribe(Self, typeof(Blockchain.PersistCompleted)); Context.System.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); } private bool AssignSyncTask(uint index, TaskSession filterSession = null) { - if (index <= Blockchain.Singleton.Height || sessions.Values.Any(p => p != filterSession && p.IndexTasks.ContainsKey(index))) + if (index <= NativeContract.Ledger.CurrentIndex(Blockchain.Singleton.View) || sessions.Values.Any(p => p != filterSession && p.IndexTasks.ContainsKey(index))) return true; Random rand = new Random(); KeyValuePair remoteNode = sessions.Where(p => p.Value != filterSession && p.Value.LastBlockIndex >= index) @@ -96,7 +96,7 @@ private void OnNewTasks(InvPayload payload) if (!sessions.TryGetValue(Sender, out TaskSession session)) return; // Do not accept payload of type InventoryType.TX if not synced on best known HeaderHeight - if (payload.Type == InventoryType.TX && Blockchain.Singleton.Height < sessions.Values.Max(p => p.LastBlockIndex)) + if (payload.Type == InventoryType.TX && NativeContract.Ledger.CurrentIndex(Blockchain.Singleton.View) < sessions.Values.Max(p => p.LastBlockIndex)) return; HashSet hashes = new HashSet(payload.Hashes); // Remove all previously processed knownHashes from the list that is being requested @@ -276,14 +276,16 @@ public static Props Props(NeoSystem system) private void RequestTasks(bool sendPing) { - if (sessions.Count() == 0) return; + if (sessions.Count == 0) return; if (sendPing) SendPingMessage(); - while (failedSyncTasks.Count() > 0) + uint currentHeight = NativeContract.Ledger.CurrentIndex(Blockchain.Singleton.View); + + while (failedSyncTasks.Count > 0) { var failedTask = failedSyncTasks.First(); - if (failedTask <= Blockchain.Singleton.Height) + if (failedTask <= currentHeight) { failedSyncTasks.Remove(failedTask); continue; @@ -295,19 +297,17 @@ private void RequestTasks(bool sendPing) var highestBlockIndex = sessions.Values.Max(p => p.LastBlockIndex); for (; taskCounts < MaxSyncTasksCount; taskCounts++) { - if (lastTaskIndex >= highestBlockIndex || lastTaskIndex >= Blockchain.Singleton.Height + InvPayload.MaxHashesCount) break; + if (lastTaskIndex >= highestBlockIndex || lastTaskIndex >= currentHeight + InvPayload.MaxHashesCount) break; if (!AssignSyncTask(++lastTaskIndex)) break; } } private void SendPingMessage() { - TrimmedBlock block; - using (SnapshotCache snapshot = Blockchain.Singleton.GetSnapshot()) - { - block = NativeContract.Ledger.GetTrimmedBlock(snapshot, NativeContract.Ledger.CurrentHash(snapshot)); - } - + DataCache snapshot = Blockchain.Singleton.View; + uint currentHeight = NativeContract.Ledger.CurrentIndex(snapshot); + UInt256 currentHash = NativeContract.Ledger.CurrentHash(snapshot); + TrimmedBlock block = NativeContract.Ledger.GetTrimmedBlock(snapshot, currentHash); foreach (KeyValuePair item in sessions) { var node = item.Key; @@ -321,7 +321,7 @@ private void SendPingMessage() { node.Tell(Message.Create(MessageCommand.Mempool)); } - node.Tell(Message.Create(MessageCommand.Ping, PingPayload.Create(Blockchain.Singleton.Height))); + node.Tell(Message.Create(MessageCommand.Ping, PingPayload.Create(currentHeight))); session.ExpireTime = TimeProvider.Current.UtcNow.AddMilliseconds(PingCoolingOffPeriod); } } diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index c5857228da..39c7f048cb 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -357,14 +357,9 @@ internal static void ResetApplicationEngineProvider() public static ApplicationEngine Run(byte[] script, DataCache snapshot = null, IVerifiable container = null, Block persistingBlock = null, int offset = 0, long gas = TestModeGas) { - SnapshotCache disposable = null; - if (snapshot is null) - { - disposable = Blockchain.Singleton.GetSnapshot(); - snapshot = disposable; - } - ApplicationEngine engine = Create(TriggerType.Application, container, snapshot, persistingBlock ?? CreateDummyBlock(snapshot), gas); - if (disposable != null) engine.Disposables.Add(disposable); + snapshot ??= Blockchain.Singleton.View; + persistingBlock ??= CreateDummyBlock(snapshot); + ApplicationEngine engine = Create(TriggerType.Application, container, snapshot, persistingBlock, gas); engine.LoadScript(script, initialPosition: offset); engine.Execute(); return engine; diff --git a/src/neo/SmartContract/ContractParametersContext.cs b/src/neo/SmartContract/ContractParametersContext.cs index 40d44b424e..c68f4974b9 100644 --- a/src/neo/SmartContract/ContractParametersContext.cs +++ b/src/neo/SmartContract/ContractParametersContext.cs @@ -2,7 +2,6 @@ using Neo.IO.Json; using Neo.Ledger; using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.VM; using System; using System.Collections.Generic; @@ -84,19 +83,13 @@ public IReadOnlyList ScriptHashes { get { - if (_ScriptHashes == null) + if (_ScriptHashes is null) { // snapshot is not necessary for Transaction if (Verifiable is Transaction) - { _ScriptHashes = Verifiable.GetScriptHashesForVerifying(null); - return _ScriptHashes; - } - - using (SnapshotCache snapshot = Blockchain.Singleton.GetSnapshot()) - { - _ScriptHashes = Verifiable.GetScriptHashesForVerifying(snapshot); - } + else + _ScriptHashes = Verifiable.GetScriptHashesForVerifying(Blockchain.Singleton.View); } return _ScriptHashes; } diff --git a/src/neo/Wallets/AssetDescriptor.cs b/src/neo/Wallets/AssetDescriptor.cs index 7cbcbdc1a4..15430e9a2b 100644 --- a/src/neo/Wallets/AssetDescriptor.cs +++ b/src/neo/Wallets/AssetDescriptor.cs @@ -16,7 +16,7 @@ public class AssetDescriptor public AssetDescriptor(UInt160 asset_id) { - using SnapshotCache snapshot = Blockchain.Singleton.GetSnapshot(); + DataCache snapshot = Blockchain.Singleton.View; var contract = NativeContract.ContractManagement.GetContract(snapshot, asset_id); if (contract is null) throw new ArgumentException(); diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index a0dc5c4945..b39bc6317a 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -252,64 +252,62 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null { accounts = new[] { from }; } - using (SnapshotCache snapshot = Blockchain.Singleton.GetSnapshot()) + DataCache snapshot = Blockchain.Singleton.View; + Dictionary cosignerList = cosigners?.ToDictionary(p => p.Account) ?? new Dictionary(); + byte[] script; + List<(UInt160 Account, BigInteger Value)> balances_gas = null; + using (ScriptBuilder sb = new ScriptBuilder()) { - Dictionary cosignerList = cosigners?.ToDictionary(p => p.Account) ?? new Dictionary(); - byte[] script; - List<(UInt160 Account, BigInteger Value)> balances_gas = null; - using (ScriptBuilder sb = new ScriptBuilder()) + foreach (var (assetId, group, sum) in outputs.GroupBy(p => p.AssetId, (k, g) => (k, g, g.Select(p => p.Value.Value).Sum()))) { - foreach (var (assetId, group, sum) in outputs.GroupBy(p => p.AssetId, (k, g) => (k, g, g.Select(p => p.Value.Value).Sum()))) - { - var balances = new List<(UInt160 Account, BigInteger Value)>(); - foreach (UInt160 account in accounts) - using (ScriptBuilder sb2 = new ScriptBuilder()) + var balances = new List<(UInt160 Account, BigInteger Value)>(); + foreach (UInt160 account in accounts) + using (ScriptBuilder sb2 = new ScriptBuilder()) + { + sb2.EmitDynamicCall(assetId, "balanceOf", account); + using (ApplicationEngine engine = ApplicationEngine.Run(sb2.ToArray(), snapshot)) { - sb2.EmitDynamicCall(assetId, "balanceOf", account); - using (ApplicationEngine engine = ApplicationEngine.Run(sb2.ToArray(), snapshot)) - { - if (engine.State.HasFlag(VMState.FAULT)) - throw new InvalidOperationException($"Execution for {assetId.ToString()}.balanceOf('{account.ToString()}' fault"); - BigInteger value = engine.ResultStack.Pop().GetInteger(); - if (value.Sign > 0) balances.Add((account, value)); - } + if (engine.State.HasFlag(VMState.FAULT)) + throw new InvalidOperationException($"Execution for {assetId}.balanceOf('{account}' fault"); + BigInteger value = engine.ResultStack.Pop().GetInteger(); + if (value.Sign > 0) balances.Add((account, value)); } - BigInteger sum_balance = balances.Select(p => p.Value).Sum(); - if (sum_balance < sum) - throw new InvalidOperationException($"It does not have enough balance, expected: {sum.ToString()} found: {sum_balance.ToString()}"); - foreach (TransferOutput output in group) + } + BigInteger sum_balance = balances.Select(p => p.Value).Sum(); + if (sum_balance < sum) + throw new InvalidOperationException($"It does not have enough balance, expected: {sum} found: {sum_balance}"); + foreach (TransferOutput output in group) + { + balances = balances.OrderBy(p => p.Value).ToList(); + var balances_used = FindPayingAccounts(balances, output.Value.Value); + foreach (var (account, value) in balances_used) { - balances = balances.OrderBy(p => p.Value).ToList(); - var balances_used = FindPayingAccounts(balances, output.Value.Value); - foreach (var (account, value) in balances_used) + if (cosignerList.TryGetValue(account, out Signer signer)) { - if (cosignerList.TryGetValue(account, out Signer signer)) - { - if (signer.Scopes != WitnessScope.Global) - signer.Scopes |= WitnessScope.CalledByEntry; - } - else + if (signer.Scopes != WitnessScope.Global) + signer.Scopes |= WitnessScope.CalledByEntry; + } + else + { + cosignerList.Add(account, new Signer { - cosignerList.Add(account, new Signer - { - Account = account, - Scopes = WitnessScope.CalledByEntry - }); - } - sb.EmitDynamicCall(output.AssetId, "transfer", account, output.ScriptHash, value, output.Data); - sb.Emit(OpCode.ASSERT); + Account = account, + Scopes = WitnessScope.CalledByEntry + }); } + sb.EmitDynamicCall(output.AssetId, "transfer", account, output.ScriptHash, value, output.Data); + sb.Emit(OpCode.ASSERT); } - if (assetId.Equals(NativeContract.GAS.Hash)) - balances_gas = balances; } - script = sb.ToArray(); + if (assetId.Equals(NativeContract.GAS.Hash)) + balances_gas = balances; } - if (balances_gas is null) - balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); - - return MakeTransaction(snapshot, script, cosignerList.Values.ToArray(), Array.Empty(), balances_gas); + script = sb.ToArray(); } + if (balances_gas is null) + balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); + + return MakeTransaction(snapshot, script, cosignerList.Values.ToArray(), Array.Empty(), balances_gas); } public Transaction MakeTransaction(byte[] script, UInt160 sender = null, Signer[] cosigners = null, TransactionAttribute[] attributes = null) @@ -323,11 +321,9 @@ public Transaction MakeTransaction(byte[] script, UInt160 sender = null, Signer[ { accounts = new[] { sender }; } - using (SnapshotCache snapshot = Blockchain.Singleton.GetSnapshot()) - { - var balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); - return MakeTransaction(snapshot, script, cosigners ?? Array.Empty(), attributes ?? Array.Empty(), balances_gas); - } + DataCache snapshot = Blockchain.Singleton.View; + var balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); + return MakeTransaction(snapshot, script, cosigners ?? Array.Empty(), attributes ?? Array.Empty(), balances_gas); } private Transaction MakeTransaction(DataCache snapshot, byte[] script, Signer[] cosigners, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) @@ -475,8 +471,7 @@ public bool Sign(ContractParametersContext context) // Try Smart contract verification - using var snapshot = Blockchain.Singleton.GetSnapshot(); - var contract = NativeContract.ContractManagement.GetContract(snapshot, scriptHash); + var contract = NativeContract.ContractManagement.GetContract(Blockchain.Singleton.View, scriptHash); if (contract != null) { diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index 40ba38c868..9df5c96f6f 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -1,5 +1,4 @@ using Akka.TestKit.Xunit2; -using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO; using Neo.Ledger; @@ -12,7 +11,6 @@ using System; using System.Linq; using System.Numerics; -using System.Reflection; namespace Neo.UnitTests.Ledger { @@ -62,12 +60,6 @@ public void Initialize() Blockchain.Singleton.MemPool.TryAdd(txSample, Blockchain.Singleton.GetSnapshot()); } - [TestMethod] - public void TestGetCurrentBlockHash() - { - Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0x00c6803707b564153d444bfcdf3a13325fc96dda55cc8a740bbd543a1d752fda")); - } - [TestMethod] public void TestValidTransaction() { @@ -85,10 +77,6 @@ public void TestValidTransaction() entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; snapshot.Commit(); - typeof(Blockchain) - .GetMethod("UpdateCurrentSnapshot", BindingFlags.Instance | BindingFlags.NonPublic) - .Invoke(Blockchain.Singleton, null); - // Make transaction var tx = CreateValidTx(walletA, acc.ScriptHash, 0); diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 8e8f31841c..a610c70ccf 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -52,7 +52,6 @@ public void TestSetup() // Create a MemoryPool with capacity of 100 _unit = new MemoryPool(TestBlockchain.TheNeoSystem, 100); - _unit.LoadPolicy(Blockchain.Singleton.GetSnapshot()); // Verify capacity equals the amount specified _unit.Capacity.Should().Be(100); @@ -429,7 +428,6 @@ public void TestGetVerifiedTransactions() public void TestReVerifyTopUnverifiedTransactionsIfNeeded() { _unit = new MemoryPool(TestBlockchain.TheNeoSystem, 600); - _unit.LoadPolicy(Blockchain.Singleton.GetSnapshot()); AddTransaction(CreateTransaction(100000001)); AddTransaction(CreateTransaction(100000001)); AddTransaction(CreateTransaction(100000001));