From f114093c327669a01f02559f22fdc563d8b2c030 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 5 Jun 2020 16:18:56 +0800 Subject: [PATCH 01/39] don't use snapshot directly in plugin --- src/neo/Ledger/Blockchain.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index b10a60e870..4e67789072 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -443,7 +443,7 @@ private void Persist(Block block) } snapshot.BlockHashIndex.GetAndChange().Set(block); foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) - plugin.OnPersist(snapshot, all_application_executed); + plugin.OnPersist(snapshot.Clone(), all_application_executed); snapshot.Commit(); List commitExceptions = null; foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) From a8faab8613f05938a2b69ee468dbcaa655a073a9 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Mon, 8 Jun 2020 19:09:08 +0800 Subject: [PATCH 02/39] persistence and ut --- src/neo/Ledger/HashState.cs | 41 ++++++ src/neo/Network/P2P/MessageCommand.cs | 2 + src/neo/Network/P2P/Payloads/InventoryType.cs | 1 + src/neo/Network/P2P/Payloads/StateRoot.cs | 127 ++++++++++++++++++ src/neo/Persistence/ClonedView.cs | 10 +- src/neo/Persistence/Prefixes.cs | 3 + src/neo/Persistence/ReadOnlyView.cs | 7 +- src/neo/Persistence/SnapshotView.cs | 18 ++- src/neo/Persistence/StoreView.cs | 12 +- .../ApplicationEngine.Storage.cs | 10 +- .../SmartContract/Native/PolicyContract.cs | 30 +++-- .../SmartContract/Native/Tokens/NeoToken.cs | 38 ++++-- .../SmartContract/Native/Tokens/Nep5Token.cs | 41 ++++-- tests/neo.UnitTests/Consensus/UT_Consensus.cs | 2 +- tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 6 +- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 4 +- .../Network/P2P/Payloads/UT_Transaction.cs | 57 ++++---- tests/neo.UnitTests/Network/P2P/UT_Message.cs | 4 +- .../Native/Tokens/UT_GasToken.cs | 12 +- .../Native/Tokens/UT_NeoToken.cs | 30 ++--- .../Native/Tokens/UT_Nep5Token.cs | 4 +- .../SmartContract/Native/UT_PolicyContract.cs | 4 +- .../SmartContract/UT_InteropPrices.cs | 8 +- .../SmartContract/UT_InteropService.NEO.cs | 4 +- .../SmartContract/UT_InteropService.cs | 13 +- tests/neo.UnitTests/UT_DataCache.cs | 15 ++- tests/neo.UnitTests/Wallets/UT_Wallet.cs | 40 ++++-- 27 files changed, 393 insertions(+), 150 deletions(-) create mode 100644 src/neo/Ledger/HashState.cs create mode 100644 src/neo/Network/P2P/Payloads/StateRoot.cs diff --git a/src/neo/Ledger/HashState.cs b/src/neo/Ledger/HashState.cs new file mode 100644 index 0000000000..9b268b580f --- /dev/null +++ b/src/neo/Ledger/HashState.cs @@ -0,0 +1,41 @@ +using Neo.IO; +using Neo.Network.P2P.Payloads; +using System.IO; + +namespace Neo.Ledger +{ + public class HashState : ICloneable, ISerializable + { + public UInt256 Hash = UInt256.Zero; + + int ISerializable.Size => Hash.Size; + + HashState ICloneable.Clone() + { + return new HashState + { + Hash = Hash + }; + } + + void ISerializable.Deserialize(BinaryReader reader) + { + Hash = reader.ReadSerializable(); + } + + void ICloneable.FromReplica(HashState replica) + { + Hash = replica.Hash; + } + + void ISerializable.Serialize(BinaryWriter writer) + { + writer.Write(Hash); + } + + internal void Set(BlockBase block) + { + Hash = block.Hash; + } + } +} diff --git a/src/neo/Network/P2P/MessageCommand.cs b/src/neo/Network/P2P/MessageCommand.cs index 89c21597cf..1c3ce68659 100644 --- a/src/neo/Network/P2P/MessageCommand.cs +++ b/src/neo/Network/P2P/MessageCommand.cs @@ -40,6 +40,8 @@ public enum MessageCommand : byte Block = 0x2c, [ReflectionCache(typeof(ConsensusPayload))] Consensus = 0x2d, + [ReflectionCache(typeof(StateRoot))] + StateRoot = 0x2e, Reject = 0x2f, //SPV protocol diff --git a/src/neo/Network/P2P/Payloads/InventoryType.cs b/src/neo/Network/P2P/Payloads/InventoryType.cs index 0a1b831d12..9effb99556 100644 --- a/src/neo/Network/P2P/Payloads/InventoryType.cs +++ b/src/neo/Network/P2P/Payloads/InventoryType.cs @@ -4,6 +4,7 @@ public enum InventoryType : byte { TX = MessageCommand.Transaction, Block = MessageCommand.Block, + StateRoot = MessageCommand.StateRoot, Consensus = MessageCommand.Consensus } } diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs new file mode 100644 index 0000000000..561ba3f5a5 --- /dev/null +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -0,0 +1,127 @@ +using Neo.Cryptography; +using Neo.IO; +using Neo.IO.Json; +using Neo.Ledger; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using System; +using System.IO; + +namespace Neo.Network.P2P.Payloads +{ + public class StateRoot : ICloneable, IInventory + { + public byte Version; + public uint Index; + public UInt256 Root; + public Witness Witness; + + InventoryType IInventory.InventoryType => InventoryType.StateRoot; + + private UInt256 _hash = null; + + public UInt256 Hash + { + get + { + if (_hash == null) + { + _hash = new UInt256(Crypto.Hash256(this.GetHashData())); + } + return _hash; + } + } + + Witness[] IVerifiable.Witnesses + { + get + { + return new[] { Witness }; + } + set + { + if (value.Length != 1) throw new ArgumentException(); + Witness = value[0]; + } + } + + public int Size => + sizeof(byte) + + sizeof(uint) + + UInt256.Length + + Witness.Size; + + StateRoot ICloneable.Clone() + { + return new StateRoot + { + Version = Version, + Index = Index, + Root = Root, + Witness = Witness, + }; + } + + void ICloneable.FromReplica(StateRoot replica) + { + Version = replica.Version; + Index = replica.Index; + Root = replica.Root; + Witness = replica.Witness; + } + + public void Deserialize(BinaryReader reader) + { + this.DeserializeUnsigned(reader); + Witness = reader.ReadSerializable(); + } + + public void DeserializeUnsigned(BinaryReader reader) + { + Version = reader.ReadByte(); + Index = reader.ReadUInt32(); + Root = reader.ReadSerializable(); + } + + public void Serialize(BinaryWriter writer) + { + this.SerializeUnsigned(writer); + writer.Write(Witness); + } + + public void SerializeUnsigned(BinaryWriter writer) + { + writer.Write(Version); + writer.Write(Index); + writer.Write(Root); + } + + public bool Verify(StoreView snapshot) + { + return this.VerifyWitnesses(snapshot, + ApplicationEngine.ECDsaVerifyPrice * (NativeContract.NEO.GetValidators(Blockchain.Singleton.GetSnapshot()).Length + 1)); + } + + public virtual UInt160[] GetScriptHashesForVerifying(StoreView snapshot) + { + var script_hash = Blockchain.Singleton.GetBlock(Index)?.NextConsensus; + return script_hash is null ? Array.Empty() : new UInt160[] { script_hash }; + } + + public byte[] GetMessage() + { + return this.GetHashData(); + } + + public JObject ToJson() + { + var json = new JObject(); + json["version"] = Version; + json["index"] = Index; + json["stateroot"] = Root.ToString(); + json["witness"] = Witness.ToJson(); + return json; + } + } +} diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index 307438b2db..846d700032 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -1,6 +1,7 @@ using Neo.IO; using Neo.IO.Caching; using Neo.Ledger; +using Neo.Network.P2P.Payloads; namespace Neo.Persistence { @@ -9,10 +10,12 @@ internal class ClonedView : StoreView public override DataCache Blocks { get; } public override DataCache Transactions { get; } public override DataCache Contracts { get; } - public override DataCache Storages { get; } public override DataCache, HeaderHashList> HeaderHashList { get; } + public override DataCache, HashState> LocalRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } + public override MetaDataCache LocalRootHashIndex { get; } + public override MetaDataCache ConfirmedRootHashIndex { get; } public override MetaDataCache ContractId { get; } public ClonedView(StoreView view) @@ -21,11 +24,14 @@ public ClonedView(StoreView view) 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.LocalRoot = view.LocalRoot.CreateSnapshot(); this.BlockHashIndex = view.BlockHashIndex.CreateSnapshot(); this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot(); + this.LocalRootHashIndex = view.LocalRootHashIndex.CreateSnapshot(); + this.ConfirmedRootHashIndex = view.ConfirmedRootHashIndex.CreateSnapshot(); this.ContractId = view.ContractId.CreateSnapshot(); + this.Storages = view.Storages; } } } diff --git a/src/neo/Persistence/Prefixes.cs b/src/neo/Persistence/Prefixes.cs index 421fe086c3..fba6d0fa69 100644 --- a/src/neo/Persistence/Prefixes.cs +++ b/src/neo/Persistence/Prefixes.cs @@ -7,11 +7,14 @@ internal static class Prefixes public const byte ST_Contract = 0x50; public const byte ST_Storage = 0x70; + public const byte ST_Root = 0x60; public const byte IX_HeaderHashList = 0x80; public const byte IX_CurrentBlock = 0xc0; public const byte IX_CurrentHeader = 0xc1; public const byte IX_ContractId = 0xc2; + public const byte IX_CurrentRoot = 0xc3; + public const byte IX_ConfirmedRoot = 0xc4; /* Prefixes 0xf0 to 0xff are reserved for external use. * diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index 5f87f236ab..fde9c13d2b 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -1,6 +1,8 @@ +using Neo.Cryptography.MPT; using Neo.IO; using Neo.IO.Caching; using Neo.Ledger; +using Neo.Network.P2P.Payloads; using System; namespace Neo.Persistence @@ -15,11 +17,14 @@ public class ReadOnlyView : StoreView 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> HeaderHashList => new StoreDataCache, HeaderHashList>(store, Prefixes.IX_HeaderHashList); + public override DataCache, HashState> LocalRoot => new StoreDataCache, HashState>(store, Prefixes.ST_Root); public override MetaDataCache BlockHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentBlock); public override MetaDataCache HeaderHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentHeader); + public override MetaDataCache LocalRootHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentRoot); + public override MetaDataCache ConfirmedRootHashIndex => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); public override MetaDataCache ContractId => new StoreMetaDataCache(store, Prefixes.IX_ContractId); + public new MPTTrie Storages => new MPTTrie((ISnapshot)store, LocalRootHashIndex.Get().Hash); public ReadOnlyView(IReadOnlyStore store) { diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index d634200134..61651c0fdd 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -1,6 +1,8 @@ +using Neo.Cryptography.MPT; using Neo.IO; using Neo.IO.Caching; using Neo.Ledger; +using Neo.Network.P2P.Payloads; using System; namespace Neo.Persistence @@ -15,10 +17,12 @@ public class SnapshotView : StoreView, IDisposable public override DataCache Blocks { get; } public override DataCache Transactions { get; } public override DataCache Contracts { get; } - public override DataCache Storages { get; } public override DataCache, HeaderHashList> HeaderHashList { get; } + public override DataCache, HashState> LocalRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } + public override MetaDataCache LocalRootHashIndex { get; } + public override MetaDataCache ConfirmedRootHashIndex { get; } public override MetaDataCache ContractId { get; } public SnapshotView(IStore store) @@ -27,15 +31,25 @@ public SnapshotView(IStore store) 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, HeaderHashList>(snapshot, Prefixes.IX_HeaderHashList); + LocalRoot = new StoreDataCache, HashState>(snapshot, Prefixes.ST_Root); BlockHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentBlock); HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); + LocalRootHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentRoot); + ConfirmedRootHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); + Storages = new MPTTrie(snapshot, CurrentRootHash); } public override void Commit() { + var current_root = LocalRootHashIndex.GetAndChange(); + current_root.Hash = Storages.Root.Hash; + current_root.Index = Height; + LocalRoot.Add(Height, new HashState() + { + Hash = Storages.Root.Hash + }); base.Commit(); snapshot.Commit(); } diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index c0126b0c95..4b9b0d6db8 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -1,3 +1,4 @@ +using Neo.Cryptography.MPT; using Neo.IO; using Neo.IO.Caching; using Neo.Ledger; @@ -14,17 +15,22 @@ public abstract class StoreView public abstract DataCache Blocks { get; } public abstract DataCache Transactions { get; } public abstract DataCache Contracts { get; } - public abstract DataCache Storages { get; } public abstract DataCache, HeaderHashList> HeaderHashList { get; } + public abstract DataCache, HashState> LocalRoot { get; } public abstract MetaDataCache BlockHashIndex { get; } public abstract MetaDataCache HeaderHashIndex { get; } + public abstract MetaDataCache LocalRootHashIndex { get; } + public abstract MetaDataCache ConfirmedRootHashIndex { get; } public abstract MetaDataCache ContractId { get; } + public MPTTrie Storages; public uint Height => BlockHashIndex.Get().Index; public uint HeaderHeight => HeaderHashIndex.Get().Index; public UInt256 CurrentBlockHash => BlockHashIndex.Get().Hash; + public UInt256 CurrentRootHash => LocalRootHashIndex.Get().Hash; public UInt256 CurrentHeaderHash => HeaderHashIndex.Get().Hash; + public StoreView Clone() { return new ClonedView(this); @@ -35,11 +41,13 @@ public virtual void Commit() Blocks.Commit(); Transactions.Commit(); Contracts.Commit(); - Storages.Commit(); HeaderHashList.Commit(); + LocalRoot.Commit(); BlockHashIndex.Commit(); HeaderHashIndex.Commit(); ContractId.Commit(); + LocalRootHashIndex.Commit(); + ConfirmedRootHashIndex.Commit(); } public bool ContainsBlock(UInt256 hash) diff --git a/src/neo/SmartContract/ApplicationEngine.Storage.cs b/src/neo/SmartContract/ApplicationEngine.Storage.cs index b579c5f37f..482c0514d7 100644 --- a/src/neo/SmartContract/ApplicationEngine.Storage.cs +++ b/src/neo/SmartContract/ApplicationEngine.Storage.cs @@ -55,11 +55,11 @@ internal StorageContext AsReadOnly(StorageContext context) internal byte[] Get(StorageContext context, byte[] key) { - return Snapshot.Storages.TryGet(new StorageKey + return Snapshot.Storages[new StorageKey { Id = context.Id, Key = key.ToArray() - })?.Value; + }]?.Value; } internal IIterator Find(StorageContext context, byte[] prefix) @@ -91,11 +91,11 @@ private void PutExInternal(StorageContext context, byte[] key, byte[] value, Sto Id = context.Id, Key = key }; - StorageItem item = Snapshot.Storages.GetAndChange(skey); + StorageItem item = Snapshot.Storages[skey]; if (item is null) { newDataSize = key.Length + value.Length; - Snapshot.Storages.Add(skey, item = new StorageItem()); + Snapshot.Storages.Put(skey, item = new StorageItem()); } else { @@ -119,7 +119,7 @@ internal void Delete(StorageContext context, byte[] key) Id = context.Id, Key = key }; - if (Snapshot.Storages.TryGet(skey)?.IsConstant == true) + if (Snapshot.Storages[skey]?.IsConstant == true) throw new InvalidOperationException(); Snapshot.Storages.Delete(skey); } diff --git a/src/neo/SmartContract/Native/PolicyContract.cs b/src/neo/SmartContract/Native/PolicyContract.cs index 2bd2244a96..41c33ae92b 100644 --- a/src/neo/SmartContract/Native/PolicyContract.cs +++ b/src/neo/SmartContract/Native/PolicyContract.cs @@ -46,19 +46,19 @@ private bool CheckCommittees(ApplicationEngine engine) internal override void Initialize(ApplicationEngine engine) { - engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_MaxBlockSize), new StorageItem + engine.Snapshot.Storages.Put(CreateStorageKey(Prefix_MaxBlockSize), new StorageItem { Value = BitConverter.GetBytes(1024u * 256u) }); - engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_MaxTransactionsPerBlock), new StorageItem + engine.Snapshot.Storages.Put(CreateStorageKey(Prefix_MaxTransactionsPerBlock), new StorageItem { Value = BitConverter.GetBytes(512u) }); - engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_FeePerByte), new StorageItem + engine.Snapshot.Storages.Put(CreateStorageKey(Prefix_FeePerByte), new StorageItem { Value = BitConverter.GetBytes(1000L) }); - engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_BlockedAccounts), new StorageItem + engine.Snapshot.Storages.Put(CreateStorageKey(Prefix_BlockedAccounts), new StorageItem { Value = new UInt160[0].ToByteArray() }); @@ -114,8 +114,10 @@ private StackItem SetMaxBlockSize(ApplicationEngine engine, Array args) if (!CheckCommittees(engine)) return false; uint value = (uint)args[0].GetBigInteger(); if (Network.P2P.Message.PayloadMaxSize <= value) return false; - StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxBlockSize)); - storage.Value = BitConverter.GetBytes(value); + StorageKey skey = CreateStorageKey(Prefix_MaxBlockSize); + StorageItem item = engine.Snapshot.Storages[skey]; + item.Value = BitConverter.GetBytes(value); + engine.Snapshot.Storages.Put(skey, item); return true; } @@ -124,8 +126,10 @@ private StackItem SetMaxTransactionsPerBlock(ApplicationEngine engine, Array arg { if (!CheckCommittees(engine)) return false; uint value = (uint)args[0].GetBigInteger(); - StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxTransactionsPerBlock)); - storage.Value = BitConverter.GetBytes(value); + StorageKey skey = CreateStorageKey(Prefix_MaxTransactionsPerBlock); + StorageItem item = engine.Snapshot.Storages[skey]; + item.Value = BitConverter.GetBytes(value); + engine.Snapshot.Storages.Put(skey, item); return true; } @@ -134,8 +138,10 @@ private StackItem SetFeePerByte(ApplicationEngine engine, Array args) { if (!CheckCommittees(engine)) return false; long value = (long)args[0].GetBigInteger(); - StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_FeePerByte)); - storage.Value = BitConverter.GetBytes(value); + StorageKey skey = CreateStorageKey(Prefix_FeePerByte); + StorageItem item = engine.Snapshot.Storages[skey]; + item.Value = BitConverter.GetBytes(value); + engine.Snapshot.Storages.Put(skey, item); return true; } @@ -148,8 +154,8 @@ private StackItem BlockAccount(ApplicationEngine engine, Array args) StorageItem storage = engine.Snapshot.Storages[key]; SortedSet accounts = new SortedSet(storage.Value.AsSerializableArray()); if (!accounts.Add(account)) return false; - storage = engine.Snapshot.Storages.GetAndChange(key); storage.Value = accounts.ToByteArray(); + engine.Snapshot.Storages.Put(key, storage); return true; } @@ -162,8 +168,8 @@ private StackItem UnblockAccount(ApplicationEngine engine, Array args) StorageItem storage = engine.Snapshot.Storages[key]; SortedSet accounts = new SortedSet(storage.Value.AsSerializableArray()); if (!accounts.Remove(account)) return false; - storage = engine.Snapshot.Storages.GetAndChange(key); storage.Value = accounts.ToByteArray(); + engine.Snapshot.Storages.Put(key, storage); return true; } } diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 1c63485b5c..f6ef2b0a06 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -42,9 +42,11 @@ protected override void OnBalanceChanging(ApplicationEngine engine, UInt160 acco if (amount.IsZero) return; if (state.VoteTo != null) { - StorageItem storage_validator = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Candidate, state.VoteTo.ToArray())); + StorageKey skey = CreateStorageKey(Prefix_Candidate, state.VoteTo.ToArray()); + StorageItem storage_validator = engine.Snapshot.Storages[skey]; CandidateState state_validator = storage_validator.GetInteroperable(); state_validator.Votes += amount; + engine.Snapshot.Storages.Put(skey, storage_validator); } } @@ -107,8 +109,11 @@ internal override void Initialize(ApplicationEngine engine) protected override bool OnPersist(ApplicationEngine engine) { if (!base.OnPersist(engine)) return false; - StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_NextValidators), () => new StorageItem()); - storage.Value = GetValidators(engine.Snapshot).ToByteArray(); + StorageItem storage = new StorageItem() + { + Value = GetValidators(engine.Snapshot).ToByteArray() + }; + engine.Snapshot.Storages.Put(CreateStorageKey(Prefix_NextValidators), storage); return true; } @@ -122,7 +127,7 @@ private StackItem UnclaimedGas(ApplicationEngine engine, Array args) public BigInteger UnclaimedGas(StoreView snapshot, UInt160 account, uint end) { - StorageItem storage = snapshot.Storages.TryGet(CreateAccountKey(account)); + StorageItem storage = snapshot.Storages[CreateAccountKey(account)]; if (storage is null) return BigInteger.Zero; NeoAccountState state = storage.GetInteroperable(); return CalculateBonus(snapshot, state.Balance, state.BalanceHeight, end); @@ -140,9 +145,10 @@ private StackItem RegisterCandidate(ApplicationEngine engine, Array args) private bool RegisterCandidate(StoreView snapshot, ECPoint pubkey) { StorageKey key = CreateStorageKey(Prefix_Candidate, pubkey); - StorageItem item = snapshot.Storages.GetAndChange(key, () => new StorageItem(new CandidateState())); + StorageItem item = new StorageItem(new CandidateState()); CandidateState state = item.GetInteroperable(); state.Registered = true; + snapshot.Storages.Put(key, item); return true; } @@ -158,13 +164,16 @@ private StackItem UnregisterCandidate(ApplicationEngine engine, Array args) private bool UnregisterCandidate(StoreView snapshot, ECPoint pubkey) { StorageKey key = CreateStorageKey(Prefix_Candidate, pubkey); - if (snapshot.Storages.TryGet(key) is null) return true; - StorageItem item = snapshot.Storages.GetAndChange(key); + if (snapshot.Storages[key] is null) return true; + StorageItem item = snapshot.Storages[key]; CandidateState state = item.GetInteroperable(); if (state.Votes.IsZero) snapshot.Storages.Delete(key); else + { state.Registered = false; + snapshot.Storages.Put(key, item); + } return true; } @@ -180,27 +189,30 @@ private StackItem Vote(ApplicationEngine engine, Array args) private bool Vote(StoreView snapshot, UInt160 account, ECPoint voteTo) { StorageKey key_account = CreateAccountKey(account); - if (snapshot.Storages.TryGet(key_account) is null) return false; - StorageItem storage_account = snapshot.Storages.GetAndChange(key_account); + if (snapshot.Storages[key_account] is null) return false; + StorageItem storage_account = snapshot.Storages[key_account]; NeoAccountState state_account = storage_account.GetInteroperable(); if (state_account.VoteTo != null) { StorageKey key = CreateStorageKey(Prefix_Candidate, state_account.VoteTo.ToArray()); - StorageItem storage_validator = snapshot.Storages.GetAndChange(key); + StorageItem storage_validator = snapshot.Storages[key]; CandidateState state_validator = storage_validator.GetInteroperable(); state_validator.Votes -= state_account.Balance; if (!state_validator.Registered && state_validator.Votes.IsZero) snapshot.Storages.Delete(key); + else + snapshot.Storages.Put(key, storage_validator); } state_account.VoteTo = voteTo; if (voteTo != null) { StorageKey key = CreateStorageKey(Prefix_Candidate, voteTo.ToArray()); - if (snapshot.Storages.TryGet(key) is null) return false; - StorageItem storage_validator = snapshot.Storages.GetAndChange(key); + if (snapshot.Storages[key] is null) return false; + StorageItem storage_validator = snapshot.Storages[key]; CandidateState state_validator = storage_validator.GetInteroperable(); if (!state_validator.Registered) return false; state_validator.Votes += state_account.Balance; + snapshot.Storages.Put(key, storage_validator); } return true; } @@ -262,7 +274,7 @@ private StackItem GetNextBlockValidators(ApplicationEngine engine, Array args) public ECPoint[] GetNextBlockValidators(StoreView snapshot) { - StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_NextValidators)); + StorageItem storage = snapshot.Storages[CreateStorageKey(Prefix_NextValidators)]; if (storage is null) return Blockchain.StandbyValidators; return storage.Value.AsSerializableArray(); } diff --git a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs index 855d864c59..26e7435025 100644 --- a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs +++ b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs @@ -69,17 +69,27 @@ internal protected virtual void Mint(ApplicationEngine engine, UInt160 account, { if (amount.Sign < 0) throw new ArgumentOutOfRangeException(nameof(amount)); if (amount.IsZero) return; - StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateAccountKey(account), () => new StorageItem(new TState())); + StorageKey skey = CreateAccountKey(account); + StorageItem storage = engine.Snapshot.Storages[skey]; + if (storage is null) storage = new StorageItem(new TState()); TState state = storage.GetInteroperable(); OnBalanceChanging(engine, account, state, amount); state.Balance += amount; - storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_TotalSupply), () => new StorageItem + engine.Snapshot.Storages.Put(skey, storage); + + skey = CreateStorageKey(Prefix_TotalSupply); + storage = engine.Snapshot.Storages[skey]; + if (storage is null) { - Value = BigInteger.Zero.ToByteArrayStandard() - }); + storage = new StorageItem() + { + Value = BigInteger.Zero.ToByteArrayStandard() + }; + } BigInteger totalSupply = new BigInteger(storage.Value); totalSupply += amount; storage.Value = totalSupply.ToByteArrayStandard(); + engine.Snapshot.Storages.Put(skey, storage); engine.SendNotification(Hash, new Array(new StackItem[] { "Transfer", StackItem.Null, account.ToArray(), amount })); } @@ -88,18 +98,24 @@ internal protected virtual void Burn(ApplicationEngine engine, UInt160 account, if (amount.Sign < 0) throw new ArgumentOutOfRangeException(nameof(amount)); if (amount.IsZero) return; StorageKey key = CreateAccountKey(account); - StorageItem storage = engine.Snapshot.Storages.GetAndChange(key); + StorageItem storage = engine.Snapshot.Storages[key]; TState state = storage.GetInteroperable(); if (state.Balance < amount) throw new InvalidOperationException(); OnBalanceChanging(engine, account, state, -amount); if (state.Balance == amount) engine.Snapshot.Storages.Delete(key); else + { state.Balance -= amount; - storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_TotalSupply)); + engine.Snapshot.Storages.Put(key, storage); + } + + key = CreateStorageKey(Prefix_TotalSupply); + storage = engine.Snapshot.Storages[key]; BigInteger totalSupply = new BigInteger(storage.Value); totalSupply -= amount; storage.Value = totalSupply.ToByteArrayStandard(); + engine.Snapshot.Storages.Put(key, storage); engine.SendNotification(Hash, new Array(new StackItem[] { "Transfer", account.ToArray(), StackItem.Null, amount })); } @@ -129,7 +145,7 @@ protected StackItem TotalSupply(ApplicationEngine engine, Array args) public virtual BigInteger TotalSupply(StoreView snapshot) { - StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_TotalSupply)); + StorageItem storage = snapshot.Storages[CreateStorageKey(Prefix_TotalSupply)]; if (storage is null) return BigInteger.Zero; return new BigInteger(storage.Value); } @@ -142,7 +158,7 @@ protected StackItem BalanceOf(ApplicationEngine engine, Array args) public virtual BigInteger BalanceOf(StoreView snapshot, UInt160 account) { - StorageItem storage = snapshot.Storages.TryGet(CreateAccountKey(account)); + StorageItem storage = snapshot.Storages[CreateAccountKey(account)]; if (storage is null) return BigInteger.Zero; return storage.GetInteroperable().Balance; } @@ -164,7 +180,7 @@ protected virtual bool Transfer(ApplicationEngine engine, UInt160 from, UInt160 ContractState contract_to = engine.Snapshot.Contracts.TryGet(to); if (contract_to?.Payable == false) return false; StorageKey key_from = CreateAccountKey(from); - StorageItem storage_from = engine.Snapshot.Storages.GetAndChange(key_from); + StorageItem storage_from = engine.Snapshot.Storages[key_from]; if (amount.IsZero) { if (storage_from != null) @@ -188,12 +204,17 @@ protected virtual bool Transfer(ApplicationEngine engine, UInt160 from, UInt160 if (state_from.Balance == amount) engine.Snapshot.Storages.Delete(key_from); else + { state_from.Balance -= amount; + engine.Snapshot.Storages.Put(key_from, storage_from); + } StorageKey key_to = CreateAccountKey(to); - StorageItem storage_to = engine.Snapshot.Storages.GetAndChange(key_to, () => new StorageItem(new TState())); + StorageItem storage_to = engine.Snapshot.Storages[key_to]; + if (storage_to is null) storage_to = new StorageItem(new TState()); TState state_to = storage_to.GetInteroperable(); OnBalanceChanging(engine, to, state_to, amount); state_to.Balance += amount; + engine.Snapshot.Storages.Put(key_to, storage_to); } } engine.SendNotification(Hash, new Array(new StackItem[] { "Transfer", from.ToArray(), to.ToArray(), amount })); diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 86eb6bc8c2..5613d888a6 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -272,7 +272,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine($"\nContract updated: {updatedContract.ScriptHash}"); // =============================================================== - mockContext.Object.Snapshot.Storages.Add(CreateStorageKeyForNativeNeo(14), new StorageItem() + mockContext.Object.Snapshot.Storages.Put(CreateStorageKeyForNativeNeo(14), new StorageItem() { Value = mockContext.Object.Validators.ToByteArray() }); diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index 7e04dfe229..b7fe1af7fc 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -116,10 +116,10 @@ public void TestValidTransaction() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; - + snapshot.Storages.Put(key, entry); snapshot.Commit(); typeof(Blockchain) diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 4e96605b7b..b420190f38 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -485,8 +485,8 @@ public void TestUpdatePoolForBlockPersisted() var key2 = CreateStorageKey(Prefix_FeePerByte); key1.Id = NativeContract.Policy.Id; key2.Id = NativeContract.Policy.Id; - snapshot.Storages.Add(key1, item1); - snapshot.Storages.Add(key2, item2); + snapshot.Storages.Put(key1, item1); + snapshot.Storages.Put(key2, item2); var tx1 = CreateTransaction(); var tx2 = CreateTransaction(); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 7e025ad4cd..7781cbfc86 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -107,10 +107,10 @@ public void FeeIsMultiSigContract() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.Storages.Put(key, entry); snapshot.Commit(); // Make transaction @@ -177,10 +177,10 @@ public void FeeIsSignatureContractDetailed() var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.Storages.Put(key, entry); snapshot.Commit(); // Make transaction @@ -288,10 +288,10 @@ public void FeeIsSignatureContract_TestScope_Global() var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.Storages.Put(key, entry); snapshot.Commit(); // Make transaction @@ -374,10 +374,10 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.Storages.Put(key, entry); snapshot.Commit(); // Make transaction @@ -461,10 +461,10 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.Storages.Put(key, entry); snapshot.Commit(); // Make transaction @@ -551,10 +551,10 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.Storages.Put(key, entry); // Make transaction // Manually creating script @@ -600,11 +600,10 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.Storages.Put(key, entry); snapshot.Commit(); // Make transaction @@ -692,11 +691,10 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.Storages.Put(key, entry); // Make transaction // Manually creating script @@ -938,11 +936,10 @@ public void FeeIsSignatureContract_TestScope_Global_Default() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.Storages.Put(key, entry); snapshot.Commit(); // Make transaction diff --git a/tests/neo.UnitTests/Network/P2P/UT_Message.cs b/tests/neo.UnitTests/Network/P2P/UT_Message.cs index 6f194ea862..574af05322 100644 --- a/tests/neo.UnitTests/Network/P2P/UT_Message.cs +++ b/tests/neo.UnitTests/Network/P2P/UT_Message.cs @@ -14,7 +14,7 @@ public class UT_Message [TestMethod] public void Serialize_Deserialize() { - var payload = PingPayload.Create(uint.MaxValue); + var payload = PingPayload.Create(uint.MaxValue, 0); var msg = Message.Create(MessageCommand.Ping, payload); var buffer = msg.ToArray(); var copy = buffer.AsSerializable(); @@ -31,7 +31,7 @@ public void Serialize_Deserialize() [TestMethod] public void Serialize_Deserialize_ByteString() { - var payload = PingPayload.Create(uint.MaxValue); + var payload = PingPayload.Create(uint.MaxValue, 0); var msg = Message.Create(MessageCommand.Ping, payload); var buffer = ByteString.CopyFrom(msg.ToArray()); var length = Message.TryDeserialize(buffer, out var copy); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index f7be52f9a6..a3b99c6ddd 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -44,7 +44,6 @@ public void Check_BalanceOfTransferAndBurn() byte[] to = new byte[20]; - var keyCount = snapshot.Storages.GetChangeSet().Count(); var supply = NativeContract.GAS.TotalSupply(snapshot); supply.Should().Be(3000000000000000); @@ -67,18 +66,15 @@ public void Check_BalanceOfTransferAndBurn() // Check unclaim unclaim = UT_NeoToken.Check_UnclaimedGas(snapshot, from); - unclaim.Value.Should().Be(new BigInteger(0)); + unclaim.Value.Should().Be(new BigInteger(300000048000)); unclaim.State.Should().BeTrue(); supply = NativeContract.GAS.TotalSupply(snapshot); supply.Should().Be(3000300000048000); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 3); // Gas // Transfer - keyCount = snapshot.Storages.GetChangeSet().Count(); - NativeContract.GAS.Transfer(snapshot, from, to, 3000300000048000, false).Should().BeFalse(); // Not signed NativeContract.GAS.Transfer(snapshot, from, to, 3000300000048001, true).Should().BeFalse(); // More than balance NativeContract.GAS.Transfer(snapshot, from, to, 3000300000048000, true).Should().BeTrue(); // All balance @@ -88,12 +84,9 @@ public void Check_BalanceOfTransferAndBurn() NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(3000300000048000); NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(0); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 1); // All - // Burn var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); - keyCount = snapshot.Storages.GetChangeSet().Count(); Assert.ThrowsException(() => NativeContract.GAS.Burn(engine, new UInt160(to), BigInteger.MinusOne)); @@ -109,14 +102,11 @@ public void Check_BalanceOfTransferAndBurn() NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(3000300000047999); - keyCount.Should().Be(snapshot.Storages.GetChangeSet().Count()); // Burn all NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(3000300000047999)); - (keyCount - 1).Should().Be(snapshot.Storages.GetChangeSet().Count()); - // Bad inputs NativeContract.GAS.Transfer(snapshot, from, to, BigInteger.MinusOne, true).Should().BeFalse(); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 12b025400b..965ed84795 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -100,14 +100,12 @@ public void Check_RegisterValidator() { var snapshot = Blockchain.Singleton.GetSnapshot(); - var keyCount = snapshot.Storages.GetChangeSet().Count(); var point = Blockchain.StandbyValidators[0].EncodePoint(true); var ret = Check_RegisterValidator(snapshot, point); // Exists ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); - snapshot.Storages.GetChangeSet().Count().Should().Be(++keyCount); // No changes point[20]++; // fake point ret = Check_RegisterValidator(snapshot, point); // New @@ -115,7 +113,6 @@ public void Check_RegisterValidator() ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 1); // New validator // Check GetRegisteredValidators @@ -141,7 +138,6 @@ public void Check_Transfer() byte[] to = new byte[20]; - var keyCount = snapshot.Storages.GetChangeSet().Count(); // Check unclaim @@ -162,15 +158,12 @@ public void Check_Transfer() unclaim.Value.Should().Be(new BigInteger(0)); unclaim.State.Should().BeTrue(); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 4); // Gas + new balance // Return balance - keyCount = snapshot.Storages.GetChangeSet().Count(); NativeContract.NEO.Transfer(snapshot, to, from, BigInteger.One, true).Should().BeTrue(); NativeContract.NEO.BalanceOf(snapshot, to).Should().Be(0); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount - 1); // Remove neo balance from address two // Bad inputs @@ -223,14 +216,15 @@ public void TestCalculateBonus() { var snapshot = Blockchain.Singleton.GetSnapshot(); StorageKey key = CreateStorageKey(20, UInt160.Zero.ToArray()); - snapshot.Storages.Add(key, new StorageItem(new NeoAccountState + snapshot.Storages.Put(key, new StorageItem(new NeoAccountState { Balance = -100 })); Action action = () => NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); action.Should().Throw(); snapshot.Storages.Delete(key); - snapshot.Storages.GetAndChange(key, () => new StorageItem(new NeoAccountState + + snapshot.Storages.Put(key, new StorageItem(new NeoAccountState { Balance = 100 })); @@ -269,7 +263,7 @@ public void TestGetNextBlockValidators2() result[5].ToArray().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); result[6].ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); - snapshot.Storages.Add(CreateStorageKey(14), new StorageItem() + snapshot.Storages.Put(CreateStorageKey(14), new StorageItem() { Value = new ECPoint[] { ECCurve.Secp256r1.G }.ToByteArray() }); @@ -324,7 +318,7 @@ public void TestGetRegisteredValidators2() result[6].Votes.Should().Be(new BigInteger(1785714)); StorageKey key = NativeContract.NEO.CreateStorageKey(33, ECCurve.Secp256r1.G); - snapshot.Storages.Add(key, new StorageItem(new CandidateState())); + snapshot.Storages.Put(key, new StorageItem(new CandidateState())); NativeContract.NEO.GetCandidates(snapshot).ToArray().Length.Should().Be(22); } @@ -388,7 +382,7 @@ public void TestUnclaimedGas() { 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(new NeoAccountState())); + snapshot.Storages.Put(CreateStorageKey(20, UInt160.Zero.ToArray()), new StorageItem(new NeoAccountState())); NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); } @@ -407,17 +401,17 @@ public void TestVote() ret.State.Should().BeTrue(); ret.Result.Should().BeFalse(); - snapshot.Storages.Add(keyAccount, new StorageItem(new NeoAccountState())); + snapshot.Storages.Put(keyAccount, new StorageItem(new NeoAccountState())); ret = Check_Vote(snapshot, account.ToArray(), ECCurve.Secp256r1.G.ToArray(), true); ret.State.Should().BeTrue(); ret.Result.Should().BeFalse(); snapshot.Storages.Delete(keyAccount); - snapshot.Storages.GetAndChange(keyAccount, () => new StorageItem(new NeoAccountState + snapshot.Storages.Put(keyAccount, new StorageItem(new NeoAccountState { VoteTo = ECCurve.Secp256r1.G })); - snapshot.Storages.Add(keyValidator, new StorageItem(new CandidateState())); + snapshot.Storages.Put(keyValidator, new StorageItem(new CandidateState())); ret = Check_Vote(snapshot, account.ToArray(), ECCurve.Secp256r1.G.ToArray(), true); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); @@ -433,16 +427,16 @@ public void TestVote() UInt160 from = engine.ScriptContainer.GetScriptHashesForVerifying(engine.Snapshot)[0]; if (addVotes) { - snapshot.Storages.Add(CreateStorageKey(20, from.ToArray()), new StorageItem(new NeoAccountState + snapshot.Storages.Put(CreateStorageKey(20, from.ToArray()), new StorageItem(new NeoAccountState { VoteTo = ECCurve.Secp256r1.G, Balance = new BigInteger(1000) })); - snapshot.Storages.Add(NativeContract.NEO.CreateStorageKey(33, ECCurve.Secp256r1.G), new StorageItem(new CandidateState())); + snapshot.Storages.Put(NativeContract.NEO.CreateStorageKey(33, ECCurve.Secp256r1.G), new StorageItem(new CandidateState())); } else { - snapshot.Storages.Add(CreateStorageKey(20, from.ToArray()), new StorageItem(new NeoAccountState + snapshot.Storages.Put(CreateStorageKey(20, from.ToArray()), new StorageItem(new NeoAccountState { Balance = new BigInteger(1000) })); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs index 8c6d8eefef..42ff27a9f9 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs @@ -36,7 +36,7 @@ public void TestTotalSupply() key.Id = test.Id; - snapshot.Storages.Add(key, item); + snapshot.Storages.Put(key, item); ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); StackItem stackItem = test.TotalSupply(ae, null); stackItem.GetBigInteger().Should().Be(1); @@ -58,7 +58,7 @@ public void TestTotalSupplyDecimal() key.Id = test.Id; - snapshot.Storages.Add(key, item); + snapshot.Storages.Put(key, item); ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); StackItem stackItem = test.TotalSupply(ae, null); diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 1740495571..858722e38c 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -27,11 +27,9 @@ public void TestSetup() public void Check_Initialize() { var snapshot = Blockchain.Singleton.GetSnapshot(); - var keyCount = snapshot.Storages.GetChangeSet().Count(); NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); - (keyCount + 4).Should().Be(snapshot.Storages.GetChangeSet().Count()); var ret = NativeContract.Policy.Call(snapshot, "getMaxTransactionsPerBlock"); ret.Should().BeOfType(); @@ -241,7 +239,7 @@ public void TestCheckPolicy() Key = new byte[sizeof(byte)] }; storageKey.Key[0] = 15; - snapshot.Storages.Add(storageKey, new StorageItem + snapshot.Storages.Put(storageKey, new StorageItem { Value = new UInt160[] { tx.Sender }.ToByteArray(), }); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs index cf93e5abb3..f5fe243107 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs @@ -62,7 +62,7 @@ public void ApplicationEngineRegularPut() StorageItem sItem = TestUtils.GetStorageItem(new byte[0] { }); var snapshot = Blockchain.Singleton.GetSnapshot(); - snapshot.Storages.Add(skey, sItem); + snapshot.Storages.Put(skey, sItem); snapshot.Contracts.Add(script.ToScriptHash(), contractState); using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) @@ -96,7 +96,7 @@ public void ApplicationEngineReusedStorage_FullReuse() StorageItem sItem = TestUtils.GetStorageItem(value); var snapshot = Blockchain.Singleton.GetSnapshot(); - snapshot.Storages.Add(skey, sItem); + snapshot.Storages.Put(skey, sItem); snapshot.Contracts.Add(script.ToScriptHash(), contractState); using (ApplicationEngine applicationEngine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) @@ -132,7 +132,7 @@ public void ApplicationEngineReusedStorage_PartialReuse() StorageItem sItem = TestUtils.GetStorageItem(oldValue); var snapshot = Blockchain.Singleton.GetSnapshot(); - snapshot.Storages.Add(skey, sItem); + snapshot.Storages.Put(skey, sItem); snapshot.Contracts.Add(script.ToScriptHash(), contractState); using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) @@ -169,7 +169,7 @@ public void ApplicationEngineReusedStorage_PartialReuseTwice() StorageItem sItem = TestUtils.GetStorageItem(oldValue); var snapshot = Blockchain.Singleton.GetSnapshot(); - snapshot.Storages.Add(skey, sItem); + snapshot.Storages.Put(skey, sItem); snapshot.Contracts.Add(script.ToScriptHash(), contractState); using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index b0a2547107..a055a9181f 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -179,7 +179,7 @@ public void TestContract_Update() Key = new byte[] { 0x01 } }; snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Add(storageKey, storageItem); + snapshot.Storages.Put(storageKey, storageItem); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(state.Script); engine.UpdateContract(script, manifest.ToJson().ToByteArray(false)); @@ -204,7 +204,7 @@ public void TestStorage_Find() Key = new byte[] { 0x01 } }; snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Add(storageKey, storageItem); + snapshot.Storages.Put(storageKey, storageItem); var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 399f063ec7..13a4bb9e85 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -441,7 +441,7 @@ public void TestStorage_Get() IsConstant = true }; snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Add(storageKey, storageItem); + snapshot.Storages.Put(storageKey, storageItem); var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); @@ -499,7 +499,7 @@ public void TestStorage_Put() IsConstant = true }; snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Add(storageKey, storageItem); + snapshot.Storages.Put(storageKey, storageItem); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); key = new byte[] { 0x01 }; @@ -508,11 +508,12 @@ public void TestStorage_Put() Assert.ThrowsException(() => engine.Put(storageContext, key, value)); //success + key = new byte[] { 0x02 }; storageItem.IsConstant = false; engine.Put(storageContext, key, value); //value length == 0 - key = new byte[] { 0x01 }; + key = new byte[] { 0x02 }; value = new byte[0]; engine.Put(storageContext, key, value); } @@ -535,7 +536,7 @@ public void TestStorage_PutEx() IsConstant = false }; snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Add(storageKey, storageItem); + snapshot.Storages.Put(storageKey, storageItem); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); var key = new byte[] { 0x01 }; @@ -566,7 +567,7 @@ public void TestStorage_Delete() IsConstant = false }; snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Add(storageKey, storageItem); + snapshot.Storages.Put(storageKey, storageItem); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); state.Manifest.Features = ContractFeatures.HasStorage; @@ -675,7 +676,7 @@ public void TestContract_Destroy() Key = new byte[] { 0x01 } }; snapshot.Contracts.Add(scriptHash, state); - snapshot.Storages.Add(storageKey, storageItem); + snapshot.Storages.Put(storageKey, storageItem); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[0]); engine.DestroyContract(); diff --git a/tests/neo.UnitTests/UT_DataCache.cs b/tests/neo.UnitTests/UT_DataCache.cs index 22bcdaa26d..1b69aa7833 100644 --- a/tests/neo.UnitTests/UT_DataCache.cs +++ b/tests/neo.UnitTests/UT_DataCache.cs @@ -1,6 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO.Caching; using Neo.Ledger; +using Neo.Persistence; using System.Linq; namespace Neo.UnitTests @@ -11,14 +12,14 @@ public class UT_DataCache [TestInitialize] public void TestSetup() { - TestBlockchain.InitializeMockNeoSystem(); + } [TestMethod] public void TestCachedFind_Between() { - var snapshot = Blockchain.Singleton.GetSnapshot(); - var storages = snapshot.Storages.CreateSnapshot(); + var store = new MemoryStore(); + var storages = new StoreDataCache(store.GetSnapshot(), Prefixes.ST_Storage); var cache = new CloneCache(storages); storages.Add @@ -56,8 +57,8 @@ public void TestCachedFind_Between() [TestMethod] public void TestCachedFind_Last() { - var snapshot = Blockchain.Singleton.GetSnapshot(); - var storages = snapshot.Storages.CreateSnapshot(); + var store = new MemoryStore(); + var storages = new StoreDataCache(store.GetSnapshot(), Prefixes.ST_Storage); var cache = new CloneCache(storages); storages.Add @@ -88,8 +89,8 @@ public void TestCachedFind_Last() [TestMethod] public void TestCachedFind_Empty() { - var snapshot = Blockchain.Singleton.GetSnapshot(); - var storages = snapshot.Storages.CreateSnapshot(); + var store = new MemoryStore(); + var storages = new StoreDataCache(store.GetSnapshot(), Prefixes.ST_Storage); var cache = new CloneCache(storages); cache.Add diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index e63145ff5d..ecb57b7968 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -203,14 +203,18 @@ public void TestGetAvailable() // Fake balance var snapshot = Blockchain.Singleton.GetSnapshot(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + snapshot.Storages.Put(key, entry); snapshot.Commit(); wallet.GetAvailable(NativeContract.GAS.Hash).Should().Be(new BigDecimal(1000000000000, 8)); - entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 0; + snapshot.Storages.Put(key, entry); snapshot.Commit(); } @@ -225,15 +229,18 @@ public void TestGetBalance() // Fake balance var snapshot = Blockchain.Singleton.GetSnapshot(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + snapshot.Storages.Put(key, entry); 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)); - entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry = snapshot.Storages[key]; entry.GetInteroperable().Balance = 0; + snapshot.Storages.Put(key, entry); snapshot.Commit(); } @@ -325,13 +332,16 @@ public void TestMakeTransaction1() // Fake balance var snapshot = Blockchain.Singleton.GetSnapshot(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - var entry1 = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - entry1.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + var entry1 = snapshot.Storages[key]; + if (entry1 is null) entry1 = new StorageItem(new AccountState()); + entry1.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + snapshot.Storages.Put(key, entry1); key = NativeContract.NEO.CreateStorageKey(20, account.ScriptHash); - var entry2 = snapshot.Storages.GetAndChange(key, () => new StorageItem(new NeoToken.NeoAccountState())); + var entry2 = snapshot.Storages[key]; + if (entry2 is null) entry2 = new StorageItem(new NeoToken.NeoAccountState()); entry2.GetInteroperable().Balance = 10000 * NativeContract.NEO.Factor; - + snapshot.Storages.Put(key, entry2); snapshot.Commit(); var tx = wallet.MakeTransaction(new TransferOutput[] @@ -356,8 +366,10 @@ public void TestMakeTransaction1() }); tx.Should().NotBeNull(); - entry1 = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - entry2 = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry1 = snapshot.Storages[key]; + if (entry1 is null) entry1 = new StorageItem(new AccountState()); + entry2 = snapshot.Storages[key]; + if (entry2 is null) entry2 = new StorageItem(new AccountState()); entry1.GetInteroperable().Balance = 0; entry2.GetInteroperable().Balance = 0; snapshot.Commit(); @@ -377,8 +389,11 @@ public void TestMakeTransaction2() // Fake balance var snapshot = Blockchain.Singleton.GetSnapshot(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + + var entry = snapshot.Storages[key]; + if (entry is null) entry = new StorageItem(new AccountState()); entry.GetInteroperable().Balance = 1000000 * NativeContract.GAS.Factor; + snapshot.Storages.Put(key, entry); snapshot.Commit(); var tx = wallet.MakeTransaction(new byte[] { }, account.ScriptHash, new TransactionAttribute[] { }); @@ -387,8 +402,9 @@ public void TestMakeTransaction2() tx = wallet.MakeTransaction(new byte[] { }, null, new TransactionAttribute[] { }); tx.Should().NotBeNull(); - entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry = snapshot.Storages[key]; entry.GetInteroperable().Balance = 0; + snapshot.Storages.Put(key, entry); snapshot.Commit(); } From 294e9b9c9f45e7e67002d8aca4925d87a41e7f95 Mon Sep 17 00:00:00 2001 From: zhangtao Date: Mon, 8 Jun 2020 22:05:49 +0800 Subject: [PATCH 03/39] fix mpt --- src/neo/Cryptography/MPT/MPTTrie.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Cryptography/MPT/MPTTrie.cs b/src/neo/Cryptography/MPT/MPTTrie.cs index df97b54f9c..006e4280f3 100644 --- a/src/neo/Cryptography/MPT/MPTTrie.cs +++ b/src/neo/Cryptography/MPT/MPTTrie.cs @@ -18,7 +18,7 @@ public partial class MPTTrie public MPTTrie(ISnapshot store, UInt256 root) { this.store = store ?? throw new ArgumentNullException(); - this.root = root is null ? HashNode.EmptyNode : new HashNode(root); + this.root = root is null || root == UInt256.Zero ? HashNode.EmptyNode : new HashNode(root); } private MPTNode Resolve(HashNode n) From bc945a567f41a58f6bae6e8710ac63c9d94b8213 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Tue, 9 Jun 2020 14:06:00 +0800 Subject: [PATCH 04/39] precommit --- src/neo/Persistence/SnapshotView.cs | 7 ------- src/neo/Persistence/StoreView.cs | 11 +++++++++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 61651c0fdd..a5d4486cd5 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -43,13 +43,6 @@ public SnapshotView(IStore store) public override void Commit() { - var current_root = LocalRootHashIndex.GetAndChange(); - current_root.Hash = Storages.Root.Hash; - current_root.Index = Height; - LocalRoot.Add(Height, new HashState() - { - Hash = Storages.Root.Hash - }); base.Commit(); snapshot.Commit(); } diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index 4b9b0d6db8..04a237e197 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -38,6 +38,7 @@ public StoreView Clone() public virtual void Commit() { + this.PreCommit(); Blocks.Commit(); Transactions.Commit(); Contracts.Commit(); @@ -50,6 +51,16 @@ public virtual void Commit() ConfirmedRootHashIndex.Commit(); } + private void PreCommit() + { + if (LocalRootHashIndex.Get().Index != Height || LocalRootHashIndex.Get().Hash != Storages.Root.Hash) + { + LocalRootHashIndex.GetAndChange().Hash = Storages.Root.Hash; + LocalRootHashIndex.GetAndChange().Index = Height; + LocalRoot.GetAndChange(Height, () => new HashState()).Hash = Storages.Root.Hash; + } + } + public bool ContainsBlock(UInt256 hash) { TrimmedBlock state = Blocks.TryGet(hash); From 6ef3ccb842c1e73fe74c917913bd4fd2cf803110 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Tue, 9 Jun 2020 15:32:32 +0800 Subject: [PATCH 05/39] fix commit --- src/neo/Ledger/Blockchain.cs | 2 +- src/neo/Persistence/SnapshotView.cs | 11 +++++++++++ src/neo/Persistence/StoreView.cs | 11 ----------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 4e67789072..b10a60e870 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -443,7 +443,7 @@ private void Persist(Block block) } snapshot.BlockHashIndex.GetAndChange().Set(block); foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) - plugin.OnPersist(snapshot.Clone(), all_application_executed); + plugin.OnPersist(snapshot, all_application_executed); snapshot.Commit(); List commitExceptions = null; foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index a5d4486cd5..bcb94461cb 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -41,8 +41,19 @@ public SnapshotView(IStore store) Storages = new MPTTrie(snapshot, CurrentRootHash); } + private void PreCommit() + { + if (LocalRootHashIndex.Get().Index != PersistingBlock?.Index || LocalRootHashIndex.Get().Hash != Storages.Root.Hash) + { + LocalRootHashIndex.GetAndChange().Hash = Storages.Root.Hash; + LocalRootHashIndex.GetAndChange().Index = PersistingBlock.Index; + LocalRoot.GetAndChange(PersistingBlock.Index, () => new HashState()).Hash = Storages.Root.Hash; + } + } + public override void Commit() { + this.PreCommit(); base.Commit(); snapshot.Commit(); } diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index 04a237e197..4b9b0d6db8 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -38,7 +38,6 @@ public StoreView Clone() public virtual void Commit() { - this.PreCommit(); Blocks.Commit(); Transactions.Commit(); Contracts.Commit(); @@ -51,16 +50,6 @@ public virtual void Commit() ConfirmedRootHashIndex.Commit(); } - private void PreCommit() - { - if (LocalRootHashIndex.Get().Index != Height || LocalRootHashIndex.Get().Hash != Storages.Root.Hash) - { - LocalRootHashIndex.GetAndChange().Hash = Storages.Root.Hash; - LocalRootHashIndex.GetAndChange().Index = Height; - LocalRoot.GetAndChange(Height, () => new HashState()).Hash = Storages.Root.Hash; - } - } - public bool ContainsBlock(UInt256 hash) { TrimmedBlock state = Blocks.TryGet(hash); From 2cd85d094390afec393205bfce40566ca2da92e7 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Tue, 9 Jun 2020 17:41:32 +0800 Subject: [PATCH 06/39] rm LocalRootHashIndex --- src/neo/Persistence/ClonedView.cs | 2 -- src/neo/Persistence/ReadOnlyView.cs | 3 +-- src/neo/Persistence/SnapshotView.cs | 6 +----- src/neo/Persistence/StoreView.cs | 4 +--- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index 846d700032..acfda7fa03 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -14,7 +14,6 @@ internal class ClonedView : StoreView public override DataCache, HashState> LocalRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public override MetaDataCache LocalRootHashIndex { get; } public override MetaDataCache ConfirmedRootHashIndex { get; } public override MetaDataCache ContractId { get; } @@ -28,7 +27,6 @@ public ClonedView(StoreView view) this.LocalRoot = view.LocalRoot.CreateSnapshot(); this.BlockHashIndex = view.BlockHashIndex.CreateSnapshot(); this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot(); - this.LocalRootHashIndex = view.LocalRootHashIndex.CreateSnapshot(); this.ConfirmedRootHashIndex = view.ConfirmedRootHashIndex.CreateSnapshot(); this.ContractId = view.ContractId.CreateSnapshot(); this.Storages = view.Storages; diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index fde9c13d2b..4c61055a60 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -21,10 +21,9 @@ public class ReadOnlyView : StoreView public override DataCache, HashState> LocalRoot => new StoreDataCache, HashState>(store, Prefixes.ST_Root); public override MetaDataCache BlockHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentBlock); public override MetaDataCache HeaderHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentHeader); - public override MetaDataCache LocalRootHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentRoot); public override MetaDataCache ConfirmedRootHashIndex => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); public override MetaDataCache ContractId => new StoreMetaDataCache(store, Prefixes.IX_ContractId); - public new MPTTrie Storages => new MPTTrie((ISnapshot)store, LocalRootHashIndex.Get().Hash); + public new MPTTrie Storages => new MPTTrie((ISnapshot)store, CurrentRootHash); public ReadOnlyView(IReadOnlyStore store) { diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index bcb94461cb..26e238c3cd 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -21,7 +21,6 @@ public class SnapshotView : StoreView, IDisposable public override DataCache, HashState> LocalRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public override MetaDataCache LocalRootHashIndex { get; } public override MetaDataCache ConfirmedRootHashIndex { get; } public override MetaDataCache ContractId { get; } @@ -36,17 +35,14 @@ public SnapshotView(IStore store) BlockHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentBlock); HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); - LocalRootHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentRoot); ConfirmedRootHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); Storages = new MPTTrie(snapshot, CurrentRootHash); } private void PreCommit() { - if (LocalRootHashIndex.Get().Index != PersistingBlock?.Index || LocalRootHashIndex.Get().Hash != Storages.Root.Hash) + if (PersistingBlock != null && (LocalRoot.TryGet(PersistingBlock.Index) is null || LocalRoot.TryGet(PersistingBlock.Index).Hash != Storages.Root.Hash)) { - LocalRootHashIndex.GetAndChange().Hash = Storages.Root.Hash; - LocalRootHashIndex.GetAndChange().Index = PersistingBlock.Index; LocalRoot.GetAndChange(PersistingBlock.Index, () => new HashState()).Hash = Storages.Root.Hash; } } diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index 4b9b0d6db8..9ead03f805 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -19,7 +19,6 @@ public abstract class StoreView public abstract DataCache, HashState> LocalRoot { get; } public abstract MetaDataCache BlockHashIndex { get; } public abstract MetaDataCache HeaderHashIndex { get; } - public abstract MetaDataCache LocalRootHashIndex { get; } public abstract MetaDataCache ConfirmedRootHashIndex { get; } public abstract MetaDataCache ContractId { get; } public MPTTrie Storages; @@ -27,7 +26,7 @@ public abstract class StoreView public uint Height => BlockHashIndex.Get().Index; public uint HeaderHeight => HeaderHashIndex.Get().Index; public UInt256 CurrentBlockHash => BlockHashIndex.Get().Hash; - public UInt256 CurrentRootHash => LocalRootHashIndex.Get().Hash; + public UInt256 CurrentRootHash => LocalRoot.TryGet(Height)?.Hash ?? UInt256.Zero; public UInt256 CurrentHeaderHash => HeaderHashIndex.Get().Hash; @@ -46,7 +45,6 @@ public virtual void Commit() BlockHashIndex.Commit(); HeaderHashIndex.Commit(); ContractId.Commit(); - LocalRootHashIndex.Commit(); ConfirmedRootHashIndex.Commit(); } From cfccec9802c81ec01b3418d9e164361046171af6 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Wed, 10 Jun 2020 10:44:07 +0800 Subject: [PATCH 07/39] fix ut --- tests/neo.UnitTests/Wallets/UT_Wallet.cs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index ecb57b7968..2c378a7112 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -296,6 +296,21 @@ public void TestMakeTransaction1() WalletAccount account = wallet.CreateAccount(contract, glkey.PrivateKey); account.Lock = false; + // Make sure balance is 0 + var snapshot = Blockchain.Singleton.GetSnapshot(); + var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); + + var entry1 = snapshot.Storages[key]; + if (entry1 is null) entry1 = new StorageItem(new AccountState()); + entry1.GetInteroperable().Balance = 0; + snapshot.Storages.Put(key, entry1); + key = NativeContract.NEO.CreateStorageKey(20, account.ScriptHash); + var entry2 = snapshot.Storages[key]; + if (entry2 is null) entry2 = new StorageItem(new NeoToken.NeoAccountState()); + entry2.GetInteroperable().Balance = 0; + snapshot.Storages.Put(key, entry2); + snapshot.Commit(); + Action action = () => wallet.MakeTransaction(new TransferOutput[] { new TransferOutput() @@ -330,15 +345,15 @@ public void TestMakeTransaction1() action.Should().Throw(); // Fake balance - var snapshot = Blockchain.Singleton.GetSnapshot(); - var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); + snapshot = Blockchain.Singleton.GetSnapshot(); + key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - var entry1 = snapshot.Storages[key]; + entry1 = snapshot.Storages[key]; if (entry1 is null) entry1 = new StorageItem(new AccountState()); entry1.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; snapshot.Storages.Put(key, entry1); key = NativeContract.NEO.CreateStorageKey(20, account.ScriptHash); - var entry2 = snapshot.Storages[key]; + entry2 = snapshot.Storages[key]; if (entry2 is null) entry2 = new StorageItem(new NeoToken.NeoAccountState()); entry2.GetInteroperable().Balance = 10000 * NativeContract.NEO.Factor; snapshot.Storages.Put(key, entry2); From ef8c14cadc8c02ba8d65860438491de895c59879 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Wed, 10 Jun 2020 10:45:23 +0800 Subject: [PATCH 08/39] pre commit --- src/neo/Persistence/SnapshotView.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 26e238c3cd..bc6e31a4ac 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -41,15 +41,16 @@ public SnapshotView(IStore store) private void PreCommit() { - if (PersistingBlock != null && (LocalRoot.TryGet(PersistingBlock.Index) is null || LocalRoot.TryGet(PersistingBlock.Index).Hash != Storages.Root.Hash)) + var index = PersistingBlock?.Index ?? Height; + if (LocalRoot.TryGet(index) is null || LocalRoot.TryGet(index).Hash != Storages.Root.Hash) { - LocalRoot.GetAndChange(PersistingBlock.Index, () => new HashState()).Hash = Storages.Root.Hash; + LocalRoot.GetAndChange(index, () => new HashState()).Hash = Storages.Root.Hash; } } public override void Commit() { - this.PreCommit(); + PreCommit(); base.Commit(); snapshot.Commit(); } From d2cc98dac580a7305d49d46558e9a7340b56fe0d Mon Sep 17 00:00:00 2001 From: KickSeason Date: Wed, 10 Jun 2020 16:32:59 +0800 Subject: [PATCH 09/39] fix clone view --- src/neo/Cryptography/MPT/MPTTrie.cs | 5 +++++ src/neo/Persistence/ClonedView.cs | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/neo/Cryptography/MPT/MPTTrie.cs b/src/neo/Cryptography/MPT/MPTTrie.cs index 006e4280f3..96ff93b51b 100644 --- a/src/neo/Cryptography/MPT/MPTTrie.cs +++ b/src/neo/Cryptography/MPT/MPTTrie.cs @@ -54,5 +54,10 @@ private void PutToStore(MPTNode node) { store.Put(Prefix, node.Hash.ToArray(), node.Encode()); } + + public MPTTrie Clone() + { + return new MPTTrie(store, root.Hash); + } } } diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index acfda7fa03..c30b58c2f7 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -1,3 +1,4 @@ +using Neo.Cryptography.MPT; using Neo.IO; using Neo.IO.Caching; using Neo.Ledger; @@ -7,6 +8,7 @@ namespace Neo.Persistence { internal class ClonedView : StoreView { + private StoreView parent; public override DataCache Blocks { get; } public override DataCache Transactions { get; } public override DataCache Contracts { get; } @@ -19,6 +21,7 @@ internal class ClonedView : StoreView public ClonedView(StoreView view) { + this.parent = view; this.PersistingBlock = view.PersistingBlock; this.Blocks = view.Blocks.CreateSnapshot(); this.Transactions = view.Transactions.CreateSnapshot(); @@ -29,7 +32,13 @@ public ClonedView(StoreView view) this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot(); this.ConfirmedRootHashIndex = view.ConfirmedRootHashIndex.CreateSnapshot(); this.ContractId = view.ContractId.CreateSnapshot(); - this.Storages = view.Storages; + this.Storages = view.Storages.Clone(); + } + + public override void Commit() + { + base.Commit(); + parent.Storages = Storages; } } } From 559831e92ca3e45d431ff5b7a1201e3733708999 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Wed, 10 Jun 2020 16:49:47 +0800 Subject: [PATCH 10/39] change name --- src/neo/Persistence/ClonedView.cs | 8 ++++---- src/neo/Persistence/ReadOnlyView.cs | 6 +++--- src/neo/Persistence/SnapshotView.cs | 14 +++++++------- src/neo/Persistence/StoreView.cs | 10 +++++----- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index c30b58c2f7..d510ae5d37 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -13,10 +13,10 @@ internal class ClonedView : StoreView public override DataCache Transactions { get; } public override DataCache Contracts { get; } public override DataCache, HeaderHashList> HeaderHashList { get; } - public override DataCache, HashState> LocalRoot { get; } + public override DataCache, HashState> LocalStateRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public override MetaDataCache ConfirmedRootHashIndex { get; } + public override MetaDataCache ConfirmedStateRootHashIndex { get; } public override MetaDataCache ContractId { get; } public ClonedView(StoreView view) @@ -27,10 +27,10 @@ public ClonedView(StoreView view) this.Transactions = view.Transactions.CreateSnapshot(); this.Contracts = view.Contracts.CreateSnapshot(); this.HeaderHashList = view.HeaderHashList.CreateSnapshot(); - this.LocalRoot = view.LocalRoot.CreateSnapshot(); + this.LocalStateRoot = view.LocalStateRoot.CreateSnapshot(); this.BlockHashIndex = view.BlockHashIndex.CreateSnapshot(); this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot(); - this.ConfirmedRootHashIndex = view.ConfirmedRootHashIndex.CreateSnapshot(); + this.ConfirmedStateRootHashIndex = view.ConfirmedStateRootHashIndex.CreateSnapshot(); this.ContractId = view.ContractId.CreateSnapshot(); this.Storages = view.Storages.Clone(); } diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index 4c61055a60..66e929e7ad 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -18,12 +18,12 @@ public class ReadOnlyView : StoreView public override DataCache Transactions => new StoreDataCache(store, Prefixes.DATA_Transaction); public override DataCache Contracts => new StoreDataCache(store, Prefixes.ST_Contract); public override DataCache, HeaderHashList> HeaderHashList => new StoreDataCache, HeaderHashList>(store, Prefixes.IX_HeaderHashList); - public override DataCache, HashState> LocalRoot => new StoreDataCache, HashState>(store, Prefixes.ST_Root); + public override DataCache, HashState> LocalStateRoot => new StoreDataCache, HashState>(store, Prefixes.ST_Root); public override MetaDataCache BlockHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentBlock); public override MetaDataCache HeaderHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentHeader); - public override MetaDataCache ConfirmedRootHashIndex => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); + public override MetaDataCache ConfirmedStateRootHashIndex => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); public override MetaDataCache ContractId => new StoreMetaDataCache(store, Prefixes.IX_ContractId); - public new MPTTrie Storages => new MPTTrie((ISnapshot)store, CurrentRootHash); + public new MPTTrie Storages => new MPTTrie((ISnapshot)store, CurrentStateRootHash); public ReadOnlyView(IReadOnlyStore store) { diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index bc6e31a4ac..8cdf205969 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -18,10 +18,10 @@ public class SnapshotView : StoreView, IDisposable public override DataCache Transactions { get; } public override DataCache Contracts { get; } public override DataCache, HeaderHashList> HeaderHashList { get; } - public override DataCache, HashState> LocalRoot { get; } + public override DataCache, HashState> LocalStateRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public override MetaDataCache ConfirmedRootHashIndex { get; } + public override MetaDataCache ConfirmedStateRootHashIndex { get; } public override MetaDataCache ContractId { get; } public SnapshotView(IStore store) @@ -31,20 +31,20 @@ public SnapshotView(IStore store) Transactions = new StoreDataCache(snapshot, Prefixes.DATA_Transaction); Contracts = new StoreDataCache(snapshot, Prefixes.ST_Contract); HeaderHashList = new StoreDataCache, HeaderHashList>(snapshot, Prefixes.IX_HeaderHashList); - LocalRoot = new StoreDataCache, HashState>(snapshot, Prefixes.ST_Root); + LocalStateRoot = new StoreDataCache, HashState>(snapshot, Prefixes.ST_Root); BlockHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentBlock); HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); - ConfirmedRootHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); - Storages = new MPTTrie(snapshot, CurrentRootHash); + ConfirmedStateRootHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); + Storages = new MPTTrie(snapshot, CurrentStateRootHash); } private void PreCommit() { var index = PersistingBlock?.Index ?? Height; - if (LocalRoot.TryGet(index) is null || LocalRoot.TryGet(index).Hash != Storages.Root.Hash) + if (LocalStateRoot.TryGet(index) is null || LocalStateRoot.TryGet(index).Hash != Storages.Root.Hash) { - LocalRoot.GetAndChange(index, () => new HashState()).Hash = Storages.Root.Hash; + LocalStateRoot.GetAndChange(index, () => new HashState()).Hash = Storages.Root.Hash; } } diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index 9ead03f805..a3fd6ebe49 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -16,17 +16,17 @@ public abstract class StoreView public abstract DataCache Transactions { get; } public abstract DataCache Contracts { get; } public abstract DataCache, HeaderHashList> HeaderHashList { get; } - public abstract DataCache, HashState> LocalRoot { get; } + public abstract DataCache, HashState> LocalStateRoot { get; } public abstract MetaDataCache BlockHashIndex { get; } public abstract MetaDataCache HeaderHashIndex { get; } - public abstract MetaDataCache ConfirmedRootHashIndex { get; } + public abstract MetaDataCache ConfirmedStateRootHashIndex { get; } public abstract MetaDataCache ContractId { get; } public MPTTrie Storages; public uint Height => BlockHashIndex.Get().Index; public uint HeaderHeight => HeaderHashIndex.Get().Index; public UInt256 CurrentBlockHash => BlockHashIndex.Get().Hash; - public UInt256 CurrentRootHash => LocalRoot.TryGet(Height)?.Hash ?? UInt256.Zero; + public UInt256 CurrentStateRootHash => LocalStateRoot.TryGet(Height)?.Hash ?? UInt256.Zero; public UInt256 CurrentHeaderHash => HeaderHashIndex.Get().Hash; @@ -41,11 +41,11 @@ public virtual void Commit() Transactions.Commit(); Contracts.Commit(); HeaderHashList.Commit(); - LocalRoot.Commit(); + LocalStateRoot.Commit(); BlockHashIndex.Commit(); HeaderHashIndex.Commit(); ContractId.Commit(); - ConfirmedRootHashIndex.Commit(); + ConfirmedStateRootHashIndex.Commit(); } public bool ContainsBlock(UInt256 hash) From 88eeff25e549cf11580cb2adf9fd06d29a53cebf Mon Sep 17 00:00:00 2001 From: KickSeason Date: Wed, 10 Jun 2020 17:01:35 +0800 Subject: [PATCH 11/39] rename --- src/neo/Persistence/ClonedView.cs | 4 ++-- src/neo/Persistence/StoreView.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index d510ae5d37..f316635057 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -16,7 +16,7 @@ internal class ClonedView : StoreView public override DataCache, HashState> LocalStateRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public override MetaDataCache ConfirmedStateRootHashIndex { get; } + public override MetaDataCache ConfirmedStateRoot { get; } public override MetaDataCache ContractId { get; } public ClonedView(StoreView view) @@ -30,7 +30,7 @@ public ClonedView(StoreView view) this.LocalStateRoot = view.LocalStateRoot.CreateSnapshot(); this.BlockHashIndex = view.BlockHashIndex.CreateSnapshot(); this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot(); - this.ConfirmedStateRootHashIndex = view.ConfirmedStateRootHashIndex.CreateSnapshot(); + this.ConfirmedStateRoot = view.ConfirmedStateRoot.CreateSnapshot(); this.ContractId = view.ContractId.CreateSnapshot(); this.Storages = view.Storages.Clone(); } diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index a3fd6ebe49..654e1fd34a 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -19,7 +19,7 @@ public abstract class StoreView public abstract DataCache, HashState> LocalStateRoot { get; } public abstract MetaDataCache BlockHashIndex { get; } public abstract MetaDataCache HeaderHashIndex { get; } - public abstract MetaDataCache ConfirmedStateRootHashIndex { get; } + public abstract MetaDataCache ConfirmedStateRoot { get; } public abstract MetaDataCache ContractId { get; } public MPTTrie Storages; @@ -45,7 +45,7 @@ public virtual void Commit() BlockHashIndex.Commit(); HeaderHashIndex.Commit(); ContractId.Commit(); - ConfirmedStateRootHashIndex.Commit(); + ConfirmedStateRoot.Commit(); } public bool ContainsBlock(UInt256 hash) From f97c15a1759935b9e737ac7219d1cdac29425cf0 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Wed, 10 Jun 2020 17:19:35 +0800 Subject: [PATCH 12/39] abstract --- src/neo/Persistence/ClonedView.cs | 1 + src/neo/Persistence/ReadOnlyView.cs | 14 ++++++++++++-- src/neo/Persistence/SnapshotView.cs | 5 +++-- src/neo/Persistence/StoreView.cs | 2 +- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index f316635057..38d50523a5 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -18,6 +18,7 @@ internal class ClonedView : StoreView public override MetaDataCache HeaderHashIndex { get; } public override MetaDataCache ConfirmedStateRoot { get; } public override MetaDataCache ContractId { get; } + public override MPTTrie Storages { get; set; } public ClonedView(StoreView view) { diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index 66e929e7ad..8af6b44fac 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -21,9 +21,19 @@ public class ReadOnlyView : StoreView public override DataCache, HashState> LocalStateRoot => new StoreDataCache, HashState>(store, Prefixes.ST_Root); public override MetaDataCache BlockHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentBlock); public override MetaDataCache HeaderHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentHeader); - public override MetaDataCache ConfirmedStateRootHashIndex => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); + public override MetaDataCache ConfirmedStateRoot => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); public override MetaDataCache ContractId => new StoreMetaDataCache(store, Prefixes.IX_ContractId); - public new MPTTrie Storages => new MPTTrie((ISnapshot)store, CurrentStateRootHash); + public override MPTTrie Storages + { + get + { + return new MPTTrie((ISnapshot)store, CurrentStateRootHash); + } + set + { + Storages = value; + } + } public ReadOnlyView(IReadOnlyStore store) { diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 8cdf205969..bd31fc3f18 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -21,8 +21,9 @@ public class SnapshotView : StoreView, IDisposable public override DataCache, HashState> LocalStateRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public override MetaDataCache ConfirmedStateRootHashIndex { get; } + public override MetaDataCache ConfirmedStateRoot { get; } public override MetaDataCache ContractId { get; } + public override MPTTrie Storages { get; set; } public SnapshotView(IStore store) { @@ -35,7 +36,7 @@ public SnapshotView(IStore store) BlockHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentBlock); HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); - ConfirmedStateRootHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); + ConfirmedStateRoot = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); Storages = new MPTTrie(snapshot, CurrentStateRootHash); } diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index 654e1fd34a..ce36a9262b 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -21,7 +21,7 @@ public abstract class StoreView public abstract MetaDataCache HeaderHashIndex { get; } public abstract MetaDataCache ConfirmedStateRoot { get; } public abstract MetaDataCache ContractId { get; } - public MPTTrie Storages; + public abstract MPTTrie Storages { get; set; } public uint Height => BlockHashIndex.Get().Index; public uint HeaderHeight => HeaderHashIndex.Get().Index; From 2b20fc88815f54ed38de3b448acf3632d5a10b88 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 11 Jun 2020 16:35:24 +0800 Subject: [PATCH 13/39] comment --- src/neo/Network/P2P/Payloads/StateRoot.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 561ba3f5a5..8a41e56838 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -47,10 +47,10 @@ Witness[] IVerifiable.Witnesses } public int Size => - sizeof(byte) + - sizeof(uint) + - UInt256.Length + - Witness.Size; + sizeof(byte) + //Version + sizeof(uint) + //Index + UInt256.Length + //Root + Witness.Size; //Witness StateRoot ICloneable.Clone() { From 1fd61360f0de3a1fc9e9a673b09dc1f821254ae6 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 11 Jun 2020 17:54:36 +0800 Subject: [PATCH 14/39] fix ReadOnlyView --- src/neo/Persistence/ReadOnlyView.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index 8af6b44fac..2ddc43a809 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -23,21 +23,12 @@ public class ReadOnlyView : StoreView public override MetaDataCache HeaderHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentHeader); public override MetaDataCache ConfirmedStateRoot => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); public override MetaDataCache ContractId => new StoreMetaDataCache(store, Prefixes.IX_ContractId); - public override MPTTrie Storages - { - get - { - return new MPTTrie((ISnapshot)store, CurrentStateRootHash); - } - set - { - Storages = value; - } - } + public override MPTTrie Storages { get; set; } public ReadOnlyView(IReadOnlyStore store) { this.store = store; + Storages = new MPTTrie((ISnapshot)store, CurrentStateRootHash); } public override void Commit() From 4b818a22ee47b5765b5099f90647ec28de99378e Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 11 Jun 2020 17:58:28 +0800 Subject: [PATCH 15/39] rm precommit --- src/neo/Ledger/Blockchain.cs | 1 + src/neo/Persistence/SnapshotView.cs | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index b10a60e870..8067f016d9 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -442,6 +442,7 @@ private void Persist(Block block) } } snapshot.BlockHashIndex.GetAndChange().Set(block); + snapshot.LocalStateRoot.GetAndChange(block.Index, () => new HashState()).Hash = snapshot.Storages.Root.Hash; foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) plugin.OnPersist(snapshot, all_application_executed); snapshot.Commit(); diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index bd31fc3f18..296e75a65b 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -40,18 +40,8 @@ public SnapshotView(IStore store) Storages = new MPTTrie(snapshot, CurrentStateRootHash); } - private void PreCommit() - { - var index = PersistingBlock?.Index ?? Height; - if (LocalStateRoot.TryGet(index) is null || LocalStateRoot.TryGet(index).Hash != Storages.Root.Hash) - { - LocalStateRoot.GetAndChange(index, () => new HashState()).Hash = Storages.Root.Hash; - } - } - public override void Commit() { - PreCommit(); base.Commit(); snapshot.Commit(); } From 0c07d4b281dc112085bef5ce539ff79837cfce1a Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 11 Jun 2020 18:06:36 +0800 Subject: [PATCH 16/39] rm HashState --- src/neo/Ledger/Blockchain.cs | 4 ++- src/neo/Ledger/HashState.cs | 41 ----------------------------- src/neo/Persistence/ClonedView.cs | 2 +- src/neo/Persistence/ReadOnlyView.cs | 2 +- src/neo/Persistence/SnapshotView.cs | 4 +-- src/neo/Persistence/StoreView.cs | 2 +- 6 files changed, 8 insertions(+), 47 deletions(-) delete mode 100644 src/neo/Ledger/HashState.cs diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 8067f016d9..834146ed26 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -442,7 +442,9 @@ private void Persist(Block block) } } snapshot.BlockHashIndex.GetAndChange().Set(block); - snapshot.LocalStateRoot.GetAndChange(block.Index, () => new HashState()).Hash = snapshot.Storages.Root.Hash; + var root_hash_index = snapshot.LocalStateRoot.GetAndChange(block.Index, () => new HashIndexState()); + root_hash_index.Index = block.Index; + root_hash_index.Hash = snapshot.Storages.Root.Hash; foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) plugin.OnPersist(snapshot, all_application_executed); snapshot.Commit(); diff --git a/src/neo/Ledger/HashState.cs b/src/neo/Ledger/HashState.cs deleted file mode 100644 index 9b268b580f..0000000000 --- a/src/neo/Ledger/HashState.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Neo.IO; -using Neo.Network.P2P.Payloads; -using System.IO; - -namespace Neo.Ledger -{ - public class HashState : ICloneable, ISerializable - { - public UInt256 Hash = UInt256.Zero; - - int ISerializable.Size => Hash.Size; - - HashState ICloneable.Clone() - { - return new HashState - { - Hash = Hash - }; - } - - void ISerializable.Deserialize(BinaryReader reader) - { - Hash = reader.ReadSerializable(); - } - - void ICloneable.FromReplica(HashState replica) - { - Hash = replica.Hash; - } - - void ISerializable.Serialize(BinaryWriter writer) - { - writer.Write(Hash); - } - - internal void Set(BlockBase block) - { - Hash = block.Hash; - } - } -} diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index 38d50523a5..76635851a4 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -13,7 +13,7 @@ internal class ClonedView : StoreView public override DataCache Transactions { get; } public override DataCache Contracts { get; } public override DataCache, HeaderHashList> HeaderHashList { get; } - public override DataCache, HashState> LocalStateRoot { get; } + public override DataCache, HashIndexState> LocalStateRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } public override MetaDataCache ConfirmedStateRoot { get; } diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index 2ddc43a809..1f493f6846 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -18,7 +18,7 @@ public class ReadOnlyView : StoreView public override DataCache Transactions => new StoreDataCache(store, Prefixes.DATA_Transaction); public override DataCache Contracts => new StoreDataCache(store, Prefixes.ST_Contract); public override DataCache, HeaderHashList> HeaderHashList => new StoreDataCache, HeaderHashList>(store, Prefixes.IX_HeaderHashList); - public override DataCache, HashState> LocalStateRoot => new StoreDataCache, HashState>(store, Prefixes.ST_Root); + public override DataCache, HashIndexState> LocalStateRoot => new StoreDataCache, HashIndexState>(store, Prefixes.ST_Root); public override MetaDataCache BlockHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentBlock); public override MetaDataCache HeaderHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentHeader); public override MetaDataCache ConfirmedStateRoot => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 296e75a65b..8a95c53f24 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -18,7 +18,7 @@ public class SnapshotView : StoreView, IDisposable public override DataCache Transactions { get; } public override DataCache Contracts { get; } public override DataCache, HeaderHashList> HeaderHashList { get; } - public override DataCache, HashState> LocalStateRoot { get; } + public override DataCache, HashIndexState> LocalStateRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } public override MetaDataCache ConfirmedStateRoot { get; } @@ -32,7 +32,7 @@ public SnapshotView(IStore store) Transactions = new StoreDataCache(snapshot, Prefixes.DATA_Transaction); Contracts = new StoreDataCache(snapshot, Prefixes.ST_Contract); HeaderHashList = new StoreDataCache, HeaderHashList>(snapshot, Prefixes.IX_HeaderHashList); - LocalStateRoot = new StoreDataCache, HashState>(snapshot, Prefixes.ST_Root); + LocalStateRoot = new StoreDataCache, HashIndexState>(snapshot, Prefixes.ST_Root); BlockHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentBlock); HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index ce36a9262b..09ff966153 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -16,7 +16,7 @@ public abstract class StoreView public abstract DataCache Transactions { get; } public abstract DataCache Contracts { get; } public abstract DataCache, HeaderHashList> HeaderHashList { get; } - public abstract DataCache, HashState> LocalStateRoot { get; } + public abstract DataCache, HashIndexState> LocalStateRoot { get; } public abstract MetaDataCache BlockHashIndex { get; } public abstract MetaDataCache HeaderHashIndex { get; } public abstract MetaDataCache ConfirmedStateRoot { get; } From fcefc80737e7f75128b0f7da4d4381d88b0a9bca Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Thu, 11 Jun 2020 19:33:45 +0800 Subject: [PATCH 17/39] add MPTDataCache --- src/neo/Cryptography/MPT/MPTTrie.cs | 10 ++---- src/neo/Persistence/ClonedView.cs | 12 ++----- src/neo/Persistence/MPTDataCache.cs | 52 +++++++++++++++++++++++++++++ src/neo/Persistence/SnapshotView.cs | 5 ++- src/neo/Persistence/StoreView.cs | 2 +- 5 files changed, 60 insertions(+), 21 deletions(-) create mode 100644 src/neo/Persistence/MPTDataCache.cs diff --git a/src/neo/Cryptography/MPT/MPTTrie.cs b/src/neo/Cryptography/MPT/MPTTrie.cs index 96ff93b51b..92b4b9a4f8 100644 --- a/src/neo/Cryptography/MPT/MPTTrie.cs +++ b/src/neo/Cryptography/MPT/MPTTrie.cs @@ -8,16 +8,17 @@ public partial class MPTTrie where TKey : notnull, ISerializable, new() where TValue : class, ISerializable, new() { - private const byte Prefix = 0xf0; + private byte Prefix = 0xf0; private readonly ISnapshot store; private MPTNode root; public MPTNode Root => root; - public MPTTrie(ISnapshot store, UInt256 root) + public MPTTrie(ISnapshot store, byte prefix, UInt256 root) { this.store = store ?? throw new ArgumentNullException(); + this.Prefix = prefix; this.root = root is null || root == UInt256.Zero ? HashNode.EmptyNode : new HashNode(root); } @@ -54,10 +55,5 @@ private void PutToStore(MPTNode node) { store.Put(Prefix, node.Hash.ToArray(), node.Encode()); } - - public MPTTrie Clone() - { - return new MPTTrie(store, root.Hash); - } } } diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index 76635851a4..60a46cb8bf 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -8,7 +8,6 @@ namespace Neo.Persistence { internal class ClonedView : StoreView { - private StoreView parent; public override DataCache Blocks { get; } public override DataCache Transactions { get; } public override DataCache Contracts { get; } @@ -18,11 +17,10 @@ internal class ClonedView : StoreView public override MetaDataCache HeaderHashIndex { get; } public override MetaDataCache ConfirmedStateRoot { get; } public override MetaDataCache ContractId { get; } - public override MPTTrie Storages { get; set; } + public override DataCache Storages { get; set; } public ClonedView(StoreView view) { - this.parent = view; this.PersistingBlock = view.PersistingBlock; this.Blocks = view.Blocks.CreateSnapshot(); this.Transactions = view.Transactions.CreateSnapshot(); @@ -33,13 +31,7 @@ public ClonedView(StoreView view) this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot(); this.ConfirmedStateRoot = view.ConfirmedStateRoot.CreateSnapshot(); this.ContractId = view.ContractId.CreateSnapshot(); - this.Storages = view.Storages.Clone(); - } - - public override void Commit() - { - base.Commit(); - parent.Storages = Storages; + this.Storages = view.Storages.CreateSnapshot(); } } } diff --git a/src/neo/Persistence/MPTDataCache.cs b/src/neo/Persistence/MPTDataCache.cs new file mode 100644 index 0000000000..a4344b7879 --- /dev/null +++ b/src/neo/Persistence/MPTDataCache.cs @@ -0,0 +1,52 @@ + +using Neo.Cryptography.MPT; +using Neo.IO; +using Neo.IO.Caching; +using System; +using System.Collections.Generic; + +namespace Neo.Persistence +{ + internal class MPTDataCache : DataCache + where TKey : IEquatable, ISerializable, new() + where TValue : class, ICloneable, ISerializable, new() + { + private MPTTrie mptTrie; + + public MPTDataCache(IReadOnlyStore store, byte prefix, UInt256 CurrentStateRootHash) + { + this.mptTrie = new MPTTrie(store as ISnapshot, prefix, CurrentStateRootHash); + } + + protected override void AddInternal(TKey key, TValue value) + { + mptTrie.Put(key, value); + } + + protected override void DeleteInternal(TKey key) + { + mptTrie.Delete(key); + } + + protected override IEnumerable<(TKey Key, TValue Value)> FindInternal(byte[] key_prefix) + { + //return mptTrie.Find(prefix); + return null; + } + + protected override TValue GetInternal(TKey key) + { + return mptTrie[key]; + } + + protected override TValue TryGetInternal(TKey key) + { + return mptTrie[key]; + } + + protected override void UpdateInternal(TKey key, TValue value) + { + mptTrie.Put(key, value); + } + } +} diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 8a95c53f24..f31cc72830 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -1,4 +1,3 @@ -using Neo.Cryptography.MPT; using Neo.IO; using Neo.IO.Caching; using Neo.Ledger; @@ -23,7 +22,7 @@ public class SnapshotView : StoreView, IDisposable public override MetaDataCache HeaderHashIndex { get; } public override MetaDataCache ConfirmedStateRoot { get; } public override MetaDataCache ContractId { get; } - public override MPTTrie Storages { get; set; } + public override DataCache Storages { get; set; } public SnapshotView(IStore store) { @@ -37,7 +36,7 @@ public SnapshotView(IStore store) HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); ConfirmedStateRoot = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); - Storages = new MPTTrie(snapshot, CurrentStateRootHash); + Storages = new MPTDataCache(snapshot, Prefixes.IX_ConfirmedRoot, CurrentStateRootHash); // TODO } public override void Commit() diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index 09ff966153..5432f01c49 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -21,7 +21,7 @@ public abstract class StoreView public abstract MetaDataCache HeaderHashIndex { get; } public abstract MetaDataCache ConfirmedStateRoot { get; } public abstract MetaDataCache ContractId { get; } - public abstract MPTTrie Storages { get; set; } + public abstract DataCache Storages { get; set; } public uint Height => BlockHashIndex.Get().Index; public uint HeaderHeight => HeaderHashIndex.Get().Index; From 45505c9ec4a47790f0e596571747d4e2b6f2c956 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Thu, 11 Jun 2020 19:41:51 +0800 Subject: [PATCH 18/39] optimze --- src/neo/Cryptography/MPT/MPTTrie.cs | 2 +- src/neo/Persistence/MPTDataCache.cs | 7 +++---- src/neo/Persistence/ReadOnlyView.cs | 3 +-- src/neo/Persistence/SnapshotView.cs | 2 +- src/neo/Persistence/StoreView.cs | 4 ++-- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/neo/Cryptography/MPT/MPTTrie.cs b/src/neo/Cryptography/MPT/MPTTrie.cs index 92b4b9a4f8..ae21683b37 100644 --- a/src/neo/Cryptography/MPT/MPTTrie.cs +++ b/src/neo/Cryptography/MPT/MPTTrie.cs @@ -8,7 +8,7 @@ public partial class MPTTrie where TKey : notnull, ISerializable, new() where TValue : class, ISerializable, new() { - private byte Prefix = 0xf0; + private byte Prefix; private readonly ISnapshot store; private MPTNode root; diff --git a/src/neo/Persistence/MPTDataCache.cs b/src/neo/Persistence/MPTDataCache.cs index a4344b7879..7c620374a8 100644 --- a/src/neo/Persistence/MPTDataCache.cs +++ b/src/neo/Persistence/MPTDataCache.cs @@ -13,9 +13,9 @@ internal class MPTDataCache : DataCache { private MPTTrie mptTrie; - public MPTDataCache(IReadOnlyStore store, byte prefix, UInt256 CurrentStateRootHash) + public MPTDataCache(IReadOnlyStore store, byte prefix, UInt256 root) { - this.mptTrie = new MPTTrie(store as ISnapshot, prefix, CurrentStateRootHash); + mptTrie = new MPTTrie(store as ISnapshot, prefix, root); } protected override void AddInternal(TKey key, TValue value) @@ -30,8 +30,7 @@ protected override void DeleteInternal(TKey key) protected override IEnumerable<(TKey Key, TValue Value)> FindInternal(byte[] key_prefix) { - //return mptTrie.Find(prefix); - return null; + return mptTrie.Find(key_prefix); } protected override TValue GetInternal(TKey key) diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index 1f493f6846..d8d8432f4a 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -17,18 +17,17 @@ public class ReadOnlyView : StoreView 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 MPTDataCache(store, Prefixes.ST_Storage, CurrentStateRootHash); public override DataCache, HeaderHashList> HeaderHashList => new StoreDataCache, HeaderHashList>(store, Prefixes.IX_HeaderHashList); public override DataCache, HashIndexState> LocalStateRoot => new StoreDataCache, HashIndexState>(store, Prefixes.ST_Root); public override MetaDataCache BlockHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentBlock); public override MetaDataCache HeaderHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentHeader); public override MetaDataCache ConfirmedStateRoot => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); public override MetaDataCache ContractId => new StoreMetaDataCache(store, Prefixes.IX_ContractId); - public override MPTTrie Storages { get; set; } public ReadOnlyView(IReadOnlyStore store) { this.store = store; - Storages = new MPTTrie((ISnapshot)store, CurrentStateRootHash); } public override void Commit() diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index f31cc72830..4c47c45598 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -36,7 +36,7 @@ public SnapshotView(IStore store) HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); ConfirmedStateRoot = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); - Storages = new MPTDataCache(snapshot, Prefixes.IX_ConfirmedRoot, CurrentStateRootHash); // TODO + Storages = new MPTDataCache(snapshot, Prefixes.ST_Storage, CurrentStateRootHash); } public override void Commit() diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index 5432f01c49..a76601679c 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -1,4 +1,3 @@ -using Neo.Cryptography.MPT; using Neo.IO; using Neo.IO.Caching; using Neo.Ledger; @@ -15,13 +14,13 @@ public abstract class StoreView public abstract DataCache Blocks { get; } public abstract DataCache Transactions { get; } public abstract DataCache Contracts { get; } + public abstract DataCache Storages { get; } public abstract DataCache, HeaderHashList> HeaderHashList { get; } public abstract DataCache, HashIndexState> LocalStateRoot { get; } public abstract MetaDataCache BlockHashIndex { get; } public abstract MetaDataCache HeaderHashIndex { get; } public abstract MetaDataCache ConfirmedStateRoot { get; } public abstract MetaDataCache ContractId { get; } - public abstract DataCache Storages { get; set; } public uint Height => BlockHashIndex.Get().Index; public uint HeaderHeight => HeaderHashIndex.Get().Index; @@ -40,6 +39,7 @@ public virtual void Commit() Blocks.Commit(); Transactions.Commit(); Contracts.Commit(); + Storages.Commit(); HeaderHashList.Commit(); LocalStateRoot.Commit(); BlockHashIndex.Commit(); From d9c5ee26aee3e145cc0d20143026a6758973f61c Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Thu, 11 Jun 2020 19:45:10 +0800 Subject: [PATCH 19/39] optimize --- src/neo/Persistence/ClonedView.cs | 4 ++-- src/neo/Persistence/SnapshotView.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index 60a46cb8bf..986e6f49a7 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -11,13 +11,13 @@ internal class ClonedView : StoreView public override DataCache Blocks { get; } public override DataCache Transactions { get; } public override DataCache Contracts { get; } + public override DataCache Storages { get; } public override DataCache, HeaderHashList> HeaderHashList { get; } public override DataCache, HashIndexState> LocalStateRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } public override MetaDataCache ConfirmedStateRoot { get; } public override MetaDataCache ContractId { get; } - public override DataCache Storages { get; set; } public ClonedView(StoreView view) { @@ -25,13 +25,13 @@ public ClonedView(StoreView view) 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.LocalStateRoot = view.LocalStateRoot.CreateSnapshot(); this.BlockHashIndex = view.BlockHashIndex.CreateSnapshot(); this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot(); this.ConfirmedStateRoot = view.ConfirmedStateRoot.CreateSnapshot(); this.ContractId = view.ContractId.CreateSnapshot(); - this.Storages = view.Storages.CreateSnapshot(); } } } diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 4c47c45598..3e1ecdecea 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -16,13 +16,13 @@ public class SnapshotView : StoreView, IDisposable public override DataCache Blocks { get; } public override DataCache Transactions { get; } public override DataCache Contracts { get; } + public override DataCache Storages { get; } public override DataCache, HeaderHashList> HeaderHashList { get; } public override DataCache, HashIndexState> LocalStateRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } public override MetaDataCache ConfirmedStateRoot { get; } public override MetaDataCache ContractId { get; } - public override DataCache Storages { get; set; } public SnapshotView(IStore store) { @@ -30,13 +30,13 @@ public SnapshotView(IStore store) Blocks = new StoreDataCache(snapshot, Prefixes.DATA_Block); Transactions = new StoreDataCache(snapshot, Prefixes.DATA_Transaction); Contracts = new StoreDataCache(snapshot, Prefixes.ST_Contract); + Storages = new MPTDataCache(snapshot, Prefixes.ST_Storage, CurrentStateRootHash); HeaderHashList = new StoreDataCache, HeaderHashList>(snapshot, Prefixes.IX_HeaderHashList); LocalStateRoot = new StoreDataCache, HashIndexState>(snapshot, Prefixes.ST_Root); BlockHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentBlock); HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); ConfirmedStateRoot = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); - Storages = new MPTDataCache(snapshot, Prefixes.ST_Storage, CurrentStateRootHash); } public override void Commit() From 550c72e63a5e5b84240706a8cf05c66de1f39303 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Thu, 11 Jun 2020 19:47:18 +0800 Subject: [PATCH 20/39] remove blank line --- src/neo/Persistence/StoreView.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index a76601679c..1a74d19e04 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -28,7 +28,6 @@ public abstract class StoreView public UInt256 CurrentStateRootHash => LocalStateRoot.TryGet(Height)?.Hash ?? UInt256.Zero; public UInt256 CurrentHeaderHash => HeaderHashIndex.Get().Hash; - public StoreView Clone() { return new ClonedView(this); From 5b6924fa85826c6ba064807fc480f553297c8473 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 10:05:09 +0800 Subject: [PATCH 21/39] StateRoot verify fee --- src/neo/Network/P2P/Payloads/StateRoot.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 8a41e56838..301b7af32f 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -99,8 +99,7 @@ public void SerializeUnsigned(BinaryWriter writer) public bool Verify(StoreView snapshot) { - return this.VerifyWitnesses(snapshot, - ApplicationEngine.ECDsaVerifyPrice * (NativeContract.NEO.GetValidators(Blockchain.Singleton.GetSnapshot()).Length + 1)); + return this.VerifyWitnesses(snapshot, 1_00000000); } public virtual UInt160[] GetScriptHashesForVerifying(StoreView snapshot) From fb09bb06d25e98e96507ccbeeb842c59aa71bd8b Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 10:19:13 +0800 Subject: [PATCH 22/39] expose Root in MPTDataCache --- src/neo/Persistence/MPTDataCache.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/neo/Persistence/MPTDataCache.cs b/src/neo/Persistence/MPTDataCache.cs index 7c620374a8..d1d002c9e1 100644 --- a/src/neo/Persistence/MPTDataCache.cs +++ b/src/neo/Persistence/MPTDataCache.cs @@ -13,6 +13,8 @@ internal class MPTDataCache : DataCache { private MPTTrie mptTrie; + public MPTNode Root => mptTrie.Root; + public MPTDataCache(IReadOnlyStore store, byte prefix, UInt256 root) { mptTrie = new MPTTrie(store as ISnapshot, prefix, root); From b197725f9eedd306bb7ec4582519c2c0a409043f Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 11:43:52 +0800 Subject: [PATCH 23/39] fix some and ut --- src/neo/Cryptography/Helper.cs | 6 -- src/neo/Cryptography/MPT/MPTTrie.Proof.cs | 4 +- src/neo/Ledger/Blockchain.cs | 3 - src/neo/Persistence/ClonedView.cs | 8 +-- src/neo/Persistence/ReadOnlyView.cs | 4 +- src/neo/Persistence/SnapshotView.cs | 12 ++-- src/neo/Persistence/StoreView.cs | 8 +-- .../ApplicationEngine.Contract.cs | 1 - .../SmartContract/ApplicationEngine.Crypto.cs | 12 ---- .../ApplicationEngine.Storage.cs | 10 ++-- .../SmartContract/Native/PolicyContract.cs | 30 ++++------ .../SmartContract/Native/Tokens/NeoToken.cs | 38 ++++-------- .../SmartContract/Native/Tokens/Nep5Token.cs | 41 ++++--------- tests/neo.UnitTests/Consensus/UT_Consensus.cs | 2 +- .../Cryptography/MPT/UT_MPTTrie.cs | 33 ++++++----- .../Cryptography/UT_Cryptography_Helper.cs | 9 --- tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 6 +- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 4 +- .../Network/P2P/Payloads/UT_Transaction.cs | 57 +++++++++--------- tests/neo.UnitTests/Network/P2P/UT_Message.cs | 4 +- .../Native/Tokens/UT_GasToken.cs | 12 +++- .../Native/Tokens/UT_NeoToken.cs | 30 ++++++---- .../Native/Tokens/UT_Nep5Token.cs | 4 +- .../SmartContract/Native/UT_PolicyContract.cs | 4 +- .../SmartContract/UT_InteropPrices.cs | 8 +-- .../SmartContract/UT_InteropService.NEO.cs | 4 +- .../SmartContract/UT_InteropService.cs | 27 ++++----- .../SmartContract/UT_SmartContractHelper.cs | 2 +- .../SmartContract/UT_Syscalls.cs | 6 +- tests/neo.UnitTests/TestUtils.cs | 35 ++++------- tests/neo.UnitTests/UT_DataCache.cs | 15 +++-- tests/neo.UnitTests/Wallets/UT_Wallet.cs | 59 +++++-------------- 32 files changed, 205 insertions(+), 293 deletions(-) diff --git a/src/neo/Cryptography/Helper.cs b/src/neo/Cryptography/Helper.cs index 1f0c460a94..3cedb53236 100644 --- a/src/neo/Cryptography/Helper.cs +++ b/src/neo/Cryptography/Helper.cs @@ -75,12 +75,6 @@ public static byte[] RIPEMD160(this byte[] value) return ripemd160.ComputeHash(value); } - public static byte[] RIPEMD160(this ReadOnlySpan value) - { - byte[] source = value.ToArray(); - return source.RIPEMD160(); - } - public static uint Murmur32(this byte[] value, uint seed) { using (Murmur3 murmur = new Murmur3(seed)) diff --git a/src/neo/Cryptography/MPT/MPTTrie.Proof.cs b/src/neo/Cryptography/MPT/MPTTrie.Proof.cs index 7b4be120ab..ab1acd2ff4 100644 --- a/src/neo/Cryptography/MPT/MPTTrie.Proof.cs +++ b/src/neo/Cryptography/MPT/MPTTrie.Proof.cs @@ -63,9 +63,9 @@ public static TValue VerifyProof(UInt256 root, TKey key, HashSet proof) { using var memoryStore = new MemoryStore(); foreach (byte[] data in proof) - memoryStore.Put(Prefix, Crypto.Hash256(data), data); + memoryStore.Put(0, Crypto.Hash256(data), data); using ISnapshot snapshot = memoryStore.GetSnapshot(); - var trie = new MPTTrie(snapshot, root); + var trie = new MPTTrie(snapshot, 0, root); return trie[key]; } } diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 834146ed26..b10a60e870 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -442,9 +442,6 @@ private void Persist(Block block) } } snapshot.BlockHashIndex.GetAndChange().Set(block); - var root_hash_index = snapshot.LocalStateRoot.GetAndChange(block.Index, () => new HashIndexState()); - root_hash_index.Index = block.Index; - root_hash_index.Hash = snapshot.Storages.Root.Hash; foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) plugin.OnPersist(snapshot, all_application_executed); snapshot.Commit(); diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index 986e6f49a7..3e9cf440ae 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -11,13 +11,13 @@ internal class ClonedView : StoreView public override DataCache Blocks { get; } public override DataCache Transactions { get; } public override DataCache Contracts { get; } - public override DataCache Storages { get; } public override DataCache, HeaderHashList> HeaderHashList { get; } public override DataCache, HashIndexState> LocalStateRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public override MetaDataCache ConfirmedStateRoot { get; } + public override MetaDataCache LatestVerifiedStateRoot { get; } public override MetaDataCache ContractId { get; } + public override DataCache Storages { get; } public ClonedView(StoreView view) { @@ -25,13 +25,13 @@ public ClonedView(StoreView view) 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.LocalStateRoot = view.LocalStateRoot.CreateSnapshot(); this.BlockHashIndex = view.BlockHashIndex.CreateSnapshot(); this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot(); - this.ConfirmedStateRoot = view.ConfirmedStateRoot.CreateSnapshot(); + this.LatestVerifiedStateRoot = view.LatestVerifiedStateRoot.CreateSnapshot(); this.ContractId = view.ContractId.CreateSnapshot(); + this.Storages = view.Storages.CreateSnapshot(); } } } diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index d8d8432f4a..5a4b3decb8 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -17,13 +17,13 @@ public class ReadOnlyView : StoreView 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 MPTDataCache(store, Prefixes.ST_Storage, CurrentStateRootHash); public override DataCache, HeaderHashList> HeaderHashList => new StoreDataCache, HeaderHashList>(store, Prefixes.IX_HeaderHashList); public override DataCache, HashIndexState> LocalStateRoot => new StoreDataCache, HashIndexState>(store, Prefixes.ST_Root); public override MetaDataCache BlockHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentBlock); public override MetaDataCache HeaderHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentHeader); - public override MetaDataCache ConfirmedStateRoot => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); + public override MetaDataCache LatestVerifiedStateRoot => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); public override MetaDataCache ContractId => new StoreMetaDataCache(store, Prefixes.IX_ContractId); + public override DataCache Storages => new MPTDataCache(store, Prefixes.ST_Storage, CurrentStateRootHash); public ReadOnlyView(IReadOnlyStore store) { diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 3e1ecdecea..26ed9f09f5 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -16,13 +16,13 @@ public class SnapshotView : StoreView, IDisposable public override DataCache Blocks { get; } public override DataCache Transactions { get; } public override DataCache Contracts { get; } - public override DataCache Storages { get; } public override DataCache, HeaderHashList> HeaderHashList { get; } public override DataCache, HashIndexState> LocalStateRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public override MetaDataCache ConfirmedStateRoot { get; } + public override MetaDataCache LatestVerifiedStateRoot { get; } public override MetaDataCache ContractId { get; } + public override DataCache Storages { get; } public SnapshotView(IStore store) { @@ -30,18 +30,22 @@ public SnapshotView(IStore store) Blocks = new StoreDataCache(snapshot, Prefixes.DATA_Block); Transactions = new StoreDataCache(snapshot, Prefixes.DATA_Transaction); Contracts = new StoreDataCache(snapshot, Prefixes.ST_Contract); - Storages = new MPTDataCache(snapshot, Prefixes.ST_Storage, CurrentStateRootHash); HeaderHashList = new StoreDataCache, HeaderHashList>(snapshot, Prefixes.IX_HeaderHashList); LocalStateRoot = new StoreDataCache, HashIndexState>(snapshot, Prefixes.ST_Root); BlockHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentBlock); HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); - ConfirmedStateRoot = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); + LatestVerifiedStateRoot = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); + Storages = new MPTDataCache(snapshot, Prefixes.ST_Storage, CurrentStateRootHash); } public override void Commit() { base.Commit(); + var root = LocalStateRoot.GetAndChange(Height, () => new HashIndexState()); + root.Index = Height; + root.Hash = ((MPTDataCache)Storages).Root.Hash; + LocalStateRoot.Commit(); snapshot.Commit(); } diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index 1a74d19e04..b324e49c0f 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -14,13 +14,13 @@ public abstract class StoreView public abstract DataCache Blocks { get; } public abstract DataCache Transactions { get; } public abstract DataCache Contracts { get; } - public abstract DataCache Storages { get; } public abstract DataCache, HeaderHashList> HeaderHashList { get; } public abstract DataCache, HashIndexState> LocalStateRoot { get; } public abstract MetaDataCache BlockHashIndex { get; } public abstract MetaDataCache HeaderHashIndex { get; } - public abstract MetaDataCache ConfirmedStateRoot { get; } + public abstract MetaDataCache LatestVerifiedStateRoot { get; } public abstract MetaDataCache ContractId { get; } + public abstract DataCache Storages { get; } public uint Height => BlockHashIndex.Get().Index; public uint HeaderHeight => HeaderHashIndex.Get().Index; @@ -38,13 +38,13 @@ public virtual void Commit() Blocks.Commit(); Transactions.Commit(); Contracts.Commit(); - Storages.Commit(); HeaderHashList.Commit(); LocalStateRoot.Commit(); BlockHashIndex.Commit(); HeaderHashIndex.Commit(); ContractId.Commit(); - ConfirmedStateRoot.Commit(); + LatestVerifiedStateRoot.Commit(); + Storages.Commit(); } public bool ContainsBlock(UInt256 hash) diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index ed2557f356..31407a596c 100644 --- a/src/neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -139,7 +139,6 @@ private void CallContractInternal(UInt160 contractHash, string method, Array arg ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method); if (md is null) throw new InvalidOperationException(); - if (args.Count != md.Parameters.Length) throw new InvalidOperationException(); int rvcount = md.ReturnType == ContractParameterType.Void ? 0 : 1; ExecutionContext context_new = LoadScript(contract.Script, rvcount); state = context_new.GetState(); diff --git a/src/neo/SmartContract/ApplicationEngine.Crypto.cs b/src/neo/SmartContract/ApplicationEngine.Crypto.cs index 70533d900c..9cb3a9abf4 100644 --- a/src/neo/SmartContract/ApplicationEngine.Crypto.cs +++ b/src/neo/SmartContract/ApplicationEngine.Crypto.cs @@ -12,24 +12,12 @@ partial class ApplicationEngine { public const long ECDsaVerifyPrice = 0_01000000; - public static readonly InteropDescriptor Neo_Crypto_RIPEMD160 = Register("Neo.Crypto.RIPEMD160", nameof(RIPEMD160), 0_01000000, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor Neo_Crypto_SHA256 = Register("Neo.Crypto.SHA256", nameof(Sha256), 0_01000000, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor Neo_Crypto_VerifyWithECDsaSecp256r1 = Register("Neo.Crypto.VerifyWithECDsaSecp256r1", nameof(VerifyWithECDsaSecp256r1), ECDsaVerifyPrice, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor Neo_Crypto_VerifyWithECDsaSecp256k1 = Register("Neo.Crypto.VerifyWithECDsaSecp256k1", nameof(VerifyWithECDsaSecp256k1), ECDsaVerifyPrice, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor Neo_Crypto_CheckMultisigWithECDsaSecp256r1 = Register("Neo.Crypto.CheckMultisigWithECDsaSecp256r1", nameof(CheckMultisigWithECDsaSecp256r1), 0, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor Neo_Crypto_CheckMultisigWithECDsaSecp256k1 = Register("Neo.Crypto.CheckMultisigWithECDsaSecp256k1", nameof(CheckMultisigWithECDsaSecp256k1), 0, TriggerType.All, CallFlags.None); - internal byte[] RIPEMD160(StackItem item) - { - ReadOnlySpan value = item switch - { - InteropInterface _interface => _interface.GetInterface().GetHashData(), - Null _ => ScriptContainer.GetHashData(), - _ => item.GetSpan() - }; - return value.RIPEMD160(); - } - internal byte[] Sha256(StackItem item) { ReadOnlySpan value = item switch diff --git a/src/neo/SmartContract/ApplicationEngine.Storage.cs b/src/neo/SmartContract/ApplicationEngine.Storage.cs index 482c0514d7..b579c5f37f 100644 --- a/src/neo/SmartContract/ApplicationEngine.Storage.cs +++ b/src/neo/SmartContract/ApplicationEngine.Storage.cs @@ -55,11 +55,11 @@ internal StorageContext AsReadOnly(StorageContext context) internal byte[] Get(StorageContext context, byte[] key) { - return Snapshot.Storages[new StorageKey + return Snapshot.Storages.TryGet(new StorageKey { Id = context.Id, Key = key.ToArray() - }]?.Value; + })?.Value; } internal IIterator Find(StorageContext context, byte[] prefix) @@ -91,11 +91,11 @@ private void PutExInternal(StorageContext context, byte[] key, byte[] value, Sto Id = context.Id, Key = key }; - StorageItem item = Snapshot.Storages[skey]; + StorageItem item = Snapshot.Storages.GetAndChange(skey); if (item is null) { newDataSize = key.Length + value.Length; - Snapshot.Storages.Put(skey, item = new StorageItem()); + Snapshot.Storages.Add(skey, item = new StorageItem()); } else { @@ -119,7 +119,7 @@ internal void Delete(StorageContext context, byte[] key) Id = context.Id, Key = key }; - if (Snapshot.Storages[skey]?.IsConstant == true) + if (Snapshot.Storages.TryGet(skey)?.IsConstant == true) throw new InvalidOperationException(); Snapshot.Storages.Delete(skey); } diff --git a/src/neo/SmartContract/Native/PolicyContract.cs b/src/neo/SmartContract/Native/PolicyContract.cs index 41c33ae92b..2bd2244a96 100644 --- a/src/neo/SmartContract/Native/PolicyContract.cs +++ b/src/neo/SmartContract/Native/PolicyContract.cs @@ -46,19 +46,19 @@ private bool CheckCommittees(ApplicationEngine engine) internal override void Initialize(ApplicationEngine engine) { - engine.Snapshot.Storages.Put(CreateStorageKey(Prefix_MaxBlockSize), new StorageItem + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_MaxBlockSize), new StorageItem { Value = BitConverter.GetBytes(1024u * 256u) }); - engine.Snapshot.Storages.Put(CreateStorageKey(Prefix_MaxTransactionsPerBlock), new StorageItem + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_MaxTransactionsPerBlock), new StorageItem { Value = BitConverter.GetBytes(512u) }); - engine.Snapshot.Storages.Put(CreateStorageKey(Prefix_FeePerByte), new StorageItem + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_FeePerByte), new StorageItem { Value = BitConverter.GetBytes(1000L) }); - engine.Snapshot.Storages.Put(CreateStorageKey(Prefix_BlockedAccounts), new StorageItem + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_BlockedAccounts), new StorageItem { Value = new UInt160[0].ToByteArray() }); @@ -114,10 +114,8 @@ private StackItem SetMaxBlockSize(ApplicationEngine engine, Array args) if (!CheckCommittees(engine)) return false; uint value = (uint)args[0].GetBigInteger(); if (Network.P2P.Message.PayloadMaxSize <= value) return false; - StorageKey skey = CreateStorageKey(Prefix_MaxBlockSize); - StorageItem item = engine.Snapshot.Storages[skey]; - item.Value = BitConverter.GetBytes(value); - engine.Snapshot.Storages.Put(skey, item); + StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxBlockSize)); + storage.Value = BitConverter.GetBytes(value); return true; } @@ -126,10 +124,8 @@ private StackItem SetMaxTransactionsPerBlock(ApplicationEngine engine, Array arg { if (!CheckCommittees(engine)) return false; uint value = (uint)args[0].GetBigInteger(); - StorageKey skey = CreateStorageKey(Prefix_MaxTransactionsPerBlock); - StorageItem item = engine.Snapshot.Storages[skey]; - item.Value = BitConverter.GetBytes(value); - engine.Snapshot.Storages.Put(skey, item); + StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxTransactionsPerBlock)); + storage.Value = BitConverter.GetBytes(value); return true; } @@ -138,10 +134,8 @@ private StackItem SetFeePerByte(ApplicationEngine engine, Array args) { if (!CheckCommittees(engine)) return false; long value = (long)args[0].GetBigInteger(); - StorageKey skey = CreateStorageKey(Prefix_FeePerByte); - StorageItem item = engine.Snapshot.Storages[skey]; - item.Value = BitConverter.GetBytes(value); - engine.Snapshot.Storages.Put(skey, item); + StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_FeePerByte)); + storage.Value = BitConverter.GetBytes(value); return true; } @@ -154,8 +148,8 @@ private StackItem BlockAccount(ApplicationEngine engine, Array args) StorageItem storage = engine.Snapshot.Storages[key]; SortedSet accounts = new SortedSet(storage.Value.AsSerializableArray()); if (!accounts.Add(account)) return false; + storage = engine.Snapshot.Storages.GetAndChange(key); storage.Value = accounts.ToByteArray(); - engine.Snapshot.Storages.Put(key, storage); return true; } @@ -168,8 +162,8 @@ private StackItem UnblockAccount(ApplicationEngine engine, Array args) StorageItem storage = engine.Snapshot.Storages[key]; SortedSet accounts = new SortedSet(storage.Value.AsSerializableArray()); if (!accounts.Remove(account)) return false; + storage = engine.Snapshot.Storages.GetAndChange(key); storage.Value = accounts.ToByteArray(); - engine.Snapshot.Storages.Put(key, storage); return true; } } diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index f6ef2b0a06..1c63485b5c 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -42,11 +42,9 @@ protected override void OnBalanceChanging(ApplicationEngine engine, UInt160 acco if (amount.IsZero) return; if (state.VoteTo != null) { - StorageKey skey = CreateStorageKey(Prefix_Candidate, state.VoteTo.ToArray()); - StorageItem storage_validator = engine.Snapshot.Storages[skey]; + StorageItem storage_validator = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Candidate, state.VoteTo.ToArray())); CandidateState state_validator = storage_validator.GetInteroperable(); state_validator.Votes += amount; - engine.Snapshot.Storages.Put(skey, storage_validator); } } @@ -109,11 +107,8 @@ internal override void Initialize(ApplicationEngine engine) protected override bool OnPersist(ApplicationEngine engine) { if (!base.OnPersist(engine)) return false; - StorageItem storage = new StorageItem() - { - Value = GetValidators(engine.Snapshot).ToByteArray() - }; - engine.Snapshot.Storages.Put(CreateStorageKey(Prefix_NextValidators), storage); + StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_NextValidators), () => new StorageItem()); + storage.Value = GetValidators(engine.Snapshot).ToByteArray(); return true; } @@ -127,7 +122,7 @@ private StackItem UnclaimedGas(ApplicationEngine engine, Array args) public BigInteger UnclaimedGas(StoreView snapshot, UInt160 account, uint end) { - StorageItem storage = snapshot.Storages[CreateAccountKey(account)]; + StorageItem storage = snapshot.Storages.TryGet(CreateAccountKey(account)); if (storage is null) return BigInteger.Zero; NeoAccountState state = storage.GetInteroperable(); return CalculateBonus(snapshot, state.Balance, state.BalanceHeight, end); @@ -145,10 +140,9 @@ private StackItem RegisterCandidate(ApplicationEngine engine, Array args) private bool RegisterCandidate(StoreView snapshot, ECPoint pubkey) { StorageKey key = CreateStorageKey(Prefix_Candidate, pubkey); - StorageItem item = new StorageItem(new CandidateState()); + StorageItem item = snapshot.Storages.GetAndChange(key, () => new StorageItem(new CandidateState())); CandidateState state = item.GetInteroperable(); state.Registered = true; - snapshot.Storages.Put(key, item); return true; } @@ -164,16 +158,13 @@ private StackItem UnregisterCandidate(ApplicationEngine engine, Array args) private bool UnregisterCandidate(StoreView snapshot, ECPoint pubkey) { StorageKey key = CreateStorageKey(Prefix_Candidate, pubkey); - if (snapshot.Storages[key] is null) return true; - StorageItem item = snapshot.Storages[key]; + if (snapshot.Storages.TryGet(key) is null) return true; + StorageItem item = snapshot.Storages.GetAndChange(key); CandidateState state = item.GetInteroperable(); if (state.Votes.IsZero) snapshot.Storages.Delete(key); else - { state.Registered = false; - snapshot.Storages.Put(key, item); - } return true; } @@ -189,30 +180,27 @@ private StackItem Vote(ApplicationEngine engine, Array args) private bool Vote(StoreView snapshot, UInt160 account, ECPoint voteTo) { StorageKey key_account = CreateAccountKey(account); - if (snapshot.Storages[key_account] is null) return false; - StorageItem storage_account = snapshot.Storages[key_account]; + if (snapshot.Storages.TryGet(key_account) is null) return false; + StorageItem storage_account = snapshot.Storages.GetAndChange(key_account); NeoAccountState state_account = storage_account.GetInteroperable(); if (state_account.VoteTo != null) { StorageKey key = CreateStorageKey(Prefix_Candidate, state_account.VoteTo.ToArray()); - StorageItem storage_validator = snapshot.Storages[key]; + StorageItem storage_validator = snapshot.Storages.GetAndChange(key); CandidateState state_validator = storage_validator.GetInteroperable(); state_validator.Votes -= state_account.Balance; if (!state_validator.Registered && state_validator.Votes.IsZero) snapshot.Storages.Delete(key); - else - snapshot.Storages.Put(key, storage_validator); } state_account.VoteTo = voteTo; if (voteTo != null) { StorageKey key = CreateStorageKey(Prefix_Candidate, voteTo.ToArray()); - if (snapshot.Storages[key] is null) return false; - StorageItem storage_validator = snapshot.Storages[key]; + if (snapshot.Storages.TryGet(key) is null) return false; + StorageItem storage_validator = snapshot.Storages.GetAndChange(key); CandidateState state_validator = storage_validator.GetInteroperable(); if (!state_validator.Registered) return false; state_validator.Votes += state_account.Balance; - snapshot.Storages.Put(key, storage_validator); } return true; } @@ -274,7 +262,7 @@ private StackItem GetNextBlockValidators(ApplicationEngine engine, Array args) public ECPoint[] GetNextBlockValidators(StoreView snapshot) { - StorageItem storage = snapshot.Storages[CreateStorageKey(Prefix_NextValidators)]; + StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_NextValidators)); if (storage is null) return Blockchain.StandbyValidators; return storage.Value.AsSerializableArray(); } diff --git a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs index 26e7435025..855d864c59 100644 --- a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs +++ b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs @@ -69,27 +69,17 @@ internal protected virtual void Mint(ApplicationEngine engine, UInt160 account, { if (amount.Sign < 0) throw new ArgumentOutOfRangeException(nameof(amount)); if (amount.IsZero) return; - StorageKey skey = CreateAccountKey(account); - StorageItem storage = engine.Snapshot.Storages[skey]; - if (storage is null) storage = new StorageItem(new TState()); + StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateAccountKey(account), () => new StorageItem(new TState())); TState state = storage.GetInteroperable(); OnBalanceChanging(engine, account, state, amount); state.Balance += amount; - engine.Snapshot.Storages.Put(skey, storage); - - skey = CreateStorageKey(Prefix_TotalSupply); - storage = engine.Snapshot.Storages[skey]; - if (storage is null) + storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_TotalSupply), () => new StorageItem { - storage = new StorageItem() - { - Value = BigInteger.Zero.ToByteArrayStandard() - }; - } + Value = BigInteger.Zero.ToByteArrayStandard() + }); BigInteger totalSupply = new BigInteger(storage.Value); totalSupply += amount; storage.Value = totalSupply.ToByteArrayStandard(); - engine.Snapshot.Storages.Put(skey, storage); engine.SendNotification(Hash, new Array(new StackItem[] { "Transfer", StackItem.Null, account.ToArray(), amount })); } @@ -98,24 +88,18 @@ internal protected virtual void Burn(ApplicationEngine engine, UInt160 account, if (amount.Sign < 0) throw new ArgumentOutOfRangeException(nameof(amount)); if (amount.IsZero) return; StorageKey key = CreateAccountKey(account); - StorageItem storage = engine.Snapshot.Storages[key]; + StorageItem storage = engine.Snapshot.Storages.GetAndChange(key); TState state = storage.GetInteroperable(); if (state.Balance < amount) throw new InvalidOperationException(); OnBalanceChanging(engine, account, state, -amount); if (state.Balance == amount) engine.Snapshot.Storages.Delete(key); else - { state.Balance -= amount; - engine.Snapshot.Storages.Put(key, storage); - } - - key = CreateStorageKey(Prefix_TotalSupply); - storage = engine.Snapshot.Storages[key]; + storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_TotalSupply)); BigInteger totalSupply = new BigInteger(storage.Value); totalSupply -= amount; storage.Value = totalSupply.ToByteArrayStandard(); - engine.Snapshot.Storages.Put(key, storage); engine.SendNotification(Hash, new Array(new StackItem[] { "Transfer", account.ToArray(), StackItem.Null, amount })); } @@ -145,7 +129,7 @@ protected StackItem TotalSupply(ApplicationEngine engine, Array args) public virtual BigInteger TotalSupply(StoreView snapshot) { - StorageItem storage = snapshot.Storages[CreateStorageKey(Prefix_TotalSupply)]; + StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_TotalSupply)); if (storage is null) return BigInteger.Zero; return new BigInteger(storage.Value); } @@ -158,7 +142,7 @@ protected StackItem BalanceOf(ApplicationEngine engine, Array args) public virtual BigInteger BalanceOf(StoreView snapshot, UInt160 account) { - StorageItem storage = snapshot.Storages[CreateAccountKey(account)]; + StorageItem storage = snapshot.Storages.TryGet(CreateAccountKey(account)); if (storage is null) return BigInteger.Zero; return storage.GetInteroperable().Balance; } @@ -180,7 +164,7 @@ protected virtual bool Transfer(ApplicationEngine engine, UInt160 from, UInt160 ContractState contract_to = engine.Snapshot.Contracts.TryGet(to); if (contract_to?.Payable == false) return false; StorageKey key_from = CreateAccountKey(from); - StorageItem storage_from = engine.Snapshot.Storages[key_from]; + StorageItem storage_from = engine.Snapshot.Storages.GetAndChange(key_from); if (amount.IsZero) { if (storage_from != null) @@ -204,17 +188,12 @@ protected virtual bool Transfer(ApplicationEngine engine, UInt160 from, UInt160 if (state_from.Balance == amount) engine.Snapshot.Storages.Delete(key_from); else - { state_from.Balance -= amount; - engine.Snapshot.Storages.Put(key_from, storage_from); - } StorageKey key_to = CreateAccountKey(to); - StorageItem storage_to = engine.Snapshot.Storages[key_to]; - if (storage_to is null) storage_to = new StorageItem(new TState()); + StorageItem storage_to = engine.Snapshot.Storages.GetAndChange(key_to, () => new StorageItem(new TState())); TState state_to = storage_to.GetInteroperable(); OnBalanceChanging(engine, to, state_to, amount); state_to.Balance += amount; - engine.Snapshot.Storages.Put(key_to, storage_to); } } engine.SendNotification(Hash, new Array(new StackItem[] { "Transfer", from.ToArray(), to.ToArray(), amount })); diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 5613d888a6..86eb6bc8c2 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -272,7 +272,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine($"\nContract updated: {updatedContract.ScriptHash}"); // =============================================================== - mockContext.Object.Snapshot.Storages.Put(CreateStorageKeyForNativeNeo(14), new StorageItem() + mockContext.Object.Snapshot.Storages.Add(CreateStorageKeyForNativeNeo(14), new StorageItem() { Value = mockContext.Object.Validators.ToByteArray() }); diff --git a/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs b/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs index 014a10e6d2..0fb6447783 100644 --- a/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs +++ b/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs @@ -86,12 +86,13 @@ public override string ToString() [TestClass] public class UT_MPTTrie { + private byte Prefix = 0xf0; private MPTNode root; private IStore mptdb; private void PutToStore(MPTNode node) { - mptdb.Put(0xf0, node.Hash.ToArray(), node.Encode()); + mptdb.Put(Prefix, node.Hash.ToArray(), node.Encode()); } [TestInitialize] @@ -124,7 +125,7 @@ public void TestInit() [TestMethod] public void TestTryGet() { - var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); Assert.AreEqual("abcd", mpt["ac01".HexToBytes()].ToString()); Assert.AreEqual("2222", mpt["ac99".HexToBytes()].ToString()); Assert.IsNull(mpt["ab99".HexToBytes()]); @@ -136,7 +137,7 @@ public void TestTryGet() [TestMethod] public void TestTryGetResolve() { - var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); Assert.AreEqual(Encoding.ASCII.GetBytes("hello").ToHexString(), mpt["acae".HexToBytes()].ToString()); } @@ -144,7 +145,7 @@ public void TestTryGetResolve() public void TestTryPut() { var store = new MemoryStore(); - var mpt = new MPTTrie(store.GetSnapshot(), null); + var mpt = new MPTTrie(store.GetSnapshot(), Prefix, null); var result = mpt.Put("ac01".HexToBytes(), "abcd".HexToBytes()); Assert.IsTrue(result); result = mpt.Put("ac99".HexToBytes(), "2222".HexToBytes()); @@ -170,7 +171,7 @@ public void TestTryDelete() Assert.AreEqual("0xdea3ab46e9461e885ed7091c1e533e0a8030b248d39cbc638962394eaca0fbb3", r1.Hash.ToString()); Assert.AreEqual("0x93e8e1ffe2f83dd92fca67330e273bcc811bf64b8f8d9d1b25d5e7366b47d60d", r.Hash.ToString()); - var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); Assert.IsNotNull(mpt["ac99".HexToBytes()]); bool result = mpt.Delete("ac99".HexToBytes()); Assert.IsTrue(result); @@ -184,7 +185,7 @@ public void TestDeleteSameValue() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt = new MPTTrie(snapshot, null); + var mpt = new MPTTrie(snapshot, Prefix, null); Assert.IsTrue(mpt.Put("ac01".HexToBytes(), "abcd".HexToBytes())); Assert.IsTrue(mpt.Put("ac02".HexToBytes(), "abcd".HexToBytes())); Assert.IsNotNull(mpt["ac01".HexToBytes()]); @@ -193,7 +194,7 @@ public void TestDeleteSameValue() Assert.IsNotNull(mpt["ac02".HexToBytes()]); snapshot.Commit(); - var mpt0 = new MPTTrie(store.GetSnapshot(), mpt.Root.Hash); + var mpt0 = new MPTTrie(store.GetSnapshot(), Prefix, mpt.Root.Hash); Assert.IsNotNull(mpt0["ac02".HexToBytes()]); } @@ -201,7 +202,7 @@ public void TestDeleteSameValue() public void TestBranchNodeRemainValue() { var store = new MemoryStore(); - var mpt = new MPTTrie(store.GetSnapshot(), null); + var mpt = new MPTTrie(store.GetSnapshot(), Prefix, null); Assert.IsTrue(mpt.Put("ac11".HexToBytes(), "ac11".HexToBytes())); Assert.IsTrue(mpt.Put("ac22".HexToBytes(), "ac22".HexToBytes())); Assert.IsTrue(mpt.Put("ac".HexToBytes(), "ac".HexToBytes())); @@ -226,7 +227,7 @@ public void TestGetProof() b.Children[9] = l2; b.Children[10] = l3; - var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); Assert.AreEqual(r.Hash.ToString(), mpt.Root.Hash.ToString()); HashSet proof = mpt.GetProof("ac01".HexToBytes()); Assert.AreEqual(4, proof.Count); @@ -239,7 +240,7 @@ public void TestGetProof() [TestMethod] public void TestVerifyProof() { - var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); HashSet proof = mpt.GetProof("ac01".HexToBytes()); TestValue value = MPTTrie.VerifyProof(root.Hash, "ac01".HexToBytes(), proof); Assert.IsNotNull(value); @@ -251,7 +252,7 @@ public void TestAddLongerKey() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt = new MPTTrie(snapshot, null); + var mpt = new MPTTrie(snapshot, Prefix, null); var result = mpt.Put(new byte[] { 0xab }, new byte[] { 0x01 }); Assert.IsTrue(result); result = mpt.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x02 }); @@ -263,12 +264,12 @@ public void TestSplitKey() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt1 = new MPTTrie(snapshot, null); + var mpt1 = new MPTTrie(snapshot, Prefix, null); Assert.IsTrue(mpt1.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x01 })); Assert.IsTrue(mpt1.Put(new byte[] { 0xab }, new byte[] { 0x02 })); HashSet set1 = mpt1.GetProof(new byte[] { 0xab, 0xcd }); Assert.AreEqual(4, set1.Count); - var mpt2 = new MPTTrie(snapshot, null); + var mpt2 = new MPTTrie(snapshot, Prefix, null); Assert.IsTrue(mpt2.Put(new byte[] { 0xab }, new byte[] { 0x02 })); Assert.IsTrue(mpt2.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x01 })); HashSet set2 = mpt2.GetProof(new byte[] { 0xab, 0xcd }); @@ -281,10 +282,10 @@ public void TestFind() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt1 = new MPTTrie(snapshot, null); + var mpt1 = new MPTTrie(snapshot, Prefix, null); var results = mpt1.Find(ReadOnlySpan.Empty).ToArray(); Assert.AreEqual(0, results.Count()); - var mpt2 = new MPTTrie(snapshot, null); + var mpt2 = new MPTTrie(snapshot, Prefix, null); Assert.IsTrue(mpt2.Put(new byte[] { 0xab, 0xcd, 0xef }, new byte[] { 0x01 })); Assert.IsTrue(mpt2.Put(new byte[] { 0xab, 0xcd, 0xe1 }, new byte[] { 0x02 })); Assert.IsTrue(mpt2.Put(new byte[] { 0xab }, new byte[] { 0x03 })); @@ -304,7 +305,7 @@ public void TestFindLeadNode() // r.Key = 0x0a0c // b.Key = 0x00 // l1.Key = 0x01 - var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); var prefix = new byte[] { 0xac, 0x01 }; // = FromNibbles(path = { 0x0a, 0x0c, 0x00, 0x01 }); var results = mpt.Find(prefix).ToArray(); Assert.AreEqual(1, results.Count()); diff --git a/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs index b2c5775903..0e17d0913c 100644 --- a/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs +++ b/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs @@ -133,15 +133,6 @@ public void TestSha256() resultStr.Should().Be("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"); } - [TestMethod] - public void TestRIPEMD160() - { - ReadOnlySpan value = Encoding.ASCII.GetBytes("hello world"); - byte[] result = value.RIPEMD160(); - string resultStr = result.ToHexString(); - resultStr.Should().Be("98c615784ccb5fe5936fbc0cbe9dfdb408d92f0f"); - } - [TestMethod] public void TestTest() { diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index b7fe1af7fc..7e04dfe229 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -116,10 +116,10 @@ public void TestValidTransaction() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); + snapshot.Commit(); typeof(Blockchain) diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index b420190f38..4e96605b7b 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -485,8 +485,8 @@ public void TestUpdatePoolForBlockPersisted() var key2 = CreateStorageKey(Prefix_FeePerByte); key1.Id = NativeContract.Policy.Id; key2.Id = NativeContract.Policy.Id; - snapshot.Storages.Put(key1, item1); - snapshot.Storages.Put(key2, item2); + snapshot.Storages.Add(key1, item1); + snapshot.Storages.Add(key2, item2); var tx1 = CreateTransaction(); var tx2 = CreateTransaction(); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 7781cbfc86..7e025ad4cd 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -107,10 +107,10 @@ public void FeeIsMultiSigContract() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); + snapshot.Commit(); // Make transaction @@ -177,10 +177,10 @@ public void FeeIsSignatureContractDetailed() var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); + snapshot.Commit(); // Make transaction @@ -288,10 +288,10 @@ public void FeeIsSignatureContract_TestScope_Global() var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); + snapshot.Commit(); // Make transaction @@ -374,10 +374,10 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); + snapshot.Commit(); // Make transaction @@ -461,10 +461,10 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); + snapshot.Commit(); // Make transaction @@ -551,10 +551,10 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); + // Make transaction // Manually creating script @@ -600,10 +600,11 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); + snapshot.Commit(); // Make transaction @@ -691,10 +692,11 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); + // Make transaction // Manually creating script @@ -936,10 +938,11 @@ public void FeeIsSignatureContract_TestScope_Global_Default() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); + snapshot.Commit(); // Make transaction diff --git a/tests/neo.UnitTests/Network/P2P/UT_Message.cs b/tests/neo.UnitTests/Network/P2P/UT_Message.cs index 574af05322..6f194ea862 100644 --- a/tests/neo.UnitTests/Network/P2P/UT_Message.cs +++ b/tests/neo.UnitTests/Network/P2P/UT_Message.cs @@ -14,7 +14,7 @@ public class UT_Message [TestMethod] public void Serialize_Deserialize() { - var payload = PingPayload.Create(uint.MaxValue, 0); + var payload = PingPayload.Create(uint.MaxValue); var msg = Message.Create(MessageCommand.Ping, payload); var buffer = msg.ToArray(); var copy = buffer.AsSerializable(); @@ -31,7 +31,7 @@ public void Serialize_Deserialize() [TestMethod] public void Serialize_Deserialize_ByteString() { - var payload = PingPayload.Create(uint.MaxValue, 0); + var payload = PingPayload.Create(uint.MaxValue); var msg = Message.Create(MessageCommand.Ping, payload); var buffer = ByteString.CopyFrom(msg.ToArray()); var length = Message.TryDeserialize(buffer, out var copy); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index a3b99c6ddd..f7be52f9a6 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -44,6 +44,7 @@ public void Check_BalanceOfTransferAndBurn() byte[] to = new byte[20]; + var keyCount = snapshot.Storages.GetChangeSet().Count(); var supply = NativeContract.GAS.TotalSupply(snapshot); supply.Should().Be(3000000000000000); @@ -66,15 +67,18 @@ public void Check_BalanceOfTransferAndBurn() // Check unclaim unclaim = UT_NeoToken.Check_UnclaimedGas(snapshot, from); - unclaim.Value.Should().Be(new BigInteger(300000048000)); + unclaim.Value.Should().Be(new BigInteger(0)); unclaim.State.Should().BeTrue(); supply = NativeContract.GAS.TotalSupply(snapshot); supply.Should().Be(3000300000048000); + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 3); // Gas // Transfer + keyCount = snapshot.Storages.GetChangeSet().Count(); + NativeContract.GAS.Transfer(snapshot, from, to, 3000300000048000, false).Should().BeFalse(); // Not signed NativeContract.GAS.Transfer(snapshot, from, to, 3000300000048001, true).Should().BeFalse(); // More than balance NativeContract.GAS.Transfer(snapshot, from, to, 3000300000048000, true).Should().BeTrue(); // All balance @@ -84,9 +88,12 @@ public void Check_BalanceOfTransferAndBurn() NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(3000300000048000); NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(0); + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 1); // All + // Burn var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); + keyCount = snapshot.Storages.GetChangeSet().Count(); Assert.ThrowsException(() => NativeContract.GAS.Burn(engine, new UInt160(to), BigInteger.MinusOne)); @@ -102,11 +109,14 @@ public void Check_BalanceOfTransferAndBurn() NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(3000300000047999); + keyCount.Should().Be(snapshot.Storages.GetChangeSet().Count()); // Burn all NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(3000300000047999)); + (keyCount - 1).Should().Be(snapshot.Storages.GetChangeSet().Count()); + // Bad inputs NativeContract.GAS.Transfer(snapshot, from, to, BigInteger.MinusOne, true).Should().BeFalse(); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 965ed84795..12b025400b 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -100,12 +100,14 @@ public void Check_RegisterValidator() { var snapshot = Blockchain.Singleton.GetSnapshot(); + var keyCount = snapshot.Storages.GetChangeSet().Count(); var point = Blockchain.StandbyValidators[0].EncodePoint(true); var ret = Check_RegisterValidator(snapshot, point); // Exists ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); + snapshot.Storages.GetChangeSet().Count().Should().Be(++keyCount); // No changes point[20]++; // fake point ret = Check_RegisterValidator(snapshot, point); // New @@ -113,6 +115,7 @@ public void Check_RegisterValidator() ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 1); // New validator // Check GetRegisteredValidators @@ -138,6 +141,7 @@ public void Check_Transfer() byte[] to = new byte[20]; + var keyCount = snapshot.Storages.GetChangeSet().Count(); // Check unclaim @@ -158,12 +162,15 @@ public void Check_Transfer() unclaim.Value.Should().Be(new BigInteger(0)); unclaim.State.Should().BeTrue(); + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 4); // Gas + new balance // Return balance + keyCount = snapshot.Storages.GetChangeSet().Count(); NativeContract.NEO.Transfer(snapshot, to, from, BigInteger.One, true).Should().BeTrue(); NativeContract.NEO.BalanceOf(snapshot, to).Should().Be(0); + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount - 1); // Remove neo balance from address two // Bad inputs @@ -216,15 +223,14 @@ public void TestCalculateBonus() { var snapshot = Blockchain.Singleton.GetSnapshot(); StorageKey key = CreateStorageKey(20, UInt160.Zero.ToArray()); - snapshot.Storages.Put(key, new StorageItem(new NeoAccountState + snapshot.Storages.Add(key, new StorageItem(new NeoAccountState { Balance = -100 })); Action action = () => NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); action.Should().Throw(); snapshot.Storages.Delete(key); - - snapshot.Storages.Put(key, new StorageItem(new NeoAccountState + snapshot.Storages.GetAndChange(key, () => new StorageItem(new NeoAccountState { Balance = 100 })); @@ -263,7 +269,7 @@ public void TestGetNextBlockValidators2() result[5].ToArray().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); result[6].ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); - snapshot.Storages.Put(CreateStorageKey(14), new StorageItem() + snapshot.Storages.Add(CreateStorageKey(14), new StorageItem() { Value = new ECPoint[] { ECCurve.Secp256r1.G }.ToByteArray() }); @@ -318,7 +324,7 @@ public void TestGetRegisteredValidators2() result[6].Votes.Should().Be(new BigInteger(1785714)); StorageKey key = NativeContract.NEO.CreateStorageKey(33, ECCurve.Secp256r1.G); - snapshot.Storages.Put(key, new StorageItem(new CandidateState())); + snapshot.Storages.Add(key, new StorageItem(new CandidateState())); NativeContract.NEO.GetCandidates(snapshot).ToArray().Length.Should().Be(22); } @@ -382,7 +388,7 @@ public void TestUnclaimedGas() { var snapshot = Blockchain.Singleton.GetSnapshot(); NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); - snapshot.Storages.Put(CreateStorageKey(20, UInt160.Zero.ToArray()), new StorageItem(new NeoAccountState())); + snapshot.Storages.Add(CreateStorageKey(20, UInt160.Zero.ToArray()), new StorageItem(new NeoAccountState())); NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); } @@ -401,17 +407,17 @@ public void TestVote() ret.State.Should().BeTrue(); ret.Result.Should().BeFalse(); - snapshot.Storages.Put(keyAccount, new StorageItem(new NeoAccountState())); + snapshot.Storages.Add(keyAccount, new StorageItem(new NeoAccountState())); ret = Check_Vote(snapshot, account.ToArray(), ECCurve.Secp256r1.G.ToArray(), true); ret.State.Should().BeTrue(); ret.Result.Should().BeFalse(); snapshot.Storages.Delete(keyAccount); - snapshot.Storages.Put(keyAccount, new StorageItem(new NeoAccountState + snapshot.Storages.GetAndChange(keyAccount, () => new StorageItem(new NeoAccountState { VoteTo = ECCurve.Secp256r1.G })); - snapshot.Storages.Put(keyValidator, new StorageItem(new CandidateState())); + snapshot.Storages.Add(keyValidator, new StorageItem(new CandidateState())); ret = Check_Vote(snapshot, account.ToArray(), ECCurve.Secp256r1.G.ToArray(), true); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); @@ -427,16 +433,16 @@ public void TestVote() UInt160 from = engine.ScriptContainer.GetScriptHashesForVerifying(engine.Snapshot)[0]; if (addVotes) { - snapshot.Storages.Put(CreateStorageKey(20, from.ToArray()), new StorageItem(new NeoAccountState + snapshot.Storages.Add(CreateStorageKey(20, from.ToArray()), new StorageItem(new NeoAccountState { VoteTo = ECCurve.Secp256r1.G, Balance = new BigInteger(1000) })); - snapshot.Storages.Put(NativeContract.NEO.CreateStorageKey(33, ECCurve.Secp256r1.G), new StorageItem(new CandidateState())); + snapshot.Storages.Add(NativeContract.NEO.CreateStorageKey(33, ECCurve.Secp256r1.G), new StorageItem(new CandidateState())); } else { - snapshot.Storages.Put(CreateStorageKey(20, from.ToArray()), new StorageItem(new NeoAccountState + snapshot.Storages.Add(CreateStorageKey(20, from.ToArray()), new StorageItem(new NeoAccountState { Balance = new BigInteger(1000) })); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs index 42ff27a9f9..8c6d8eefef 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs @@ -36,7 +36,7 @@ public void TestTotalSupply() key.Id = test.Id; - snapshot.Storages.Put(key, item); + snapshot.Storages.Add(key, item); ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); StackItem stackItem = test.TotalSupply(ae, null); stackItem.GetBigInteger().Should().Be(1); @@ -58,7 +58,7 @@ public void TestTotalSupplyDecimal() key.Id = test.Id; - snapshot.Storages.Put(key, item); + snapshot.Storages.Add(key, item); ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); StackItem stackItem = test.TotalSupply(ae, null); diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 858722e38c..1740495571 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -27,9 +27,11 @@ public void TestSetup() public void Check_Initialize() { var snapshot = Blockchain.Singleton.GetSnapshot(); + var keyCount = snapshot.Storages.GetChangeSet().Count(); NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); + (keyCount + 4).Should().Be(snapshot.Storages.GetChangeSet().Count()); var ret = NativeContract.Policy.Call(snapshot, "getMaxTransactionsPerBlock"); ret.Should().BeOfType(); @@ -239,7 +241,7 @@ public void TestCheckPolicy() Key = new byte[sizeof(byte)] }; storageKey.Key[0] = 15; - snapshot.Storages.Put(storageKey, new StorageItem + snapshot.Storages.Add(storageKey, new StorageItem { Value = new UInt160[] { tx.Sender }.ToByteArray(), }); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs index f5fe243107..cf93e5abb3 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs @@ -62,7 +62,7 @@ public void ApplicationEngineRegularPut() StorageItem sItem = TestUtils.GetStorageItem(new byte[0] { }); var snapshot = Blockchain.Singleton.GetSnapshot(); - snapshot.Storages.Put(skey, sItem); + snapshot.Storages.Add(skey, sItem); snapshot.Contracts.Add(script.ToScriptHash(), contractState); using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) @@ -96,7 +96,7 @@ public void ApplicationEngineReusedStorage_FullReuse() StorageItem sItem = TestUtils.GetStorageItem(value); var snapshot = Blockchain.Singleton.GetSnapshot(); - snapshot.Storages.Put(skey, sItem); + snapshot.Storages.Add(skey, sItem); snapshot.Contracts.Add(script.ToScriptHash(), contractState); using (ApplicationEngine applicationEngine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) @@ -132,7 +132,7 @@ public void ApplicationEngineReusedStorage_PartialReuse() StorageItem sItem = TestUtils.GetStorageItem(oldValue); var snapshot = Blockchain.Singleton.GetSnapshot(); - snapshot.Storages.Put(skey, sItem); + snapshot.Storages.Add(skey, sItem); snapshot.Contracts.Add(script.ToScriptHash(), contractState); using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) @@ -169,7 +169,7 @@ public void ApplicationEngineReusedStorage_PartialReuseTwice() StorageItem sItem = TestUtils.GetStorageItem(oldValue); var snapshot = Blockchain.Singleton.GetSnapshot(); - snapshot.Storages.Put(skey, sItem); + snapshot.Storages.Add(skey, sItem); snapshot.Contracts.Add(script.ToScriptHash(), contractState); using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index a055a9181f..b0a2547107 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -179,7 +179,7 @@ public void TestContract_Update() Key = new byte[] { 0x01 } }; snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Put(storageKey, storageItem); + snapshot.Storages.Add(storageKey, storageItem); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(state.Script); engine.UpdateContract(script, manifest.ToJson().ToByteArray(false)); @@ -204,7 +204,7 @@ public void TestStorage_Find() Key = new byte[] { 0x01 } }; snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Put(storageKey, storageItem); + snapshot.Storages.Add(storageKey, storageItem); var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 5842f80387..399f063ec7 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -55,7 +55,7 @@ public void Runtime_GetNotifications_Test() snapshot.Contracts.Add(scriptHash2, new ContractState() { Script = script.ToArray(), - Manifest = TestUtils.CreateManifest(scriptHash2, "test", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer), + Manifest = TestUtils.CreateDefaultManifest(scriptHash2, "test"), }); } @@ -223,7 +223,7 @@ public void TestExecutionEngine_GetCallingScriptHash() var contract = new ContractState() { - Manifest = TestUtils.CreateManifest(scriptA.ToArray().ToScriptHash(), "test", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer), + Manifest = TestUtils.CreateDefaultManifest(scriptA.ToArray().ToScriptHash(), "test"), Script = scriptA.ToArray() }; engine = GetEngine(true, true, false); @@ -441,7 +441,7 @@ public void TestStorage_Get() IsConstant = true }; snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Put(storageKey, storageItem); + snapshot.Storages.Add(storageKey, storageItem); var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); @@ -499,7 +499,7 @@ public void TestStorage_Put() IsConstant = true }; snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Put(storageKey, storageItem); + snapshot.Storages.Add(storageKey, storageItem); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); key = new byte[] { 0x01 }; @@ -508,12 +508,11 @@ public void TestStorage_Put() Assert.ThrowsException(() => engine.Put(storageContext, key, value)); //success - key = new byte[] { 0x02 }; storageItem.IsConstant = false; engine.Put(storageContext, key, value); //value length == 0 - key = new byte[] { 0x02 }; + key = new byte[] { 0x01 }; value = new byte[0]; engine.Put(storageContext, key, value); } @@ -536,7 +535,7 @@ public void TestStorage_PutEx() IsConstant = false }; snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Put(storageKey, storageItem); + snapshot.Storages.Add(storageKey, storageItem); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); var key = new byte[] { 0x01 }; @@ -567,7 +566,7 @@ public void TestStorage_Delete() IsConstant = false }; snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Put(storageKey, storageItem); + snapshot.Storages.Add(storageKey, storageItem); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); state.Manifest.Features = ContractFeatures.HasStorage; @@ -601,10 +600,10 @@ public void TestStorageContext_AsReadOnly() public void TestContract_Call() { var snapshot = Blockchain.Singleton.GetSnapshot(); + var state = TestUtils.GetContract("method"); + state.Manifest.Features = ContractFeatures.HasStorage; string method = "method"; var args = new VM.Types.Array { 0, 1 }; - var state = TestUtils.GetContract(method, args.Count); - state.Manifest.Features = ContractFeatures.HasStorage; snapshot.Contracts.Add(state.ScriptHash, state); var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); @@ -628,12 +627,12 @@ public void TestContract_CallEx() { var snapshot = Blockchain.Singleton.GetSnapshot(); - string method = "method"; - var args = new VM.Types.Array { 0, 1 }; - var state = TestUtils.GetContract(method, args.Count); + var state = TestUtils.GetContract("method"); state.Manifest.Features = ContractFeatures.HasStorage; snapshot.Contracts.Add(state.ScriptHash, state); + string method = "method"; + var args = new VM.Types.Array { 0, 1 }; foreach (var flags in new CallFlags[] { CallFlags.None, CallFlags.AllowCall, CallFlags.AllowModifyStates, CallFlags.All }) { @@ -676,7 +675,7 @@ public void TestContract_Destroy() Key = new byte[] { 0x01 } }; snapshot.Contracts.Add(scriptHash, state); - snapshot.Storages.Put(storageKey, storageItem); + snapshot.Storages.Add(storageKey, storageItem); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[0]); engine.DestroyContract(); diff --git a/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs index 0f4e9f5f74..3677041aa2 100644 --- a/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs +++ b/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -139,7 +139,7 @@ public void TestVerifyWitnesses() Header header3 = new Header() { PrevHash = index3, Witness = new Witness { VerificationScript = new byte[0] } }; snapshot3.Contracts.Add(UInt160.Zero, new ContractState() { - Manifest = TestUtils.CreateManifest(UInt160.Zero, "verify", ContractParameterType.Boolean, ContractParameterType.Signature), + Manifest = TestUtils.CreateDefaultManifest(UInt160.Zero, "verify"), }); 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 96b2ac0345..848079aef3 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -339,9 +339,9 @@ public void System_Runtime_GetInvocationCounter() contracts.Delete(contractA.ScriptHash); contracts.Delete(contractB.ScriptHash); contracts.Delete(contractC.ScriptHash); - contractA.Manifest = TestUtils.CreateManifest(contractA.ScriptHash, "dummyMain", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer); - contractB.Manifest = TestUtils.CreateManifest(contractA.ScriptHash, "dummyMain", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer); - contractC.Manifest = TestUtils.CreateManifest(contractA.ScriptHash, "dummyMain", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer); + contractA.Manifest = TestUtils.CreateDefaultManifest(contractA.ScriptHash, "dummyMain"); + contractB.Manifest = TestUtils.CreateDefaultManifest(contractA.ScriptHash, "dummyMain"); + contractC.Manifest = TestUtils.CreateDefaultManifest(contractA.ScriptHash, "dummyMain"); contracts.Add(contractA.ScriptHash, contractA); contracts.Add(contractB.ScriptHash, contractB); contracts.Add(contractC.ScriptHash, contractC); diff --git a/tests/neo.UnitTests/TestUtils.cs b/tests/neo.UnitTests/TestUtils.cs index ef380908dd..fd8e6fd620 100644 --- a/tests/neo.UnitTests/TestUtils.cs +++ b/tests/neo.UnitTests/TestUtils.cs @@ -17,7 +17,7 @@ public static class TestUtils { public static readonly Random TestRandom = new Random(1337); // use fixed seed for guaranteed determinism - public static ContractManifest CreateDefaultManifest(UInt160 hash) + public static ContractManifest CreateDefaultManifest(UInt160 hash, string method = null) { return new ContractManifest() { @@ -26,7 +26,15 @@ public static ContractManifest CreateDefaultManifest(UInt160 hash) { Hash = hash, Events = new ContractEventDescriptor[0], - Methods = new ContractMethodDescriptor[0] + Methods = method == null ? new ContractMethodDescriptor[0] : new ContractMethodDescriptor[] + { + new ContractMethodDescriptor() + { + Name = method, + Parameters = new ContractParameterDefinition[0], + ReturnType = ContractParameterType.Integer + } + } }, Features = ContractFeatures.NoProperty, Groups = new ContractGroup[0], @@ -36,25 +44,6 @@ public static ContractManifest CreateDefaultManifest(UInt160 hash) }; } - public static ContractManifest CreateManifest(UInt160 hash, string method, ContractParameterType returnType, params ContractParameterType[] parameterTypes) - { - ContractManifest manifest = CreateDefaultManifest(hash); - manifest.Abi.Methods = new ContractMethodDescriptor[] - { - new ContractMethodDescriptor() - { - Name = method, - Parameters = parameterTypes.Select((p, i) => new ContractParameterDefinition - { - Name = $"p{i}", - Type = p - }).ToArray(), - ReturnType = returnType - } - }; - return manifest; - } - public static byte[] GetByteArray(int length, byte firstByte) { byte[] array = new byte[length]; @@ -93,13 +82,13 @@ public static Transaction GetTransaction() }; } - internal static ContractState GetContract(string method = "test", int parametersCount = 0) + internal static ContractState GetContract(string method = null) { return new ContractState { Id = 0x43000000, Script = new byte[] { 0x01, 0x01, 0x01, 0x01 }, - Manifest = CreateManifest(UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"), method, ContractParameterType.Any, Enumerable.Repeat(ContractParameterType.Any, parametersCount).ToArray()) + Manifest = CreateDefaultManifest(UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"), method) }; } diff --git a/tests/neo.UnitTests/UT_DataCache.cs b/tests/neo.UnitTests/UT_DataCache.cs index 1b69aa7833..22bcdaa26d 100644 --- a/tests/neo.UnitTests/UT_DataCache.cs +++ b/tests/neo.UnitTests/UT_DataCache.cs @@ -1,7 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO.Caching; using Neo.Ledger; -using Neo.Persistence; using System.Linq; namespace Neo.UnitTests @@ -12,14 +11,14 @@ public class UT_DataCache [TestInitialize] public void TestSetup() { - + TestBlockchain.InitializeMockNeoSystem(); } [TestMethod] public void TestCachedFind_Between() { - var store = new MemoryStore(); - var storages = new StoreDataCache(store.GetSnapshot(), Prefixes.ST_Storage); + var snapshot = Blockchain.Singleton.GetSnapshot(); + var storages = snapshot.Storages.CreateSnapshot(); var cache = new CloneCache(storages); storages.Add @@ -57,8 +56,8 @@ public void TestCachedFind_Between() [TestMethod] public void TestCachedFind_Last() { - var store = new MemoryStore(); - var storages = new StoreDataCache(store.GetSnapshot(), Prefixes.ST_Storage); + var snapshot = Blockchain.Singleton.GetSnapshot(); + var storages = snapshot.Storages.CreateSnapshot(); var cache = new CloneCache(storages); storages.Add @@ -89,8 +88,8 @@ public void TestCachedFind_Last() [TestMethod] public void TestCachedFind_Empty() { - var store = new MemoryStore(); - var storages = new StoreDataCache(store.GetSnapshot(), Prefixes.ST_Storage); + var snapshot = Blockchain.Singleton.GetSnapshot(); + var storages = snapshot.Storages.CreateSnapshot(); var cache = new CloneCache(storages); cache.Add diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index 2c378a7112..e63145ff5d 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -203,18 +203,14 @@ public void TestGetAvailable() // Fake balance var snapshot = Blockchain.Singleton.GetSnapshot(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); snapshot.Commit(); wallet.GetAvailable(NativeContract.GAS.Hash).Should().Be(new BigDecimal(1000000000000, 8)); - entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 0; - snapshot.Storages.Put(key, entry); snapshot.Commit(); } @@ -229,18 +225,15 @@ public void TestGetBalance() // Fake balance var snapshot = Blockchain.Singleton.GetSnapshot(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); 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)); - entry = snapshot.Storages[key]; + entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 0; - snapshot.Storages.Put(key, entry); snapshot.Commit(); } @@ -296,21 +289,6 @@ public void TestMakeTransaction1() WalletAccount account = wallet.CreateAccount(contract, glkey.PrivateKey); account.Lock = false; - // Make sure balance is 0 - var snapshot = Blockchain.Singleton.GetSnapshot(); - var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - - var entry1 = snapshot.Storages[key]; - if (entry1 is null) entry1 = new StorageItem(new AccountState()); - entry1.GetInteroperable().Balance = 0; - snapshot.Storages.Put(key, entry1); - key = NativeContract.NEO.CreateStorageKey(20, account.ScriptHash); - var entry2 = snapshot.Storages[key]; - if (entry2 is null) entry2 = new StorageItem(new NeoToken.NeoAccountState()); - entry2.GetInteroperable().Balance = 0; - snapshot.Storages.Put(key, entry2); - snapshot.Commit(); - Action action = () => wallet.MakeTransaction(new TransferOutput[] { new TransferOutput() @@ -345,18 +323,15 @@ public void TestMakeTransaction1() action.Should().Throw(); // Fake balance - snapshot = Blockchain.Singleton.GetSnapshot(); - key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - - entry1 = snapshot.Storages[key]; - if (entry1 is null) entry1 = new StorageItem(new AccountState()); + var snapshot = Blockchain.Singleton.GetSnapshot(); + var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); + var entry1 = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry1.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry1); + key = NativeContract.NEO.CreateStorageKey(20, account.ScriptHash); - entry2 = snapshot.Storages[key]; - if (entry2 is null) entry2 = new StorageItem(new NeoToken.NeoAccountState()); + var entry2 = snapshot.Storages.GetAndChange(key, () => new StorageItem(new NeoToken.NeoAccountState())); entry2.GetInteroperable().Balance = 10000 * NativeContract.NEO.Factor; - snapshot.Storages.Put(key, entry2); + snapshot.Commit(); var tx = wallet.MakeTransaction(new TransferOutput[] @@ -381,10 +356,8 @@ public void TestMakeTransaction1() }); tx.Should().NotBeNull(); - entry1 = snapshot.Storages[key]; - if (entry1 is null) entry1 = new StorageItem(new AccountState()); - entry2 = snapshot.Storages[key]; - if (entry2 is null) entry2 = new StorageItem(new AccountState()); + entry1 = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry2 = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry1.GetInteroperable().Balance = 0; entry2.GetInteroperable().Balance = 0; snapshot.Commit(); @@ -404,11 +377,8 @@ public void TestMakeTransaction2() // Fake balance var snapshot = Blockchain.Singleton.GetSnapshot(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - - var entry = snapshot.Storages[key]; - if (entry is null) entry = new StorageItem(new AccountState()); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 1000000 * NativeContract.GAS.Factor; - snapshot.Storages.Put(key, entry); snapshot.Commit(); var tx = wallet.MakeTransaction(new byte[] { }, account.ScriptHash, new TransactionAttribute[] { }); @@ -417,9 +387,8 @@ public void TestMakeTransaction2() tx = wallet.MakeTransaction(new byte[] { }, null, new TransactionAttribute[] { }); tx.Should().NotBeNull(); - entry = snapshot.Storages[key]; + entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 0; - snapshot.Storages.Put(key, entry); snapshot.Commit(); } From 2376eb2f55dbce3e61cfa8bb8a466b454640615b Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 13:14:30 +0800 Subject: [PATCH 24/39] merge master --- src/neo/Cryptography/Helper.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/neo/Cryptography/Helper.cs b/src/neo/Cryptography/Helper.cs index 3cedb53236..1f0c460a94 100644 --- a/src/neo/Cryptography/Helper.cs +++ b/src/neo/Cryptography/Helper.cs @@ -75,6 +75,12 @@ public static byte[] RIPEMD160(this byte[] value) return ripemd160.ComputeHash(value); } + public static byte[] RIPEMD160(this ReadOnlySpan value) + { + byte[] source = value.ToArray(); + return source.RIPEMD160(); + } + public static uint Murmur32(this byte[] value, uint seed) { using (Murmur3 murmur = new Murmur3(seed)) From a42998fae97553fee8bc2d412a3d06499ce836f8 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 13:16:38 +0800 Subject: [PATCH 25/39] master --- .../ApplicationEngine.Contract.cs | 1 + .../SmartContract/ApplicationEngine.Crypto.cs | 12 +++++++ .../Cryptography/MPT/UT_MPTTrie.cs | 33 +++++++++-------- .../Cryptography/UT_Cryptography_Helper.cs | 9 +++++ .../SmartContract/UT_InteropService.cs | 14 ++++---- .../SmartContract/UT_SmartContractHelper.cs | 2 +- .../SmartContract/UT_Syscalls.cs | 6 ++-- tests/neo.UnitTests/TestUtils.cs | 35 ++++++++++++------- 8 files changed, 72 insertions(+), 40 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index 31407a596c..ed2557f356 100644 --- a/src/neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -139,6 +139,7 @@ private void CallContractInternal(UInt160 contractHash, string method, Array arg ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method); if (md is null) throw new InvalidOperationException(); + if (args.Count != md.Parameters.Length) throw new InvalidOperationException(); int rvcount = md.ReturnType == ContractParameterType.Void ? 0 : 1; ExecutionContext context_new = LoadScript(contract.Script, rvcount); state = context_new.GetState(); diff --git a/src/neo/SmartContract/ApplicationEngine.Crypto.cs b/src/neo/SmartContract/ApplicationEngine.Crypto.cs index 9cb3a9abf4..70533d900c 100644 --- a/src/neo/SmartContract/ApplicationEngine.Crypto.cs +++ b/src/neo/SmartContract/ApplicationEngine.Crypto.cs @@ -12,12 +12,24 @@ partial class ApplicationEngine { public const long ECDsaVerifyPrice = 0_01000000; + public static readonly InteropDescriptor Neo_Crypto_RIPEMD160 = Register("Neo.Crypto.RIPEMD160", nameof(RIPEMD160), 0_01000000, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor Neo_Crypto_SHA256 = Register("Neo.Crypto.SHA256", nameof(Sha256), 0_01000000, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor Neo_Crypto_VerifyWithECDsaSecp256r1 = Register("Neo.Crypto.VerifyWithECDsaSecp256r1", nameof(VerifyWithECDsaSecp256r1), ECDsaVerifyPrice, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor Neo_Crypto_VerifyWithECDsaSecp256k1 = Register("Neo.Crypto.VerifyWithECDsaSecp256k1", nameof(VerifyWithECDsaSecp256k1), ECDsaVerifyPrice, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor Neo_Crypto_CheckMultisigWithECDsaSecp256r1 = Register("Neo.Crypto.CheckMultisigWithECDsaSecp256r1", nameof(CheckMultisigWithECDsaSecp256r1), 0, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor Neo_Crypto_CheckMultisigWithECDsaSecp256k1 = Register("Neo.Crypto.CheckMultisigWithECDsaSecp256k1", nameof(CheckMultisigWithECDsaSecp256k1), 0, TriggerType.All, CallFlags.None); + internal byte[] RIPEMD160(StackItem item) + { + ReadOnlySpan value = item switch + { + InteropInterface _interface => _interface.GetInterface().GetHashData(), + Null _ => ScriptContainer.GetHashData(), + _ => item.GetSpan() + }; + return value.RIPEMD160(); + } + internal byte[] Sha256(StackItem item) { ReadOnlySpan value = item switch diff --git a/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs b/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs index 0fb6447783..014a10e6d2 100644 --- a/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs +++ b/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs @@ -86,13 +86,12 @@ public override string ToString() [TestClass] public class UT_MPTTrie { - private byte Prefix = 0xf0; private MPTNode root; private IStore mptdb; private void PutToStore(MPTNode node) { - mptdb.Put(Prefix, node.Hash.ToArray(), node.Encode()); + mptdb.Put(0xf0, node.Hash.ToArray(), node.Encode()); } [TestInitialize] @@ -125,7 +124,7 @@ public void TestInit() [TestMethod] public void TestTryGet() { - var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); Assert.AreEqual("abcd", mpt["ac01".HexToBytes()].ToString()); Assert.AreEqual("2222", mpt["ac99".HexToBytes()].ToString()); Assert.IsNull(mpt["ab99".HexToBytes()]); @@ -137,7 +136,7 @@ public void TestTryGet() [TestMethod] public void TestTryGetResolve() { - var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); Assert.AreEqual(Encoding.ASCII.GetBytes("hello").ToHexString(), mpt["acae".HexToBytes()].ToString()); } @@ -145,7 +144,7 @@ public void TestTryGetResolve() public void TestTryPut() { var store = new MemoryStore(); - var mpt = new MPTTrie(store.GetSnapshot(), Prefix, null); + var mpt = new MPTTrie(store.GetSnapshot(), null); var result = mpt.Put("ac01".HexToBytes(), "abcd".HexToBytes()); Assert.IsTrue(result); result = mpt.Put("ac99".HexToBytes(), "2222".HexToBytes()); @@ -171,7 +170,7 @@ public void TestTryDelete() Assert.AreEqual("0xdea3ab46e9461e885ed7091c1e533e0a8030b248d39cbc638962394eaca0fbb3", r1.Hash.ToString()); Assert.AreEqual("0x93e8e1ffe2f83dd92fca67330e273bcc811bf64b8f8d9d1b25d5e7366b47d60d", r.Hash.ToString()); - var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); Assert.IsNotNull(mpt["ac99".HexToBytes()]); bool result = mpt.Delete("ac99".HexToBytes()); Assert.IsTrue(result); @@ -185,7 +184,7 @@ public void TestDeleteSameValue() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt = new MPTTrie(snapshot, Prefix, null); + var mpt = new MPTTrie(snapshot, null); Assert.IsTrue(mpt.Put("ac01".HexToBytes(), "abcd".HexToBytes())); Assert.IsTrue(mpt.Put("ac02".HexToBytes(), "abcd".HexToBytes())); Assert.IsNotNull(mpt["ac01".HexToBytes()]); @@ -194,7 +193,7 @@ public void TestDeleteSameValue() Assert.IsNotNull(mpt["ac02".HexToBytes()]); snapshot.Commit(); - var mpt0 = new MPTTrie(store.GetSnapshot(), Prefix, mpt.Root.Hash); + var mpt0 = new MPTTrie(store.GetSnapshot(), mpt.Root.Hash); Assert.IsNotNull(mpt0["ac02".HexToBytes()]); } @@ -202,7 +201,7 @@ public void TestDeleteSameValue() public void TestBranchNodeRemainValue() { var store = new MemoryStore(); - var mpt = new MPTTrie(store.GetSnapshot(), Prefix, null); + var mpt = new MPTTrie(store.GetSnapshot(), null); Assert.IsTrue(mpt.Put("ac11".HexToBytes(), "ac11".HexToBytes())); Assert.IsTrue(mpt.Put("ac22".HexToBytes(), "ac22".HexToBytes())); Assert.IsTrue(mpt.Put("ac".HexToBytes(), "ac".HexToBytes())); @@ -227,7 +226,7 @@ public void TestGetProof() b.Children[9] = l2; b.Children[10] = l3; - var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); Assert.AreEqual(r.Hash.ToString(), mpt.Root.Hash.ToString()); HashSet proof = mpt.GetProof("ac01".HexToBytes()); Assert.AreEqual(4, proof.Count); @@ -240,7 +239,7 @@ public void TestGetProof() [TestMethod] public void TestVerifyProof() { - var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); HashSet proof = mpt.GetProof("ac01".HexToBytes()); TestValue value = MPTTrie.VerifyProof(root.Hash, "ac01".HexToBytes(), proof); Assert.IsNotNull(value); @@ -252,7 +251,7 @@ public void TestAddLongerKey() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt = new MPTTrie(snapshot, Prefix, null); + var mpt = new MPTTrie(snapshot, null); var result = mpt.Put(new byte[] { 0xab }, new byte[] { 0x01 }); Assert.IsTrue(result); result = mpt.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x02 }); @@ -264,12 +263,12 @@ public void TestSplitKey() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt1 = new MPTTrie(snapshot, Prefix, null); + var mpt1 = new MPTTrie(snapshot, null); Assert.IsTrue(mpt1.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x01 })); Assert.IsTrue(mpt1.Put(new byte[] { 0xab }, new byte[] { 0x02 })); HashSet set1 = mpt1.GetProof(new byte[] { 0xab, 0xcd }); Assert.AreEqual(4, set1.Count); - var mpt2 = new MPTTrie(snapshot, Prefix, null); + var mpt2 = new MPTTrie(snapshot, null); Assert.IsTrue(mpt2.Put(new byte[] { 0xab }, new byte[] { 0x02 })); Assert.IsTrue(mpt2.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x01 })); HashSet set2 = mpt2.GetProof(new byte[] { 0xab, 0xcd }); @@ -282,10 +281,10 @@ public void TestFind() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt1 = new MPTTrie(snapshot, Prefix, null); + var mpt1 = new MPTTrie(snapshot, null); var results = mpt1.Find(ReadOnlySpan.Empty).ToArray(); Assert.AreEqual(0, results.Count()); - var mpt2 = new MPTTrie(snapshot, Prefix, null); + var mpt2 = new MPTTrie(snapshot, null); Assert.IsTrue(mpt2.Put(new byte[] { 0xab, 0xcd, 0xef }, new byte[] { 0x01 })); Assert.IsTrue(mpt2.Put(new byte[] { 0xab, 0xcd, 0xe1 }, new byte[] { 0x02 })); Assert.IsTrue(mpt2.Put(new byte[] { 0xab }, new byte[] { 0x03 })); @@ -305,7 +304,7 @@ public void TestFindLeadNode() // r.Key = 0x0a0c // b.Key = 0x00 // l1.Key = 0x01 - var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); var prefix = new byte[] { 0xac, 0x01 }; // = FromNibbles(path = { 0x0a, 0x0c, 0x00, 0x01 }); var results = mpt.Find(prefix).ToArray(); Assert.AreEqual(1, results.Count()); diff --git a/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs index 0e17d0913c..b2c5775903 100644 --- a/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs +++ b/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs @@ -133,6 +133,15 @@ public void TestSha256() resultStr.Should().Be("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"); } + [TestMethod] + public void TestRIPEMD160() + { + ReadOnlySpan value = Encoding.ASCII.GetBytes("hello world"); + byte[] result = value.RIPEMD160(); + string resultStr = result.ToHexString(); + resultStr.Should().Be("98c615784ccb5fe5936fbc0cbe9dfdb408d92f0f"); + } + [TestMethod] public void TestTest() { diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 399f063ec7..5b83133e37 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -55,7 +55,7 @@ public void Runtime_GetNotifications_Test() snapshot.Contracts.Add(scriptHash2, new ContractState() { Script = script.ToArray(), - Manifest = TestUtils.CreateDefaultManifest(scriptHash2, "test"), + Manifest = TestUtils.CreateManifest(scriptHash2, "test", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer), }); } @@ -223,7 +223,7 @@ public void TestExecutionEngine_GetCallingScriptHash() var contract = new ContractState() { - Manifest = TestUtils.CreateDefaultManifest(scriptA.ToArray().ToScriptHash(), "test"), + Manifest = TestUtils.CreateManifest(scriptA.ToArray().ToScriptHash(), "test", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer), Script = scriptA.ToArray() }; engine = GetEngine(true, true, false); @@ -600,10 +600,10 @@ public void TestStorageContext_AsReadOnly() public void TestContract_Call() { var snapshot = Blockchain.Singleton.GetSnapshot(); - var state = TestUtils.GetContract("method"); - state.Manifest.Features = ContractFeatures.HasStorage; string method = "method"; var args = new VM.Types.Array { 0, 1 }; + var state = TestUtils.GetContract(method, args.Count); + state.Manifest.Features = ContractFeatures.HasStorage; snapshot.Contracts.Add(state.ScriptHash, state); var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); @@ -627,12 +627,12 @@ public void TestContract_CallEx() { var snapshot = Blockchain.Singleton.GetSnapshot(); - var state = TestUtils.GetContract("method"); + string method = "method"; + var args = new VM.Types.Array { 0, 1 }; + var state = TestUtils.GetContract(method, args.Count); state.Manifest.Features = ContractFeatures.HasStorage; snapshot.Contracts.Add(state.ScriptHash, state); - string method = "method"; - var args = new VM.Types.Array { 0, 1 }; foreach (var flags in new CallFlags[] { CallFlags.None, CallFlags.AllowCall, CallFlags.AllowModifyStates, CallFlags.All }) { diff --git a/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs index 3677041aa2..0f4e9f5f74 100644 --- a/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs +++ b/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -139,7 +139,7 @@ public void TestVerifyWitnesses() Header header3 = new Header() { PrevHash = index3, Witness = new Witness { VerificationScript = new byte[0] } }; snapshot3.Contracts.Add(UInt160.Zero, new ContractState() { - Manifest = TestUtils.CreateDefaultManifest(UInt160.Zero, "verify"), + Manifest = TestUtils.CreateManifest(UInt160.Zero, "verify", ContractParameterType.Boolean, ContractParameterType.Signature), }); 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 848079aef3..96b2ac0345 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -339,9 +339,9 @@ public void System_Runtime_GetInvocationCounter() contracts.Delete(contractA.ScriptHash); contracts.Delete(contractB.ScriptHash); contracts.Delete(contractC.ScriptHash); - contractA.Manifest = TestUtils.CreateDefaultManifest(contractA.ScriptHash, "dummyMain"); - contractB.Manifest = TestUtils.CreateDefaultManifest(contractA.ScriptHash, "dummyMain"); - contractC.Manifest = TestUtils.CreateDefaultManifest(contractA.ScriptHash, "dummyMain"); + contractA.Manifest = TestUtils.CreateManifest(contractA.ScriptHash, "dummyMain", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer); + contractB.Manifest = TestUtils.CreateManifest(contractA.ScriptHash, "dummyMain", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer); + contractC.Manifest = TestUtils.CreateManifest(contractA.ScriptHash, "dummyMain", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer); contracts.Add(contractA.ScriptHash, contractA); contracts.Add(contractB.ScriptHash, contractB); contracts.Add(contractC.ScriptHash, contractC); diff --git a/tests/neo.UnitTests/TestUtils.cs b/tests/neo.UnitTests/TestUtils.cs index fd8e6fd620..ef380908dd 100644 --- a/tests/neo.UnitTests/TestUtils.cs +++ b/tests/neo.UnitTests/TestUtils.cs @@ -17,7 +17,7 @@ public static class TestUtils { public static readonly Random TestRandom = new Random(1337); // use fixed seed for guaranteed determinism - public static ContractManifest CreateDefaultManifest(UInt160 hash, string method = null) + public static ContractManifest CreateDefaultManifest(UInt160 hash) { return new ContractManifest() { @@ -26,15 +26,7 @@ public static ContractManifest CreateDefaultManifest(UInt160 hash, string method { Hash = hash, Events = new ContractEventDescriptor[0], - Methods = method == null ? new ContractMethodDescriptor[0] : new ContractMethodDescriptor[] - { - new ContractMethodDescriptor() - { - Name = method, - Parameters = new ContractParameterDefinition[0], - ReturnType = ContractParameterType.Integer - } - } + Methods = new ContractMethodDescriptor[0] }, Features = ContractFeatures.NoProperty, Groups = new ContractGroup[0], @@ -44,6 +36,25 @@ public static ContractManifest CreateDefaultManifest(UInt160 hash, string method }; } + public static ContractManifest CreateManifest(UInt160 hash, string method, ContractParameterType returnType, params ContractParameterType[] parameterTypes) + { + ContractManifest manifest = CreateDefaultManifest(hash); + manifest.Abi.Methods = new ContractMethodDescriptor[] + { + new ContractMethodDescriptor() + { + Name = method, + Parameters = parameterTypes.Select((p, i) => new ContractParameterDefinition + { + Name = $"p{i}", + Type = p + }).ToArray(), + ReturnType = returnType + } + }; + return manifest; + } + public static byte[] GetByteArray(int length, byte firstByte) { byte[] array = new byte[length]; @@ -82,13 +93,13 @@ public static Transaction GetTransaction() }; } - internal static ContractState GetContract(string method = null) + internal static ContractState GetContract(string method = "test", int parametersCount = 0) { return new ContractState { Id = 0x43000000, Script = new byte[] { 0x01, 0x01, 0x01, 0x01 }, - Manifest = CreateDefaultManifest(UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"), method) + Manifest = CreateManifest(UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"), method, ContractParameterType.Any, Enumerable.Repeat(ContractParameterType.Any, parametersCount).ToArray()) }; } From 10f2f3c9440d2f91f3c5ce147d475bb3a5d905e2 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 13:20:52 +0800 Subject: [PATCH 26/39] fix mpt ut --- .../Cryptography/MPT/UT_MPTTrie.cs | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs b/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs index 014a10e6d2..0fb6447783 100644 --- a/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs +++ b/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs @@ -86,12 +86,13 @@ public override string ToString() [TestClass] public class UT_MPTTrie { + private byte Prefix = 0xf0; private MPTNode root; private IStore mptdb; private void PutToStore(MPTNode node) { - mptdb.Put(0xf0, node.Hash.ToArray(), node.Encode()); + mptdb.Put(Prefix, node.Hash.ToArray(), node.Encode()); } [TestInitialize] @@ -124,7 +125,7 @@ public void TestInit() [TestMethod] public void TestTryGet() { - var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); Assert.AreEqual("abcd", mpt["ac01".HexToBytes()].ToString()); Assert.AreEqual("2222", mpt["ac99".HexToBytes()].ToString()); Assert.IsNull(mpt["ab99".HexToBytes()]); @@ -136,7 +137,7 @@ public void TestTryGet() [TestMethod] public void TestTryGetResolve() { - var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); Assert.AreEqual(Encoding.ASCII.GetBytes("hello").ToHexString(), mpt["acae".HexToBytes()].ToString()); } @@ -144,7 +145,7 @@ public void TestTryGetResolve() public void TestTryPut() { var store = new MemoryStore(); - var mpt = new MPTTrie(store.GetSnapshot(), null); + var mpt = new MPTTrie(store.GetSnapshot(), Prefix, null); var result = mpt.Put("ac01".HexToBytes(), "abcd".HexToBytes()); Assert.IsTrue(result); result = mpt.Put("ac99".HexToBytes(), "2222".HexToBytes()); @@ -170,7 +171,7 @@ public void TestTryDelete() Assert.AreEqual("0xdea3ab46e9461e885ed7091c1e533e0a8030b248d39cbc638962394eaca0fbb3", r1.Hash.ToString()); Assert.AreEqual("0x93e8e1ffe2f83dd92fca67330e273bcc811bf64b8f8d9d1b25d5e7366b47d60d", r.Hash.ToString()); - var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); Assert.IsNotNull(mpt["ac99".HexToBytes()]); bool result = mpt.Delete("ac99".HexToBytes()); Assert.IsTrue(result); @@ -184,7 +185,7 @@ public void TestDeleteSameValue() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt = new MPTTrie(snapshot, null); + var mpt = new MPTTrie(snapshot, Prefix, null); Assert.IsTrue(mpt.Put("ac01".HexToBytes(), "abcd".HexToBytes())); Assert.IsTrue(mpt.Put("ac02".HexToBytes(), "abcd".HexToBytes())); Assert.IsNotNull(mpt["ac01".HexToBytes()]); @@ -193,7 +194,7 @@ public void TestDeleteSameValue() Assert.IsNotNull(mpt["ac02".HexToBytes()]); snapshot.Commit(); - var mpt0 = new MPTTrie(store.GetSnapshot(), mpt.Root.Hash); + var mpt0 = new MPTTrie(store.GetSnapshot(), Prefix, mpt.Root.Hash); Assert.IsNotNull(mpt0["ac02".HexToBytes()]); } @@ -201,7 +202,7 @@ public void TestDeleteSameValue() public void TestBranchNodeRemainValue() { var store = new MemoryStore(); - var mpt = new MPTTrie(store.GetSnapshot(), null); + var mpt = new MPTTrie(store.GetSnapshot(), Prefix, null); Assert.IsTrue(mpt.Put("ac11".HexToBytes(), "ac11".HexToBytes())); Assert.IsTrue(mpt.Put("ac22".HexToBytes(), "ac22".HexToBytes())); Assert.IsTrue(mpt.Put("ac".HexToBytes(), "ac".HexToBytes())); @@ -226,7 +227,7 @@ public void TestGetProof() b.Children[9] = l2; b.Children[10] = l3; - var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); Assert.AreEqual(r.Hash.ToString(), mpt.Root.Hash.ToString()); HashSet proof = mpt.GetProof("ac01".HexToBytes()); Assert.AreEqual(4, proof.Count); @@ -239,7 +240,7 @@ public void TestGetProof() [TestMethod] public void TestVerifyProof() { - var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); HashSet proof = mpt.GetProof("ac01".HexToBytes()); TestValue value = MPTTrie.VerifyProof(root.Hash, "ac01".HexToBytes(), proof); Assert.IsNotNull(value); @@ -251,7 +252,7 @@ public void TestAddLongerKey() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt = new MPTTrie(snapshot, null); + var mpt = new MPTTrie(snapshot, Prefix, null); var result = mpt.Put(new byte[] { 0xab }, new byte[] { 0x01 }); Assert.IsTrue(result); result = mpt.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x02 }); @@ -263,12 +264,12 @@ public void TestSplitKey() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt1 = new MPTTrie(snapshot, null); + var mpt1 = new MPTTrie(snapshot, Prefix, null); Assert.IsTrue(mpt1.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x01 })); Assert.IsTrue(mpt1.Put(new byte[] { 0xab }, new byte[] { 0x02 })); HashSet set1 = mpt1.GetProof(new byte[] { 0xab, 0xcd }); Assert.AreEqual(4, set1.Count); - var mpt2 = new MPTTrie(snapshot, null); + var mpt2 = new MPTTrie(snapshot, Prefix, null); Assert.IsTrue(mpt2.Put(new byte[] { 0xab }, new byte[] { 0x02 })); Assert.IsTrue(mpt2.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x01 })); HashSet set2 = mpt2.GetProof(new byte[] { 0xab, 0xcd }); @@ -281,10 +282,10 @@ public void TestFind() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt1 = new MPTTrie(snapshot, null); + var mpt1 = new MPTTrie(snapshot, Prefix, null); var results = mpt1.Find(ReadOnlySpan.Empty).ToArray(); Assert.AreEqual(0, results.Count()); - var mpt2 = new MPTTrie(snapshot, null); + var mpt2 = new MPTTrie(snapshot, Prefix, null); Assert.IsTrue(mpt2.Put(new byte[] { 0xab, 0xcd, 0xef }, new byte[] { 0x01 })); Assert.IsTrue(mpt2.Put(new byte[] { 0xab, 0xcd, 0xe1 }, new byte[] { 0x02 })); Assert.IsTrue(mpt2.Put(new byte[] { 0xab }, new byte[] { 0x03 })); @@ -304,7 +305,7 @@ public void TestFindLeadNode() // r.Key = 0x0a0c // b.Key = 0x00 // l1.Key = 0x01 - var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); var prefix = new byte[] { 0xac, 0x01 }; // = FromNibbles(path = { 0x0a, 0x0c, 0x00, 0x01 }); var results = mpt.Find(prefix).ToArray(); Assert.AreEqual(1, results.Count()); From fae1d14eef654a6410c566a46e258d4b4fcc6502 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 14:00:06 +0800 Subject: [PATCH 27/39] fix Storages and name --- src/neo/Persistence/ClonedView.cs | 9 +++++---- src/neo/Persistence/Prefixes.cs | 1 - src/neo/Persistence/ReadOnlyView.cs | 5 +++-- src/neo/Persistence/SnapshotView.cs | 7 ++++--- src/neo/Persistence/StoreView.cs | 9 +++++---- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index 3e9cf440ae..db0f7c52fa 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -11,13 +11,14 @@ internal class ClonedView : StoreView public override DataCache Blocks { get; } public override DataCache Transactions { get; } public override DataCache Contracts { get; } + public override DataCache Storages { get; } public override DataCache, HeaderHashList> HeaderHashList { get; } public override DataCache, HashIndexState> LocalStateRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public override MetaDataCache LatestVerifiedStateRoot { get; } + public override MetaDataCache ValidatorsStateRoot { get; } public override MetaDataCache ContractId { get; } - public override DataCache Storages { get; } + public ClonedView(StoreView view) { @@ -25,13 +26,13 @@ public ClonedView(StoreView view) 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.LocalStateRoot = view.LocalStateRoot.CreateSnapshot(); this.BlockHashIndex = view.BlockHashIndex.CreateSnapshot(); this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot(); - this.LatestVerifiedStateRoot = view.LatestVerifiedStateRoot.CreateSnapshot(); + this.ValidatorsStateRoot = view.ValidatorsStateRoot.CreateSnapshot(); this.ContractId = view.ContractId.CreateSnapshot(); - this.Storages = view.Storages.CreateSnapshot(); } } } diff --git a/src/neo/Persistence/Prefixes.cs b/src/neo/Persistence/Prefixes.cs index fba6d0fa69..1c6acd05a8 100644 --- a/src/neo/Persistence/Prefixes.cs +++ b/src/neo/Persistence/Prefixes.cs @@ -13,7 +13,6 @@ internal static class Prefixes public const byte IX_CurrentBlock = 0xc0; public const byte IX_CurrentHeader = 0xc1; public const byte IX_ContractId = 0xc2; - public const byte IX_CurrentRoot = 0xc3; public const byte IX_ConfirmedRoot = 0xc4; /* Prefixes 0xf0 to 0xff are reserved for external use. diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index 5a4b3decb8..911a05d00d 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -17,13 +17,14 @@ public class ReadOnlyView : StoreView 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 MPTDataCache(store, Prefixes.ST_Storage, CurrentStateRootHash); public override DataCache, HeaderHashList> HeaderHashList => new StoreDataCache, HeaderHashList>(store, Prefixes.IX_HeaderHashList); public override DataCache, HashIndexState> LocalStateRoot => new StoreDataCache, HashIndexState>(store, Prefixes.ST_Root); public override MetaDataCache BlockHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentBlock); public override MetaDataCache HeaderHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentHeader); - public override MetaDataCache LatestVerifiedStateRoot => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); + public override MetaDataCache ValidatorsStateRoot => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); public override MetaDataCache ContractId => new StoreMetaDataCache(store, Prefixes.IX_ContractId); - public override DataCache Storages => new MPTDataCache(store, Prefixes.ST_Storage, CurrentStateRootHash); + public ReadOnlyView(IReadOnlyStore store) { diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 26ed9f09f5..3fb8b980b2 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -16,13 +16,14 @@ public class SnapshotView : StoreView, IDisposable public override DataCache Blocks { get; } public override DataCache Transactions { get; } public override DataCache Contracts { get; } + public override DataCache Storages { get; } public override DataCache, HeaderHashList> HeaderHashList { get; } public override DataCache, HashIndexState> LocalStateRoot { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public override MetaDataCache LatestVerifiedStateRoot { get; } + public override MetaDataCache ValidatorsStateRoot { get; } public override MetaDataCache ContractId { get; } - public override DataCache Storages { get; } + public SnapshotView(IStore store) { @@ -35,7 +36,7 @@ public SnapshotView(IStore store) BlockHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentBlock); HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); - LatestVerifiedStateRoot = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); + ValidatorsStateRoot = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); Storages = new MPTDataCache(snapshot, Prefixes.ST_Storage, CurrentStateRootHash); } diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index b324e49c0f..5d3578e9eb 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -14,13 +14,13 @@ public abstract class StoreView public abstract DataCache Blocks { get; } public abstract DataCache Transactions { get; } public abstract DataCache Contracts { get; } + public abstract DataCache Storages { get; } public abstract DataCache, HeaderHashList> HeaderHashList { get; } public abstract DataCache, HashIndexState> LocalStateRoot { get; } public abstract MetaDataCache BlockHashIndex { get; } public abstract MetaDataCache HeaderHashIndex { get; } - public abstract MetaDataCache LatestVerifiedStateRoot { get; } + public abstract MetaDataCache ValidatorsStateRoot { get; } public abstract MetaDataCache ContractId { get; } - public abstract DataCache Storages { get; } public uint Height => BlockHashIndex.Get().Index; public uint HeaderHeight => HeaderHashIndex.Get().Index; @@ -38,13 +38,14 @@ public virtual void Commit() Blocks.Commit(); Transactions.Commit(); Contracts.Commit(); + Storages.Commit(); HeaderHashList.Commit(); LocalStateRoot.Commit(); BlockHashIndex.Commit(); HeaderHashIndex.Commit(); ContractId.Commit(); - LatestVerifiedStateRoot.Commit(); - Storages.Commit(); + ValidatorsStateRoot.Commit(); + } public bool ContainsBlock(UInt256 hash) From 520d03be1e5bfd22a11fdc084f93c96a87e0cd57 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 14:02:32 +0800 Subject: [PATCH 28/39] rename --- src/neo/Persistence/Prefixes.cs | 4 ++-- src/neo/Persistence/SnapshotView.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo/Persistence/Prefixes.cs b/src/neo/Persistence/Prefixes.cs index 1c6acd05a8..8a1329bea4 100644 --- a/src/neo/Persistence/Prefixes.cs +++ b/src/neo/Persistence/Prefixes.cs @@ -7,13 +7,13 @@ internal static class Prefixes public const byte ST_Contract = 0x50; public const byte ST_Storage = 0x70; - public const byte ST_Root = 0x60; + public const byte ST_LocalStateRoot = 0x60; public const byte IX_HeaderHashList = 0x80; public const byte IX_CurrentBlock = 0xc0; public const byte IX_CurrentHeader = 0xc1; public const byte IX_ContractId = 0xc2; - public const byte IX_ConfirmedRoot = 0xc4; + public const byte IX_ValidatorsStateRoot = 0xc4; /* Prefixes 0xf0 to 0xff are reserved for external use. * diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 3fb8b980b2..811fac33de 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -32,11 +32,11 @@ public SnapshotView(IStore store) Transactions = new StoreDataCache(snapshot, Prefixes.DATA_Transaction); Contracts = new StoreDataCache(snapshot, Prefixes.ST_Contract); HeaderHashList = new StoreDataCache, HeaderHashList>(snapshot, Prefixes.IX_HeaderHashList); - LocalStateRoot = new StoreDataCache, HashIndexState>(snapshot, Prefixes.ST_Root); + LocalStateRoot = new StoreDataCache, HashIndexState>(snapshot, Prefixes.ST_LocalStateRoot); BlockHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentBlock); HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); - ValidatorsStateRoot = new StoreMetaDataCache(snapshot, Prefixes.IX_ConfirmedRoot); + ValidatorsStateRoot = new StoreMetaDataCache(snapshot, Prefixes.IX_ValidatorsStateRoot); Storages = new MPTDataCache(snapshot, Prefixes.ST_Storage, CurrentStateRootHash); } From 80235bc02fd062114cbc8704aeeeff15b85d698a Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 14:09:47 +0800 Subject: [PATCH 29/39] add comment --- src/neo/Persistence/SnapshotView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 811fac33de..9db4c9ce8a 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -37,7 +37,7 @@ public SnapshotView(IStore store) HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); ValidatorsStateRoot = new StoreMetaDataCache(snapshot, Prefixes.IX_ValidatorsStateRoot); - Storages = new MPTDataCache(snapshot, Prefixes.ST_Storage, CurrentStateRootHash); + Storages = new MPTDataCache(snapshot, Prefixes.ST_Storage, CurrentStateRootHash);//Need BlockHashIndex and LocalStateRoot loaded. } public override void Commit() From a3b491d5ecc5e2b5a1e5c30e2b0371b1540d3c73 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 14:12:32 +0800 Subject: [PATCH 30/39] proof prefix --- src/neo/Cryptography/MPT/MPTTrie.Proof.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/neo/Cryptography/MPT/MPTTrie.Proof.cs b/src/neo/Cryptography/MPT/MPTTrie.Proof.cs index ab1acd2ff4..dfcf20c71d 100644 --- a/src/neo/Cryptography/MPT/MPTTrie.Proof.cs +++ b/src/neo/Cryptography/MPT/MPTTrie.Proof.cs @@ -61,11 +61,12 @@ private bool GetProof(ref MPTNode node, ReadOnlySpan path, HashSet public static TValue VerifyProof(UInt256 root, TKey key, HashSet proof) { + const byte proof_prefix = 0x00; using var memoryStore = new MemoryStore(); foreach (byte[] data in proof) - memoryStore.Put(0, Crypto.Hash256(data), data); + memoryStore.Put(proof_prefix, Crypto.Hash256(data), data); using ISnapshot snapshot = memoryStore.GetSnapshot(); - var trie = new MPTTrie(snapshot, 0, root); + var trie = new MPTTrie(snapshot, proof_prefix, root); return trie[key]; } } From aeff67cc557e744ffcd0c9cb6b58b604f314db4d Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 14:14:03 +0800 Subject: [PATCH 31/39] fix --- src/neo/Persistence/ReadOnlyView.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index 911a05d00d..84601063cb 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -19,10 +19,10 @@ public class ReadOnlyView : StoreView public override DataCache Contracts => new StoreDataCache(store, Prefixes.ST_Contract); public override DataCache Storages => new MPTDataCache(store, Prefixes.ST_Storage, CurrentStateRootHash); public override DataCache, HeaderHashList> HeaderHashList => new StoreDataCache, HeaderHashList>(store, Prefixes.IX_HeaderHashList); - public override DataCache, HashIndexState> LocalStateRoot => new StoreDataCache, HashIndexState>(store, Prefixes.ST_Root); + public override DataCache, HashIndexState> LocalStateRoot => new StoreDataCache, HashIndexState>(store, Prefixes.ST_LocalStateRoot); public override MetaDataCache BlockHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentBlock); public override MetaDataCache HeaderHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentHeader); - public override MetaDataCache ValidatorsStateRoot => new StoreMetaDataCache(store, Prefixes.IX_ConfirmedRoot); + public override MetaDataCache ValidatorsStateRoot => new StoreMetaDataCache(store, Prefixes.IX_ValidatorsStateRoot); public override MetaDataCache ContractId => new StoreMetaDataCache(store, Prefixes.IX_ContractId); From 1337cd729942339545abc8277e523486708be5aa Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 14:18:56 +0800 Subject: [PATCH 32/39] format --- src/neo/Persistence/ReadOnlyView.cs | 1 - src/neo/Persistence/SnapshotView.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index 84601063cb..ecabcc87e0 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -25,7 +25,6 @@ public class ReadOnlyView : StoreView public override MetaDataCache ValidatorsStateRoot => new StoreMetaDataCache(store, Prefixes.IX_ValidatorsStateRoot); public override MetaDataCache ContractId => new StoreMetaDataCache(store, Prefixes.IX_ContractId); - public ReadOnlyView(IReadOnlyStore store) { this.store = store; diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 9db4c9ce8a..1057bf2904 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -24,7 +24,6 @@ public class SnapshotView : StoreView, IDisposable public override MetaDataCache ValidatorsStateRoot { get; } public override MetaDataCache ContractId { get; } - public SnapshotView(IStore store) { this.snapshot = store.GetSnapshot(); From 17b67e676543aff0dd63855bff30a35127c908d5 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 14:23:43 +0800 Subject: [PATCH 33/39] format --- src/neo/Persistence/ClonedView.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index db0f7c52fa..025b9c03f5 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -19,7 +19,6 @@ internal class ClonedView : StoreView public override MetaDataCache ValidatorsStateRoot { get; } public override MetaDataCache ContractId { get; } - public ClonedView(StoreView view) { this.PersistingBlock = view.PersistingBlock; From b018556af6e474469ccc10a167cb9cf0f59b4d42 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 14:25:49 +0800 Subject: [PATCH 34/39] format --- src/neo/Persistence/StoreView.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index 5d3578e9eb..7fd39901fe 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -45,7 +45,6 @@ public virtual void Commit() HeaderHashIndex.Commit(); ContractId.Commit(); ValidatorsStateRoot.Commit(); - } public bool ContainsBlock(UInt256 hash) From 404185a72b264385b5746147eb2383e63d897116 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 15:50:14 +0800 Subject: [PATCH 35/39] add StateRoot ut --- .../Network/P2P/Payloads/UT_StateRoot.cs | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 tests/neo.UnitTests/Network/P2P/Payloads/UT_StateRoot.cs diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_StateRoot.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_StateRoot.cs new file mode 100644 index 0000000000..930ac58038 --- /dev/null +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_StateRoot.cs @@ -0,0 +1,76 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using System.IO; +using System.Text; + +namespace Neo.UnitTests.Network.P2P.Payloads +{ + [TestClass] + public class UT_StateRoot + { + StateRoot state_root; + + [TestInitialize] + public void TestSetup() + { + TestBlockchain.InitializeMockNeoSystem(); + state_root = new StateRoot() + { + Version = 0, + Index = 1234, + Root = UInt256.Parse("5f4f1af77b127c9037c0204f682420a5ce621f3d8f4c8bdd9fd37422e0c58e9b"), + Witness = new Witness() + { + InvocationScript = new byte[] { 0x01 }, + VerificationScript = new byte[] { 0x02 } + } + }; + } + + [TestMethod] + public void TestSerializeUnsigned() + { + using MemoryStream ms = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(ms); + + state_root.SerializeUnsigned(writer); + + Assert.AreEqual("00d20400009b8ec5e02274d39fdd8b4c8f3d1f62cea52024684f20c037907c127bf71a4f5f", ms.ToArray().ToHexString()); + } + + [TestMethod] + public void TestDesializeUnsigned() + { + var data = "00d20400009b8ec5e02274d39fdd8b4c8f3d1f62cea52024684f20c037907c127bf71a4f5f".HexToBytes(); + using MemoryStream ms = new MemoryStream(data, false); + using BinaryReader reader = new BinaryReader(ms, Encoding.UTF8); + + var state_root_d = new StateRoot(); + state_root_d.DeserializeUnsigned(reader); + + Assert.AreEqual(state_root.Version, state_root_d.Version); + Assert.AreEqual(state_root.Index, state_root_d.Index); + Assert.AreEqual(state_root.Root, state_root_d.Root); + } + + [TestMethod] + public void TestGetScriptHashesForVerifying() + { + state_root.Index = 0; + var snapshot = Blockchain.Singleton.GetSnapshot(); + var scriptHashes = state_root.GetScriptHashesForVerifying(snapshot); + Assert.AreEqual(Blockchain.GenesisBlock.NextConsensus, scriptHashes[0]); + } + + [TestMethod] + public void TestToJson() + { + var json = state_root.ToJson(); + Assert.AreEqual(0, json["version"].AsNumber()); + Assert.AreEqual(1234, json["index"].AsNumber()); + Assert.AreEqual(state_root.Root.ToString(), json["stateroot"].AsString()); + } + } +} From 2acfacfb3fb336412842f8fae77c175d94cf3fbf Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Sat, 13 Jun 2020 10:13:08 +0800 Subject: [PATCH 36/39] reset mpt prefix --- src/neo/Cryptography/MPT/MPTTrie.Proof.cs | 5 ++-- src/neo/Cryptography/MPT/MPTTrie.cs | 5 ++-- src/neo/Persistence/MPTDataCache.cs | 4 +-- src/neo/Persistence/Prefixes.cs | 1 - src/neo/Persistence/ReadOnlyView.cs | 2 +- src/neo/Persistence/SnapshotView.cs | 2 +- .../Cryptography/MPT/UT_MPTTrie.cs | 30 +++++++++---------- 7 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/neo/Cryptography/MPT/MPTTrie.Proof.cs b/src/neo/Cryptography/MPT/MPTTrie.Proof.cs index dfcf20c71d..7b4be120ab 100644 --- a/src/neo/Cryptography/MPT/MPTTrie.Proof.cs +++ b/src/neo/Cryptography/MPT/MPTTrie.Proof.cs @@ -61,12 +61,11 @@ private bool GetProof(ref MPTNode node, ReadOnlySpan path, HashSet public static TValue VerifyProof(UInt256 root, TKey key, HashSet proof) { - const byte proof_prefix = 0x00; using var memoryStore = new MemoryStore(); foreach (byte[] data in proof) - memoryStore.Put(proof_prefix, Crypto.Hash256(data), data); + memoryStore.Put(Prefix, Crypto.Hash256(data), data); using ISnapshot snapshot = memoryStore.GetSnapshot(); - var trie = new MPTTrie(snapshot, proof_prefix, root); + var trie = new MPTTrie(snapshot, root); return trie[key]; } } diff --git a/src/neo/Cryptography/MPT/MPTTrie.cs b/src/neo/Cryptography/MPT/MPTTrie.cs index ae21683b37..006e4280f3 100644 --- a/src/neo/Cryptography/MPT/MPTTrie.cs +++ b/src/neo/Cryptography/MPT/MPTTrie.cs @@ -8,17 +8,16 @@ public partial class MPTTrie where TKey : notnull, ISerializable, new() where TValue : class, ISerializable, new() { - private byte Prefix; + private const byte Prefix = 0xf0; private readonly ISnapshot store; private MPTNode root; public MPTNode Root => root; - public MPTTrie(ISnapshot store, byte prefix, UInt256 root) + public MPTTrie(ISnapshot store, UInt256 root) { this.store = store ?? throw new ArgumentNullException(); - this.Prefix = prefix; this.root = root is null || root == UInt256.Zero ? HashNode.EmptyNode : new HashNode(root); } diff --git a/src/neo/Persistence/MPTDataCache.cs b/src/neo/Persistence/MPTDataCache.cs index d1d002c9e1..7463d58859 100644 --- a/src/neo/Persistence/MPTDataCache.cs +++ b/src/neo/Persistence/MPTDataCache.cs @@ -15,9 +15,9 @@ internal class MPTDataCache : DataCache public MPTNode Root => mptTrie.Root; - public MPTDataCache(IReadOnlyStore store, byte prefix, UInt256 root) + public MPTDataCache(IReadOnlyStore store, UInt256 root) { - mptTrie = new MPTTrie(store as ISnapshot, prefix, root); + mptTrie = new MPTTrie(store as ISnapshot, root); } protected override void AddInternal(TKey key, TValue value) diff --git a/src/neo/Persistence/Prefixes.cs b/src/neo/Persistence/Prefixes.cs index 8a1329bea4..744f027d2d 100644 --- a/src/neo/Persistence/Prefixes.cs +++ b/src/neo/Persistence/Prefixes.cs @@ -6,7 +6,6 @@ internal static class Prefixes public const byte DATA_Transaction = 0x02; public const byte ST_Contract = 0x50; - public const byte ST_Storage = 0x70; public const byte ST_LocalStateRoot = 0x60; public const byte IX_HeaderHashList = 0x80; diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index ecabcc87e0..b2147f2c34 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -17,7 +17,7 @@ public class ReadOnlyView : StoreView 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 MPTDataCache(store, Prefixes.ST_Storage, CurrentStateRootHash); + public override DataCache Storages => new MPTDataCache(store, CurrentStateRootHash); public override DataCache, HeaderHashList> HeaderHashList => new StoreDataCache, HeaderHashList>(store, Prefixes.IX_HeaderHashList); public override DataCache, HashIndexState> LocalStateRoot => new StoreDataCache, HashIndexState>(store, Prefixes.ST_LocalStateRoot); public override MetaDataCache BlockHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentBlock); diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 1057bf2904..0e9a898c71 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -36,7 +36,7 @@ public SnapshotView(IStore store) HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); ValidatorsStateRoot = new StoreMetaDataCache(snapshot, Prefixes.IX_ValidatorsStateRoot); - Storages = new MPTDataCache(snapshot, Prefixes.ST_Storage, CurrentStateRootHash);//Need BlockHashIndex and LocalStateRoot loaded. + Storages = new MPTDataCache(snapshot, CurrentStateRootHash);//Need BlockHashIndex and LocalStateRoot loaded. } public override void Commit() diff --git a/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs b/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs index 0fb6447783..7b93f34b60 100644 --- a/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs +++ b/tests/neo.UnitTests/Cryptography/MPT/UT_MPTTrie.cs @@ -125,7 +125,7 @@ public void TestInit() [TestMethod] public void TestTryGet() { - var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); Assert.AreEqual("abcd", mpt["ac01".HexToBytes()].ToString()); Assert.AreEqual("2222", mpt["ac99".HexToBytes()].ToString()); Assert.IsNull(mpt["ab99".HexToBytes()]); @@ -137,7 +137,7 @@ public void TestTryGet() [TestMethod] public void TestTryGetResolve() { - var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); Assert.AreEqual(Encoding.ASCII.GetBytes("hello").ToHexString(), mpt["acae".HexToBytes()].ToString()); } @@ -145,7 +145,7 @@ public void TestTryGetResolve() public void TestTryPut() { var store = new MemoryStore(); - var mpt = new MPTTrie(store.GetSnapshot(), Prefix, null); + var mpt = new MPTTrie(store.GetSnapshot(), null); var result = mpt.Put("ac01".HexToBytes(), "abcd".HexToBytes()); Assert.IsTrue(result); result = mpt.Put("ac99".HexToBytes(), "2222".HexToBytes()); @@ -171,7 +171,7 @@ public void TestTryDelete() Assert.AreEqual("0xdea3ab46e9461e885ed7091c1e533e0a8030b248d39cbc638962394eaca0fbb3", r1.Hash.ToString()); Assert.AreEqual("0x93e8e1ffe2f83dd92fca67330e273bcc811bf64b8f8d9d1b25d5e7366b47d60d", r.Hash.ToString()); - var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); Assert.IsNotNull(mpt["ac99".HexToBytes()]); bool result = mpt.Delete("ac99".HexToBytes()); Assert.IsTrue(result); @@ -185,7 +185,7 @@ public void TestDeleteSameValue() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt = new MPTTrie(snapshot, Prefix, null); + var mpt = new MPTTrie(snapshot, null); Assert.IsTrue(mpt.Put("ac01".HexToBytes(), "abcd".HexToBytes())); Assert.IsTrue(mpt.Put("ac02".HexToBytes(), "abcd".HexToBytes())); Assert.IsNotNull(mpt["ac01".HexToBytes()]); @@ -194,7 +194,7 @@ public void TestDeleteSameValue() Assert.IsNotNull(mpt["ac02".HexToBytes()]); snapshot.Commit(); - var mpt0 = new MPTTrie(store.GetSnapshot(), Prefix, mpt.Root.Hash); + var mpt0 = new MPTTrie(store.GetSnapshot(), mpt.Root.Hash); Assert.IsNotNull(mpt0["ac02".HexToBytes()]); } @@ -202,7 +202,7 @@ public void TestDeleteSameValue() public void TestBranchNodeRemainValue() { var store = new MemoryStore(); - var mpt = new MPTTrie(store.GetSnapshot(), Prefix, null); + var mpt = new MPTTrie(store.GetSnapshot(), null); Assert.IsTrue(mpt.Put("ac11".HexToBytes(), "ac11".HexToBytes())); Assert.IsTrue(mpt.Put("ac22".HexToBytes(), "ac22".HexToBytes())); Assert.IsTrue(mpt.Put("ac".HexToBytes(), "ac".HexToBytes())); @@ -227,7 +227,7 @@ public void TestGetProof() b.Children[9] = l2; b.Children[10] = l3; - var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); Assert.AreEqual(r.Hash.ToString(), mpt.Root.Hash.ToString()); HashSet proof = mpt.GetProof("ac01".HexToBytes()); Assert.AreEqual(4, proof.Count); @@ -240,7 +240,7 @@ public void TestGetProof() [TestMethod] public void TestVerifyProof() { - var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); HashSet proof = mpt.GetProof("ac01".HexToBytes()); TestValue value = MPTTrie.VerifyProof(root.Hash, "ac01".HexToBytes(), proof); Assert.IsNotNull(value); @@ -252,7 +252,7 @@ public void TestAddLongerKey() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt = new MPTTrie(snapshot, Prefix, null); + var mpt = new MPTTrie(snapshot, null); var result = mpt.Put(new byte[] { 0xab }, new byte[] { 0x01 }); Assert.IsTrue(result); result = mpt.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x02 }); @@ -264,12 +264,12 @@ public void TestSplitKey() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt1 = new MPTTrie(snapshot, Prefix, null); + var mpt1 = new MPTTrie(snapshot, null); Assert.IsTrue(mpt1.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x01 })); Assert.IsTrue(mpt1.Put(new byte[] { 0xab }, new byte[] { 0x02 })); HashSet set1 = mpt1.GetProof(new byte[] { 0xab, 0xcd }); Assert.AreEqual(4, set1.Count); - var mpt2 = new MPTTrie(snapshot, Prefix, null); + var mpt2 = new MPTTrie(snapshot, null); Assert.IsTrue(mpt2.Put(new byte[] { 0xab }, new byte[] { 0x02 })); Assert.IsTrue(mpt2.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x01 })); HashSet set2 = mpt2.GetProof(new byte[] { 0xab, 0xcd }); @@ -282,10 +282,10 @@ public void TestFind() { var store = new MemoryStore(); var snapshot = store.GetSnapshot(); - var mpt1 = new MPTTrie(snapshot, Prefix, null); + var mpt1 = new MPTTrie(snapshot, null); var results = mpt1.Find(ReadOnlySpan.Empty).ToArray(); Assert.AreEqual(0, results.Count()); - var mpt2 = new MPTTrie(snapshot, Prefix, null); + var mpt2 = new MPTTrie(snapshot, null); Assert.IsTrue(mpt2.Put(new byte[] { 0xab, 0xcd, 0xef }, new byte[] { 0x01 })); Assert.IsTrue(mpt2.Put(new byte[] { 0xab, 0xcd, 0xe1 }, new byte[] { 0x02 })); Assert.IsTrue(mpt2.Put(new byte[] { 0xab }, new byte[] { 0x03 })); @@ -305,7 +305,7 @@ public void TestFindLeadNode() // r.Key = 0x0a0c // b.Key = 0x00 // l1.Key = 0x01 - var mpt = new MPTTrie(mptdb.GetSnapshot(), Prefix, root.Hash); + var mpt = new MPTTrie(mptdb.GetSnapshot(), root.Hash); var prefix = new byte[] { 0xac, 0x01 }; // = FromNibbles(path = { 0x0a, 0x0c, 0x00, 0x01 }); var results = mpt.Find(prefix).ToArray(); Assert.AreEqual(1, results.Count()); From 0d7490a24b38451e14ae1c08a750a0c9367f0cc8 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Mon, 15 Jun 2020 18:24:39 +0800 Subject: [PATCH 37/39] rm GetMessage --- src/neo/Network/P2P/Payloads/StateRoot.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 301b7af32f..e375c6c472 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -108,11 +108,6 @@ public virtual UInt160[] GetScriptHashesForVerifying(StoreView snapshot) return script_hash is null ? Array.Empty() : new UInt160[] { script_hash }; } - public byte[] GetMessage() - { - return this.GetHashData(); - } - public JObject ToJson() { var json = new JObject(); From 59c8706d4c4d77e9d6db8e6c15a3e4e40d8f3924 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Tue, 16 Jun 2020 11:21:50 +0800 Subject: [PATCH 38/39] throw exception when no script hash in state root --- src/neo/Network/P2P/Payloads/StateRoot.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index e375c6c472..5e7d2f57fa 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -105,7 +105,8 @@ public bool Verify(StoreView snapshot) public virtual UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { var script_hash = Blockchain.Singleton.GetBlock(Index)?.NextConsensus; - return script_hash is null ? Array.Empty() : new UInt160[] { script_hash }; + if (script_hash is null) throw new System.InvalidOperationException("No script hash for state root verifying"); + return new UInt160[] { script_hash }; } public JObject ToJson() From ac6a24b1e0b50604e3b469312e55a55044762a29 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Tue, 16 Jun 2020 14:50:29 +0800 Subject: [PATCH 39/39] UpdateLocalStateRoot when Storages changed --- src/neo/Ledger/Blockchain.cs | 1 + src/neo/Persistence/Helper.cs | 9 +++++++++ src/neo/Persistence/SnapshotView.cs | 4 ---- tests/neo.UnitTests/Consensus/UT_Consensus.cs | 3 +++ tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 2 +- .../Network/P2P/Payloads/UT_Transaction.cs | 14 ++++++++------ tests/neo.UnitTests/Wallets/UT_Wallet.cs | 10 +++++++++- 7 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index b937d8c0a4..db2413f861 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -444,6 +444,7 @@ private void Persist(Block block) snapshot.BlockHashIndex.GetAndChange().Set(block); foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) plugin.OnPersist(snapshot, all_application_executed); + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); List commitExceptions = null; foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) diff --git a/src/neo/Persistence/Helper.cs b/src/neo/Persistence/Helper.cs index 51d9314bfc..965d4566a6 100644 --- a/src/neo/Persistence/Helper.cs +++ b/src/neo/Persistence/Helper.cs @@ -1,4 +1,5 @@ using System; +using Neo.Ledger; namespace Neo.Persistence { @@ -8,5 +9,13 @@ public static byte[] EnsureNotNull(this byte[] source) { return source ?? Array.Empty(); } + + public static void UpdateLocalStateRoot(this SnapshotView snapshot) + { + snapshot.Storages.Commit(); + var root = snapshot.LocalStateRoot.GetAndChange(snapshot.Height, () => new HashIndexState()); + root.Index = snapshot.Height; + root.Hash = ((MPTDataCache)snapshot.Storages).Root.Hash; + } } } diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 0e9a898c71..2bbffc0cb5 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -42,10 +42,6 @@ public SnapshotView(IStore store) public override void Commit() { base.Commit(); - var root = LocalStateRoot.GetAndChange(Height, () => new HashIndexState()); - root.Index = Height; - root.Hash = ((MPTDataCache)Storages).Root.Hash; - LocalStateRoot.Commit(); snapshot.Commit(); } diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 86eb6bc8c2..f99f7ba8ac 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -10,6 +10,7 @@ using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Cryptography; @@ -276,6 +277,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm { Value = mockContext.Object.Validators.ToByteArray() }); + mockContext.Object.Snapshot.UpdateLocalStateRoot(); mockContext.Object.Snapshot.Commit(); // =============================================================== @@ -408,6 +410,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine("mockContext Reset for returning Blockchain.Singleton snapshot to original state."); mockContext.Object.Reset(0); mockContext.Object.Snapshot.Storages.Delete(CreateStorageKeyForNativeNeo(14)); + mockContext.Object.Snapshot.UpdateLocalStateRoot(); mockContext.Object.Snapshot.Commit(); Console.WriteLine("mockContext Reset."); diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index 7e04dfe229..2f107b5a48 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -119,7 +119,7 @@ public void TestValidTransaction() var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; - + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); typeof(Blockchain) diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 169aba50d2..a2ab5a2a59 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -5,6 +5,7 @@ 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; @@ -111,6 +112,7 @@ public void FeeIsMultiSigContract() entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); // Make transaction @@ -180,7 +182,7 @@ public void FeeIsSignatureContractDetailed() var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); // Make transaction @@ -291,7 +293,7 @@ public void FeeIsSignatureContract_TestScope_Global() var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); // Make transaction @@ -377,7 +379,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); // Make transaction @@ -464,7 +466,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); // Make transaction @@ -604,7 +606,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); // Make transaction @@ -942,7 +944,7 @@ public void FeeIsSignatureContract_TestScope_Global_Default() var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); // Make transaction diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index e63145ff5d..65e5ffa2b9 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -3,6 +3,7 @@ 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; @@ -205,12 +206,14 @@ public void TestGetAvailable() var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); wallet.GetAvailable(NativeContract.GAS.Hash).Should().Be(new BigDecimal(1000000000000, 8)); entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 0; + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); } @@ -227,6 +230,7 @@ public void TestGetBalance() var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); wallet.GetBalance(UInt160.Zero, new UInt160[] { account.ScriptHash }).Should().Be(new BigDecimal(0, 0)); @@ -234,6 +238,7 @@ public void TestGetBalance() entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 0; + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); } @@ -331,7 +336,7 @@ public void TestMakeTransaction1() key = NativeContract.NEO.CreateStorageKey(20, account.ScriptHash); var entry2 = snapshot.Storages.GetAndChange(key, () => new StorageItem(new NeoToken.NeoAccountState())); entry2.GetInteroperable().Balance = 10000 * NativeContract.NEO.Factor; - + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); var tx = wallet.MakeTransaction(new TransferOutput[] @@ -360,6 +365,7 @@ public void TestMakeTransaction1() entry2 = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry1.GetInteroperable().Balance = 0; entry2.GetInteroperable().Balance = 0; + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); } @@ -379,6 +385,7 @@ public void TestMakeTransaction2() var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 1000000 * NativeContract.GAS.Factor; + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); var tx = wallet.MakeTransaction(new byte[] { }, account.ScriptHash, new TransactionAttribute[] { }); @@ -389,6 +396,7 @@ public void TestMakeTransaction2() entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 0; + snapshot.UpdateLocalStateRoot(); snapshot.Commit(); }