diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index d05b4a64ea..cab0ce8370 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -21,7 +21,7 @@ internal class ConsensusContext : IDisposable, ISerializable /// /// Key for saving consensus state. /// - private static readonly byte[] ConsensusStateKey = { 0xf4 }; + private const byte ConsensusStatePrefix = 0xf4; public Block Block; public byte ViewNumber; @@ -42,11 +42,11 @@ internal class ConsensusContext : IDisposable, ISerializable /// public SendersFeeMonitor SendersFeeMonitor = new SendersFeeMonitor(); - public Snapshot Snapshot { get; private set; } + public SnapshotView Snapshot { get; private set; } private KeyPair keyPair; private int _witnessSize; private readonly Wallet wallet; - private readonly Store store; + private readonly IStore store; public int F => (Validators.Length - 1) / 3; public int M => Validators.Length - F; @@ -74,7 +74,7 @@ internal class ConsensusContext : IDisposable, ISerializable public int Size => throw new NotImplementedException(); - public ConsensusContext(Wallet wallet, Store store) + public ConsensusContext(Wallet wallet, IStore store) { this.wallet = wallet; this.store = store; @@ -146,7 +146,7 @@ public uint GetPrimaryIndex(byte viewNumber) public bool Load() { - byte[] data = store.Get(ConsensusStateKey); + byte[] data = store.TryGet(ConsensusStatePrefix, null); if (data is null || data.Length == 0) return false; using (MemoryStream ms = new MemoryStream(data, false)) using (BinaryReader reader = new BinaryReader(ms)) @@ -409,7 +409,7 @@ public void Reset(byte viewNumber) public void Save() { - store.PutSync(ConsensusStateKey, this.ToArray()); + store.PutSync(ConsensusStatePrefix, null, this.ToArray()); } public void Serialize(BinaryWriter writer) diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 9d0bd5a343..3c5c334e11 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -46,7 +46,7 @@ internal class Timer { public uint Height; public byte ViewNumber; } /// private bool isRecovering = false; - public ConsensusService(IActorRef localNode, IActorRef taskManager, Store store, Wallet wallet) + public ConsensusService(IActorRef localNode, IActorRef taskManager, IStore store, Wallet wallet) : this(localNode, taskManager, new ConsensusContext(wallet, store)) { } @@ -601,7 +601,7 @@ protected override void PostStop() base.PostStop(); } - public static Props Props(IActorRef localNode, IActorRef taskManager, Store store, Wallet wallet) + public static Props Props(IActorRef localNode, IActorRef taskManager, IStore store, Wallet wallet) { return Akka.Actor.Props.Create(() => new ConsensusService(localNode, taskManager, store, wallet)).WithMailbox("consensus-service-mailbox"); } diff --git a/src/neo/IO/Caching/CloneCache.cs b/src/neo/IO/Caching/CloneCache.cs index 0dd030fcb6..559ee3d279 100644 --- a/src/neo/IO/Caching/CloneCache.cs +++ b/src/neo/IO/Caching/CloneCache.cs @@ -19,15 +19,15 @@ protected override void AddInternal(TKey key, TValue value) innerCache.Add(key, value); } - public override void DeleteInternal(TKey key) + protected override void DeleteInternal(TKey key) { innerCache.Delete(key); } - protected override IEnumerable> FindInternal(byte[] key_prefix) + protected override IEnumerable<(TKey, TValue)> FindInternal(byte[] key_prefix) { - foreach (KeyValuePair pair in innerCache.Find(key_prefix)) - yield return new KeyValuePair(pair.Key, pair.Value.Clone()); + foreach (var (key, value) in innerCache.Find(key_prefix)) + yield return (key, value.Clone()); } protected override TValue GetInternal(TKey key) diff --git a/src/neo/IO/Caching/DataCache.cs b/src/neo/IO/Caching/DataCache.cs index dc97031d10..373c4f2757 100644 --- a/src/neo/IO/Caching/DataCache.cs +++ b/src/neo/IO/Caching/DataCache.cs @@ -107,7 +107,7 @@ public void Delete(TKey key) } } - public abstract void DeleteInternal(TKey key); + protected abstract void DeleteInternal(TKey key); public void DeleteWhere(Func predicate) { @@ -123,7 +123,7 @@ public void DeleteWhere(Func predicate) /// /// Must maintain the deserialized format of TKey /// Entries found with the desired prefix - public IEnumerable> Find(byte[] key_prefix = null) + public IEnumerable<(TKey Key, TValue Value)> Find(byte[] key_prefix = null) { IEnumerable<(byte[], TKey, TValue)> cached; lock (dictionary) @@ -159,13 +159,13 @@ public void DeleteWhere(Func predicate) { if (!c2 || (c1 && ByteArrayComparer.Default.Compare(i1.KeyBytes, i2.KeyBytes) < 0)) { - yield return new KeyValuePair(i1.Key, i1.Item); + yield return (i1.Key, i1.Item); c1 = e1.MoveNext(); i1 = c1 ? e1.Current : default; } else { - yield return new KeyValuePair(i2.Key, i2.Item); + yield return (i2.Key, i2.Item); c2 = e2.MoveNext(); i2 = c2 ? e2.Current : default; } @@ -173,7 +173,7 @@ public void DeleteWhere(Func predicate) } } - protected abstract IEnumerable> FindInternal(byte[] key_prefix); + protected abstract IEnumerable<(TKey Key, TValue Value)> FindInternal(byte[] key_prefix); public IEnumerable GetChangeSet() { diff --git a/src/neo/IO/Data/LevelDB/SliceBuilder.cs b/src/neo/IO/Data/LevelDB/SliceBuilder.cs index d5888c6b5e..cf1cff0264 100644 --- a/src/neo/IO/Data/LevelDB/SliceBuilder.cs +++ b/src/neo/IO/Data/LevelDB/SliceBuilder.cs @@ -38,19 +38,22 @@ public SliceBuilder Add(long value) public SliceBuilder Add(IEnumerable value) { - data.AddRange(value); + if (value != null) + data.AddRange(value); return this; } public SliceBuilder Add(string value) { - data.AddRange(Encoding.UTF8.GetBytes(value)); + if (value != null) + data.AddRange(Encoding.UTF8.GetBytes(value)); return this; } public SliceBuilder Add(ISerializable value) { - data.AddRange(value.ToArray()); + if (value != null) + data.AddRange(value.ToArray()); return this; } diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 07575b895e..14b38860cf 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -62,9 +62,10 @@ public class FillCompleted { } private readonly Dictionary block_cache = new Dictionary(); private readonly Dictionary> block_cache_unverified = new Dictionary>(); internal readonly RelayCache ConsensusRelayCache = new RelayCache(100); - private Snapshot currentSnapshot; + private SnapshotView currentSnapshot; - public Store Store { get; } + public IStore Store { get; } + public ReadOnlyView View { get; } public MemoryPool MemPool { get; } public uint Height => currentSnapshot.Height; public uint HeaderHeight => currentSnapshot.HeaderHeight; @@ -95,27 +96,28 @@ static Blockchain() } } - public Blockchain(NeoSystem system, Store store) + public Blockchain(NeoSystem system, IStore store) { this.system = system; this.MemPool = new MemoryPool(system, ProtocolSettings.Default.MemoryPoolMaxTransactions); this.Store = store; + this.View = new ReadOnlyView(store); lock (lockObj) { if (singleton != null) throw new InvalidOperationException(); - header_index.AddRange(store.GetHeaderHashList().Find().OrderBy(p => (uint)p.Key).SelectMany(p => p.Value.Hashes)); + header_index.AddRange(View.HeaderHashList.Find().OrderBy(p => (uint)p.Key).SelectMany(p => p.Value.Hashes)); stored_header_count += (uint)header_index.Count; if (stored_header_count == 0) { - header_index.AddRange(store.GetBlocks().Find().OrderBy(p => p.Value.Index).Select(p => p.Key)); + header_index.AddRange(View.Blocks.Find().OrderBy(p => p.Value.Index).Select(p => p.Key)); } else { - HashIndexState hashIndex = store.GetHeaderHashIndex().Get(); + HashIndexState hashIndex = View.HeaderHashIndex.Get(); if (hashIndex.Index >= stored_header_count) { - DataCache cache = store.GetBlocks(); + DataCache cache = View.Blocks; for (UInt256 hash = hashIndex.Hash; hash != header_index[(int)stored_header_count - 1];) { header_index.Insert((int)stored_header_count, hash); @@ -139,13 +141,13 @@ public Blockchain(NeoSystem system, Store store) public bool ContainsBlock(UInt256 hash) { if (block_cache.ContainsKey(hash)) return true; - return Store.ContainsBlock(hash); + return View.ContainsBlock(hash); } public bool ContainsTransaction(UInt256 hash) { if (MemPool.ContainsKey(hash)) return true; - return Store.ContainsTransaction(hash); + return View.ContainsTransaction(hash); } private static Transaction DeployNativeContracts() @@ -175,11 +177,19 @@ private static Transaction DeployNativeContracts() }; } + public Block GetBlock(uint index) + { + if (index == 0) return GenesisBlock; + UInt256 hash = GetBlockHash(index); + if (hash == null) return null; + return GetBlock(hash); + } + public Block GetBlock(UInt256 hash) { if (block_cache.TryGetValue(hash, out Block block)) return block; - return Store.GetBlock(hash); + return View.GetBlock(hash); } public UInt256 GetBlockHash(uint index) @@ -193,16 +203,38 @@ public static UInt160 GetConsensusAddress(ECPoint[] validators) return Contract.CreateMultiSigRedeemScript(validators.Length - (validators.Length - 1) / 3, validators).ToScriptHash(); } - public Snapshot GetSnapshot() + public Header GetHeader(uint index) + { + if (index == 0) return GenesisBlock.Header; + UInt256 hash = GetBlockHash(index); + if (hash == null) return null; + return GetHeader(hash); + } + + public Header GetHeader(UInt256 hash) + { + if (block_cache.TryGetValue(hash, out Block block)) + return block.Header; + return View.GetHeader(hash); + } + + public UInt256 GetNextBlockHash(UInt256 hash) + { + Header header = GetHeader(hash); + if (header == null) return null; + return GetBlockHash(header.Index + 1); + } + + public SnapshotView GetSnapshot() { - return Store.GetSnapshot(); + return new SnapshotView(Store); } public Transaction GetTransaction(UInt256 hash) { if (MemPool.TryGetValue(hash, out Transaction transaction)) return transaction; - return Store.GetTransaction(hash); + return View.GetTransaction(hash); } private void OnImport(IEnumerable blocks) @@ -237,7 +269,7 @@ private void OnFillMemoryPool(IEnumerable transactions) // Add the transactions to the memory pool foreach (var tx in transactions) { - if (Store.ContainsTransaction(tx.Hash)) + if (View.ContainsTransaction(tx.Hash)) continue; if (!NativeContract.Policy.CheckPolicy(tx, currentSnapshot)) continue; @@ -320,7 +352,7 @@ private RelayResultReason OnNewBlock(Block block) if (block.Index == header_index.Count) { header_index.Add(block.Hash); - using (Snapshot snapshot = GetSnapshot()) + using (SnapshotView snapshot = GetSnapshot()) { snapshot.Blocks.Add(block.Hash, block.Header.Trim()); snapshot.HeaderHashIndex.GetAndChange().Set(block); @@ -344,7 +376,7 @@ private RelayResultReason OnNewConsensus(ConsensusPayload payload) private void OnNewHeaders(Header[] headers) { - using (Snapshot snapshot = GetSnapshot()) + using (SnapshotView snapshot = GetSnapshot()) { foreach (Header header in headers) { @@ -425,7 +457,7 @@ protected override void OnReceive(object message) private void Persist(Block block) { - using (Snapshot snapshot = GetSnapshot()) + using (SnapshotView snapshot = GetSnapshot()) { List all_application_executed = new List(); snapshot.PersistingBlock = block; @@ -503,12 +535,12 @@ protected override void PostStop() currentSnapshot?.Dispose(); } - public static Props Props(NeoSystem system, Store store) + public static Props Props(NeoSystem system, IStore store) { return Akka.Actor.Props.Create(() => new Blockchain(system, store)).WithMailbox("blockchain-mailbox"); } - private void SaveHeaderHashList(Snapshot snapshot = null) + private void SaveHeaderHashList(SnapshotView snapshot = null) { if ((header_index.Count - stored_header_count < 2000)) return; diff --git a/src/neo/Ledger/MemoryPool.cs b/src/neo/Ledger/MemoryPool.cs index 78df9b97f6..4b9f1b8139 100644 --- a/src/neo/Ledger/MemoryPool.cs +++ b/src/neo/Ledger/MemoryPool.cs @@ -105,7 +105,7 @@ public MemoryPool(NeoSystem system, int capacity) Capacity = capacity; } - internal bool LoadPolicy(Snapshot snapshot) + internal bool LoadPolicy(StoreView snapshot) { _maxTxPerBlock = (int)NativeContract.Policy.GetMaxTransactionsPerBlock(snapshot); long newFeePerByte = NativeContract.Policy.GetFeePerByte(snapshot); @@ -348,7 +348,7 @@ internal void InvalidateVerifiedTransactions() } // Note: this must only be called from a single thread (the Blockchain actor) - internal void UpdatePoolForBlockPersisted(Block block, Snapshot snapshot) + internal void UpdatePoolForBlockPersisted(Block block, StoreView snapshot) { bool policyChanged = LoadPolicy(snapshot); @@ -407,7 +407,7 @@ internal void InvalidateAllTransactions() } private int ReverifyTransactions(SortedSet verifiedSortedTxPool, - SortedSet unverifiedSortedTxPool, int count, double millisecondsTimeout, Snapshot snapshot) + SortedSet unverifiedSortedTxPool, int count, double millisecondsTimeout, StoreView snapshot) { DateTime reverifyCutOffTimeStamp = DateTime.UtcNow.AddMilliseconds(millisecondsTimeout); List reverifiedItems = new List(count); @@ -483,7 +483,7 @@ internal void InvalidateAllTransactions() /// Max transactions to reverify, the value passed can be >=1 /// The snapshot to use for verifying. /// true if more unsorted messages exist, otherwise false - internal bool ReVerifyTopUnverifiedTransactionsIfNeeded(int maxToVerify, Snapshot snapshot) + internal bool ReVerifyTopUnverifiedTransactionsIfNeeded(int maxToVerify, StoreView snapshot) { if (Blockchain.Singleton.Height < Blockchain.Singleton.HeaderHeight) return false; diff --git a/src/neo/NeoSystem.cs b/src/neo/NeoSystem.cs index 9265f47645..b1ef9b6ec8 100644 --- a/src/neo/NeoSystem.cs +++ b/src/neo/NeoSystem.cs @@ -26,11 +26,11 @@ public class NeoSystem : IDisposable public IActorRef Consensus { get; private set; } public RpcServer RpcServer { get; private set; } - private readonly Store store; + private readonly IStore store; private ChannelsConfig start_message = null; private bool suspend = false; - public NeoSystem(Store store) + public NeoSystem(IStore store) { this.store = store; Plugin.LoadPlugins(this); @@ -69,7 +69,7 @@ internal void ResumeNodeStartup() } } - public void StartConsensus(Wallet wallet, Store consensus_store = null, bool ignoreRecoveryLogs = false) + public void StartConsensus(Wallet wallet, IStore consensus_store = null, bool ignoreRecoveryLogs = false) { Consensus = ActorSystem.ActorOf(ConsensusService.Props(this.LocalNode, this.TaskManager, consensus_store ?? store, wallet)); Consensus.Tell(new ConsensusService.Start { IgnoreRecoveryLogs = ignoreRecoveryLogs }, Blockchain); diff --git a/src/neo/Network/P2P/Payloads/BlockBase.cs b/src/neo/Network/P2P/Payloads/BlockBase.cs index 4274cb990a..37ab7abe66 100644 --- a/src/neo/Network/P2P/Payloads/BlockBase.cs +++ b/src/neo/Network/P2P/Payloads/BlockBase.cs @@ -74,7 +74,7 @@ void IVerifiable.DeserializeUnsigned(BinaryReader reader) NextConsensus = reader.ReadSerializable(); } - UInt160[] IVerifiable.GetScriptHashesForVerifying(Snapshot snapshot) + UInt160[] IVerifiable.GetScriptHashesForVerifying(StoreView snapshot) { if (PrevHash == UInt256.Zero) return new[] { Witness.ScriptHash }; Header prev_header = snapshot.GetHeader(PrevHash); @@ -124,7 +124,7 @@ public void FromJson(JObject json) Witness = ((JArray)json["witnesses"]).Select(p => Witness.FromJson(p)).FirstOrDefault(); } - public virtual bool Verify(Snapshot snapshot) + public virtual bool Verify(StoreView snapshot) { Header prev_header = snapshot.GetHeader(PrevHash); if (prev_header == null) return false; diff --git a/src/neo/Network/P2P/Payloads/ConsensusPayload.cs b/src/neo/Network/P2P/Payloads/ConsensusPayload.cs index 062e5d9830..21730a3470 100644 --- a/src/neo/Network/P2P/Payloads/ConsensusPayload.cs +++ b/src/neo/Network/P2P/Payloads/ConsensusPayload.cs @@ -95,7 +95,7 @@ void IVerifiable.DeserializeUnsigned(BinaryReader reader) Data = reader.ReadVarBytes(); } - UInt160[] IVerifiable.GetScriptHashesForVerifying(Snapshot snapshot) + UInt160[] IVerifiable.GetScriptHashesForVerifying(StoreView snapshot) { ECPoint[] validators = NativeContract.NEO.GetNextBlockValidators(snapshot); if (validators.Length <= ValidatorIndex) @@ -118,7 +118,7 @@ void IVerifiable.SerializeUnsigned(BinaryWriter writer) writer.WriteVarBytes(Data); } - public bool Verify(Snapshot snapshot) + public bool Verify(StoreView snapshot) { if (BlockIndex <= snapshot.Height) return false; diff --git a/src/neo/Network/P2P/Payloads/IInventory.cs b/src/neo/Network/P2P/Payloads/IInventory.cs index 26b62346d9..2b175647c5 100644 --- a/src/neo/Network/P2P/Payloads/IInventory.cs +++ b/src/neo/Network/P2P/Payloads/IInventory.cs @@ -8,6 +8,6 @@ public interface IInventory : IVerifiable InventoryType InventoryType { get; } - bool Verify(Snapshot snapshot); + bool Verify(StoreView snapshot); } } diff --git a/src/neo/Network/P2P/Payloads/IVerifiable.cs b/src/neo/Network/P2P/Payloads/IVerifiable.cs index 8540d8a626..cecd0570da 100644 --- a/src/neo/Network/P2P/Payloads/IVerifiable.cs +++ b/src/neo/Network/P2P/Payloads/IVerifiable.cs @@ -10,7 +10,7 @@ public interface IVerifiable : ISerializable void DeserializeUnsigned(BinaryReader reader); - UInt160[] GetScriptHashesForVerifying(Snapshot snapshot); + UInt160[] GetScriptHashesForVerifying(StoreView snapshot); void SerializeUnsigned(BinaryWriter writer); } diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index de81275877..6bda3f8c6b 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -123,14 +123,14 @@ public override int GetHashCode() return Hash.GetHashCode(); } - public UInt160[] GetScriptHashesForVerifying(Snapshot snapshot) + public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { var hashes = new HashSet { Sender }; hashes.UnionWith(Cosigners.Select(p => p.Account)); return hashes.OrderBy(p => p).ToArray(); } - public virtual bool Reverify(Snapshot snapshot, BigInteger totalSenderFeeFromPool) + public virtual bool Reverify(StoreView snapshot, BigInteger totalSenderFeeFromPool) { if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) return false; @@ -202,12 +202,12 @@ public static Transaction FromJson(JObject json) return tx; } - bool IInventory.Verify(Snapshot snapshot) + bool IInventory.Verify(StoreView snapshot) { return Verify(snapshot, BigInteger.Zero); } - public virtual bool Verify(Snapshot snapshot, BigInteger totalSenderFeeFromPool) + public virtual bool Verify(StoreView snapshot, BigInteger totalSenderFeeFromPool) { if (!Reverify(snapshot, totalSenderFeeFromPool)) return false; int size = Size; diff --git a/src/neo/Network/P2P/ProtocolHandler.cs b/src/neo/Network/P2P/ProtocolHandler.cs index 1e62e4dfbf..e16d7f238c 100644 --- a/src/neo/Network/P2P/ProtocolHandler.cs +++ b/src/neo/Network/P2P/ProtocolHandler.cs @@ -162,7 +162,7 @@ private void OnGetBlocksMessageReceived(GetBlocksPayload payload) { UInt256 hash = payload.HashStart; int count = payload.Count < 0 || payload.Count > InvPayload.MaxHashesCount ? InvPayload.MaxHashesCount : payload.Count; - TrimmedBlock state = Blockchain.Singleton.Store.GetBlocks().TryGet(hash); + TrimmedBlock state = Blockchain.Singleton.View.Blocks.TryGet(hash); if (state == null) return; List hashes = new List(); for (uint i = 1; i <= count; i++) @@ -182,7 +182,7 @@ private void OnGetBlockDataMessageReceived(GetBlockDataPayload payload) { for (uint i = payload.IndexStart, max = payload.IndexStart + payload.Count; i < max; i++) { - Block block = Blockchain.Singleton.Store.GetBlock(i); + Block block = Blockchain.Singleton.GetBlock(i); if (block == null) break; @@ -237,7 +237,7 @@ private void OnGetHeadersMessageReceived(GetBlocksPayload payload) { UInt256 hash = payload.HashStart; int count = payload.Count < 0 || payload.Count > HeadersPayload.MaxHeadersCount ? HeadersPayload.MaxHeadersCount : payload.Count; - DataCache cache = Blockchain.Singleton.Store.GetBlocks(); + DataCache cache = Blockchain.Singleton.View.Blocks; TrimmedBlock state = cache.TryGet(hash); if (state == null) return; List
headers = new List
(); @@ -273,11 +273,11 @@ private void OnInvMessageReceived(InvPayload payload) switch (payload.Type) { case InventoryType.Block: - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) hashes = hashes.Where(p => !snapshot.ContainsBlock(p)).ToArray(); break; case InventoryType.TX: - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) hashes = hashes.Where(p => !snapshot.ContainsTransaction(p)).ToArray(); break; } diff --git a/src/neo/Network/RPC/RpcServer.cs b/src/neo/Network/RPC/RpcServer.cs index 7414d54d10..953783b5ed 100644 --- a/src/neo/Network/RPC/RpcServer.cs +++ b/src/neo/Network/RPC/RpcServer.cs @@ -57,7 +57,7 @@ public void DeserializeUnsigned(BinaryReader reader) throw new NotImplementedException(); } - public UInt160[] GetScriptHashesForVerifying(Snapshot snapshot) + public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { return _scriptHashesForVerifying; } @@ -435,12 +435,12 @@ private JObject GetBlock(JObject key, bool verbose) if (key is JNumber) { uint index = uint.Parse(key.AsString()); - block = Blockchain.Singleton.Store.GetBlock(index); + block = Blockchain.Singleton.GetBlock(index); } else { UInt256 hash = UInt256.Parse(key.AsString()); - block = Blockchain.Singleton.Store.GetBlock(hash); + block = Blockchain.Singleton.View.GetBlock(hash); } if (block == null) throw new RpcException(-100, "Unknown block"); @@ -448,7 +448,7 @@ private JObject GetBlock(JObject key, bool verbose) { JObject json = block.ToJson(); json["confirmations"] = Blockchain.Singleton.Height - block.Index + 1; - UInt256 hash = Blockchain.Singleton.Store.GetNextBlockHash(block.Hash); + UInt256 hash = Blockchain.Singleton.GetNextBlockHash(block.Hash); if (hash != null) json["nextblockhash"] = hash.ToString(); return json; @@ -476,12 +476,12 @@ private JObject GetBlockHeader(JObject key, bool verbose) if (key is JNumber) { uint height = uint.Parse(key.AsString()); - header = Blockchain.Singleton.Store.GetHeader(height); + header = Blockchain.Singleton.GetHeader(height); } else { UInt256 hash = UInt256.Parse(key.AsString()); - header = Blockchain.Singleton.Store.GetHeader(hash); + header = Blockchain.Singleton.View.GetHeader(hash); } if (header == null) throw new RpcException(-100, "Unknown block"); @@ -490,7 +490,7 @@ private JObject GetBlockHeader(JObject key, bool verbose) { JObject json = header.ToJson(); json["confirmations"] = Blockchain.Singleton.Height - header.Index + 1; - UInt256 hash = Blockchain.Singleton.Store.GetNextBlockHash(header.Hash); + UInt256 hash = Blockchain.Singleton.GetNextBlockHash(header.Hash); if (hash != null) json["nextblockhash"] = hash.ToString(); return json; @@ -516,7 +516,7 @@ private JObject GetConnectionCount() private JObject GetContractState(UInt160 script_hash) { - ContractState contract = Blockchain.Singleton.Store.GetContracts().TryGet(script_hash); + ContractState contract = Blockchain.Singleton.View.Contracts.TryGet(script_hash); return contract?.ToJson() ?? throw new RpcException(-100, "Unknown contract"); } @@ -564,10 +564,10 @@ private JObject GetRawTransaction(UInt256 hash, bool verbose) if (verbose) { JObject json = tx.ToJson(); - TransactionState txState = Blockchain.Singleton.Store.GetTransactions().TryGet(hash); + TransactionState txState = Blockchain.Singleton.View.Transactions.TryGet(hash); if (txState != null) { - Header header = Blockchain.Singleton.Store.GetHeader(txState.BlockIndex); + Header header = Blockchain.Singleton.GetHeader(txState.BlockIndex); json["blockhash"] = header.Hash.ToString(); json["confirmations"] = Blockchain.Singleton.Height - header.Index + 1; json["blocktime"] = header.Timestamp; @@ -580,7 +580,7 @@ private JObject GetRawTransaction(UInt256 hash, bool verbose) private JObject GetStorage(UInt160 script_hash, byte[] key) { - StorageItem item = Blockchain.Singleton.Store.GetStorages().TryGet(new StorageKey + StorageItem item = Blockchain.Singleton.View.Storages.TryGet(new StorageKey { ScriptHash = script_hash, Key = key @@ -590,14 +590,14 @@ private JObject GetStorage(UInt160 script_hash, byte[] key) private JObject GetTransactionHeight(UInt256 hash) { - uint? height = Blockchain.Singleton.Store.GetTransactions().TryGet(hash)?.BlockIndex; + uint? height = Blockchain.Singleton.View.Transactions.TryGet(hash)?.BlockIndex; if (height.HasValue) return height.Value; throw new RpcException(-100, "Unknown transaction"); } private JObject GetValidators() { - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { var validators = NativeContract.NEO.GetValidators(snapshot); return NativeContract.NEO.GetRegisteredValidators(snapshot).Select(p => diff --git a/src/neo/Persistence/CloneSnapshot.cs b/src/neo/Persistence/ClonedView.cs similarity index 52% rename from src/neo/Persistence/CloneSnapshot.cs rename to src/neo/Persistence/ClonedView.cs index 0b79bd2739..927207d6a1 100644 --- a/src/neo/Persistence/CloneSnapshot.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -4,7 +4,7 @@ namespace Neo.Persistence { - internal class CloneSnapshot : Snapshot + internal class ClonedView : StoreView { public override DataCache Blocks { get; } public override DataCache Transactions { get; } @@ -14,16 +14,16 @@ internal class CloneSnapshot : Snapshot public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public CloneSnapshot(Snapshot snapshot) + public ClonedView(StoreView view) { - this.PersistingBlock = snapshot.PersistingBlock; - this.Blocks = snapshot.Blocks.CreateSnapshot(); - this.Transactions = snapshot.Transactions.CreateSnapshot(); - this.Contracts = snapshot.Contracts.CreateSnapshot(); - this.Storages = snapshot.Storages.CreateSnapshot(); - this.HeaderHashList = snapshot.HeaderHashList.CreateSnapshot(); - this.BlockHashIndex = snapshot.BlockHashIndex.CreateSnapshot(); - this.HeaderHashIndex = snapshot.HeaderHashIndex.CreateSnapshot(); + this.PersistingBlock = view.PersistingBlock; + this.Blocks = view.Blocks.CreateSnapshot(); + this.Transactions = view.Transactions.CreateSnapshot(); + this.Contracts = view.Contracts.CreateSnapshot(); + this.Storages = view.Storages.CreateSnapshot(); + this.HeaderHashList = view.HeaderHashList.CreateSnapshot(); + this.BlockHashIndex = view.BlockHashIndex.CreateSnapshot(); + this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot(); } } } diff --git a/src/neo/Persistence/Helper.cs b/src/neo/Persistence/Helper.cs deleted file mode 100644 index 7f412e47d3..0000000000 --- a/src/neo/Persistence/Helper.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Neo.Ledger; -using Neo.Network.P2P.Payloads; - -namespace Neo.Persistence -{ - public static class Helper - { - public static bool ContainsBlock(this IPersistence persistence, UInt256 hash) - { - TrimmedBlock state = persistence.Blocks.TryGet(hash); - if (state == null) return false; - return state.IsBlock; - } - - public static bool ContainsTransaction(this IPersistence persistence, UInt256 hash) - { - TransactionState state = persistence.Transactions.TryGet(hash); - return state != null; - } - - public static Block GetBlock(this IPersistence persistence, uint index) - { - if (index == 0) return Blockchain.GenesisBlock; - UInt256 hash = Blockchain.Singleton.GetBlockHash(index); - if (hash == null) return null; - return persistence.GetBlock(hash); - } - - public static Block GetBlock(this IPersistence persistence, UInt256 hash) - { - TrimmedBlock state = persistence.Blocks.TryGet(hash); - if (state == null) return null; - if (!state.IsBlock) return null; - return state.GetBlock(persistence.Transactions); - } - - public static Header GetHeader(this IPersistence persistence, uint index) - { - if (index == 0) return Blockchain.GenesisBlock.Header; - UInt256 hash = Blockchain.Singleton.GetBlockHash(index); - if (hash == null) return null; - return persistence.GetHeader(hash); - } - - public static Header GetHeader(this IPersistence persistence, UInt256 hash) - { - return persistence.Blocks.TryGet(hash)?.Header; - } - - public static UInt256 GetNextBlockHash(this IPersistence persistence, UInt256 hash) - { - TrimmedBlock state = persistence.Blocks.TryGet(hash); - if (state == null) return null; - return Blockchain.Singleton.GetBlockHash(state.Index + 1); - } - - public static Transaction GetTransaction(this IPersistence persistence, UInt256 hash) - { - return persistence.Transactions.TryGet(hash)?.Transaction; - } - } -} diff --git a/src/neo/Persistence/IPersistence.cs b/src/neo/Persistence/IPersistence.cs deleted file mode 100644 index 0632b5d0fa..0000000000 --- a/src/neo/Persistence/IPersistence.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Neo.IO.Caching; -using Neo.IO.Wrappers; -using Neo.Ledger; - -namespace Neo.Persistence -{ - public interface IPersistence - { - DataCache Blocks { get; } - DataCache Transactions { get; } - DataCache Contracts { get; } - DataCache Storages { get; } - DataCache HeaderHashList { get; } - MetaDataCache BlockHashIndex { get; } - MetaDataCache HeaderHashIndex { get; } - } -} diff --git a/src/neo/Persistence/IReadOnlyStore.cs b/src/neo/Persistence/IReadOnlyStore.cs new file mode 100644 index 0000000000..7a23bd4c80 --- /dev/null +++ b/src/neo/Persistence/IReadOnlyStore.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Neo.Persistence +{ + /// + /// This interface provides methods to read from the database. + /// + public interface IReadOnlyStore + { + IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix); + byte[] TryGet(byte table, byte[] key); + } +} diff --git a/src/neo/Persistence/ISnapshot.cs b/src/neo/Persistence/ISnapshot.cs new file mode 100644 index 0000000000..335089d4bc --- /dev/null +++ b/src/neo/Persistence/ISnapshot.cs @@ -0,0 +1,14 @@ +using System; + +namespace Neo.Persistence +{ + /// + /// This interface provides methods for reading, writing, and committing from/to snapshot. + /// + public interface ISnapshot : IDisposable, IReadOnlyStore + { + void Commit(); + void Delete(byte table, byte[] key); + void Put(byte table, byte[] key, byte[] value); + } +} diff --git a/src/neo/Persistence/IStore.cs b/src/neo/Persistence/IStore.cs new file mode 100644 index 0000000000..e91e0b9386 --- /dev/null +++ b/src/neo/Persistence/IStore.cs @@ -0,0 +1,15 @@ +using System; + +namespace Neo.Persistence +{ + /// + /// This interface provides methods for reading, writing from/to database. Developers should implement this interface to provide new storage engines for NEO. + /// + public interface IStore : IDisposable, IReadOnlyStore + { + void Delete(byte table, byte[] key); + ISnapshot GetSnapshot(); + void Put(byte table, byte[] key, byte[] value); + void PutSync(byte table, byte[] key, byte[] value); + } +} diff --git a/src/neo/Persistence/LevelDB/DbCache.cs b/src/neo/Persistence/LevelDB/DbCache.cs deleted file mode 100644 index ae55b31326..0000000000 --- a/src/neo/Persistence/LevelDB/DbCache.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Neo.IO; -using Neo.IO.Caching; -using Neo.IO.Data.LevelDB; -using System; -using System.Collections.Generic; - -namespace Neo.Persistence.LevelDB -{ - public class DbCache : DataCache - where TKey : IEquatable, ISerializable, new() - where TValue : class, ICloneable, ISerializable, new() - { - private readonly DB db; - private readonly ReadOptions options; - private readonly WriteBatch batch; - private readonly byte prefix; - - public DbCache(DB db, ReadOptions options, WriteBatch batch, byte prefix) - { - this.db = db; - this.options = options ?? ReadOptions.Default; - this.batch = batch; - this.prefix = prefix; - } - - protected override void AddInternal(TKey key, TValue value) - { - batch?.Put(prefix, key, value); - } - - public override void DeleteInternal(TKey key) - { - batch?.Delete(prefix, key); - } - - protected override IEnumerable> FindInternal(byte[] key_prefix) - { - return db.Find(options, SliceBuilder.Begin(prefix).Add(key_prefix), (k, v) => new KeyValuePair(k.ToArray().AsSerializable(1), v.ToArray().AsSerializable())); - } - - protected override TValue GetInternal(TKey key) - { - return db.Get(options, prefix, key); - } - - protected override TValue TryGetInternal(TKey key) - { - return db.TryGet(options, prefix, key); - } - - protected override void UpdateInternal(TKey key, TValue value) - { - batch?.Put(prefix, key, value); - } - } -} diff --git a/src/neo/Persistence/LevelDB/DbMetaDataCache.cs b/src/neo/Persistence/LevelDB/DbMetaDataCache.cs deleted file mode 100644 index 0163d84e39..0000000000 --- a/src/neo/Persistence/LevelDB/DbMetaDataCache.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Neo.IO; -using Neo.IO.Caching; -using Neo.IO.Data.LevelDB; -using System; - -namespace Neo.Persistence.LevelDB -{ - internal class DbMetaDataCache : MetaDataCache - where T : class, ICloneable, ISerializable, new() - { - private readonly DB db; - private readonly ReadOptions options; - private readonly WriteBatch batch; - private readonly byte prefix; - - public DbMetaDataCache(DB db, ReadOptions options, WriteBatch batch, byte prefix, Func factory = null) - : base(factory) - { - this.db = db; - this.options = options ?? ReadOptions.Default; - this.batch = batch; - this.prefix = prefix; - } - - protected override void AddInternal(T item) - { - batch?.Put(prefix, item.ToArray()); - } - - protected override T TryGetInternal() - { - if (!db.TryGet(options, prefix, out Slice slice)) - return null; - return slice.ToArray().AsSerializable(); - } - - protected override void UpdateInternal(T item) - { - batch?.Put(prefix, item.ToArray()); - } - } -} diff --git a/src/neo/Persistence/LevelDB/DbSnapshot.cs b/src/neo/Persistence/LevelDB/DbSnapshot.cs deleted file mode 100644 index 365584fa7c..0000000000 --- a/src/neo/Persistence/LevelDB/DbSnapshot.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Neo.IO.Caching; -using Neo.IO.Data.LevelDB; -using Neo.IO.Wrappers; -using Neo.Ledger; -using LSnapshot = Neo.IO.Data.LevelDB.Snapshot; - -namespace Neo.Persistence.LevelDB -{ - internal class DbSnapshot : Snapshot - { - private readonly DB db; - private readonly LSnapshot snapshot; - private readonly WriteBatch batch; - - public override DataCache Blocks { get; } - public override DataCache Transactions { get; } - public override DataCache Contracts { get; } - public override DataCache Storages { get; } - public override DataCache HeaderHashList { get; } - public override MetaDataCache BlockHashIndex { get; } - public override MetaDataCache HeaderHashIndex { get; } - - public DbSnapshot(DB db) - { - this.db = db; - this.snapshot = db.GetSnapshot(); - this.batch = new WriteBatch(); - ReadOptions options = new ReadOptions { FillCache = false, Snapshot = snapshot }; - Blocks = new DbCache(db, options, batch, Prefixes.DATA_Block); - Transactions = new DbCache(db, options, batch, Prefixes.DATA_Transaction); - Contracts = new DbCache(db, options, batch, Prefixes.ST_Contract); - Storages = new DbCache(db, options, batch, Prefixes.ST_Storage); - HeaderHashList = new DbCache(db, options, batch, Prefixes.IX_HeaderHashList); - BlockHashIndex = new DbMetaDataCache(db, options, batch, Prefixes.IX_CurrentBlock); - HeaderHashIndex = new DbMetaDataCache(db, options, batch, Prefixes.IX_CurrentHeader); - } - - public override void Commit() - { - base.Commit(); - db.Write(WriteOptions.Default, batch); - } - - public override void Dispose() - { - snapshot.Dispose(); - } - } -} diff --git a/src/neo/Persistence/LevelDB/LevelDBStore.cs b/src/neo/Persistence/LevelDB/LevelDBStore.cs deleted file mode 100644 index 805c1fe915..0000000000 --- a/src/neo/Persistence/LevelDB/LevelDBStore.cs +++ /dev/null @@ -1,94 +0,0 @@ -using Neo.IO.Caching; -using Neo.IO.Data.LevelDB; -using Neo.IO.Wrappers; -using Neo.Ledger; -using System; -using System.Reflection; - -namespace Neo.Persistence.LevelDB -{ - public class LevelDBStore : Store, IDisposable - { - private readonly DB db; - - public LevelDBStore(string path) - { - this.db = DB.Open(path, new Options { CreateIfMissing = true }); - if (db.TryGet(ReadOptions.Default, SliceBuilder.Begin(Prefixes.SYS_Version), out Slice value) && Version.TryParse(value.ToString(), out Version version) && version >= Version.Parse("2.9.1")) - return; - WriteBatch batch = new WriteBatch(); - ReadOptions options = new ReadOptions { FillCache = false }; - using (Iterator it = db.NewIterator(options)) - { - for (it.SeekToFirst(); it.Valid(); it.Next()) - { - batch.Delete(it.Key()); - } - } - db.Put(WriteOptions.Default, SliceBuilder.Begin(Prefixes.SYS_Version), Assembly.GetExecutingAssembly().GetName().Version.ToString()); - db.Write(WriteOptions.Default, batch); - } - - public void Dispose() - { - db.Dispose(); - } - - public override byte[] Get(byte[] key) - { - if (!db.TryGet(ReadOptions.Default, key, out Slice slice)) - return null; - return slice.ToArray(); - } - - public override DataCache GetBlocks() - { - return new DbCache(db, null, null, Prefixes.DATA_Block); - } - - public override DataCache GetContracts() - { - return new DbCache(db, null, null, Prefixes.ST_Contract); - } - - public override Snapshot GetSnapshot() - { - return new DbSnapshot(db); - } - - public override DataCache GetStorages() - { - return new DbCache(db, null, null, Prefixes.ST_Storage); - } - - public override DataCache GetTransactions() - { - return new DbCache(db, null, null, Prefixes.DATA_Transaction); - } - - public override DataCache GetHeaderHashList() - { - return new DbCache(db, null, null, Prefixes.IX_HeaderHashList); - } - - public override MetaDataCache GetBlockHashIndex() - { - return new DbMetaDataCache(db, null, null, Prefixes.IX_CurrentBlock); - } - - public override MetaDataCache GetHeaderHashIndex() - { - return new DbMetaDataCache(db, null, null, Prefixes.IX_CurrentHeader); - } - - public override void Put(byte[] key, byte[] value) - { - db.Put(WriteOptions.Default, key, value); - } - - public override void PutSync(byte[] key, byte[] value) - { - db.Put(new WriteOptions { Sync = true }, key, value); - } - } -} diff --git a/src/neo/Persistence/LevelDB/Snapshot.cs b/src/neo/Persistence/LevelDB/Snapshot.cs new file mode 100644 index 0000000000..dbf5cbe278 --- /dev/null +++ b/src/neo/Persistence/LevelDB/Snapshot.cs @@ -0,0 +1,55 @@ +using Neo.IO.Data.LevelDB; +using System.Collections.Generic; +using System.Linq; +using LSnapshot = Neo.IO.Data.LevelDB.Snapshot; + +namespace Neo.Persistence.LevelDB +{ + internal class Snapshot : ISnapshot + { + private readonly DB db; + private readonly LSnapshot snapshot; + private readonly ReadOptions options; + private readonly WriteBatch batch; + + public Snapshot(DB db) + { + this.db = db; + this.snapshot = db.GetSnapshot(); + this.options = new ReadOptions { FillCache = false, Snapshot = snapshot }; + this.batch = new WriteBatch(); + } + + public void Commit() + { + db.Write(WriteOptions.Default, batch); + } + + public void Delete(byte table, byte[] key) + { + batch.Delete(SliceBuilder.Begin(table).Add(key)); + } + + public void Dispose() + { + snapshot.Dispose(); + } + + public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix) + { + return db.Find(options, SliceBuilder.Begin(table).Add(prefix), (k, v) => (k.ToArray().Skip(1).ToArray(), v.ToArray())); + } + + public void Put(byte table, byte[] key, byte[] value) + { + batch.Put(SliceBuilder.Begin(table).Add(key), value); + } + + public byte[] TryGet(byte table, byte[] key) + { + if (!db.TryGet(options, SliceBuilder.Begin(table).Add(key), out Slice slice)) + return null; + return slice.ToArray(); + } + } +} diff --git a/src/neo/Persistence/LevelDB/Store.cs b/src/neo/Persistence/LevelDB/Store.cs new file mode 100644 index 0000000000..fbded76391 --- /dev/null +++ b/src/neo/Persistence/LevelDB/Store.cs @@ -0,0 +1,69 @@ +using Neo.IO.Data.LevelDB; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Neo.Persistence.LevelDB +{ + public class Store : IStore + { + private const byte SYS_Version = 0xf0; + private readonly DB db; + + public Store(string path) + { + this.db = DB.Open(path, new Options { CreateIfMissing = true }); + if (db.TryGet(ReadOptions.Default, SliceBuilder.Begin(SYS_Version), out Slice value) && Version.TryParse(value.ToString(), out Version version) && version >= Version.Parse("2.9.1")) + return; + WriteBatch batch = new WriteBatch(); + ReadOptions options = new ReadOptions { FillCache = false }; + using (Iterator it = db.NewIterator(options)) + { + for (it.SeekToFirst(); it.Valid(); it.Next()) + { + batch.Delete(it.Key()); + } + } + db.Put(WriteOptions.Default, SliceBuilder.Begin(SYS_Version), Assembly.GetExecutingAssembly().GetName().Version.ToString()); + db.Write(WriteOptions.Default, batch); + } + + public void Delete(byte table, byte[] key) + { + db.Delete(WriteOptions.Default, SliceBuilder.Begin(table).Add(key)); + } + + public void Dispose() + { + db.Dispose(); + } + + public IEnumerable<(byte[], byte[])> Find(byte table, byte[] prefix) + { + return db.Find(ReadOptions.Default, SliceBuilder.Begin(table).Add(prefix), (k, v) => (k.ToArray().Skip(1).ToArray(), v.ToArray())); + } + + public ISnapshot GetSnapshot() + { + return new Snapshot(db); + } + + public void Put(byte table, byte[] key, byte[] value) + { + db.Put(WriteOptions.Default, SliceBuilder.Begin(table).Add(key), value); + } + + public void PutSync(byte table, byte[] key, byte[] value) + { + db.Put(new WriteOptions { Sync = true }, SliceBuilder.Begin(table).Add(key), value); + } + + public byte[] TryGet(byte table, byte[] key) + { + if (!db.TryGet(ReadOptions.Default, SliceBuilder.Begin(table).Add(key), out Slice slice)) + return null; + return slice.ToArray(); + } + } +} diff --git a/src/neo/Persistence/Memory/ByteArrayEqualityComparer.cs b/src/neo/Persistence/Memory/ByteArrayEqualityComparer.cs new file mode 100644 index 0000000000..97096498aa --- /dev/null +++ b/src/neo/Persistence/Memory/ByteArrayEqualityComparer.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; + +namespace Neo.Persistence.Memory +{ + internal class ByteArrayEqualityComparer : IEqualityComparer + { + public static readonly ByteArrayEqualityComparer Default = new ByteArrayEqualityComparer(); + + public unsafe bool Equals(byte[] x, byte[] y) + { + if (ReferenceEquals(x, y)) return true; + if (x is null || y is null) return false; + int len = x.Length; + if (len != y.Length) return false; + if (len == 0) return true; + fixed (byte* xp = x, yp = y) + { + long* xlp = (long*)xp, ylp = (long*)yp; + for (; len >= 8; len -= 8) + { + if (*xlp != *ylp) return false; + xlp++; + ylp++; + } + byte* xbp = (byte*)xlp, ybp = (byte*)ylp; + for (; len > 0; len--) + { + if (*xbp != *ybp) return false; + xbp++; + ybp++; + } + } + return true; + } + + public int GetHashCode(byte[] obj) + { + unchecked + { + int hash = 17; + foreach (byte element in obj) + hash = hash * 31 + element; + return hash; + } + } + } +} diff --git a/src/neo/Persistence/Memory/Helper.cs b/src/neo/Persistence/Memory/Helper.cs new file mode 100644 index 0000000000..c3535d897d --- /dev/null +++ b/src/neo/Persistence/Memory/Helper.cs @@ -0,0 +1,12 @@ +namespace Neo.Persistence.Memory +{ + internal static class Helper + { + private static readonly byte[] EmptyBytes = new byte[0]; + + public static byte[] EnsureNotNull(this byte[] source) + { + return source ?? EmptyBytes; + } + } +} diff --git a/src/neo/Persistence/Memory/Snapshot.cs b/src/neo/Persistence/Memory/Snapshot.cs new file mode 100644 index 0000000000..82455ddea8 --- /dev/null +++ b/src/neo/Persistence/Memory/Snapshot.cs @@ -0,0 +1,63 @@ +using Neo.IO; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.Persistence.Memory +{ + internal class Snapshot : ISnapshot + { + private readonly ConcurrentDictionary[] innerData; + private readonly ImmutableDictionary[] immutableData; + private readonly ConcurrentDictionary[] writeBatch; + + public Snapshot(ConcurrentDictionary[] innerData) + { + this.innerData = innerData; + this.immutableData = innerData.Select(p => p.ToImmutableDictionary(ByteArrayEqualityComparer.Default)).ToArray(); + this.writeBatch = new ConcurrentDictionary[innerData.Length]; + for (int i = 0; i < writeBatch.Length; i++) + writeBatch[i] = new ConcurrentDictionary(ByteArrayEqualityComparer.Default); + } + + public void Commit() + { + for (int i = 0; i < writeBatch.Length; i++) + foreach (var pair in writeBatch[i]) + if (pair.Value is null) + innerData[i].TryRemove(pair.Key, out _); + else + innerData[i][pair.Key] = pair.Value; + } + + public void Delete(byte table, byte[] key) + { + writeBatch[table][key.EnsureNotNull()] = null; + } + + public void Dispose() + { + } + + public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix) + { + IEnumerable> records = immutableData[table]; + if (prefix?.Length > 0) + records = records.Where(p => p.Key.Length >= prefix.Length && p.Key.Take(prefix.Length).SequenceEqual(prefix)); + records = records.OrderBy(p => p.Key, ByteArrayComparer.Default); + return records.Select(p => (p.Key, p.Value)); + } + + public void Put(byte table, byte[] key, byte[] value) + { + writeBatch[table][key.EnsureNotNull()] = value; + } + + public byte[] TryGet(byte table, byte[] key) + { + immutableData[table].TryGetValue(key.EnsureNotNull(), out byte[] value); + return value; + } + } +} diff --git a/src/neo/Persistence/Memory/Store.cs b/src/neo/Persistence/Memory/Store.cs new file mode 100644 index 0000000000..5e2d11eeb9 --- /dev/null +++ b/src/neo/Persistence/Memory/Store.cs @@ -0,0 +1,60 @@ +using Neo.IO; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Persistence.Memory +{ + public class Store : IStore + { + private readonly ConcurrentDictionary[] innerData; + + public Store() + { + innerData = new ConcurrentDictionary[256]; + for (int i = 0; i < innerData.Length; i++) + innerData[i] = new ConcurrentDictionary(ByteArrayEqualityComparer.Default); + } + + public void Delete(byte table, byte[] key) + { + innerData[table].TryRemove(key.EnsureNotNull(), out _); + } + + public void Dispose() + { + } + + public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix) + { + IEnumerable> records = innerData[table]; + if (prefix?.Length > 0) + records = records.Where(p => p.Key.Length >= prefix.Length && p.Key.Take(prefix.Length).SequenceEqual(prefix)); + records = records.OrderBy(p => p.Key, ByteArrayComparer.Default); + foreach (var pair in records) + yield return (pair.Key, pair.Value); + } + + public ISnapshot GetSnapshot() + { + return new Snapshot(innerData); + } + + public void Put(byte table, byte[] key, byte[] value) + { + PutSync(table, key, value); + } + + public void PutSync(byte table, byte[] key, byte[] value) + { + innerData[table][key.EnsureNotNull()] = value; + } + + public byte[] TryGet(byte table, byte[] key) + { + innerData[table].TryGetValue(key.EnsureNotNull(), out byte[] value); + return value; + } + } +} diff --git a/src/neo/Persistence/LevelDB/Prefixes.cs b/src/neo/Persistence/Prefixes.cs similarity index 76% rename from src/neo/Persistence/LevelDB/Prefixes.cs rename to src/neo/Persistence/Prefixes.cs index f40359a55a..dad8540787 100644 --- a/src/neo/Persistence/LevelDB/Prefixes.cs +++ b/src/neo/Persistence/Prefixes.cs @@ -1,4 +1,4 @@ -namespace Neo.Persistence.LevelDB +namespace Neo.Persistence { internal static class Prefixes { @@ -12,9 +12,7 @@ internal static class Prefixes public const byte IX_CurrentBlock = 0xc0; public const byte IX_CurrentHeader = 0xc1; - public const byte SYS_Version = 0xf0; - - /* Prefixes 0xf1 to 0xff are reserved for external use. + /* Prefixes 0xf0 to 0xff are reserved for external use. * * Note: The saved consensus state uses the Prefix 0xf4 */ diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs new file mode 100644 index 0000000000..f138b616c1 --- /dev/null +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -0,0 +1,33 @@ +using Neo.IO.Caching; +using Neo.IO.Wrappers; +using Neo.Ledger; +using System; + +namespace Neo.Persistence +{ + /// + /// Provide a read-only for accessing directly from database instead of from snapshot. + /// + public class ReadOnlyView : StoreView + { + private readonly IReadOnlyStore store; + + public override DataCache Blocks => new StoreDataCache(store, Prefixes.DATA_Block); + public override DataCache Transactions => new StoreDataCache(store, Prefixes.DATA_Transaction); + public override DataCache Contracts => new StoreDataCache(store, Prefixes.ST_Contract); + public override DataCache Storages => new StoreDataCache(store, Prefixes.ST_Storage); + public override DataCache HeaderHashList => new StoreDataCache(store, Prefixes.IX_HeaderHashList); + public override MetaDataCache BlockHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentBlock); + public override MetaDataCache HeaderHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentHeader); + + public ReadOnlyView(IReadOnlyStore store) + { + this.store = store; + } + + public override void Commit() + { + throw new NotSupportedException(); + } + } +} diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs new file mode 100644 index 0000000000..5eb9071fe3 --- /dev/null +++ b/src/neo/Persistence/SnapshotView.cs @@ -0,0 +1,46 @@ +using Neo.IO.Caching; +using Neo.IO.Wrappers; +using Neo.Ledger; +using System; + +namespace Neo.Persistence +{ + /// + /// Provide a for accessing snapshots. + /// + public class SnapshotView : StoreView, IDisposable + { + private readonly ISnapshot snapshot; + + public override DataCache Blocks { get; } + public override DataCache Transactions { get; } + public override DataCache Contracts { get; } + public override DataCache Storages { get; } + public override DataCache HeaderHashList { get; } + public override MetaDataCache BlockHashIndex { get; } + public override MetaDataCache HeaderHashIndex { get; } + + public SnapshotView(IStore store) + { + this.snapshot = store.GetSnapshot(); + Blocks = new StoreDataCache(snapshot, Prefixes.DATA_Block); + Transactions = new StoreDataCache(snapshot, Prefixes.DATA_Transaction); + Contracts = new StoreDataCache(snapshot, Prefixes.ST_Contract); + Storages = new StoreDataCache(snapshot, Prefixes.ST_Storage); + HeaderHashList = new StoreDataCache(snapshot, Prefixes.IX_HeaderHashList); + BlockHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentBlock); + HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); + } + + public override void Commit() + { + base.Commit(); + snapshot.Commit(); + } + + public void Dispose() + { + snapshot.Dispose(); + } + } +} diff --git a/src/neo/Persistence/Store.cs b/src/neo/Persistence/Store.cs deleted file mode 100644 index eab5c182b9..0000000000 --- a/src/neo/Persistence/Store.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Neo.IO.Caching; -using Neo.IO.Wrappers; -using Neo.Ledger; - -namespace Neo.Persistence -{ - public abstract class Store : IPersistence - { - DataCache IPersistence.Blocks => GetBlocks(); - DataCache IPersistence.Transactions => GetTransactions(); - DataCache IPersistence.Contracts => GetContracts(); - DataCache IPersistence.Storages => GetStorages(); - DataCache IPersistence.HeaderHashList => GetHeaderHashList(); - MetaDataCache IPersistence.BlockHashIndex => GetBlockHashIndex(); - MetaDataCache IPersistence.HeaderHashIndex => GetHeaderHashIndex(); - - public abstract byte[] Get(byte[] key); - public abstract DataCache GetBlocks(); - public abstract DataCache GetTransactions(); - public abstract DataCache GetContracts(); - public abstract DataCache GetStorages(); - public abstract DataCache GetHeaderHashList(); - public abstract MetaDataCache GetBlockHashIndex(); - public abstract MetaDataCache GetHeaderHashIndex(); - public abstract void Put(byte[] key, byte[] value); - public abstract void PutSync(byte[] key, byte[] value); - - public abstract Snapshot GetSnapshot(); - } -} diff --git a/src/neo/Persistence/StoreDataCache.cs b/src/neo/Persistence/StoreDataCache.cs new file mode 100644 index 0000000000..995a34290f --- /dev/null +++ b/src/neo/Persistence/StoreDataCache.cs @@ -0,0 +1,54 @@ +using Neo.IO; +using Neo.IO.Caching; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Persistence +{ + internal class StoreDataCache : DataCache + where TKey : IEquatable, ISerializable, new() + where TValue : class, ICloneable, ISerializable, new() + { + private readonly IReadOnlyStore store; + private readonly ISnapshot snapshot; + private readonly byte prefix; + + public StoreDataCache(IReadOnlyStore store, byte prefix) + { + this.store = store; + this.snapshot = store as ISnapshot; + this.prefix = prefix; + } + + protected override void AddInternal(TKey key, TValue value) + { + snapshot?.Put(prefix, key.ToArray(), value.ToArray()); + } + + protected override void DeleteInternal(TKey key) + { + snapshot?.Delete(prefix, key.ToArray()); + } + + protected override IEnumerable<(TKey, TValue)> FindInternal(byte[] key_prefix) + { + return store.Find(prefix, key_prefix).Select(p => (p.Key.AsSerializable(), p.Value.AsSerializable())); + } + + protected override TValue GetInternal(TKey key) + { + return store.TryGet(prefix, key.ToArray()).AsSerializable(); + } + + protected override TValue TryGetInternal(TKey key) + { + return store.TryGet(prefix, key.ToArray())?.AsSerializable(); + } + + protected override void UpdateInternal(TKey key, TValue value) + { + snapshot?.Put(prefix, key.ToArray(), value.ToArray()); + } + } +} diff --git a/src/neo/Persistence/StoreMetaDataCache.cs b/src/neo/Persistence/StoreMetaDataCache.cs new file mode 100644 index 0000000000..152a315e03 --- /dev/null +++ b/src/neo/Persistence/StoreMetaDataCache.cs @@ -0,0 +1,37 @@ +using Neo.IO; +using Neo.IO.Caching; +using System; + +namespace Neo.Persistence +{ + internal class StoreMetaDataCache : MetaDataCache + where T : class, ICloneable, ISerializable, new() + { + private readonly IReadOnlyStore store; + private readonly ISnapshot snapshot; + private readonly byte prefix; + + public StoreMetaDataCache(IReadOnlyStore store, byte prefix, Func factory = null) + : base(factory) + { + this.store = store; + this.snapshot = store as ISnapshot; + this.prefix = prefix; + } + + protected override void AddInternal(T item) + { + snapshot?.Put(prefix, null, item.ToArray()); + } + + protected override T TryGetInternal() + { + return store.TryGet(prefix, null)?.AsSerializable(); + } + + protected override void UpdateInternal(T item) + { + snapshot?.Put(prefix, null, item.ToArray()); + } + } +} diff --git a/src/neo/Persistence/Snapshot.cs b/src/neo/Persistence/StoreView.cs similarity index 53% rename from src/neo/Persistence/Snapshot.cs rename to src/neo/Persistence/StoreView.cs index 1e900800b0..c23e000ff2 100644 --- a/src/neo/Persistence/Snapshot.cs +++ b/src/neo/Persistence/StoreView.cs @@ -2,11 +2,13 @@ using Neo.IO.Wrappers; using Neo.Ledger; using Neo.Network.P2P.Payloads; -using System; namespace Neo.Persistence { - public abstract class Snapshot : IDisposable, IPersistence + /// + /// It provides a set of properties and methods for reading formatted data from the underlying storage. Such as and . + /// + public abstract class StoreView { public Block PersistingBlock { get; internal set; } public abstract DataCache Blocks { get; } @@ -22,9 +24,9 @@ public abstract class Snapshot : IDisposable, IPersistence public UInt256 CurrentBlockHash => BlockHashIndex.Get().Hash; public UInt256 CurrentHeaderHash => HeaderHashIndex.Get().Hash; - public Snapshot Clone() + public StoreView Clone() { - return new CloneSnapshot(this); + return new ClonedView(this); } public virtual void Commit() @@ -38,8 +40,35 @@ public virtual void Commit() HeaderHashIndex.Commit(); } - public virtual void Dispose() + public bool ContainsBlock(UInt256 hash) { + TrimmedBlock state = Blocks.TryGet(hash); + if (state == null) return false; + return state.IsBlock; + } + + public bool ContainsTransaction(UInt256 hash) + { + TransactionState state = Transactions.TryGet(hash); + return state != null; + } + + public Block GetBlock(UInt256 hash) + { + TrimmedBlock state = Blocks.TryGet(hash); + if (state == null) return null; + if (!state.IsBlock) return null; + return state.GetBlock(Transactions); + } + + public Header GetHeader(UInt256 hash) + { + return Blocks.TryGet(hash)?.Header; + } + + public Transaction GetTransaction(UInt256 hash) + { + return Transactions.TryGet(hash)?.Transaction; } } } diff --git a/src/neo/Plugins/IPersistencePlugin.cs b/src/neo/Plugins/IPersistencePlugin.cs index 0f06ae51eb..14a3316115 100644 --- a/src/neo/Plugins/IPersistencePlugin.cs +++ b/src/neo/Plugins/IPersistencePlugin.cs @@ -7,8 +7,8 @@ namespace Neo.Plugins { public interface IPersistencePlugin { - void OnPersist(Snapshot snapshot, IReadOnlyList applicationExecutedList); - void OnCommit(Snapshot snapshot); + void OnPersist(StoreView snapshot, IReadOnlyList applicationExecutedList); + void OnCommit(StoreView snapshot); bool ShouldThrowExceptionFromCommit(Exception ex); } } diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index 41c17aebeb..eb4eb5e7c2 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -21,7 +21,7 @@ public partial class ApplicationEngine : ExecutionEngine public TriggerType Trigger { get; } public IVerifiable ScriptContainer { get; } - public Snapshot Snapshot { get; } + public StoreView Snapshot { get; } public long GasConsumed { get; private set; } = 0; public UInt160 CurrentScriptHash => CurrentContext?.GetState().ScriptHash; public UInt160 CallingScriptHash => InvocationStack.Count > 1 ? InvocationStack.Peek(1).GetState().ScriptHash : null; @@ -29,7 +29,7 @@ public partial class ApplicationEngine : ExecutionEngine public IReadOnlyList Notifications => notifications; internal Dictionary InvocationCounter { get; } = new Dictionary(); - public ApplicationEngine(TriggerType trigger, IVerifiable container, Snapshot snapshot, long gas, bool testMode = false) + public ApplicationEngine(TriggerType trigger, IVerifiable container, StoreView snapshot, long gas, bool testMode = false) { this.gas_amount = GasFree + gas; this.testMode = testMode; @@ -84,7 +84,7 @@ protected override bool PreExecuteInstruction() return AddGas(OpCodePrices[CurrentContext.CurrentInstruction.OpCode]); } - private static Block CreateDummyBlock(Snapshot snapshot) + private static Block CreateDummyBlock(StoreView snapshot) { var currentBlock = snapshot.Blocks[snapshot.CurrentBlockHash]; return new Block @@ -105,7 +105,7 @@ private static Block CreateDummyBlock(Snapshot snapshot) }; } - public static ApplicationEngine Run(byte[] script, Snapshot snapshot, + public static ApplicationEngine Run(byte[] script, StoreView snapshot, IVerifiable container = null, Block persistingBlock = null, bool testMode = false, long extraGAS = default) { snapshot.PersistingBlock = persistingBlock ?? snapshot.PersistingBlock ?? CreateDummyBlock(snapshot); @@ -117,7 +117,7 @@ private static Block CreateDummyBlock(Snapshot snapshot) public static ApplicationEngine Run(byte[] script, IVerifiable container = null, Block persistingBlock = null, bool testMode = false, long extraGAS = default) { - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { return Run(script, snapshot, container, persistingBlock, testMode, extraGAS); } diff --git a/src/neo/SmartContract/ContractParametersContext.cs b/src/neo/SmartContract/ContractParametersContext.cs index 327c8b1ef8..4465e7831e 100644 --- a/src/neo/SmartContract/ContractParametersContext.cs +++ b/src/neo/SmartContract/ContractParametersContext.cs @@ -94,7 +94,7 @@ public IReadOnlyList ScriptHashes return _ScriptHashes; } - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { _ScriptHashes = Verifiable.GetScriptHashesForVerifying(snapshot); } diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 03e543a5b4..4ddaf5fca5 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -254,7 +254,7 @@ public static UInt160 ToScriptHash(this byte[] script) return new UInt160(Crypto.Default.Hash160(script)); } - internal static bool VerifyWitnesses(this IVerifiable verifiable, Snapshot snapshot, long gas) + internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snapshot, long gas) { if (gas < 0) return false; diff --git a/src/neo/SmartContract/Iterators/StorageIterator.cs b/src/neo/SmartContract/Iterators/StorageIterator.cs index f35d70d890..a42875e1aa 100644 --- a/src/neo/SmartContract/Iterators/StorageIterator.cs +++ b/src/neo/SmartContract/Iterators/StorageIterator.cs @@ -6,9 +6,9 @@ namespace Neo.SmartContract.Iterators { internal class StorageIterator : IIterator { - private readonly IEnumerator> enumerator; + private readonly IEnumerator<(StorageKey Key, StorageItem Value)> enumerator; - public StorageIterator(IEnumerator> enumerator) + public StorageIterator(IEnumerator<(StorageKey, StorageItem)> enumerator) { this.enumerator = enumerator; } diff --git a/src/neo/SmartContract/Native/PolicyContract.cs b/src/neo/SmartContract/Native/PolicyContract.cs index 797104924e..3726cf49fb 100644 --- a/src/neo/SmartContract/Native/PolicyContract.cs +++ b/src/neo/SmartContract/Native/PolicyContract.cs @@ -29,7 +29,7 @@ public PolicyContract() Manifest.Features = ContractFeatures.HasStorage; } - internal bool CheckPolicy(Transaction tx, Snapshot snapshot) + internal bool CheckPolicy(Transaction tx, StoreView snapshot) { UInt160[] blockedAccounts = GetBlockedAccounts(snapshot); if (blockedAccounts.Intersect(tx.GetScriptHashesForVerifying(snapshot)).Any()) @@ -72,7 +72,7 @@ private StackItem GetMaxTransactionsPerBlock(ApplicationEngine engine, VMArray a return GetMaxTransactionsPerBlock(engine.Snapshot); } - public uint GetMaxTransactionsPerBlock(Snapshot snapshot) + public uint GetMaxTransactionsPerBlock(StoreView snapshot) { return BitConverter.ToUInt32(snapshot.Storages[CreateStorageKey(Prefix_MaxTransactionsPerBlock)].Value, 0); } @@ -83,7 +83,7 @@ private StackItem GetMaxBlockSize(ApplicationEngine engine, VMArray args) return GetMaxBlockSize(engine.Snapshot); } - public uint GetMaxBlockSize(Snapshot snapshot) + public uint GetMaxBlockSize(StoreView snapshot) { return BitConverter.ToUInt32(snapshot.Storages[CreateStorageKey(Prefix_MaxBlockSize)].Value, 0); } @@ -94,7 +94,7 @@ private StackItem GetFeePerByte(ApplicationEngine engine, VMArray args) return GetFeePerByte(engine.Snapshot); } - public long GetFeePerByte(Snapshot snapshot) + public long GetFeePerByte(StoreView snapshot) { return BitConverter.ToInt64(snapshot.Storages[CreateStorageKey(Prefix_FeePerByte)].Value, 0); } @@ -105,7 +105,7 @@ private StackItem GetBlockedAccounts(ApplicationEngine engine, VMArray args) return GetBlockedAccounts(engine.Snapshot).Select(p => (StackItem)p.ToArray()).ToList(); } - public UInt160[] GetBlockedAccounts(Snapshot snapshot) + public UInt160[] GetBlockedAccounts(StoreView snapshot) { return snapshot.Storages[CreateStorageKey(Prefix_BlockedAccounts)].Value.AsSerializableArray(); } diff --git a/src/neo/SmartContract/Native/Tokens/GasToken.cs b/src/neo/SmartContract/Native/Tokens/GasToken.cs index 4266494a4f..be46335940 100644 --- a/src/neo/SmartContract/Native/Tokens/GasToken.cs +++ b/src/neo/SmartContract/Native/Tokens/GasToken.cs @@ -60,7 +60,7 @@ private StackItem GetSysFeeAmount(ApplicationEngine engine, VMArray args) return GetSysFeeAmount(engine.Snapshot, index); } - public BigInteger GetSysFeeAmount(Snapshot snapshot, uint index) + public BigInteger GetSysFeeAmount(StoreView snapshot, uint index) { if (index == 0) return Blockchain.GenesisBlock.Transactions.Sum(p => p.SystemFee); StorageKey key = CreateStorageKey(Prefix_SystemFeeAmount, BitConverter.GetBytes(index)); diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index ba059aff4d..e0023b3841 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -33,7 +33,7 @@ internal NeoToken() this.TotalAmount = 100000000 * Factor; } - public override BigInteger TotalSupply(Snapshot snapshot) + public override BigInteger TotalSupply(StoreView snapshot) { return TotalAmount; } @@ -64,7 +64,7 @@ private void DistributeGas(ApplicationEngine engine, UInt160 account, AccountSta engine.Snapshot.Storages.GetAndChange(CreateAccountKey(account)).Value = state.ToByteArray(); } - private BigInteger CalculateBonus(Snapshot snapshot, BigInteger value, uint start, uint end) + private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint start, uint end) { if (value.IsZero || start >= end) return BigInteger.Zero; if (value.Sign < 0) throw new ArgumentOutOfRangeException(nameof(value)); @@ -124,7 +124,7 @@ private StackItem UnclaimedGas(ApplicationEngine engine, VMArray args) return UnclaimedGas(engine.Snapshot, account, end); } - public BigInteger UnclaimedGas(Snapshot snapshot, UInt160 account, uint end) + public BigInteger UnclaimedGas(StoreView snapshot, UInt160 account, uint end) { StorageItem storage = snapshot.Storages.TryGet(CreateAccountKey(account)); if (storage is null) return BigInteger.Zero; @@ -139,7 +139,7 @@ private StackItem RegisterValidator(ApplicationEngine engine, VMArray args) return RegisterValidator(engine.Snapshot, pubkey); } - private bool RegisterValidator(Snapshot snapshot, ECPoint pubkey) + private bool RegisterValidator(StoreView snapshot, ECPoint pubkey) { StorageKey key = CreateStorageKey(Prefix_Validator, pubkey); if (snapshot.Storages.TryGet(key) != null) return false; @@ -199,7 +199,7 @@ private StackItem GetRegisteredValidators(ApplicationEngine engine, VMArray args return GetRegisteredValidators(engine.Snapshot).Select(p => new Struct(new StackItem[] { p.PublicKey.ToArray(), p.Votes })).ToArray(); } - public IEnumerable<(ECPoint PublicKey, BigInteger Votes)> GetRegisteredValidators(Snapshot snapshot) + public IEnumerable<(ECPoint PublicKey, BigInteger Votes)> GetRegisteredValidators(StoreView snapshot) { byte[] prefix_key = StorageKey.CreateSearchPrefix(Hash, new[] { Prefix_Validator }); return snapshot.Storages.Find(prefix_key).Select(p => @@ -215,7 +215,7 @@ private StackItem GetValidators(ApplicationEngine engine, VMArray args) return GetValidators(engine.Snapshot).Select(p => (StackItem)p.ToArray()).ToList(); } - public ECPoint[] GetValidators(Snapshot snapshot) + public ECPoint[] GetValidators(StoreView snapshot) { StorageItem storage_count = snapshot.Storages.TryGet(CreateStorageKey(Prefix_ValidatorsCount)); if (storage_count is null) return Blockchain.StandbyValidators; @@ -240,7 +240,7 @@ private StackItem GetNextBlockValidators(ApplicationEngine engine, VMArray args) return GetNextBlockValidators(engine.Snapshot).Select(p => (StackItem)p.ToArray()).ToList(); } - public ECPoint[] GetNextBlockValidators(Snapshot snapshot) + public ECPoint[] GetNextBlockValidators(StoreView snapshot) { StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_NextValidators)); if (storage is null) return Blockchain.StandbyValidators; diff --git a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs index 6d35d00410..5728c2d8be 100644 --- a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs +++ b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs @@ -138,7 +138,7 @@ protected StackItem TotalSupply(ApplicationEngine engine, VMArray args) return TotalSupply(engine.Snapshot); } - public virtual BigInteger TotalSupply(Snapshot snapshot) + public virtual BigInteger TotalSupply(StoreView snapshot) { StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_TotalSupply)); if (storage is null) return BigInteger.Zero; @@ -151,7 +151,7 @@ protected StackItem BalanceOf(ApplicationEngine engine, VMArray args) return BalanceOf(engine.Snapshot, new UInt160(args[0].GetSpan().ToArray())); } - public virtual BigInteger BalanceOf(Snapshot snapshot, UInt160 account) + public virtual BigInteger BalanceOf(StoreView snapshot, UInt160 account) { StorageItem storage = snapshot.Storages.TryGet(CreateAccountKey(account)); if (storage is null) return BigInteger.Zero; diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index bc52b9b368..f2cf92e7b2 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -221,7 +221,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null throw new ArgumentException($"The address {from.ToString()} was not found in the wallet"); accounts = new[] { from }; } - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { HashSet cosignerList = new HashSet(); byte[] script; @@ -290,14 +290,14 @@ public Transaction MakeTransaction(byte[] script, UInt160 sender = null, Transac throw new ArgumentException($"The address {sender.ToString()} was not found in the wallet"); accounts = new[] { sender }; } - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + using (SnapshotView 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, attributes ?? new TransactionAttribute[0], cosigners ?? new Cosigner[0], balances_gas); } } - private Transaction MakeTransaction(Snapshot snapshot, byte[] script, TransactionAttribute[] attributes, Cosigner[] cosigners, List<(UInt160 Account, BigInteger Value)> balances_gas) + private Transaction MakeTransaction(StoreView snapshot, byte[] script, TransactionAttribute[] attributes, Cosigner[] cosigners, List<(UInt160 Account, BigInteger Value)> balances_gas) { Random rand = new Random(); foreach (var (account, value) in balances_gas) diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index c10e6c94e3..bc4c2277a0 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -41,7 +41,7 @@ public void ConsensusService_Primary_Sends_PrepareRequest_After_OnStart() TestProbe subscriber = CreateTestProbe(); var mockWallet = new Mock(); mockWallet.Setup(p => p.GetAccount(It.IsAny())).Returns(p => new TestWalletAccount(p)); - ConsensusContext context = new ConsensusContext(mockWallet.Object, TestBlockchain.GetStore()); + ConsensusContext context = new ConsensusContext(mockWallet.Object, TestBlockchain.Store); int timeIndex = 0; var timeValues = new[] { diff --git a/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs b/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs index 821b6f8da5..ee5eb5f9d1 100644 --- a/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs +++ b/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs @@ -38,7 +38,7 @@ public void TestSetup() _validatorKeys[x] = new KeyPair(pk); } - _context = new ConsensusContext(mockWallet.Object, TestBlockchain.GetStore()) + _context = new ConsensusContext(mockWallet.Object, TestBlockchain.Store) { Validators = _validatorKeys.Select(u => u.PublicKey).ToArray() }; diff --git a/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs b/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs index 9847bddd48..cbf4a109d9 100644 --- a/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs +++ b/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs @@ -1,4 +1,5 @@ using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; @@ -9,12 +10,12 @@ namespace Neo.UnitTests.Extensions { public static class NativeContractExtensions { - public static StackItem Call(this NativeContract contract, Neo.Persistence.Snapshot snapshot, string method, params ContractParameter[] args) + public static StackItem Call(this NativeContract contract, StoreView snapshot, string method, params ContractParameter[] args) { return Call(contract, snapshot, null, method, args); } - public static StackItem Call(this NativeContract contract, Neo.Persistence.Snapshot snapshot, IVerifiable container, string method, params ContractParameter[] args) + public static StackItem Call(this NativeContract contract, StoreView snapshot, IVerifiable container, string method, params ContractParameter[] args) { var engine = new ApplicationEngine(TriggerType.Application, container, snapshot, 0, true); diff --git a/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs b/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs index f06a7eb201..4a04d97c84 100644 --- a/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs +++ b/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs @@ -1,5 +1,6 @@ using FluentAssertions; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; @@ -33,14 +34,14 @@ public ManualWitness(params UInt160[] hashForVerify) public void DeserializeUnsigned(BinaryReader reader) { } - public UInt160[] GetScriptHashesForVerifying(Persistence.Snapshot snapshot) => _hashForVerify; + public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) => _hashForVerify; public void Serialize(BinaryWriter writer) { } public void SerializeUnsigned(BinaryWriter writer) { } } - public static bool Transfer(this NativeContract contract, Persistence.Snapshot snapshot, byte[] from, byte[] to, BigInteger amount, bool signFrom) + public static bool Transfer(this NativeContract contract, StoreView snapshot, byte[] from, byte[] to, BigInteger amount, bool signFrom) { var engine = new ApplicationEngine(TriggerType.Application, new ManualWitness(signFrom ? new UInt160(from) : null), snapshot, 0, true); @@ -89,7 +90,7 @@ public static string[] SupportedStandards(this NativeContract contract) .ToArray(); } - public static BigInteger TotalSupply(this NativeContract contract, Persistence.Snapshot snapshot) + public static BigInteger TotalSupply(this NativeContract contract, StoreView snapshot) { var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); @@ -109,7 +110,7 @@ public static BigInteger TotalSupply(this NativeContract contract, Persistence.S return (result as VM.Types.Integer).GetBigInteger(); } - public static BigInteger BalanceOf(this NativeContract contract, Persistence.Snapshot snapshot, byte[] account) + public static BigInteger BalanceOf(this NativeContract contract, StoreView snapshot, byte[] account) { var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); diff --git a/tests/neo.UnitTests/IO/Caching/UT_DataCache.cs b/tests/neo.UnitTests/IO/Caching/UT_DataCache.cs index 437f2b92f1..cd9752c819 100644 --- a/tests/neo.UnitTests/IO/Caching/UT_DataCache.cs +++ b/tests/neo.UnitTests/IO/Caching/UT_DataCache.cs @@ -105,7 +105,7 @@ class MyDataCache : DataCache { public Dictionary InnerDict = new Dictionary(); - public override void DeleteInternal(TKey key) + protected override void DeleteInternal(TKey key) { InnerDict.Remove(key); } @@ -115,9 +115,9 @@ protected override void AddInternal(TKey key, TValue value) InnerDict.Add(key, value); } - protected override IEnumerable> FindInternal(byte[] key_prefix) + protected override IEnumerable<(TKey, TValue)> FindInternal(byte[] key_prefix) { - return InnerDict.Where(kvp => kvp.Key.ToArray().Take(key_prefix.Length).SequenceEqual(key_prefix)); + return InnerDict.Where(kvp => kvp.Key.ToArray().Take(key_prefix.Length).SequenceEqual(key_prefix)).Select(p => (p.Key, p.Value)); } protected override TValue GetInternal(TKey key) diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index af0ec69a79..27dd15b6aa 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -9,7 +9,7 @@ namespace Neo.UnitTests.Ledger { internal class TestBlock : Block { - public override bool Verify(Snapshot snapshot) + public override bool Verify(StoreView snapshot) { return true; } @@ -22,7 +22,7 @@ public static TestBlock Cast(Block input) internal class TestHeader : Header { - public override bool Verify(Snapshot snapshot) + public override bool Verify(StoreView snapshot) { return true; } @@ -37,14 +37,14 @@ public static TestHeader Cast(Header input) public class UT_Blockchain { private NeoSystem system; - private Store store; + private IStore store; Transaction txSample = Blockchain.GenesisBlock.Transactions[0]; [TestInitialize] public void Initialize() { - system = TestBlockchain.InitializeMockNeoSystem(); - store = TestBlockchain.GetStore(); + system = TestBlockchain.TheNeoSystem; + store = TestBlockchain.Store; Blockchain.Singleton.MemPool.TryAdd(txSample.Hash, txSample); } diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 631ae06dbc..c68504f4c6 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -3,7 +3,6 @@ using Moq; using Neo.Cryptography; using Neo.IO; -using Neo.IO.Caching; using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; @@ -40,11 +39,11 @@ public void TestSetup() // protect against external changes on TimeProvider TimeProvider.ResetToDefault(); - NeoSystem TheNeoSystem = TestBlockchain.InitializeMockNeoSystem(); + TestBlockchain.InitializeMockNeoSystem(); // Create a MemoryPool with capacity of 100 - _unit = new MemoryPool(TheNeoSystem, 100); - _unit.LoadPolicy(TestBlockchain.GetStore().GetSnapshot()); + _unit = new MemoryPool(TestBlockchain.TheNeoSystem, 100); + _unit.LoadPolicy(Blockchain.Singleton.GetSnapshot()); // Verify capacity equals the amount specified _unit.Capacity.Should().Be(100); @@ -52,7 +51,7 @@ public void TestSetup() _unit.VerifiedCount.Should().Be(0); _unit.UnVerifiedCount.Should().Be(0); _unit.Count.Should().Be(0); - _unit2 = new MemoryPool(TheNeoSystem, 0); + _unit2 = new MemoryPool(TestBlockchain.TheNeoSystem, 0); plugin = new TestIMemoryPoolTxObserverPlugin(); } @@ -75,8 +74,8 @@ private Transaction CreateTransactionWithFee(long fee) var randomBytes = new byte[16]; random.NextBytes(randomBytes); Mock mock = new Mock(); - mock.Setup(p => p.Reverify(It.IsAny(), It.IsAny())).Returns(true); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(true); + mock.Setup(p => p.Reverify(It.IsAny(), It.IsAny())).Returns(true); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(true); mock.Object.Script = randomBytes; mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = fee; @@ -100,8 +99,8 @@ private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee) random.NextBytes(randomBytes); Mock mock = new Mock(); UInt160 sender = UInt160.Zero; - mock.Setup(p => p.Reverify(It.IsAny(), It.IsAny())).Returns(((Snapshot snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee)); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(true); + mock.Setup(p => p.Reverify(It.IsAny(), It.IsAny())).Returns(((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee)); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(true); mock.Object.Script = randomBytes; mock.Object.Sender = sender; mock.Object.NetworkFee = fee; @@ -223,7 +222,7 @@ public void BlockPersistAndReverificationWillAbandonTxAsBalanceTransfered() // Simulate the transfer process in tx by burning the balance UInt160 sender = block.Transactions[0].Sender; - Snapshot snapshot = Blockchain.Singleton.GetSnapshot(); + SnapshotView snapshot = Blockchain.Singleton.GetSnapshot(); BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, sender); ApplicationEngine applicationEngine = new ApplicationEngine(TriggerType.All, block, snapshot, (long)balance); @@ -412,10 +411,8 @@ public void TestGetVerifiedTransactions() [TestMethod] public void TestReVerifyTopUnverifiedTransactionsIfNeeded() { - NeoSystem TheNeoSystem = TestBlockchain.InitializeMockNeoSystem(); - var s = Blockchain.Singleton.Height; - _unit = new MemoryPool(TheNeoSystem, 600); - _unit.LoadPolicy(TestBlockchain.GetStore().GetSnapshot()); + _unit = new MemoryPool(TestBlockchain.TheNeoSystem, 600); + _unit.LoadPolicy(Blockchain.Singleton.GetSnapshot()); AddTransaction(CreateTransaction(100000001)); AddTransaction(CreateTransaction(100000001)); AddTransaction(CreateTransaction(100000001)); @@ -475,7 +472,7 @@ public void TestTryGetValue() [TestMethod] public void TestUpdatePoolForBlockPersisted() { - var mockSnapshot = new Mock(); + var snapshot = Blockchain.Singleton.GetSnapshot(); byte[] transactionsPerBlock = { 0x18, 0x00, 0x00, 0x00 }; // 24 byte[] feePerByte = { 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 1048576 StorageItem item1 = new StorageItem @@ -486,14 +483,12 @@ public void TestUpdatePoolForBlockPersisted() { Value = feePerByte }; - var myDataCache = new MyDataCache(); var key1 = CreateStorageKey(Prefix_MaxTransactionsPerBlock); var key2 = CreateStorageKey(Prefix_FeePerByte); key1.ScriptHash = NativeContract.Policy.Hash; key2.ScriptHash = NativeContract.Policy.Hash; - myDataCache.Add(key1, item1); - myDataCache.Add(key2, item2); - mockSnapshot.SetupGet(p => p.Storages).Returns(myDataCache); + snapshot.Storages.Add(key1, item1); + snapshot.Storages.Add(key2, item2); var tx1 = CreateTransaction(); var tx2 = CreateTransaction(); @@ -505,7 +500,7 @@ public void TestUpdatePoolForBlockPersisted() _unit.UnVerifiedCount.Should().Be(0); _unit.VerifiedCount.Should().Be(1); - _unit.UpdatePoolForBlockPersisted(block, mockSnapshot.Object); + _unit.UpdatePoolForBlockPersisted(block, snapshot); _unit.UnVerifiedCount.Should().Be(0); _unit.VerifiedCount.Should().Be(0); @@ -524,48 +519,4 @@ public StorageKey CreateStorageKey(byte prefix, byte[] key = null) return storageKey; } } - - public class MyDataCache : DataCache - where TKey : IEquatable, ISerializable - where TValue : class, ICloneable, ISerializable, new() - { - private readonly TValue _defaultValue; - - public MyDataCache() - { - _defaultValue = null; - } - - public MyDataCache(TValue defaultValue) - { - this._defaultValue = defaultValue; - } - public override void DeleteInternal(TKey key) - { - } - - protected override void AddInternal(TKey key, TValue value) - { - Add(key, value); - } - - protected override IEnumerable> FindInternal(byte[] key_prefix) - { - return Enumerable.Empty>(); - } - - protected override TValue GetInternal(TKey key) - { - return TryGet(key); - } - - protected override TValue TryGetInternal(TKey key) - { - return _defaultValue; - } - - protected override void UpdateInternal(TKey key, TValue value) - { - } - } } diff --git a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs index 81fb0d9354..ac5cf57b7c 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -18,8 +18,8 @@ private Transaction CreateTransactionWithFee(long networkFee, long systemFee) var randomBytes = new byte[16]; random.NextBytes(randomBytes); Mock mock = new Mock(); - mock.Setup(p => p.Reverify(It.IsAny(), It.IsAny())).Returns(true); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(true); + mock.Setup(p => p.Reverify(It.IsAny(), It.IsAny())).Returns(true); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(true); mock.Object.Script = randomBytes; mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = networkFee; diff --git a/tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs b/tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs index 3704279701..482297f7ab 100644 --- a/tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs +++ b/tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs @@ -1,4 +1,4 @@ -using FluentAssertions; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO; using Neo.Ledger; @@ -42,7 +42,7 @@ public void TestGetIsBlock() [TestMethod] public void TestGetBlock() { - var cache = new TestDataCache(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var tx1 = TestUtils.GetTransaction(); tx1.Script = new byte[] { 0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01, @@ -63,12 +63,12 @@ public void TestGetBlock() Transaction = tx2, BlockIndex = 1 }; - cache.Add(tx1.Hash, state1); - cache.Add(tx2.Hash, state2); + snapshot.Transactions.Add(tx1.Hash, state1); + snapshot.Transactions.Add(tx2.Hash, state2); TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); tblock.Hashes = new UInt256[] { tx1.Hash, tx2.Hash }; - Block block = tblock.GetBlock(cache); + Block block = tblock.GetBlock(snapshot.Transactions); block.Index.Should().Be(1); block.MerkleRoot.Should().Be(UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff02")); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index cf5f4504fe..af12fe148e 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -5,7 +5,6 @@ using Neo.IO.Json; using Neo.Ledger; using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.SmartContract.Native.Tokens; @@ -20,13 +19,12 @@ namespace Neo.UnitTests.Network.P2P.Payloads public class UT_Transaction { Transaction uut; - Store store; [TestInitialize] public void TestSetup() { + TestBlockchain.InitializeMockNeoSystem(); uut = new Transaction(); - store = TestBlockchain.GetStore(); } [TestMethod] @@ -86,10 +84,9 @@ public void Size_Get() [TestMethod] public void FeeIsMultiSigContract() { - var store = TestBlockchain.GetStore(); var walletA = TestUtils.GenerateTestWallet(); var walletB = TestUtils.GenerateTestWallet(); - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); using (var unlockA = walletA.Unlock("123")) using (var unlockB = walletB.Unlock("123")) @@ -121,6 +118,8 @@ public void FeeIsMultiSigContract() } .ToByteArray(); + snapshot.Commit(); + // Make transaction var tx = walletA.MakeTransaction(new TransferOutput[] @@ -175,7 +174,7 @@ public void FeeIsMultiSigContract() public void FeeIsSignatureContractDetailed() { var wallet = TestUtils.GenerateTestWallet(); - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); using (var unlock = wallet.Unlock("123")) { @@ -196,6 +195,8 @@ public void FeeIsSignatureContractDetailed() } .ToByteArray(); + snapshot.Commit(); + // Make transaction // self-transfer of 1e-8 GAS @@ -290,7 +291,7 @@ public void FeeIsSignatureContractDetailed() public void FeeIsSignatureContract_TestScope_Global() { var wallet = TestUtils.GenerateTestWallet(); - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); // no password on this wallet using (var unlock = wallet.Unlock("")) @@ -312,6 +313,8 @@ public void FeeIsSignatureContract_TestScope_Global() } .ToByteArray(); + snapshot.Commit(); + // Make transaction // Manually creating script @@ -381,7 +384,7 @@ public void FeeIsSignatureContract_TestScope_Global() public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() { var wallet = TestUtils.GenerateTestWallet(); - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); // no password on this wallet using (var unlock = wallet.Unlock("")) @@ -403,6 +406,8 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() } .ToByteArray(); + snapshot.Commit(); + // Make transaction // Manually creating script @@ -473,7 +478,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() { var wallet = TestUtils.GenerateTestWallet(); - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); // no password on this wallet using (var unlock = wallet.Unlock("")) @@ -495,6 +500,8 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() } .ToByteArray(); + snapshot.Commit(); + // Make transaction // Manually creating script @@ -568,7 +575,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() { var wallet = TestUtils.GenerateTestWallet(); - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); // no password on this wallet using (var unlock = wallet.Unlock("")) @@ -626,7 +633,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() { var wallet = TestUtils.GenerateTestWallet(); - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); // no password on this wallet using (var unlock = wallet.Unlock("")) @@ -648,6 +655,8 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() } .ToByteArray(); + snapshot.Commit(); + // Make transaction // Manually creating script @@ -723,7 +732,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() public void FeeIsSignatureContract_TestScope_NoScopeFAULT() { var wallet = TestUtils.GenerateTestWallet(); - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); // no password on this wallet using (var unlock = wallet.Unlock("")) @@ -775,7 +784,7 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() [TestMethod] public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() { - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); Transaction txSimple = new Transaction { Version = 0x00, @@ -981,7 +990,7 @@ public void FeeIsSignatureContract_TestScope_Global_Default() cosigner.Scopes.Should().Be(WitnessScope.Global); var wallet = TestUtils.GenerateTestWallet(); - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); // no password on this wallet using (var unlock = wallet.Unlock("")) @@ -1003,6 +1012,8 @@ public void FeeIsSignatureContract_TestScope_Global_Default() } .ToByteArray(); + snapshot.Commit(); + // Make transaction // Manually creating script diff --git a/tests/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs b/tests/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs index f8b932c4f2..1f62a77580 100644 --- a/tests/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs +++ b/tests/neo.UnitTests/Network/P2P/UT_ProtocolHandler.cs @@ -9,26 +9,18 @@ namespace Neo.UnitTests.Network.P2P [TestClass] public class UT_ProtocolHandler : TestKit { - private NeoSystem testBlockchain; - [TestCleanup] public void Cleanup() { Shutdown(); } - [TestInitialize] - public void TestSetup() - { - testBlockchain = TestBlockchain.InitializeMockNeoSystem(); - } - [TestMethod] public void ProtocolHandler_Test_SendVersion_TellParent() { var senderProbe = CreateTestProbe(); var parent = CreateTestProbe(); - var protocolActor = ActorOfAsTestActorRef(() => new ProtocolHandler(testBlockchain), parent); + var protocolActor = ActorOfAsTestActorRef(() => new ProtocolHandler(TestBlockchain.TheNeoSystem), parent); var payload = new VersionPayload() { diff --git a/tests/neo.UnitTests/Network/P2P/UT_RemoteNode.cs b/tests/neo.UnitTests/Network/P2P/UT_RemoteNode.cs index 570cc904da..a700902f6c 100644 --- a/tests/neo.UnitTests/Network/P2P/UT_RemoteNode.cs +++ b/tests/neo.UnitTests/Network/P2P/UT_RemoteNode.cs @@ -23,7 +23,7 @@ public UT_RemoteNode() [ClassInitialize] public static void TestSetup(TestContext ctx) { - testBlockchain = TestBlockchain.InitializeMockNeoSystem(); + testBlockchain = TestBlockchain.TheNeoSystem; } [TestMethod] diff --git a/tests/neo.UnitTests/Network/RPC/UT_RpcServer.cs b/tests/neo.UnitTests/Network/RPC/UT_RpcServer.cs index fae945a21a..cfdfe7fbd8 100644 --- a/tests/neo.UnitTests/Network/RPC/UT_RpcServer.cs +++ b/tests/neo.UnitTests/Network/RPC/UT_RpcServer.cs @@ -14,8 +14,7 @@ public class UT_RpcServer [TestInitialize] public void Setup() { - var system = TestBlockchain.InitializeMockNeoSystem(); - server = new RpcServer(system); + server = new RpcServer(TestBlockchain.TheNeoSystem); } [TestCleanup] diff --git a/tests/neo.UnitTests/Network/RPC/UT_TransactionManager.cs b/tests/neo.UnitTests/Network/RPC/UT_TransactionManager.cs index e1cce967cd..e11c551a9a 100644 --- a/tests/neo.UnitTests/Network/RPC/UT_TransactionManager.cs +++ b/tests/neo.UnitTests/Network/RPC/UT_TransactionManager.cs @@ -3,6 +3,7 @@ using Neo.Cryptography; using Neo.IO; using Neo.IO.Json; +using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Network.RPC; @@ -156,8 +157,7 @@ public void TestSignMulti() .AddSignature(keyPair1) .Sign(); - var store = TestBlockchain.GetStore(); - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var tx = txManager.Tx; Assert.IsTrue(tx.VerifyWitnesses(snapshot, tx.NetworkFee)); diff --git a/tests/neo.UnitTests/Plugins/UT_Plugin.cs b/tests/neo.UnitTests/Plugins/UT_Plugin.cs index 3c6098e47a..7c3224c82a 100644 --- a/tests/neo.UnitTests/Plugins/UT_Plugin.cs +++ b/tests/neo.UnitTests/Plugins/UT_Plugin.cs @@ -65,8 +65,7 @@ public void TestNotifyPluginsLoadedAfterSystemConstructed() [TestMethod] public void TestResumeNodeStartupAndSuspendNodeStartup() { - var system = TestBlockchain.InitializeMockNeoSystem(); - TestLogPlugin.TestLoadPlugins(system); + TestLogPlugin.TestLoadPlugins(TestBlockchain.TheNeoSystem); TestLogPlugin.TestSuspendNodeStartup(); TestLogPlugin.TestSuspendNodeStartup(); TestLogPlugin.TestResumeNodeStartup().Should().BeFalse(); diff --git a/tests/neo.UnitTests/SmartContract/Iterators/UT_StorageIterator.cs b/tests/neo.UnitTests/SmartContract/Iterators/UT_StorageIterator.cs index aad833b04e..a0126b3b03 100644 --- a/tests/neo.UnitTests/SmartContract/Iterators/UT_StorageIterator.cs +++ b/tests/neo.UnitTests/SmartContract/Iterators/UT_StorageIterator.cs @@ -14,7 +14,7 @@ public class UT_StorageIterator [TestMethod] public void TestGeneratorAndDispose() { - StorageIterator storageIterator = new StorageIterator(new List>().GetEnumerator()); + StorageIterator storageIterator = new StorageIterator(new List<(StorageKey, StorageItem)>().GetEnumerator()); Assert.IsNotNull(storageIterator); Action action = () => storageIterator.Dispose(); action.Should().NotThrow(); @@ -23,12 +23,12 @@ public void TestGeneratorAndDispose() [TestMethod] public void TestKeyAndValueAndNext() { - List> list = new List>(); + List<(StorageKey, StorageItem)> list = new List<(StorageKey, StorageItem)>(); StorageKey storageKey = new StorageKey(); storageKey.Key = new byte[1]; StorageItem storageItem = new StorageItem(); storageItem.Value = new byte[1]; - list.Add(new KeyValuePair(storageKey, storageItem)); + list.Add((storageKey, storageItem)); StorageIterator storageIterator = new StorageIterator(list.GetEnumerator()); storageIterator.Next(); Assert.AreEqual(new ByteArray(new byte[1]), storageIterator.Key()); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index 7e811d3eda..96beff3cbd 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -2,7 +2,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Ledger; using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Extensions; @@ -17,13 +16,10 @@ namespace Neo.UnitTests.SmartContract.Native.Tokens [TestClass] public class UT_GasToken { - Store Store; - [TestInitialize] public void TestSetup() { TestBlockchain.InitializeMockNeoSystem(); - Store = TestBlockchain.GetStore(); } [TestMethod] @@ -41,7 +37,7 @@ public void TestSetup() [TestMethod] public void Check_BalanceOfTransferAndBurn() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); snapshot.PersistingBlock = new Block() { Index = 1000 }; byte[] from = Contract.CreateMultiSigRedeemScript(Blockchain.StandbyValidators.Length / 2 + 1, @@ -133,7 +129,7 @@ public void Check_BalanceOfTransferAndBurn() [TestMethod] public void Check_BadScript() { - var engine = new ApplicationEngine(TriggerType.Application, null, Store.GetSnapshot(), 0); + var engine = new ApplicationEngine(TriggerType.Application, null, Blockchain.Singleton.GetSnapshot(), 0); var script = new ScriptBuilder(); script.Emit(OpCode.NOP); @@ -160,7 +156,7 @@ public void TestGetSysFeeAmount1() [TestMethod] public void TestGetSysFeeAmount2() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); NativeContract.GAS.GetSysFeeAmount(snapshot, 0).Should().Be(new BigInteger(0)); NativeContract.GAS.GetSysFeeAmount(snapshot, 1).Should().Be(new BigInteger(0)); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 19f7ad2f6a..8ae4516cab 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -21,13 +21,10 @@ namespace Neo.UnitTests.SmartContract.Native.Tokens [TestClass] public class UT_NeoToken { - private Store Store; - [TestInitialize] public void TestSetup() { TestBlockchain.InitializeMockNeoSystem(); - Store = TestBlockchain.GetStore(); } [TestMethod] @@ -45,7 +42,7 @@ public void TestSetup() [TestMethod] public void Check_Vote() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); snapshot.PersistingBlock = new Block() { Index = 1000 }; byte[] from = Contract.CreateMultiSigRedeemScript(Blockchain.StandbyValidators.Length / 2 + 1, @@ -85,7 +82,7 @@ public void Check_Vote() [TestMethod] public void Check_UnclaimedGas() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); snapshot.PersistingBlock = new Block() { Index = 1000 }; byte[] from = Contract.CreateMultiSigRedeemScript(Blockchain.StandbyValidators.Length / 2 + 1, @@ -103,7 +100,7 @@ public void Check_UnclaimedGas() [TestMethod] public void Check_RegisterValidator() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var ret = Check_RegisterValidator(snapshot, new byte[0]); ret.State.Should().BeFalse(); @@ -148,7 +145,7 @@ public void Check_RegisterValidator() [TestMethod] public void Check_Transfer() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); snapshot.PersistingBlock = new Block() { Index = 1000 }; byte[] from = Contract.CreateMultiSigRedeemScript(Blockchain.StandbyValidators.Length / 2 + 1, @@ -201,7 +198,7 @@ public void Check_Transfer() [TestMethod] public void Check_BalanceOf() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); byte[] account = Contract.CreateMultiSigRedeemScript(Blockchain.StandbyValidators.Length / 2 + 1, Blockchain.StandbyValidators).ToScriptHash().ToArray(); @@ -215,7 +212,7 @@ public void Check_BalanceOf() [TestMethod] public void Check_Initialize() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); // StandbyValidators @@ -240,7 +237,7 @@ public void Check_Initialize() [TestMethod] public void Check_BadScript() { - var engine = new ApplicationEngine(TriggerType.Application, null, Store.GetSnapshot(), 0); + var engine = new ApplicationEngine(TriggerType.Application, null, Blockchain.Singleton.GetSnapshot(), 0); var script = new ScriptBuilder(); script.Emit(OpCode.NOP); @@ -252,7 +249,7 @@ public void Check_BadScript() [TestMethod] public void TestCalculateBonus() { - Snapshot snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); StorageKey key = CreateStorageKey(20, UInt160.Zero.ToArray()); snapshot.Storages.Add(key, new StorageItem { @@ -295,7 +292,7 @@ public void TestGetNextBlockValidators1() [TestMethod] public void TestGetNextBlockValidators2() { - Snapshot snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var result = NativeContract.NEO.GetNextBlockValidators(snapshot); result.Length.Should().Be(7); result[0].ToArray().ToHexString().Should().Be("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"); @@ -343,7 +340,7 @@ public void TestGetRegisteredValidators1() [TestMethod] public void TestGetRegisteredValidators2() { - Snapshot snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var result = NativeContract.NEO.GetRegisteredValidators(snapshot).ToArray(); result.Length.Should().Be(7); result[0].PublicKey.ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); @@ -390,7 +387,7 @@ public void TestGetValidators1() [TestMethod] public void TestGetValidators2() { - Snapshot snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var result = NativeContract.NEO.GetValidators(snapshot); result[0].ToArray().ToHexString().Should().Be("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"); result[1].ToArray().ToHexString().Should().Be("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"); @@ -416,7 +413,7 @@ public void TestGetValidators2() [TestMethod] public void TestInitialize() { - Snapshot snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var engine = new ApplicationEngine(TriggerType.System, null, snapshot, 0, true); Action action = () => NativeContract.NEO.Initialize(engine); action.Should().Throw(); @@ -425,6 +422,7 @@ public void TestInitialize() NativeContract.NEO.Initialize(engine).Should().BeFalse(); snapshot.Storages.Delete(CreateStorageKey(11)); + snapshot.PersistingBlock = Blockchain.GenesisBlock; engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); NativeContract.NEO.Initialize(engine).Should().BeTrue(); } @@ -448,14 +446,14 @@ public void TestOnBalanceChanging() [TestMethod] public void TestTotalSupply() { - Snapshot snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); NativeContract.NEO.TotalSupply(snapshot).Should().Be(new BigInteger(100000000)); } [TestMethod] public void TestUnclaimedGas() { - Snapshot snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); snapshot.Storages.Add(CreateStorageKey(20, UInt160.Zero.ToArray()), new StorageItem { @@ -467,7 +465,7 @@ public void TestUnclaimedGas() [TestMethod] public void TestVote() { - Snapshot snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); UInt160 account = UInt160.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4"); StorageKey keyAccount = CreateStorageKey(20, account.ToArray()); StorageKey keyValidator = CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()); @@ -529,7 +527,8 @@ public void TestValidatorState_ToByteArray() internal (bool State, bool Result) Transfer4TesingOnBalanceChanging(BigInteger amount, bool addVotes) { - Snapshot snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); + snapshot.PersistingBlock = Blockchain.GenesisBlock; var engine = new ApplicationEngine(TriggerType.Application, Blockchain.GenesisBlock, snapshot, 0, true); ScriptBuilder sb = new ScriptBuilder(); var tmp = engine.ScriptContainer.GetScriptHashesForVerifying(engine.Snapshot); @@ -578,7 +577,7 @@ public void TestValidatorState_ToByteArray() return (true, result.ToBoolean()); } - internal static (bool State, bool Result) Check_Vote(Snapshot snapshot, byte[] account, byte[][] pubkeys, bool signAccount) + internal static (bool State, bool Result) Check_Vote(StoreView snapshot, byte[] account, byte[][] pubkeys, bool signAccount) { var engine = new ApplicationEngine(TriggerType.Application, new Nep5NativeContractExtensions.ManualWitness(signAccount ? new UInt160(account) : UInt160.Zero), snapshot, 0, true); @@ -608,7 +607,7 @@ internal static (bool State, bool Result) Check_Vote(Snapshot snapshot, byte[] a return (true, result.ToBoolean()); } - internal static (bool State, bool Result) Check_RegisterValidator(Snapshot snapshot, byte[] pubkey) + internal static (bool State, bool Result) Check_RegisterValidator(StoreView snapshot, byte[] pubkey) { var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); @@ -632,7 +631,7 @@ internal static (bool State, bool Result) Check_RegisterValidator(Snapshot snaps return (true, result.ToBoolean()); } - internal static ECPoint[] Check_GetValidators(Snapshot snapshot) + internal static ECPoint[] Check_GetValidators(StoreView snapshot) { var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); @@ -652,7 +651,7 @@ internal static ECPoint[] Check_GetValidators(Snapshot snapshot) return (result as VM.Types.Array).Select(u => u.GetSpan().AsSerializable()).ToArray(); } - internal static (BigInteger Value, bool State) Check_UnclaimedGas(Snapshot snapshot, byte[] address) + internal static (BigInteger Value, bool State) Check_UnclaimedGas(StoreView snapshot, byte[] address) { var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs index a34c7a109f..a3bc7fa531 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs @@ -1,8 +1,6 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; using Neo.Ledger; -using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native.Tokens; using Neo.VM; @@ -20,8 +18,7 @@ public class UT_Nep5Token [TestMethod] public void TestTotalSupply() { - var mockSnapshot = new Mock(); - var myDataCache = new TestDataCache(); + var snapshot = Blockchain.Singleton.GetSnapshot(); StorageItem item = new StorageItem { Value = new byte[] { 0x01 } @@ -38,10 +35,9 @@ public void TestTotalSupply() var Hash = script.ToScriptHash(); key.ScriptHash = Hash; - myDataCache.Add(key, item); - mockSnapshot.SetupGet(p => p.Storages).Returns(myDataCache); + snapshot.Storages.Add(key, item); TestNep5Token test = new TestNep5Token(); - ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); StackItem stackItem = test.TotalSupply(ae, null); stackItem.GetBigInteger().Should().Be(1); } @@ -49,8 +45,7 @@ public void TestTotalSupply() [TestMethod] public void TestTotalSupplyDecimal() { - var mockSnapshot = new Mock(); - var myDataCache = new TestDataCache(); + var snapshot = Blockchain.Singleton.GetSnapshot(); TestNep5Token test = new TestNep5Token(); BigInteger totalSupply = 100_000_000; @@ -73,10 +68,9 @@ public void TestTotalSupplyDecimal() var Hash = script.ToScriptHash(); key.ScriptHash = Hash; - myDataCache.Add(key, item); - mockSnapshot.SetupGet(p => p.Storages).Returns(myDataCache); + snapshot.Storages.Add(key, item); - ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); StackItem stackItem = test.TotalSupply(ae, null); stackItem.GetBigInteger().Should().Be(10_000_000_000_000_000); } diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 61e93de6ad..71cfd3c093 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -1,6 +1,6 @@ -using FluentAssertions; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.Persistence; +using Neo.Ledger; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; @@ -13,13 +13,10 @@ namespace Neo.UnitTests.SmartContract.Native [TestClass] public class UT_NativeContract { - Store Store; - [TestInitialize] public void TestSetup() { TestBlockchain.InitializeMockNeoSystem(); - Store = TestBlockchain.GetStore(); } [TestMethod] @@ -37,7 +34,7 @@ public void TestInitialize() [TestMethod] public void TestInvoke() { - ApplicationEngine engine1 = new ApplicationEngine(TriggerType.Application, null, Store.GetSnapshot(), 0); + ApplicationEngine engine1 = new ApplicationEngine(TriggerType.Application, null, Blockchain.Singleton.GetSnapshot(), 0); TestNativeContract testNativeContract = new TestNativeContract(); ScriptBuilder sb1 = new ScriptBuilder(); @@ -46,7 +43,7 @@ public void TestInvoke() engine1.LoadScript(sb1.ToArray()); testNativeContract.Invoke(engine1).Should().BeFalse(); - ApplicationEngine engine2 = new ApplicationEngine(TriggerType.Application, null, Store.GetSnapshot(), 0); + ApplicationEngine engine2 = new ApplicationEngine(TriggerType.Application, null, Blockchain.Singleton.GetSnapshot(), 0); ScriptBuilder sb2 = new ScriptBuilder(); sb2.EmitSysCall("test".ToInteropMethodHash()); @@ -68,14 +65,14 @@ public void TestInvoke() [TestMethod] public void TestOnPersistWithArgs() { - ApplicationEngine engine1 = new ApplicationEngine(TriggerType.Application, null, Store.GetSnapshot(), 0); + ApplicationEngine engine1 = new ApplicationEngine(TriggerType.Application, null, Blockchain.Singleton.GetSnapshot(), 0); TestNativeContract testNativeContract = new TestNativeContract(); VMArray args = new VMArray(); VM.Types.Boolean result1 = new VM.Types.Boolean(false); testNativeContract.TestOnPersist(engine1, args).Should().Be(result1); - ApplicationEngine engine2 = new ApplicationEngine(TriggerType.System, null, Store.GetSnapshot(), 0); + ApplicationEngine engine2 = new ApplicationEngine(TriggerType.System, null, Blockchain.Singleton.GetSnapshot(), 0); VM.Types.Boolean result2 = new VM.Types.Boolean(true); testNativeContract.TestOnPersist(engine2, args).Should().Be(result2); } diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index b75141459f..0b15d0732d 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -15,13 +15,10 @@ namespace Neo.UnitTests.SmartContract.Native [TestClass] public class UT_PolicyContract { - Store Store; - [TestInitialize] public void TestSetup() { TestBlockchain.InitializeMockNeoSystem(); - Store = TestBlockchain.GetStore(); } [TestMethod] @@ -30,7 +27,7 @@ public void TestSetup() [TestMethod] public void Check_Initialize() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var keyCount = snapshot.Storages.GetChangeSet().Count(); NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)).Should().BeTrue(); @@ -57,7 +54,7 @@ public void Check_Initialize() [TestMethod] public void Check_SetMaxBlockSize() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); // Fake blockchain @@ -103,7 +100,7 @@ public void Check_SetMaxBlockSize() [TestMethod] public void Check_SetMaxTransactionsPerBlock() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); // Fake blockchain @@ -138,7 +135,7 @@ public void Check_SetMaxTransactionsPerBlock() [TestMethod] public void Check_SetFeePerByte() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); // Fake blockchain @@ -173,7 +170,7 @@ public void Check_SetFeePerByte() [TestMethod] public void Check_Block_UnblockAccount() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); // Fake blockchain @@ -233,7 +230,7 @@ public void Check_Block_UnblockAccount() public void TestCheckPolicy() { Transaction tx = Blockchain.GenesisBlock.Transactions[0]; - Snapshot snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); StorageKey storageKey = new StorageKey { @@ -248,7 +245,7 @@ public void TestCheckPolicy() NativeContract.Policy.CheckPolicy(tx, snapshot).Should().BeFalse(); - snapshot = Store.GetSnapshot().Clone(); + snapshot = Blockchain.Singleton.GetSnapshot(); NativeContract.Policy.CheckPolicy(tx, snapshot).Should().BeTrue(); } } diff --git a/tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs b/tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs index d8bdd8a857..3790aaf094 100644 --- a/tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs +++ b/tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs @@ -17,19 +17,17 @@ public class UT_ApplicationEngine { private string message = null; private StackItem item = null; - private Store Store; [TestInitialize] public void TestSetup() { TestBlockchain.InitializeMockNeoSystem(); - Store = TestBlockchain.GetStore(); } [TestMethod] public void TestLog() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); ApplicationEngine.Log += Test_Log1; string logMessage = "TestMessage"; @@ -54,7 +52,7 @@ public void TestLog() [TestMethod] public void TestNotify() { - var snapshot = Store.GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); ApplicationEngine.Notify += Test_Notify1; StackItem notifyItem = "TestItem"; @@ -79,10 +77,10 @@ public void TestNotify() [TestMethod] public void TestDisposable() { - var snapshot = Store.GetSnapshot().Clone(); - var replica = snapshot.Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); + var m = new Mock(); var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); - engine.AddDisposable(replica).Should().Be(replica); + engine.AddDisposable(m.Object).Should().Be(m.Object); Action action = () => engine.Dispose(); action.Should().NotThrow(); } @@ -110,19 +108,12 @@ private void Test_Notify2(object sender, NotifyEventArgs e) [TestMethod] public void TestCreateDummyBlock() { - var mockSnapshot = new Mock(); - UInt256 currentBlockHash = UInt256.Parse("0x0000000000000000000000000000000000000000000000000000000000000000"); - TrimmedBlock block = new TrimmedBlock(); - var cache = new TestDataCache(); - cache.Add(currentBlockHash, block); - mockSnapshot.SetupGet(p => p.Blocks).Returns(cache); - TestMetaDataCache testCache = new TestMetaDataCache(); - mockSnapshot.SetupGet(p => p.BlockHashIndex).Returns(testCache); + var snapshot = Blockchain.Singleton.GetSnapshot(); byte[] SyscallSystemRuntimeCheckWitnessHash = new byte[] { 0x68, 0xf8, 0x27, 0xec, 0x8c }; - ApplicationEngine.Run(SyscallSystemRuntimeCheckWitnessHash, mockSnapshot.Object); - mockSnapshot.Object.PersistingBlock.Version.Should().Be(0); - mockSnapshot.Object.PersistingBlock.PrevHash.Should().Be(currentBlockHash); - mockSnapshot.Object.PersistingBlock.MerkleRoot.Should().Be(new UInt256()); + ApplicationEngine.Run(SyscallSystemRuntimeCheckWitnessHash, snapshot); + snapshot.PersistingBlock.Version.Should().Be(0); + snapshot.PersistingBlock.PrevHash.Should().Be(Blockchain.GenesisBlock.Hash); + snapshot.PersistingBlock.MerkleRoot.Should().Be(new UInt256()); } [TestMethod] @@ -134,10 +125,8 @@ public void TestOnSysCall() engine.LoadScript(SyscallSystemRuntimeCheckWitnessHash); engine.GetOnSysCall(descriptor.Hash).Should().BeFalse(); - var mockSnapshot = new Mock(); - TestMetaDataCache testCache = new TestMetaDataCache(); - mockSnapshot.SetupGet(p => p.BlockHashIndex).Returns(testCache); - engine = new TestApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0, true); + var snapshot = Blockchain.Singleton.GetSnapshot(); + engine = new TestApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(SyscallSystemRuntimeCheckWitnessHash); engine.GetOnSysCall(descriptor.Hash).Should().BeTrue(); } @@ -151,7 +140,7 @@ private static bool Blockchain_GetHeight(ApplicationEngine engine) public class TestApplicationEngine : ApplicationEngine { - public TestApplicationEngine(TriggerType trigger, IVerifiable container, Snapshot snapshot, long gas, bool testMode = false) : base(trigger, container, snapshot, gas, testMode) + public TestApplicationEngine(TriggerType trigger, IVerifiable container, StoreView snapshot, long gas, bool testMode = false) : base(trigger, container, snapshot, gas, testMode) { } diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index 3e60b91591..351f885f11 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -1,12 +1,10 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; using Neo.Cryptography; using Neo.Cryptography.ECC; using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Enumerators; using Neo.SmartContract.Iterators; @@ -142,10 +140,10 @@ public void TestAccount_IsStandard() InteropService.Invoke(engine, InteropService.Neo_Account_IsStandard).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeTrue(); - var mockSnapshot = new Mock(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); - engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Add(state.ScriptHash, state); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[] { 0x01 }); engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); InteropService.Invoke(engine, InteropService.Neo_Account_IsStandard).Should().BeTrue(); @@ -176,10 +174,10 @@ public void TestContract_Create() engine.CurrentContext.EvaluationStack.Push(script); InteropService.Invoke(engine, InteropService.Neo_Contract_Create).Should().BeTrue(); - var mockSnapshot = new Mock(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); - engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Add(state.ScriptHash, state); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[] { 0x01 }); engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); engine.CurrentContext.EvaluationStack.Push(state.Script); @@ -219,7 +217,7 @@ public void TestContract_Update() Signature = signature } }; - var mockSnapshot = new Mock(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); state.Manifest.Features = ContractFeatures.HasStorage; var storageItem = new StorageItem @@ -233,9 +231,9 @@ public void TestContract_Update() ScriptHash = state.ScriptHash, Key = new byte[] { 0x01 } }; - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); - mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); - engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Add(state.ScriptHash, state); + snapshot.Storages.Add(storageKey, storageItem); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(state.Script); engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); engine.CurrentContext.EvaluationStack.Push(script); @@ -244,10 +242,10 @@ public void TestContract_Update() // Remove Storage flag with something stored state.Manifest.Features = ContractFeatures.NoProperty; - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); - mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); + snapshot.Contracts.Add(state.ScriptHash, state); + snapshot.Storages.Add(storageKey, storageItem); - engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(state.Script); engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); engine.CurrentContext.EvaluationStack.Push(script); @@ -257,7 +255,7 @@ public void TestContract_Update() [TestMethod] public void TestStorage_Find() { - var mockSnapshot = new Mock(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); state.Manifest.Features = ContractFeatures.HasStorage; @@ -271,9 +269,9 @@ public void TestStorage_Find() ScriptHash = state.ScriptHash, Key = new byte[] { 0x01 } }; - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); - mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); - var engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Add(state.ScriptHash, state); + snapshot.Storages.Add(storageKey, storageItem); + var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[] { 0x01 }); engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 83f4a1485b..f04d6f5b6c 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -1,12 +1,10 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; using Neo.Cryptography; using Neo.Cryptography.ECC; using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Manifest; using Neo.VM; @@ -31,7 +29,7 @@ public void TestSetup() public void Runtime_GetNotifications_Test() { UInt160 scriptHash2; - var snapshot = TestBlockchain.GetStore().GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); using (var script = new ScriptBuilder()) { @@ -445,10 +443,10 @@ public void TestBlockchain_GetContract() InteropService.Invoke(engine, InteropService.System_Blockchain_GetContract).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().Should().Be(StackItem.Null); - var mockSnapshot = new Mock(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); - engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Add(state.ScriptHash, state); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[] { 0x01 }); engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); InteropService.Invoke(engine, InteropService.System_Blockchain_GetContract).Should().BeTrue(); @@ -483,7 +481,7 @@ public void TestStorage_GetReadOnlyContext() [TestMethod] public void TestStorage_Get() { - var mockSnapshot = new Mock(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); state.Manifest.Features = ContractFeatures.HasStorage; @@ -498,9 +496,9 @@ public void TestStorage_Get() Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, IsConstant = true }; - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); - mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); - var engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Add(state.ScriptHash, state); + snapshot.Storages.Add(storageKey, storageItem); + var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[] { 0x01 }); engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); @@ -512,8 +510,8 @@ public void TestStorage_Get() InteropService.Invoke(engine, InteropService.System_Storage_Get).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToHexString().Should().Be(storageItem.Value.ToHexString()); - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache()); - engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Delete(state.ScriptHash); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[] { 0x01 }); engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); engine.CurrentContext.EvaluationStack.Push(new InteropInterface(new StorageContext @@ -574,7 +572,7 @@ public void TestStorage_Put() InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeFalse(); //storage value is constant - var mockSnapshot = new Mock(); + var snapshot = Blockchain.Singleton.GetSnapshot(); state.Manifest.Features = ContractFeatures.HasStorage; var storageKey = new StorageKey @@ -587,9 +585,9 @@ public void TestStorage_Put() Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, IsConstant = true }; - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); - mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); - engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Add(state.ScriptHash, state); + snapshot.Storages.Add(storageKey, storageItem); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[] { 0x01 }); key = new byte[] { 0x01 }; value = new byte[] { 0x02 }; @@ -622,7 +620,7 @@ public void TestStorage_PutEx() engine.CurrentContext.EvaluationStack.Push(1); InteropService.Invoke(engine, InteropService.System_Storage_PutEx).Should().BeFalse(); - var mockSnapshot = new Mock(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); state.Manifest.Features = ContractFeatures.HasStorage; var storageKey = new StorageKey @@ -635,9 +633,9 @@ public void TestStorage_PutEx() Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, IsConstant = false }; - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); - mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); - engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Add(state.ScriptHash, state); + snapshot.Storages.Add(storageKey, storageItem); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[] { 0x01 }); var key = new byte[] { 0x01 }; var value = new byte[] { 0x02 }; @@ -661,7 +659,7 @@ public void TestStorage_Delete() InteropService.Invoke(engine, InteropService.System_Storage_Delete).Should().BeFalse(); - var mockSnapshot = new Mock(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); state.Manifest.Features = ContractFeatures.HasStorage; var storageKey = new StorageKey @@ -674,9 +672,9 @@ public void TestStorage_Delete() Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, IsConstant = false }; - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); - mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); - engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Add(state.ScriptHash, state); + snapshot.Storages.Add(storageKey, storageItem); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[] { 0x01 }); state.Manifest.Features = ContractFeatures.HasStorage; var key = new byte[] { 0x01 }; @@ -733,13 +731,13 @@ public void TestInvoke() [TestMethod] public void TestContract_Call() { - var mockSnapshot = new Mock(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); state.Manifest.Features = ContractFeatures.HasStorage; byte[] method = Encoding.UTF8.GetBytes("method"); byte[] args = new byte[0]; - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); - var engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Add(state.ScriptHash, state); + var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[] { 0x01 }); engine.CurrentContext.EvaluationStack.Push(args); @@ -773,7 +771,7 @@ public void TestContract_Destroy() var engine = GetEngine(false, true); InteropService.Invoke(engine, InteropService.System_Contract_Destroy).Should().BeTrue(); - var mockSnapshot = new Mock(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); state.Manifest.Features = ContractFeatures.HasStorage; var scriptHash = UInt160.Parse("0xcb9f3b7c6fb1cf2c13a40637c189bdd066a272b4"); @@ -788,17 +786,17 @@ public void TestContract_Destroy() ScriptHash = scriptHash, Key = new byte[] { 0x01 } }; - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(scriptHash, state)); - mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); - engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Add(scriptHash, state); + snapshot.Storages.Add(storageKey, storageItem); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[0]); InteropService.Invoke(engine, InteropService.System_Contract_Destroy).Should().BeTrue(); //storages are removed - mockSnapshot = new Mock(); + snapshot = Blockchain.Singleton.GetSnapshot(); state = TestUtils.GetContract(); - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(scriptHash, state)); - engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + snapshot.Contracts.Add(scriptHash, state); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[0]); InteropService.Invoke(engine, InteropService.System_Contract_Destroy).Should().BeTrue(); } @@ -812,7 +810,7 @@ public static void LogEvent(object sender, LogEventArgs args) private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSnapshot = false) { var tx = TestUtils.GetTransaction(); - var snapshot = TestBlockchain.GetStore().GetSnapshot().Clone(); + var snapshot = Blockchain.Singleton.GetSnapshot(); ApplicationEngine engine; if (hasContainer && hasSnapshot) { diff --git a/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs index 8a85e7a4b4..6421bd1a31 100644 --- a/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs +++ b/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -1,9 +1,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; using Neo.Ledger; using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.SmartContract; using Neo.VM.Types; using Neo.Wallets; @@ -265,41 +263,31 @@ public void TestToScriptHash() [TestMethod] public void TestVerifyWitnesses() { - var mockSnapshot1 = new Mock(); + var snapshot1 = Blockchain.Singleton.GetSnapshot(); UInt256 index1 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); - TestDataCache testDataCache1 = new TestDataCache(); - testDataCache1.Add(index1, new TrimmedBlock()); - testDataCache1.Delete(index1); - mockSnapshot1.SetupGet(p => p.Blocks).Returns(testDataCache1); - Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(new Header() { PrevHash = index1 }, mockSnapshot1.Object, 100)); + snapshot1.Blocks.Add(index1, new TrimmedBlock()); + snapshot1.Blocks.Delete(index1); + Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(new Header() { PrevHash = index1 }, snapshot1, 100)); - var mockSnapshot2 = new Mock(); + var snapshot2 = Blockchain.Singleton.GetSnapshot(); UInt256 index2 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); TrimmedBlock block2 = new TrimmedBlock(); block2.NextConsensus = UInt160.Zero; - TestDataCache testDataCache21 = new TestDataCache(); - testDataCache21.Add(index2, block2); + snapshot2.Blocks.Add(index2, block2); Header header2 = new Header() { PrevHash = index2, Witness = new Witness { VerificationScript = new byte[0] } }; - mockSnapshot2.SetupGet(p => p.Blocks).Returns(testDataCache21); - TestDataCache testDataCache22 = new TestDataCache(); - testDataCache22.Add(UInt160.Zero, new ContractState()); - testDataCache22.Delete(UInt160.Zero); - mockSnapshot2.SetupGet(p => p.Contracts).Returns(testDataCache22); - Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header2, mockSnapshot2.Object, 100)); + snapshot2.Contracts.Add(UInt160.Zero, new ContractState()); + snapshot2.Contracts.Delete(UInt160.Zero); + Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header2, snapshot2, 100)); - var mockSnapshot3 = new Mock(); + var snapshot3 = Blockchain.Singleton.GetSnapshot(); UInt256 index3 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); TrimmedBlock block3 = new TrimmedBlock(); block3.NextConsensus = UInt160.Zero; - TestDataCache testDataCache31 = new TestDataCache(); - testDataCache31.Add(index3, block3); + snapshot3.Blocks.Add(index3, block3); Header header3 = new Header() { PrevHash = index3, Witness = new Witness { VerificationScript = new byte[0] } }; - mockSnapshot3.SetupGet(p => p.Blocks).Returns(testDataCache31); - TestDataCache testDataCache32 = new TestDataCache(); - testDataCache32.Add(UInt160.Zero, new ContractState()); - mockSnapshot3.SetupGet(p => p.Contracts).Returns(testDataCache32); - Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header3, mockSnapshot3.Object, 100)); + snapshot3.Contracts.Add(UInt160.Zero, new ContractState()); + Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header3, snapshot3, 100)); } } } diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index f54b533106..7a1c4212c0 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -45,7 +45,7 @@ public void System_Blockchain_GetBlock() Transactions = new Transaction[] { tx } }; - var snapshot = TestBlockchain.GetStore().GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); using (var script = new ScriptBuilder()) { @@ -63,8 +63,8 @@ public void System_Blockchain_GetBlock() // With block - var blocks = (TestDataCache)snapshot.Blocks; - var txs = (TestDataCache)snapshot.Transactions; + var blocks = snapshot.Blocks; + var txs = snapshot.Transactions; blocks.Add(block.Hash, block.Trim()); txs.Add(tx.Hash, new TransactionState() { Transaction = tx, BlockIndex = block.Index, VMState = VMState.HALT }); @@ -88,7 +88,7 @@ public void System_Blockchain_GetBlock() [TestMethod] public void System_ExecutionEngine_GetScriptContainer() { - var snapshot = TestBlockchain.GetStore().GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); using (var script = new ScriptBuilder()) { script.EmitSysCall(InteropService.System_ExecutionEngine_GetScriptContainer); @@ -136,8 +136,8 @@ public void System_ExecutionEngine_GetScriptContainer() public void System_Runtime_GetInvocationCounter() { ContractState contractA, contractB, contractC; - var snapshot = TestBlockchain.GetStore().GetSnapshot(); - var contracts = (TestDataCache)snapshot.Contracts; + var snapshot = Blockchain.Singleton.GetSnapshot(); + var contracts = snapshot.Contracts; // Create dummy contracts diff --git a/tests/neo.UnitTests/TestBlockchain.cs b/tests/neo.UnitTests/TestBlockchain.cs index 5740c13b08..6b0cdccd94 100644 --- a/tests/neo.UnitTests/TestBlockchain.cs +++ b/tests/neo.UnitTests/TestBlockchain.cs @@ -1,67 +1,29 @@ -using Moq; -using Neo.IO.Wrappers; using Neo.Ledger; using Neo.Persistence; using System; +using MemoryStore = Neo.Persistence.Memory.Store; namespace Neo.UnitTests { public static class TestBlockchain { - private static NeoSystem TheNeoSystem; - private static Mock _Store; - - public static Store GetStore() - { - if (_Store == null) InitializeMockNeoSystem(); - return _Store.Object; - } + public static readonly IStore Store; + public static readonly NeoSystem TheNeoSystem; static TestBlockchain() { - InitializeMockNeoSystem(); - GetStore(); - } - - public static NeoSystem InitializeMockNeoSystem() - { - if (TheNeoSystem == null) - { - var mockSnapshot = new Mock(); - mockSnapshot.SetupGet(p => p.Blocks).Returns(new TestDataCache()); - mockSnapshot.SetupGet(p => p.Transactions).Returns(new TestDataCache()); - mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache()); - mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache()); - mockSnapshot.SetupGet(p => p.HeaderHashList).Returns(new TestDataCache()); - mockSnapshot.SetupGet(p => p.BlockHashIndex).Returns(new TestMetaDataCache()); - mockSnapshot.SetupGet(p => p.HeaderHashIndex).Returns(new TestMetaDataCache()); - - _Store = new Mock(); - - var defaultTx = TestUtils.CreateRandomHashTransaction(); - var txState = new TransactionState - { - BlockIndex = 1, - Transaction = defaultTx - }; - _Store.Setup(p => p.GetBlocks()).Returns(new TestDataCache()); - _Store.Setup(p => p.GetTransactions()).Returns(new TestDataCache(defaultTx.Hash, txState)); - _Store.Setup(p => p.GetContracts()).Returns(new TestDataCache()); - _Store.Setup(p => p.GetStorages()).Returns(new TestDataCache()); - _Store.Setup(p => p.GetHeaderHashList()).Returns(new TestDataCache()); - _Store.Setup(p => p.GetBlockHashIndex()).Returns(new TestMetaDataCache()); - _Store.Setup(p => p.GetHeaderHashIndex()).Returns(new TestMetaDataCache()); - _Store.Setup(p => p.GetSnapshot()).Returns(mockSnapshot.Object); + Store = new MemoryStore(); - Console.WriteLine("initialize NeoSystem"); - TheNeoSystem = new NeoSystem(_Store.Object); // new Mock(mockStore.Object); + Console.WriteLine("initialize NeoSystem"); + TheNeoSystem = new NeoSystem(Store); - // Ensure that blockchain is loaded + // Ensure that blockchain is loaded - var blockchain = Blockchain.Singleton; - } + var _ = Blockchain.Singleton; + } - return TheNeoSystem; + public static void InitializeMockNeoSystem() + { } } } diff --git a/tests/neo.UnitTests/TestDataCache.cs b/tests/neo.UnitTests/TestDataCache.cs deleted file mode 100644 index 37300f22e1..0000000000 --- a/tests/neo.UnitTests/TestDataCache.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Neo.IO; -using Neo.IO.Caching; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Neo.UnitTests -{ - public class TestDataCache : DataCache - where TKey : IEquatable, ISerializable - where TValue : class, ICloneable, ISerializable, new() - { - private readonly Dictionary dic = new Dictionary(); - - public TestDataCache() { } - - public TestDataCache(TKey key, TValue value) - { - dic.Add(key, value); - } - - public override void DeleteInternal(TKey key) - { - dic.Remove(key); - } - - protected override void AddInternal(TKey key, TValue value) - { - dic.Add(key, value); - } - - protected override IEnumerable> FindInternal(byte[] key_prefix) - { - return dic.ToList(); - } - - protected override TValue GetInternal(TKey key) - { - if (dic[key] == null) throw new NotImplementedException(); - return dic[key]; - } - - protected override TValue TryGetInternal(TKey key) - { - return dic.TryGetValue(key, out TValue value) ? value : null; - } - - protected override void UpdateInternal(TKey key, TValue value) - { - dic[key] = value; - } - } -} diff --git a/tests/neo.UnitTests/TestMetaDataCache.cs b/tests/neo.UnitTests/TestMetaDataCache.cs deleted file mode 100644 index 0cb5646928..0000000000 --- a/tests/neo.UnitTests/TestMetaDataCache.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Neo.IO; -using Neo.IO.Caching; - -namespace Neo.UnitTests -{ - public class TestMetaDataCache : MetaDataCache where T : class, ICloneable, ISerializable, new() - { - public TestMetaDataCache() - : base(null) - { - } - - protected override void AddInternal(T item) - { - } - - protected override T TryGetInternal() - { - return null; - } - - protected override void UpdateInternal(T item) - { - } - } -} diff --git a/tests/neo.UnitTests/TestVerifiable.cs b/tests/neo.UnitTests/TestVerifiable.cs index c0920df480..7959eeec3b 100644 --- a/tests/neo.UnitTests/TestVerifiable.cs +++ b/tests/neo.UnitTests/TestVerifiable.cs @@ -27,7 +27,7 @@ public void DeserializeUnsigned(BinaryReader reader) throw new NotImplementedException(); } - public UInt160[] GetScriptHashesForVerifying(Snapshot snapshot) + public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { throw new NotImplementedException(); } diff --git a/tests/neo.UnitTests/UT_DataCache.cs b/tests/neo.UnitTests/UT_DataCache.cs index a428e72d8d..0cee679316 100644 --- a/tests/neo.UnitTests/UT_DataCache.cs +++ b/tests/neo.UnitTests/UT_DataCache.cs @@ -17,7 +17,7 @@ public void TestSetup() [TestMethod] public void TestCachedFind_Between() { - var snapshot = TestBlockchain.GetStore().GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var storages = snapshot.Storages; var cache = new CloneCache(storages); @@ -60,7 +60,7 @@ public void TestCachedFind_Between() [TestMethod] public void TestCachedFind_Last() { - var snapshot = TestBlockchain.GetStore().GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var storages = snapshot.Storages; var cache = new CloneCache(storages); @@ -98,7 +98,7 @@ public void TestCachedFind_Last() [TestMethod] public void TestCachedFind_Empty() { - var snapshot = TestBlockchain.GetStore().GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var storages = snapshot.Storages; var cache = new CloneCache(storages); diff --git a/tests/neo.UnitTests/UT_NeoSystem.cs b/tests/neo.UnitTests/UT_NeoSystem.cs index 2d71db97df..1ed00464fa 100644 --- a/tests/neo.UnitTests/UT_NeoSystem.cs +++ b/tests/neo.UnitTests/UT_NeoSystem.cs @@ -1,4 +1,4 @@ -using FluentAssertions; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Neo.UnitTests @@ -11,7 +11,7 @@ public class UT_NeoSystem [TestInitialize] public void Setup() { - neoSystem = TestBlockchain.InitializeMockNeoSystem(); + neoSystem = TestBlockchain.TheNeoSystem; } [TestMethod] diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index e6bf40721c..ed02f4d61e 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -3,7 +3,6 @@ using Neo.Cryptography.ECC; using Neo.Ledger; using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.SmartContract.Native.Tokens; @@ -90,7 +89,6 @@ public override bool VerifyPassword(string password) [TestClass] public class UT_Wallet { - Store store; private static KeyPair glkey; private static string nep2Key; @@ -104,7 +102,7 @@ public static void ClassInit(TestContext context) [TestInitialize] public void TestSetup() { - store = TestBlockchain.GetStore(); + TestBlockchain.InitializeMockNeoSystem(); } [TestMethod] @@ -198,7 +196,7 @@ public void TestGetAvailable() account.Lock = false; // Fake balance - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem { @@ -209,6 +207,7 @@ public void TestGetAvailable() Balance = 10000 * NativeContract.GAS.Factor } .ToByteArray(); + snapshot.Commit(); wallet.GetAvailable(NativeContract.GAS.Hash).Should().Be(new BigDecimal(1000000000000, 8)); @@ -217,6 +216,7 @@ public void TestGetAvailable() Balance = 0 } .ToByteArray(); + snapshot.Commit(); } [TestMethod] @@ -228,7 +228,7 @@ public void TestGetBalance() account.Lock = false; // Fake balance - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem { @@ -239,6 +239,7 @@ public void TestGetBalance() Balance = 10000 * NativeContract.GAS.Factor } .ToByteArray(); + snapshot.Commit(); wallet.GetBalance(UInt160.Zero, new UInt160[] { account.ScriptHash }).Should().Be(new BigDecimal(0, 0)); wallet.GetBalance(NativeContract.GAS.Hash, new UInt160[] { account.ScriptHash }).Should().Be(new BigDecimal(1000000000000, 8)); @@ -248,6 +249,7 @@ public void TestGetBalance() Balance = 0 } .ToByteArray(); + snapshot.Commit(); } [TestMethod] @@ -336,29 +338,31 @@ public void TestMakeTransaction1() action.Should().Throw(); // Fake balance - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem + var entry1 = snapshot.Storages.GetAndChange(key, () => new StorageItem { Value = new Nep5AccountState().ToByteArray() }); - entry.Value = new Nep5AccountState() + entry1.Value = new Nep5AccountState() { Balance = 10000 * NativeContract.GAS.Factor } .ToByteArray(); key = NativeContract.NEO.CreateStorageKey(20, account.ScriptHash); - entry = snapshot.Storages.GetAndChange(key, () => new StorageItem + var entry2 = snapshot.Storages.GetAndChange(key, () => new StorageItem { Value = new Nep5AccountState().ToByteArray() }); - entry.Value = new NeoToken.AccountState() + entry2.Value = new NeoToken.AccountState() { Balance = 10000 * NativeContract.NEO.Factor } .ToByteArray(); + snapshot.Commit(); + var tx = wallet.MakeTransaction(new TransferOutput[] { new TransferOutput() @@ -381,11 +385,17 @@ public void TestMakeTransaction1() }); tx.Should().NotBeNull(); - entry.Value = new NeoToken.AccountState() + entry1.Value = new Nep5AccountState() + { + Balance = 0 + } + .ToByteArray(); + entry2.Value = new NeoToken.AccountState() { Balance = 0 } .ToByteArray(); + snapshot.Commit(); } [TestMethod] @@ -400,7 +410,7 @@ public void TestMakeTransaction2() account.Lock = false; // Fake balance - var snapshot = store.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem { @@ -411,6 +421,7 @@ public void TestMakeTransaction2() Balance = 1000000 * NativeContract.GAS.Factor } .ToByteArray(); + snapshot.Commit(); var tx = wallet.MakeTransaction(new byte[] { }, account.ScriptHash, new TransactionAttribute[] { }); tx.Should().NotBeNull(); @@ -423,6 +434,7 @@ public void TestMakeTransaction2() Balance = 0 } .ToByteArray(); + snapshot.Commit(); } [TestMethod]