diff --git a/src/neo/Ledger/ContractIdState.cs b/src/neo/Ledger/ContractIdState.cs new file mode 100644 index 0000000000..b29f1d21ac --- /dev/null +++ b/src/neo/Ledger/ContractIdState.cs @@ -0,0 +1,37 @@ +using Neo.IO; +using System; +using System.IO; + +namespace Neo.Ledger +{ + public class ContractIdState : ICloneable, ISerializable + { + public int NextId; + + int ISerializable.Size => sizeof(int); + + ContractIdState ICloneable.Clone() + { + return new ContractIdState + { + NextId = NextId + }; + } + + void ISerializable.Deserialize(BinaryReader reader) + { + NextId = reader.ReadInt32(); + if (NextId < 0) throw new FormatException(); + } + + void ICloneable.FromReplica(ContractIdState replica) + { + NextId = replica.NextId; + } + + void ISerializable.Serialize(BinaryWriter writer) + { + writer.Write(NextId); + } + } +} diff --git a/src/neo/Ledger/ContractState.cs b/src/neo/Ledger/ContractState.cs index f6a50b67d0..a47a6366f7 100644 --- a/src/neo/Ledger/ContractState.cs +++ b/src/neo/Ledger/ContractState.cs @@ -12,6 +12,7 @@ namespace Neo.Ledger { public class ContractState : ICloneable, ISerializable, IInteroperable { + public int Id; public byte[] Script; public ContractManifest Manifest; @@ -31,12 +32,13 @@ public UInt160 ScriptHash } } - int ISerializable.Size => Script.GetVarSize() + Manifest.ToJson().ToString().GetVarSize(); + int ISerializable.Size => sizeof(int) + Script.GetVarSize() + Manifest.ToJson().ToString().GetVarSize(); ContractState ICloneable.Clone() { return new ContractState { + Id = Id, Script = Script, Manifest = Manifest.Clone() }; @@ -44,18 +46,21 @@ ContractState ICloneable.Clone() void ISerializable.Deserialize(BinaryReader reader) { + Id = reader.ReadInt32(); Script = reader.ReadVarBytes(); Manifest = reader.ReadSerializable(); } void ICloneable.FromReplica(ContractState replica) { + Id = replica.Id; Script = replica.Script; Manifest = replica.Manifest.Clone(); } void ISerializable.Serialize(BinaryWriter writer) { + writer.Write(Id); writer.WriteVarBytes(Script); writer.Write(Manifest); } @@ -63,20 +68,13 @@ void ISerializable.Serialize(BinaryWriter writer) public JObject ToJson() { JObject json = new JObject(); + json["id"] = Id; json["hash"] = ScriptHash.ToString(); json["script"] = Convert.ToBase64String(Script); json["manifest"] = Manifest.ToJson(); return json; } - public static ContractState FromJson(JObject json) - { - ContractState contractState = new ContractState(); - contractState.Script = Convert.FromBase64String(json["script"].AsString()); - contractState.Manifest = ContractManifest.FromJson(json["manifest"]); - return contractState; - } - public StackItem ToStackItem(ReferenceCounter referenceCounter) { return new Array(referenceCounter, new StackItem[] { Script, HasStorage, Payable }); diff --git a/src/neo/Ledger/StorageKey.cs b/src/neo/Ledger/StorageKey.cs index 70e045560e..af7258f2ce 100644 --- a/src/neo/Ledger/StorageKey.cs +++ b/src/neo/Ledger/StorageKey.cs @@ -7,12 +7,12 @@ namespace Neo.Ledger { public class StorageKey : IEquatable, ISerializable { - public UInt160 ScriptHash; + public int Id; public byte[] Key; - int ISerializable.Size => ScriptHash.Size + (Key.Length / 16 + 1) * 17; + int ISerializable.Size => sizeof(int) + (Key.Length / 16 + 1) * 17; - internal static byte[] CreateSearchPrefix(UInt160 hash, byte[] prefix) + internal static byte[] CreateSearchPrefix(int id, byte[] prefix) { using (MemoryStream ms = new MemoryStream()) { @@ -27,13 +27,13 @@ internal static byte[] CreateSearchPrefix(UInt160 hash, byte[] prefix) } if (remain > 0) ms.Write(prefix, index, remain); - return Helper.Concat(hash.ToArray(), ms.ToArray()); + return Helper.Concat(BitConverter.GetBytes(id), ms.ToArray()); } } void ISerializable.Deserialize(BinaryReader reader) { - ScriptHash = reader.ReadSerializable(); + Id = reader.ReadInt32(); Key = reader.ReadBytesWithGrouping(); } @@ -43,7 +43,7 @@ public bool Equals(StorageKey other) return false; if (ReferenceEquals(this, other)) return true; - return ScriptHash.Equals(other.ScriptHash) && MemoryExtensions.SequenceEqual(Key, other.Key); + return Id == other.Id && MemoryExtensions.SequenceEqual(Key, other.Key); } public override bool Equals(object obj) @@ -54,12 +54,12 @@ public override bool Equals(object obj) public override int GetHashCode() { - return ScriptHash.GetHashCode() + (int)Key.Murmur32(0); + return Id.GetHashCode() + (int)Key.Murmur32(0); } void ISerializable.Serialize(BinaryWriter writer) { - writer.Write(ScriptHash); + writer.Write(Id); writer.WriteBytesWithGrouping(Key); } } diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index f820b8f31b..307438b2db 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -13,6 +13,7 @@ internal class ClonedView : StoreView public override DataCache, HeaderHashList> HeaderHashList { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } + public override MetaDataCache ContractId { get; } public ClonedView(StoreView view) { @@ -24,6 +25,7 @@ public ClonedView(StoreView view) this.HeaderHashList = view.HeaderHashList.CreateSnapshot(); this.BlockHashIndex = view.BlockHashIndex.CreateSnapshot(); this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot(); + this.ContractId = view.ContractId.CreateSnapshot(); } } } diff --git a/src/neo/Persistence/Prefixes.cs b/src/neo/Persistence/Prefixes.cs index dad8540787..421fe086c3 100644 --- a/src/neo/Persistence/Prefixes.cs +++ b/src/neo/Persistence/Prefixes.cs @@ -11,6 +11,7 @@ internal static class Prefixes public const byte IX_HeaderHashList = 0x80; public const byte IX_CurrentBlock = 0xc0; public const byte IX_CurrentHeader = 0xc1; + public const byte IX_ContractId = 0xc2; /* Prefixes 0xf0 to 0xff are reserved for external use. * diff --git a/src/neo/Persistence/ReadOnlyView.cs b/src/neo/Persistence/ReadOnlyView.cs index 18bf05fae5..5f87f236ab 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -19,6 +19,7 @@ public class ReadOnlyView : StoreView public override DataCache, HeaderHashList> HeaderHashList => new StoreDataCache, HeaderHashList>(store, Prefixes.IX_HeaderHashList); public override MetaDataCache BlockHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentBlock); public override MetaDataCache HeaderHashIndex => new StoreMetaDataCache(store, Prefixes.IX_CurrentHeader); + public override MetaDataCache ContractId => new StoreMetaDataCache(store, Prefixes.IX_ContractId); public ReadOnlyView(IReadOnlyStore store) { diff --git a/src/neo/Persistence/SnapshotView.cs b/src/neo/Persistence/SnapshotView.cs index 3b20025cd0..d634200134 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -19,6 +19,7 @@ public class SnapshotView : StoreView, IDisposable public override DataCache, HeaderHashList> HeaderHashList { get; } public override MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } + public override MetaDataCache ContractId { get; } public SnapshotView(IStore store) { @@ -30,6 +31,7 @@ public SnapshotView(IStore store) HeaderHashList = new StoreDataCache, HeaderHashList>(snapshot, Prefixes.IX_HeaderHashList); BlockHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentBlock); HeaderHashIndex = new StoreMetaDataCache(snapshot, Prefixes.IX_CurrentHeader); + ContractId = new StoreMetaDataCache(snapshot, Prefixes.IX_ContractId); } public override void Commit() diff --git a/src/neo/Persistence/StoreView.cs b/src/neo/Persistence/StoreView.cs index 4c2a1eed78..c0126b0c95 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -18,6 +18,7 @@ public abstract class StoreView public abstract DataCache, HeaderHashList> HeaderHashList { get; } public abstract MetaDataCache BlockHashIndex { get; } public abstract MetaDataCache HeaderHashIndex { get; } + public abstract MetaDataCache ContractId { get; } public uint Height => BlockHashIndex.Get().Index; public uint HeaderHeight => HeaderHashIndex.Get().Index; @@ -38,6 +39,7 @@ public virtual void Commit() HeaderHashList.Commit(); BlockHashIndex.Commit(); HeaderHashIndex.Commit(); + ContractId.Commit(); } public bool ContainsBlock(UInt256 hash) diff --git a/src/neo/SmartContract/InteropService.Contract.cs b/src/neo/SmartContract/InteropService.Contract.cs index e6df9d8aa8..14823db8c8 100644 --- a/src/neo/SmartContract/InteropService.Contract.cs +++ b/src/neo/SmartContract/InteropService.Contract.cs @@ -38,6 +38,7 @@ private static bool Contract_Create(ApplicationEngine engine) if (contract != null) return false; contract = new ContractState { + Id = engine.Snapshot.ContractId.GetAndChange().NextId++, Script = script, Manifest = ContractManifest.Parse(manifest) }; @@ -66,27 +67,13 @@ private static bool Contract_Update(ApplicationEngine engine) if (engine.Snapshot.Contracts.TryGet(hash_new) != null) return false; contract = new ContractState { + Id = contract.Id, Script = script, Manifest = contract.Manifest }; contract.Manifest.Abi.Hash = hash_new; engine.Snapshot.Contracts.Add(hash_new, contract); - if (contract.HasStorage) - { - foreach (var (key, value) in engine.Snapshot.Storages.Find(engine.CurrentScriptHash.ToArray()).ToArray()) - { - engine.Snapshot.Storages.Add(new StorageKey - { - ScriptHash = hash_new, - Key = key.Key - }, new StorageItem - { - Value = value.Value, - IsConstant = false - }); - } - } - Contract_Destroy(engine); + engine.Snapshot.Contracts.Delete(engine.CurrentScriptHash); } if (manifest.Length > 0) { diff --git a/src/neo/SmartContract/InteropService.Native.cs b/src/neo/SmartContract/InteropService.Native.cs index f664c4020a..da3263b4a2 100644 --- a/src/neo/SmartContract/InteropService.Native.cs +++ b/src/neo/SmartContract/InteropService.Native.cs @@ -22,6 +22,7 @@ private static bool Native_Deploy(ApplicationEngine engine) { engine.Snapshot.Contracts.Add(contract.Hash, new ContractState { + Id = contract.Id, Script = contract.Script, Manifest = contract.Manifest }); diff --git a/src/neo/SmartContract/InteropService.Storage.cs b/src/neo/SmartContract/InteropService.Storage.cs index ebf826b7f5..3355a5f83c 100644 --- a/src/neo/SmartContract/InteropService.Storage.cs +++ b/src/neo/SmartContract/InteropService.Storage.cs @@ -24,14 +24,6 @@ public static class Storage public static readonly InteropDescriptor PutEx = Register("System.Storage.PutEx", Storage_PutEx, GetStoragePrice, TriggerType.Application, CallFlags.AllowModifyStates); public static readonly InteropDescriptor Delete = Register("System.Storage.Delete", Storage_Delete, 0_01000000, TriggerType.Application, CallFlags.AllowModifyStates); - private static bool CheckStorageContext(ApplicationEngine engine, StorageContext context) - { - ContractState contract = engine.Snapshot.Contracts.TryGet(context.ScriptHash); - if (contract == null) return false; - if (!contract.HasStorage) return false; - return true; - } - private static long GetStoragePrice(EvaluationStack stack) { return (stack.Peek(1).GetByteLength() + stack.Peek(2).GetByteLength()) * GasPerByte; @@ -42,11 +34,10 @@ private static bool PutExInternal(ApplicationEngine engine, StorageContext conte if (key.Length > MaxKeySize) return false; if (value.Length > MaxValueSize) return false; if (context.IsReadOnly) return false; - if (!CheckStorageContext(engine, context)) return false; StorageKey skey = new StorageKey { - ScriptHash = context.ScriptHash, + Id = context.Id, Key = key }; @@ -68,9 +59,12 @@ private static bool PutExInternal(ApplicationEngine engine, StorageContext conte private static bool Storage_GetContext(ApplicationEngine engine) { + ContractState contract = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash); + if (contract == null) return false; + if (!contract.HasStorage) return false; engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new StorageContext { - ScriptHash = engine.CurrentScriptHash, + Id = contract.Id, IsReadOnly = false })); return true; @@ -78,9 +72,12 @@ private static bool Storage_GetContext(ApplicationEngine engine) private static bool Storage_GetReadOnlyContext(ApplicationEngine engine) { + ContractState contract = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash); + if (contract == null) return false; + if (!contract.HasStorage) return false; engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new StorageContext { - ScriptHash = engine.CurrentScriptHash, + Id = contract.Id, IsReadOnly = true })); return true; @@ -94,7 +91,7 @@ private static bool Storage_AsReadOnly(ApplicationEngine engine) if (!context.IsReadOnly) context = new StorageContext { - ScriptHash = context.ScriptHash, + Id = context.Id, IsReadOnly = true }; engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(context)); @@ -108,11 +105,10 @@ private static bool Storage_Get(ApplicationEngine engine) if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) { StorageContext context = _interface.GetInterface(); - if (!CheckStorageContext(engine, context)) return false; byte[] key = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray(); StorageItem item = engine.Snapshot.Storages.TryGet(new StorageKey { - ScriptHash = context.ScriptHash, + Id = context.Id, Key = key }); engine.CurrentContext.EvaluationStack.Push(item?.Value ?? StackItem.Null); @@ -126,9 +122,8 @@ private static bool Storage_Find(ApplicationEngine engine) if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) { StorageContext context = _interface.GetInterface(); - if (!CheckStorageContext(engine, context)) return false; byte[] prefix = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray(); - byte[] prefix_key = StorageKey.CreateSearchPrefix(context.ScriptHash, prefix); + byte[] prefix_key = StorageKey.CreateSearchPrefix(context.Id, prefix); StorageIterator iterator = engine.AddDisposable(new StorageIterator(engine.Snapshot.Storages.Find(prefix_key).Where(p => p.Key.Key.AsSpan().StartsWith(prefix)).GetEnumerator())); engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(iterator)); return true; @@ -163,10 +158,9 @@ private static bool Storage_Delete(ApplicationEngine engine) { StorageContext context = _interface.GetInterface(); if (context.IsReadOnly) return false; - if (!CheckStorageContext(engine, context)) return false; StorageKey key = new StorageKey { - ScriptHash = context.ScriptHash, + Id = context.Id, Key = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray() }; if (engine.Snapshot.Storages.TryGet(key)?.IsConstant == true) return false; diff --git a/src/neo/SmartContract/Native/NativeContract.cs b/src/neo/SmartContract/Native/NativeContract.cs index 60c1d6c8db..b7c7f85251 100644 --- a/src/neo/SmartContract/Native/NativeContract.cs +++ b/src/neo/SmartContract/Native/NativeContract.cs @@ -28,6 +28,7 @@ public abstract class NativeContract public uint ServiceHash { get; } public byte[] Script { get; } public UInt160 Hash { get; } + public abstract int Id { get; } public ContractManifest Manifest { get; } public virtual string[] SupportedStandards { get; } = { "NEP-10" }; @@ -71,7 +72,7 @@ protected StorageKey CreateStorageKey(byte prefix, byte[] key = null) { StorageKey storageKey = new StorageKey { - ScriptHash = Hash, + Id = Id, Key = new byte[sizeof(byte) + (key?.Length ?? 0)] }; storageKey.Key[0] = prefix; diff --git a/src/neo/SmartContract/Native/PolicyContract.cs b/src/neo/SmartContract/Native/PolicyContract.cs index 2e48520380..ee5f45376e 100644 --- a/src/neo/SmartContract/Native/PolicyContract.cs +++ b/src/neo/SmartContract/Native/PolicyContract.cs @@ -18,6 +18,7 @@ namespace Neo.SmartContract.Native public sealed class PolicyContract : NativeContract { public override string ServiceName => "Neo.Native.Policy"; + public override int Id => -3; private const byte Prefix_MaxTransactionsPerBlock = 23; private const byte Prefix_FeePerByte = 10; diff --git a/src/neo/SmartContract/Native/Tokens/GasToken.cs b/src/neo/SmartContract/Native/Tokens/GasToken.cs index daa57b6747..7e89bd02c2 100644 --- a/src/neo/SmartContract/Native/Tokens/GasToken.cs +++ b/src/neo/SmartContract/Native/Tokens/GasToken.cs @@ -16,6 +16,7 @@ namespace Neo.SmartContract.Native.Tokens public sealed class GasToken : Nep5Token { public override string ServiceName => "Neo.Native.Tokens.GAS"; + public override int Id => -2; public override string Name => "GAS"; public override string Symbol => "gas"; public override byte Decimals => 8; diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 699e09467b..aaea004edf 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -19,6 +19,7 @@ namespace Neo.SmartContract.Native.Tokens public sealed class NeoToken : Nep5Token { public override string ServiceName => "Neo.Native.Tokens.NEO"; + public override int Id => -1; public override string Name => "NEO"; public override string Symbol => "neo"; public override byte Decimals => 0; @@ -201,7 +202,7 @@ private StackItem GetRegisteredValidators(ApplicationEngine engine, Array args) public IEnumerable<(ECPoint PublicKey, BigInteger Votes)> GetRegisteredValidators(StoreView snapshot) { - byte[] prefix_key = StorageKey.CreateSearchPrefix(Hash, new[] { Prefix_Validator }); + byte[] prefix_key = StorageKey.CreateSearchPrefix(Id, new[] { Prefix_Validator }); return snapshot.Storages.Find(prefix_key).Select(p => ( p.Key.Key.AsSerializable(1), diff --git a/src/neo/SmartContract/StorageContext.cs b/src/neo/SmartContract/StorageContext.cs index 9937caa4f8..2944583f38 100644 --- a/src/neo/SmartContract/StorageContext.cs +++ b/src/neo/SmartContract/StorageContext.cs @@ -2,7 +2,7 @@ namespace Neo.SmartContract { internal class StorageContext { - public UInt160 ScriptHash; + public int Id; public bool IsReadOnly; } } diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 97ebacfdbe..c7a0687729 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -915,7 +915,7 @@ private StorageKey CreateStorageKeyForNativeNeo(byte prefix) { StorageKey storageKey = new StorageKey { - ScriptHash = NativeContract.NEO.Hash, + Id = NativeContract.NEO.Id, Key = new byte[sizeof(byte)] }; storageKey.Key[0] = prefix; diff --git a/tests/neo.UnitTests/Ledger/UT_ContractState.cs b/tests/neo.UnitTests/Ledger/UT_ContractState.cs index 670f31d757..8f730a20c0 100644 --- a/tests/neo.UnitTests/Ledger/UT_ContractState.cs +++ b/tests/neo.UnitTests/Ledger/UT_ContractState.cs @@ -84,7 +84,7 @@ public void TestDeserialize() public void TestGetSize() { ISerializable newContract = contract; - newContract.Size.Should().Be(368); + newContract.Size.Should().Be(372); } [TestMethod] diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 38a456bcf3..86ad694641 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 key1 = CreateStorageKey(Prefix_MaxTransactionsPerBlock); var key2 = CreateStorageKey(Prefix_FeePerByte); - key1.ScriptHash = NativeContract.Policy.Hash; - key2.ScriptHash = NativeContract.Policy.Hash; + key1.Id = NativeContract.Policy.Id; + key2.Id = NativeContract.Policy.Id; snapshot.Storages.Add(key1, item1); snapshot.Storages.Add(key2, item2); @@ -510,7 +510,7 @@ public StorageKey CreateStorageKey(byte prefix, byte[] key = null) { StorageKey storageKey = new StorageKey { - ScriptHash = null, + Id = 0, Key = new byte[sizeof(byte) + (key?.Length ?? 0)] }; storageKey.Key[0] = prefix; diff --git a/tests/neo.UnitTests/Ledger/UT_StorageKey.cs b/tests/neo.UnitTests/Ledger/UT_StorageKey.cs index 1941cbc0cc..e71cdba716 100644 --- a/tests/neo.UnitTests/Ledger/UT_StorageKey.cs +++ b/tests/neo.UnitTests/Ledger/UT_StorageKey.cs @@ -18,30 +18,30 @@ public void TestSetup() } [TestMethod] - public void ScriptHash_Get() + public void Id_Get() { - uut.ScriptHash.Should().BeNull(); + uut.Id.Should().Be(0); } [TestMethod] public void Size() { - var ut = new StorageKey() { Key = new byte[17], ScriptHash = UInt160.Zero }; + var ut = new StorageKey() { Key = new byte[17], Id = 0 }; ut.ToArray().Length.Should().Be(((ISerializable)ut).Size); - ut = new StorageKey() { Key = new byte[0], ScriptHash = UInt160.Zero }; + ut = new StorageKey() { Key = new byte[0], Id = 0 }; ut.ToArray().Length.Should().Be(((ISerializable)ut).Size); - ut = new StorageKey() { Key = new byte[16], ScriptHash = UInt160.Zero }; + ut = new StorageKey() { Key = new byte[16], Id = 0 }; ut.ToArray().Length.Should().Be(((ISerializable)ut).Size); } [TestMethod] - public void ScriptHash_Set() + public void Id_Set() { - UInt160 val = new UInt160(TestUtils.GetByteArray(20, 0x42)); - uut.ScriptHash = val; - uut.ScriptHash.Should().Be(val); + int val = 1; + uut.Id = val; + uut.Id.Should().Be(val); } [TestMethod] @@ -75,14 +75,14 @@ public void Equals_Null() [TestMethod] public void Equals_SameHash_SameKey() { - UInt160 val = new UInt160(TestUtils.GetByteArray(20, 0x42)); + int val = 0x42000000; byte[] keyVal = TestUtils.GetByteArray(10, 0x42); StorageKey newSk = new StorageKey { - ScriptHash = val, + Id = val, Key = keyVal }; - uut.ScriptHash = val; + uut.Id = val; uut.Key = keyVal; uut.Equals(newSk).Should().BeTrue(); @@ -91,14 +91,14 @@ public void Equals_SameHash_SameKey() [TestMethod] public void Equals_DiffHash_SameKey() { - UInt160 val = new UInt160(TestUtils.GetByteArray(20, 0x42)); + int val = 0x42000000; byte[] keyVal = TestUtils.GetByteArray(10, 0x42); StorageKey newSk = new StorageKey { - ScriptHash = val, + Id = val, Key = keyVal }; - uut.ScriptHash = new UInt160(TestUtils.GetByteArray(20, 0x88)); + uut.Id = 0x78000000; uut.Key = keyVal; uut.Equals(newSk).Should().BeFalse(); @@ -108,14 +108,14 @@ public void Equals_DiffHash_SameKey() [TestMethod] public void Equals_SameHash_DiffKey() { - UInt160 val = new UInt160(TestUtils.GetByteArray(20, 0x42)); + int val = 0x42000000; byte[] keyVal = TestUtils.GetByteArray(10, 0x42); StorageKey newSk = new StorageKey { - ScriptHash = val, + Id = val, Key = keyVal }; - uut.ScriptHash = val; + uut.Id = val; uut.Key = TestUtils.GetByteArray(10, 0x88); uut.Equals(newSk).Should().BeFalse(); @@ -124,9 +124,9 @@ public void Equals_SameHash_DiffKey() [TestMethod] public void GetHashCode_Get() { - uut.ScriptHash = new UInt160(TestUtils.GetByteArray(20, 0x42)); + uut.Id = 0x42000000; uut.Key = TestUtils.GetByteArray(10, 0x42); - uut.GetHashCode().Should().Be(806209853); + uut.GetHashCode().Should().Be(1374529787); } [TestMethod] @@ -143,13 +143,13 @@ public void TestDeserialize() using (BinaryWriter writer = new BinaryWriter(ms)) using (BinaryReader reader = new BinaryReader(ms)) { - uut.ScriptHash = new UInt160(TestUtils.GetByteArray(20, 0x42)); + uut.Id = 0x42000000; uut.Key = TestUtils.GetByteArray(10, 0x42); ((ISerializable)uut).Serialize(writer); ms.Seek(0, SeekOrigin.Begin); StorageKey dest = new StorageKey(); ((ISerializable)dest).Deserialize(reader); - dest.ScriptHash.Should().Be(uut.ScriptHash); + dest.Id.Should().Be(uut.Id); dest.Key.Should().BeEquivalentTo(uut.Key); } } diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index 51caa8db9c..614322aa20 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -164,7 +164,7 @@ public void TestGetSysFeeAmount2() byte[] key = BitConverter.GetBytes(1); StorageKey storageKey = new StorageKey { - ScriptHash = NativeContract.GAS.Hash, + Id = NativeContract.GAS.Id, Key = new byte[sizeof(byte) + key.Length] }; storageKey.Key[0] = 15; diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 6111c9b052..6533b07541 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -704,7 +704,7 @@ internal static StorageKey CreateStorageKey(byte prefix, byte[] key = null) { StorageKey storageKey = new StorageKey { - ScriptHash = NativeContract.NEO.Hash, + Id = NativeContract.NEO.Id, Key = new byte[sizeof(byte) + (key?.Length ?? 0)] }; storageKey.Key[0] = prefix; diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs index 3cb10defe3..1e31914441 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep5Token.cs @@ -19,6 +19,8 @@ public class UT_Nep5Token public void TestTotalSupply() { var snapshot = Blockchain.Singleton.GetSnapshot(); + + TestNep5Token test = new TestNep5Token(); StorageItem item = new StorageItem { Value = new byte[] { 0x01 } @@ -33,10 +35,9 @@ public void TestTotalSupply() script = sb.ToArray(); } var Hash = script.ToScriptHash(); - key.ScriptHash = Hash; + key.Id = test.Id; snapshot.Storages.Add(key, item); - TestNep5Token test = new TestNep5Token(); ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); StackItem stackItem = test.TotalSupply(ae, null); stackItem.GetBigInteger().Should().Be(1); @@ -65,7 +66,7 @@ public void TestTotalSupplyDecimal() script = sb.ToArray(); } var Hash = script.ToScriptHash(); - key.ScriptHash = Hash; + key.Id = test.Id; snapshot.Storages.Add(key, item); @@ -78,7 +79,7 @@ public StorageKey CreateStorageKey(byte prefix, byte[] key = null) { StorageKey storageKey = new StorageKey { - ScriptHash = null, + Id = 0, Key = new byte[sizeof(byte) + (key?.Length ?? 0)] }; storageKey.Key[0] = prefix; @@ -89,6 +90,8 @@ public StorageKey CreateStorageKey(byte prefix, byte[] key = null) public class TestNep5Token : Nep5Token { + public override int Id => 0x10000005; + public override string Name => throw new NotImplementedException(); public override string Symbol => throw new NotImplementedException(); diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 71cfd3c093..2252e60d8a 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -89,6 +89,9 @@ public void TestTestCall() public class TestNativeContract : NativeContract { public override string ServiceName => "test"; + + public override int Id => 0x10000006; + public StackItem TestOnPersist(ApplicationEngine engine, VMArray args) { return OnPersist(engine, args); diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 0b15d0732d..a173585182 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -234,7 +234,7 @@ public void TestCheckPolicy() StorageKey storageKey = new StorageKey { - ScriptHash = NativeContract.Policy.Hash, + Id = NativeContract.Policy.Id, Key = new byte[sizeof(byte)] }; storageKey.Key[0] = 15; diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index 959eeecae8..814f55cb67 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -229,7 +229,7 @@ public void TestContract_Update() var storageKey = new StorageKey { - ScriptHash = state.ScriptHash, + Id = state.Id, Key = new byte[] { 0x01 } }; snapshot.Contracts.Add(state.ScriptHash, state); @@ -239,18 +239,6 @@ public void TestContract_Update() engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); engine.CurrentContext.EvaluationStack.Push(script); InteropService.Invoke(engine, InteropService.Contract.Update).Should().BeTrue(); - - // Remove Storage flag with something stored - - state.Manifest.Features = ContractFeatures.NoProperty; - snapshot.Contracts.Add(state.ScriptHash, state); - snapshot.Storages.Add(storageKey, storageItem); - - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); - engine.LoadScript(state.Script); - engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); - engine.CurrentContext.EvaluationStack.Push(script); - InteropService.Invoke(engine, InteropService.Contract.Update).Should().BeFalse(); } [TestMethod] @@ -267,7 +255,7 @@ public void TestStorage_Find() }; var storageKey = new StorageKey { - ScriptHash = state.ScriptHash, + Id = state.Id, Key = new byte[] { 0x01 } }; snapshot.Contracts.Add(state.ScriptHash, state); @@ -278,7 +266,7 @@ public void TestStorage_Find() engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); engine.CurrentContext.EvaluationStack.Push(new InteropInterface(new StorageContext { - ScriptHash = state.ScriptHash, + Id = state.Id, IsReadOnly = false })); InteropService.Invoke(engine, InteropService.Storage.Find).Should().BeTrue(); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 1fa676af60..7ad570ef0f 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -480,20 +480,26 @@ public void TestBlockchain_GetContract() [TestMethod] public void TestStorage_GetContext() { - var engine = GetEngine(); + var engine = GetEngine(false, true); + var state = TestUtils.GetContract(); + state.Manifest.Features = ContractFeatures.HasStorage; + engine.Snapshot.Contracts.Add(state.ScriptHash, state); + engine.LoadScript(state.Script); InteropService.Invoke(engine, InteropService.Storage.GetContext).Should().BeTrue(); var ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); - ret.GetInterface().ScriptHash.Should().Be(engine.CurrentScriptHash); ret.GetInterface().IsReadOnly.Should().BeFalse(); } [TestMethod] public void TestStorage_GetReadOnlyContext() { - var engine = GetEngine(); + var engine = GetEngine(false, true); + var state = TestUtils.GetContract(); + state.Manifest.Features = ContractFeatures.HasStorage; + engine.Snapshot.Contracts.Add(state.ScriptHash, state); + engine.LoadScript(state.Script); InteropService.Invoke(engine, InteropService.Storage.GetReadOnlyContext).Should().BeTrue(); var ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); - ret.GetInterface().ScriptHash.Should().Be(engine.CurrentScriptHash); ret.GetInterface().IsReadOnly.Should().BeTrue(); } @@ -506,7 +512,7 @@ public void TestStorage_Get() var storageKey = new StorageKey { - ScriptHash = state.ScriptHash, + Id = state.Id, Key = new byte[] { 0x01 } }; @@ -523,25 +529,11 @@ public void TestStorage_Get() engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); engine.CurrentContext.EvaluationStack.Push(new InteropInterface(new StorageContext { - ScriptHash = state.ScriptHash, + Id = state.Id, IsReadOnly = false })); InteropService.Invoke(engine, InteropService.Storage.Get).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToHexString().Should().Be(storageItem.Value.ToHexString()); - - snapshot.Contracts.Delete(state.ScriptHash); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); - engine.LoadScript(new byte[] { 0x01 }); - engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(new StorageContext - { - ScriptHash = state.ScriptHash, - IsReadOnly = false - })); - InteropService.Invoke(engine, InteropService.Storage.Get).Should().BeFalse(); - - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Storage.Get).Should().BeFalse(); } [TestMethod] @@ -559,11 +551,11 @@ public void TestStorage_Put() var state = TestUtils.GetContract(); var storageContext = new StorageContext { - ScriptHash = state.ScriptHash, + Id = state.Id, IsReadOnly = false }; engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.Put).Should().BeFalse(); + InteropService.Invoke(engine, InteropService.Storage.Put).Should().BeTrue(); //key.Length > MaxStorageKeySize key = new byte[InteropService.Storage.MaxKeySize + 1]; @@ -596,7 +588,7 @@ public void TestStorage_Put() var storageKey = new StorageKey { - ScriptHash = state.ScriptHash, + Id = state.Id, Key = new byte[] { 0x01 } }; var storageItem = new StorageItem @@ -644,7 +636,7 @@ public void TestStorage_PutEx() state.Manifest.Features = ContractFeatures.HasStorage; var storageKey = new StorageKey { - ScriptHash = new UInt160(TestUtils.GetByteArray(20, 0x42)), + Id = 0x42000000, Key = new byte[] { 0x01 } }; var storageItem = new StorageItem @@ -660,7 +652,7 @@ public void TestStorage_PutEx() var value = new byte[] { 0x02 }; var storageContext = new StorageContext { - ScriptHash = state.ScriptHash, + Id = state.Id, IsReadOnly = false }; engine.CurrentContext.EvaluationStack.Push((int)StorageFlags.None); @@ -683,7 +675,7 @@ public void TestStorage_Delete() state.Manifest.Features = ContractFeatures.HasStorage; var storageKey = new StorageKey { - ScriptHash = new UInt160(TestUtils.GetByteArray(20, 0x42)), + Id = 0x42000000, Key = new byte[] { 0x01 } }; var storageItem = new StorageItem @@ -699,7 +691,7 @@ public void TestStorage_Delete() var key = new byte[] { 0x01 }; var storageContext = new StorageContext { - ScriptHash = state.ScriptHash, + Id = state.Id, IsReadOnly = false }; engine.CurrentContext.EvaluationStack.Push(key); @@ -711,13 +703,6 @@ public void TestStorage_Delete() engine.CurrentContext.EvaluationStack.Push(key); engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); InteropService.Invoke(engine, InteropService.Storage.Delete).Should().BeFalse(); - - //CheckStorageContext fail - storageContext.IsReadOnly = false; - state.Manifest.Features = ContractFeatures.NoProperty; - engine.CurrentContext.EvaluationStack.Push(key); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.Delete).Should().BeFalse(); } [TestMethod] @@ -730,7 +715,7 @@ public void TestStorageContext_AsReadOnly() var state = TestUtils.GetContract(); var storageContext = new StorageContext { - ScriptHash = state.ScriptHash, + Id = state.Id, IsReadOnly = false }; engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); @@ -855,7 +840,7 @@ public void TestContract_Destroy() var storageKey = new StorageKey { - ScriptHash = scriptHash, + Id = 0x43000000, Key = new byte[] { 0x01 } }; snapshot.Contracts.Add(scriptHash, state); diff --git a/tests/neo.UnitTests/SmartContract/UT_StorageContext.cs b/tests/neo.UnitTests/SmartContract/UT_StorageContext.cs deleted file mode 100644 index d1210169dd..0000000000 --- a/tests/neo.UnitTests/SmartContract/UT_StorageContext.cs +++ /dev/null @@ -1,23 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.IO; -using Neo.SmartContract; - -namespace Neo.UnitTests.SmartContract -{ - [TestClass] - public class UT_StorageContext - { - [TestMethod] - public void TestToArray() - { - UInt160 script_hash = new byte[] { 0x00 }.ToScriptHash(); - StorageContext context = new StorageContext() - { - ScriptHash = script_hash, - IsReadOnly = true - }; - context.ScriptHash.ToArray().Should().BeEquivalentTo(new byte[] { 0x00 }.ToScriptHash().ToArray()); - } - } -} diff --git a/tests/neo.UnitTests/UT_DataCache.cs b/tests/neo.UnitTests/UT_DataCache.cs index 0cee679316..4b8ad1de74 100644 --- a/tests/neo.UnitTests/UT_DataCache.cs +++ b/tests/neo.UnitTests/UT_DataCache.cs @@ -21,40 +21,40 @@ public void TestCachedFind_Between() var storages = snapshot.Storages; var cache = new CloneCache(storages); - storages.DeleteWhere((k, v) => k.ScriptHash == UInt160.Zero); + storages.DeleteWhere((k, v) => k.Id == 0); storages.Add ( - new StorageKey() { Key = new byte[] { 0x01, 0x01 }, ScriptHash = UInt160.Zero }, + new StorageKey() { Key = new byte[] { 0x01, 0x01 }, Id = 0 }, new StorageItem() { IsConstant = false, Value = new byte[] { } } ); storages.Add ( - new StorageKey() { Key = new byte[] { 0x00, 0x01 }, ScriptHash = UInt160.Zero }, + new StorageKey() { Key = new byte[] { 0x00, 0x01 }, Id = 0 }, new StorageItem() { IsConstant = false, Value = new byte[] { } } ); storages.Add ( - new StorageKey() { Key = new byte[] { 0x00, 0x03 }, ScriptHash = UInt160.Zero }, + new StorageKey() { Key = new byte[] { 0x00, 0x03 }, Id = 0 }, new StorageItem() { IsConstant = false, Value = new byte[] { } } ); cache.Add ( - new StorageKey() { Key = new byte[] { 0x01, 0x02 }, ScriptHash = UInt160.Zero }, + new StorageKey() { Key = new byte[] { 0x01, 0x02 }, Id = 0 }, new StorageItem() { IsConstant = false, Value = new byte[] { } } ); cache.Add ( - new StorageKey() { Key = new byte[] { 0x00, 0x02 }, ScriptHash = UInt160.Zero }, + new StorageKey() { Key = new byte[] { 0x00, 0x02 }, Id = 0 }, new StorageItem() { IsConstant = false, Value = new byte[] { } } ); CollectionAssert.AreEqual( - cache.Find(new byte[21]).Select(u => u.Key.Key[1]).ToArray(), + cache.Find(new byte[5]).Select(u => u.Key.Key[1]).ToArray(), new byte[] { 0x01, 0x02, 0x03 } ); - storages.DeleteWhere((k, v) => k.ScriptHash == UInt160.Zero); + storages.DeleteWhere((k, v) => k.Id == 0); } [TestMethod] @@ -64,35 +64,33 @@ public void TestCachedFind_Last() var storages = snapshot.Storages; var cache = new CloneCache(storages); - storages.DeleteWhere((k, v) => k.ScriptHash == UInt160.Zero); + storages.DeleteWhere((k, v) => k.Id == 0); storages.Add ( - new StorageKey() { Key = new byte[] { 0x00, 0x01 }, ScriptHash = UInt160.Zero }, + new StorageKey() { Key = new byte[] { 0x00, 0x01 }, Id = 0 }, new StorageItem() { IsConstant = false, Value = new byte[] { } } ); storages.Add ( - new StorageKey() { Key = new byte[] { 0x01, 0x01 }, ScriptHash = UInt160.Zero }, + new StorageKey() { Key = new byte[] { 0x01, 0x01 }, Id = 0 }, new StorageItem() { IsConstant = false, Value = new byte[] { } } ); cache.Add ( - new StorageKey() { Key = new byte[] { 0x00, 0x02 }, ScriptHash = UInt160.Zero }, + new StorageKey() { Key = new byte[] { 0x00, 0x02 }, Id = 0 }, new StorageItem() { IsConstant = false, Value = new byte[] { } } ); cache.Add ( - new StorageKey() { Key = new byte[] { 0x01, 0x02 }, ScriptHash = UInt160.Zero }, + new StorageKey() { Key = new byte[] { 0x01, 0x02 }, Id = 0 }, new StorageItem() { IsConstant = false, Value = new byte[] { } } ); - - CollectionAssert.AreEqual( - cache.Find(new byte[21]).Select(u => u.Key.Key[1]).ToArray(), + CollectionAssert.AreEqual(cache.Find(new byte[5]).Select(u => u.Key.Key[1]).ToArray(), new byte[] { 0x01, 0x02 } ); - storages.DeleteWhere((k, v) => k.ScriptHash == UInt160.Zero); + storages.DeleteWhere((k, v) => k.Id == 0); } [TestMethod] @@ -102,25 +100,25 @@ public void TestCachedFind_Empty() var storages = snapshot.Storages; var cache = new CloneCache(storages); - storages.DeleteWhere((k, v) => k.ScriptHash == UInt160.Zero); + storages.DeleteWhere((k, v) => k.Id == 0); cache.Add ( - new StorageKey() { Key = new byte[] { 0x00, 0x02 }, ScriptHash = UInt160.Zero }, + new StorageKey() { Key = new byte[] { 0x00, 0x02 }, Id = 0 }, new StorageItem() { IsConstant = false, Value = new byte[] { } } ); cache.Add ( - new StorageKey() { Key = new byte[] { 0x01, 0x02 }, ScriptHash = UInt160.Zero }, + new StorageKey() { Key = new byte[] { 0x01, 0x02 }, Id = 0 }, new StorageItem() { IsConstant = false, Value = new byte[] { } } ); CollectionAssert.AreEqual( - cache.Find(new byte[21]).Select(u => u.Key.Key[1]).ToArray(), + cache.Find(new byte[5]).Select(u => u.Key.Key[1]).ToArray(), new byte[] { 0x02 } ); - storages.DeleteWhere((k, v) => k.ScriptHash == UInt160.Zero); + storages.DeleteWhere((k, v) => k.Id == 0); } } }