diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index b5af18af84..c8ca847cbc 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -10,7 +10,6 @@ using Neo.Persistence; using Neo.Plugins; using Neo.SmartContract; -using Neo.SmartContract.Native; using Neo.VM; using System; using System.Collections.Concurrent; @@ -53,7 +52,7 @@ private class UnverifiedBlocksList { public LinkedList Blocks = new Linke PrimaryIndex = 0, Nonce = 2083236893 }, - Transactions = new[] { DeployNativeContracts() } + Transactions = Array.Empty() }; private readonly static Script onPersistScript, postPersistScript; @@ -92,20 +91,12 @@ static Blockchain() using (ScriptBuilder sb = new ScriptBuilder()) { - foreach (NativeContract contract in new NativeContract[] { NativeContract.GAS, NativeContract.NEO }) - { - sb.EmitAppCall(contract.Hash, "onPersist"); - sb.Emit(OpCode.DROP); - } + sb.EmitSysCall(ApplicationEngine.System_Contract_NativeOnPersist); onPersistScript = sb.ToArray(); } using (ScriptBuilder sb = new ScriptBuilder()) { - foreach (NativeContract contract in new NativeContract[] { NativeContract.NEO, NativeContract.Oracle }) - { - sb.EmitAppCall(contract.Hash, "postPersist"); - sb.Emit(OpCode.DROP); - } + sb.EmitSysCall(ApplicationEngine.System_Contract_NativePostPersist); postPersistScript = sb.ToArray(); } } @@ -165,39 +156,6 @@ public bool ContainsTransaction(UInt256 hash) return View.ContainsTransaction(hash); } - private static Transaction DeployNativeContracts() - { - byte[] script; - using (ScriptBuilder sb = new ScriptBuilder()) - { - sb.EmitSysCall(ApplicationEngine.Neo_Native_Deploy); - script = sb.ToArray(); - } - return new Transaction - { - Version = 0, - Script = script, - SystemFee = 0, - Signers = new[] - { - new Signer - { - Account = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash(), - Scopes = WitnessScope.None - } - }, - Attributes = Array.Empty(), - Witnesses = new[] - { - new Witness - { - InvocationScript = Array.Empty(), - VerificationScript = new[] { (byte)OpCode.PUSH1 } - } - } - }; - } - public Block GetBlock(uint index) { if (index == 0) return GenesisBlock; @@ -437,9 +395,8 @@ private void Persist(Block block) } List all_application_executed = new List(); snapshot.PersistingBlock = block; - if (block.Index > 0) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.OnPersist, null, snapshot)) { - using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.OnPersist, null, snapshot); engine.LoadScript(onPersistScript); if (engine.Execute() != VMState.HALT) throw new InvalidOperationException(); ApplicationExecuted application_executed = new ApplicationExecuted(engine); diff --git a/src/neo/Ledger/ContractIdState.cs b/src/neo/Ledger/ContractIdState.cs deleted file mode 100644 index b29f1d21ac..0000000000 --- a/src/neo/Ledger/ContractIdState.cs +++ /dev/null @@ -1,37 +0,0 @@ -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 deleted file mode 100644 index a88c3ae9ef..0000000000 --- a/src/neo/Ledger/ContractState.cs +++ /dev/null @@ -1,95 +0,0 @@ -using Neo.IO; -using Neo.IO.Json; -using Neo.SmartContract; -using Neo.SmartContract.Manifest; -using Neo.VM; -using Neo.VM.Types; -using System; -using System.IO; -using System.Linq; -using Array = Neo.VM.Types.Array; - -namespace Neo.Ledger -{ - public class ContractState : ICloneable, ISerializable, IInteroperable - { - public int Id; - public ushort UpdateCounter; - public UInt160 Hash; - public byte[] Script; - public ContractManifest Manifest; - - int ISerializable.Size => sizeof(int) + sizeof(ushort) + UInt160.Length + Script.GetVarSize() + Manifest.Size; - - ContractState ICloneable.Clone() - { - return new ContractState - { - Id = Id, - UpdateCounter = UpdateCounter, - Hash = Hash, - Script = Script, - Manifest = Manifest.Clone() - }; - } - - void ISerializable.Deserialize(BinaryReader reader) - { - Id = reader.ReadInt32(); - UpdateCounter = reader.ReadUInt16(); - Hash = reader.ReadSerializable(); - Script = reader.ReadVarBytes(); - Manifest = reader.ReadSerializable(); - } - - void ICloneable.FromReplica(ContractState replica) - { - Id = replica.Id; - UpdateCounter = replica.UpdateCounter; - Hash = replica.Hash; - Script = replica.Script; - Manifest = replica.Manifest.Clone(); - } - - void IInteroperable.FromStackItem(StackItem stackItem) - { - throw new NotSupportedException(); - } - - void ISerializable.Serialize(BinaryWriter writer) - { - writer.Write(Id); - writer.Write(UpdateCounter); - writer.Write(Hash); - writer.WriteVarBytes(Script); - writer.Write(Manifest); - } - - /// - /// Return true if is allowed - /// - /// The contract that we are calling - /// The method that we are calling - /// Return true or false - public bool CanCall(ContractState targetContract, string targetMethod) - { - return Manifest.Permissions.Any(u => u.IsAllowed(targetContract, targetMethod)); - } - - public JObject ToJson() - { - JObject json = new JObject(); - json["id"] = Id; - json["updatecounter"] = UpdateCounter; - json["hash"] = Hash.ToString(); - json["script"] = Convert.ToBase64String(Script); - json["manifest"] = Manifest.ToJson(); - return json; - } - - public StackItem ToStackItem(ReferenceCounter referenceCounter) - { - return new Array(referenceCounter, new StackItem[] { Id, (int)UpdateCounter, Hash.ToArray(), Script, Manifest.ToString() }); - } - } -} diff --git a/src/neo/Ledger/StorageItem.cs b/src/neo/Ledger/StorageItem.cs index db364d5c7b..7b8f99bec3 100644 --- a/src/neo/Ledger/StorageItem.cs +++ b/src/neo/Ledger/StorageItem.cs @@ -23,7 +23,7 @@ public byte[] Value return value ??= cache switch { BigInteger bi => bi.ToByteArrayStandard(), - IInteroperable interoperable => BinarySerializer.Serialize(interoperable.ToStackItem(null), 4096), + IInteroperable interoperable => BinarySerializer.Serialize(interoperable.ToStackItem(null), 1024 * 1024), IReadOnlyCollection list => list.ToByteArray(), null => null, _ => throw new InvalidCastException() diff --git a/src/neo/Persistence/ClonedView.cs b/src/neo/Persistence/ClonedView.cs index 307438b2db..03d945c849 100644 --- a/src/neo/Persistence/ClonedView.cs +++ b/src/neo/Persistence/ClonedView.cs @@ -8,24 +8,20 @@ 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 MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public override MetaDataCache ContractId { get; } public ClonedView(StoreView view) { this.PersistingBlock = view.PersistingBlock; this.Blocks = view.Blocks.CreateSnapshot(); this.Transactions = view.Transactions.CreateSnapshot(); - this.Contracts = view.Contracts.CreateSnapshot(); this.Storages = view.Storages.CreateSnapshot(); this.HeaderHashList = view.HeaderHashList.CreateSnapshot(); this.BlockHashIndex = view.BlockHashIndex.CreateSnapshot(); this.HeaderHashIndex = view.HeaderHashIndex.CreateSnapshot(); - this.ContractId = view.ContractId.CreateSnapshot(); } } } diff --git a/src/neo/Persistence/Prefixes.cs b/src/neo/Persistence/Prefixes.cs index 421fe086c3..fcd7549325 100644 --- a/src/neo/Persistence/Prefixes.cs +++ b/src/neo/Persistence/Prefixes.cs @@ -5,13 +5,11 @@ internal static class Prefixes public const byte DATA_Block = 0x01; public const byte DATA_Transaction = 0x02; - public const byte ST_Contract = 0x50; public const byte ST_Storage = 0x70; 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 5f87f236ab..a874c33697 100644 --- a/src/neo/Persistence/ReadOnlyView.cs +++ b/src/neo/Persistence/ReadOnlyView.cs @@ -14,12 +14,10 @@ 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 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 d634200134..ce66270509 100644 --- a/src/neo/Persistence/SnapshotView.cs +++ b/src/neo/Persistence/SnapshotView.cs @@ -14,24 +14,20 @@ 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 MetaDataCache BlockHashIndex { get; } public override MetaDataCache HeaderHashIndex { get; } - public override MetaDataCache ContractId { get; } public SnapshotView(IStore store) { this.snapshot = store.GetSnapshot(); Blocks = new StoreDataCache(snapshot, Prefixes.DATA_Block); Transactions = new StoreDataCache(snapshot, Prefixes.DATA_Transaction); - Contracts = new StoreDataCache(snapshot, Prefixes.ST_Contract); Storages = new StoreDataCache(snapshot, Prefixes.ST_Storage); HeaderHashList = new StoreDataCache, 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 a54d5aeac8..4671c12381 100644 --- a/src/neo/Persistence/StoreView.cs +++ b/src/neo/Persistence/StoreView.cs @@ -13,12 +13,10 @@ public abstract class StoreView public Block PersistingBlock { get; internal set; } 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 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; @@ -34,12 +32,10 @@ public virtual void Commit() { Blocks.Commit(); Transactions.Commit(); - Contracts.Commit(); Storages.Commit(); HeaderHashList.Commit(); BlockHashIndex.Commit(); HeaderHashIndex.Commit(); - ContractId.Commit(); } public bool ContainsBlock(UInt256 hash) diff --git a/src/neo/SmartContract/ApplicationEngine.Blockchain.cs b/src/neo/SmartContract/ApplicationEngine.Blockchain.cs index f6b7f82c60..2186792752 100644 --- a/src/neo/SmartContract/ApplicationEngine.Blockchain.cs +++ b/src/neo/SmartContract/ApplicationEngine.Blockchain.cs @@ -13,7 +13,6 @@ partial class ApplicationEngine public static readonly InteropDescriptor System_Blockchain_GetTransaction = Register("System.Blockchain.GetTransaction", nameof(GetTransaction), 0_01000000, CallFlags.ReadStates, true); public static readonly InteropDescriptor System_Blockchain_GetTransactionHeight = Register("System.Blockchain.GetTransactionHeight", nameof(GetTransactionHeight), 0_01000000, CallFlags.ReadStates, true); public static readonly InteropDescriptor System_Blockchain_GetTransactionFromBlock = Register("System.Blockchain.GetTransactionFromBlock", nameof(GetTransactionFromBlock), 0_01000000, CallFlags.ReadStates, true); - public static readonly InteropDescriptor System_Blockchain_GetContract = Register("System.Blockchain.GetContract", nameof(GetContract), 0_01000000, CallFlags.ReadStates, true); protected internal uint GetBlockchainHeight() { @@ -87,11 +86,6 @@ protected internal Transaction GetTransactionFromBlock(byte[] blockIndexOrHash, return Snapshot.GetTransaction(block.Hashes[txIndex + 1]); } - protected internal ContractState GetContract(UInt160 hash) - { - return Snapshot.Contracts.TryGet(hash); - } - private static bool IsTraceableBlock(StoreView snapshot, uint index) { if (index > snapshot.Height) return false; diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index 4997979fd9..2d794439a3 100644 --- a/src/neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -1,6 +1,4 @@ using Neo.Cryptography.ECC; -using Neo.IO; -using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.SmartContract.Manifest; using Neo.SmartContract.Native; @@ -12,11 +10,9 @@ namespace Neo.SmartContract { partial class ApplicationEngine { - public static readonly InteropDescriptor System_Contract_Create = Register("System.Contract.Create", nameof(CreateContract), 0, CallFlags.WriteStates, false); - public static readonly InteropDescriptor System_Contract_Update = Register("System.Contract.Update", nameof(UpdateContract), 0, CallFlags.WriteStates, false); - public static readonly InteropDescriptor System_Contract_Destroy = Register("System.Contract.Destroy", nameof(DestroyContract), 0_01000000, CallFlags.WriteStates, false); public static readonly InteropDescriptor System_Contract_Call = Register("System.Contract.Call", nameof(CallContract), 0_01000000, CallFlags.AllowCall, false); public static readonly InteropDescriptor System_Contract_CallEx = Register("System.Contract.CallEx", nameof(CallContractEx), 0_01000000, CallFlags.AllowCall, false); + public static readonly InteropDescriptor System_Contract_CallNative = Register("System.Contract.CallNative", nameof(CallNativeContract), 0, CallFlags.AllowCall, false); public static readonly InteropDescriptor System_Contract_IsStandard = Register("System.Contract.IsStandard", nameof(IsStandardContract), 0_00030000, CallFlags.ReadStates, true); public static readonly InteropDescriptor System_Contract_GetCallFlags = Register("System.Contract.GetCallFlags", nameof(GetCallFlags), 0_00030000, CallFlags.None, false); /// @@ -24,91 +20,8 @@ partial class ApplicationEngine /// Warning: check first that input public key is valid, before creating the script. /// public static readonly InteropDescriptor System_Contract_CreateStandardAccount = Register("System.Contract.CreateStandardAccount", nameof(CreateStandardAccount), 0_00010000, CallFlags.None, true); - - protected internal void CreateContract(byte[] nefFile, byte[] manifest) - { - if (!(ScriptContainer is Transaction tx)) - throw new InvalidOperationException(); - if (nefFile.Length == 0) - throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}"); - if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) - throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}"); - - AddGas(StoragePrice * (nefFile.Length + manifest.Length)); - - NefFile nef = nefFile.AsSerializable(); - UInt160 hash = Helper.GetContractHash(tx.Sender, nef.Script); - ContractState contract = Snapshot.Contracts.TryGet(hash); - if (contract != null) throw new InvalidOperationException($"Contract Already Exists: {hash}"); - contract = new ContractState - { - Id = Snapshot.ContractId.GetAndChange().NextId++, - UpdateCounter = 0, - Script = nef.Script, - Hash = hash, - Manifest = ContractManifest.Parse(manifest) - }; - - if (!contract.Manifest.IsValid(hash)) throw new InvalidOperationException($"Invalid Manifest Hash: {hash}"); - - Snapshot.Contracts.Add(hash, contract); - - // We should push it onto the caller's stack. - - Push(Convert(contract)); - - // Execute _deploy - - ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy"); - if (md != null) - CallContractInternal(contract, md, new Array(ReferenceCounter) { false }, CallFlags.All, ReturnTypeConvention.EnsureIsEmpty); - } - - protected internal void UpdateContract(byte[] nefFile, byte[] manifest) - { - if (nefFile is null && manifest is null) throw new ArgumentException(); - - AddGas(StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0))); - - var contract = Snapshot.Contracts.GetAndChange(CurrentScriptHash); - if (contract is null) throw new InvalidOperationException($"Updating Contract Does Not Exist: {CurrentScriptHash}"); - - if (nefFile != null) - { - if (nefFile.Length == 0) - throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}"); - - NefFile nef = nefFile.AsSerializable(); - - // Update script - contract.Script = nef.Script; - } - if (manifest != null) - { - if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) - throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}"); - contract.Manifest = ContractManifest.Parse(manifest); - if (!contract.Manifest.IsValid(contract.Hash)) - throw new InvalidOperationException($"Invalid Manifest Hash: {contract.Hash}"); - } - contract.UpdateCounter++; // Increase update counter - if (nefFile != null) - { - ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy"); - if (md != null) - CallContractInternal(contract, md, new Array(ReferenceCounter) { true }, CallFlags.All, ReturnTypeConvention.EnsureIsEmpty); - } - } - - protected internal void DestroyContract() - { - UInt160 hash = CurrentScriptHash; - ContractState contract = Snapshot.Contracts.TryGet(hash); - if (contract == null) return; - Snapshot.Contracts.Delete(hash); - foreach (var (key, _) in Snapshot.Storages.Find(BitConverter.GetBytes(contract.Id))) - Snapshot.Storages.Delete(key); - } + public static readonly InteropDescriptor System_Contract_NativeOnPersist = Register("System.Contract.NativeOnPersist", nameof(NativeOnPersist), 0, CallFlags.WriteStates, false); + public static readonly InteropDescriptor System_Contract_NativePostPersist = Register("System.Contract.NativePostPersist", nameof(NativePostPersist), 0, CallFlags.WriteStates, false); protected internal void CallContract(UInt160 contractHash, string method, Array args) { @@ -126,12 +39,12 @@ private void CallContractInternal(UInt160 contractHash, string method, Array arg { if (method.StartsWith('_')) throw new ArgumentException($"Invalid Method Name: {method}"); - ContractState contract = Snapshot.Contracts.TryGet(contractHash); + ContractState contract = NativeContract.Management.GetContract(Snapshot, contractHash); if (contract is null) throw new InvalidOperationException($"Called Contract Does Not Exist: {contractHash}"); ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method); if (md is null) throw new InvalidOperationException($"Method {method} Does Not Exist In Contract {contractHash}"); - ContractState currentContract = Snapshot.Contracts.TryGet(CurrentScriptHash); + ContractState currentContract = NativeContract.Management.GetContract(Snapshot, CurrentScriptHash); if (currentContract?.CanCall(contract, method) == false) throw new InvalidOperationException($"Cannot Call Method {method} Of Contract {contractHash} From Contract {CurrentScriptHash}"); @@ -172,9 +85,17 @@ private void CallContractInternal(ContractState contract, ContractMethodDescript } } + protected internal void CallNativeContract(string name) + { + NativeContract contract = NativeContract.GetContract(name); + if (contract is null || contract.ActiveBlockIndex > Snapshot.PersistingBlock.Index) + throw new InvalidOperationException(); + contract.Invoke(this); + } + protected internal bool IsStandardContract(UInt160 hash) { - ContractState contract = Snapshot.Contracts.TryGet(hash); + ContractState contract = NativeContract.Management.GetContract(Snapshot, hash); // It's a stored contract @@ -208,5 +129,23 @@ protected internal UInt160 CreateStandardAccount(ECPoint pubKey) { return Contract.CreateSignatureRedeemScript(pubKey).ToScriptHash(); } + + protected internal void NativeOnPersist() + { + if (Trigger != TriggerType.OnPersist) + throw new InvalidOperationException(); + foreach (NativeContract contract in NativeContract.Contracts) + if (contract.ActiveBlockIndex <= Snapshot.PersistingBlock.Index) + contract.OnPersist(this); + } + + protected internal void NativePostPersist() + { + if (Trigger != TriggerType.PostPersist) + throw new InvalidOperationException(); + foreach (NativeContract contract in NativeContract.Contracts) + if (contract.ActiveBlockIndex <= Snapshot.PersistingBlock.Index) + contract.PostPersist(this); + } } } diff --git a/src/neo/SmartContract/ApplicationEngine.Native.cs b/src/neo/SmartContract/ApplicationEngine.Native.cs deleted file mode 100644 index 832aa86e9d..0000000000 --- a/src/neo/SmartContract/ApplicationEngine.Native.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Neo.Ledger; -using Neo.SmartContract.Native; -using System; - -namespace Neo.SmartContract -{ - partial class ApplicationEngine - { - public static readonly InteropDescriptor Neo_Native_Deploy = Register("Neo.Native.Deploy", nameof(DeployNativeContracts), 0, CallFlags.WriteStates, false); - public static readonly InteropDescriptor Neo_Native_Call = Register("Neo.Native.Call", nameof(CallNativeContract), 0, CallFlags.AllowCall, false); - - protected internal void DeployNativeContracts() - { - if (Snapshot.PersistingBlock.Index != 0) - throw new InvalidOperationException(); - foreach (NativeContract contract in NativeContract.Contracts) - { - Snapshot.Contracts.Add(contract.Hash, new ContractState - { - Id = contract.Id, - Script = contract.Script, - Hash = contract.Hash, // Use the native hash - Manifest = contract.Manifest - }); - contract.Initialize(this); - } - } - - protected internal void CallNativeContract(string name) - { - NativeContract.GetContract(name).Invoke(this); - } - } -} diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index 6a54571dcb..cfe344e379 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -93,7 +93,7 @@ protected internal bool CheckWitnessInternal(UInt160 hash) if (!CurrentContext.GetState().CallFlags.HasFlag(CallFlags.ReadStates)) throw new InvalidOperationException($"Cannot call this SYSCALL without the flag AllowStates."); - var contract = Snapshot.Contracts[CallingScriptHash]; + var contract = NativeContract.Management.GetContract(Snapshot, CallingScriptHash); // check if current group is the required one if (contract.Manifest.Groups.Select(p => p.PubKey).Intersect(signer.AllowedGroups).Any()) return true; diff --git a/src/neo/SmartContract/ApplicationEngine.Storage.cs b/src/neo/SmartContract/ApplicationEngine.Storage.cs index 368be261b9..5e7d70dcb8 100644 --- a/src/neo/SmartContract/ApplicationEngine.Storage.cs +++ b/src/neo/SmartContract/ApplicationEngine.Storage.cs @@ -1,5 +1,6 @@ using Neo.Ledger; using Neo.SmartContract.Iterators; +using Neo.SmartContract.Native; using System; using System.Linq; @@ -22,7 +23,7 @@ partial class ApplicationEngine protected internal StorageContext GetStorageContext() { - ContractState contract = Snapshot.Contracts.TryGet(CurrentScriptHash); + ContractState contract = NativeContract.Management.GetContract(Snapshot, CurrentScriptHash); return new StorageContext { Id = contract.Id, @@ -32,7 +33,7 @@ protected internal StorageContext GetStorageContext() protected internal StorageContext GetReadOnlyContext() { - ContractState contract = Snapshot.Contracts.TryGet(CurrentScriptHash); + ContractState contract = NativeContract.Management.GetContract(Snapshot, CurrentScriptHash); return new StorageContext { Id = contract.Id, diff --git a/src/neo/SmartContract/Callbacks/MethodCallback.cs b/src/neo/SmartContract/Callbacks/MethodCallback.cs index f2b0709d0a..3900f7c420 100644 --- a/src/neo/SmartContract/Callbacks/MethodCallback.cs +++ b/src/neo/SmartContract/Callbacks/MethodCallback.cs @@ -1,6 +1,6 @@ using Neo.IO; -using Neo.Ledger; using Neo.SmartContract.Manifest; +using Neo.SmartContract.Native; using System; using System.Linq; using Array = Neo.VM.Types.Array; @@ -18,8 +18,8 @@ public MethodCallback(ApplicationEngine engine, UInt160 hash, string method) : base(ApplicationEngine.System_Contract_Call, false) { if (method.StartsWith('_')) throw new ArgumentException(); - this.contract = engine.Snapshot.Contracts[hash]; - ContractState currentContract = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash); + this.contract = NativeContract.Management.GetContract(engine.Snapshot, hash); + ContractState currentContract = NativeContract.Management.GetContract(engine.Snapshot, engine.CurrentScriptHash); if (currentContract?.CanCall(this.contract, method) == false) throw new InvalidOperationException(); this.method = this.contract.Manifest.Abi.Methods.First(p => p.Name == method); diff --git a/src/neo/SmartContract/ContractState.cs b/src/neo/SmartContract/ContractState.cs new file mode 100644 index 0000000000..f5dc3510b9 --- /dev/null +++ b/src/neo/SmartContract/ContractState.cs @@ -0,0 +1,57 @@ +using Neo.IO; +using Neo.IO.Json; +using Neo.SmartContract.Manifest; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Linq; +using Array = Neo.VM.Types.Array; + +namespace Neo.SmartContract +{ + public class ContractState : IInteroperable + { + public int Id; + public ushort UpdateCounter; + public UInt160 Hash; + public byte[] Script; + public ContractManifest Manifest; + + void IInteroperable.FromStackItem(StackItem stackItem) + { + Array array = (Array)stackItem; + Id = (int)array[0].GetInteger(); + UpdateCounter = (ushort)array[1].GetInteger(); + Hash = new UInt160(array[2].GetSpan()); + Script = array[3].GetSpan().ToArray(); + Manifest = ContractManifest.Parse(array[4].GetSpan()); + } + + /// + /// Return true if is allowed + /// + /// The contract that we are calling + /// The method that we are calling + /// Return true or false + public bool CanCall(ContractState targetContract, string targetMethod) + { + return Manifest.Permissions.Any(u => u.IsAllowed(targetContract, targetMethod)); + } + + public JObject ToJson() + { + JObject json = new JObject(); + json["id"] = Id; + json["updatecounter"] = UpdateCounter; + json["hash"] = Hash.ToString(); + json["script"] = Convert.ToBase64String(Script); + json["manifest"] = Manifest.ToJson(); + return json; + } + + public StackItem ToStackItem(ReferenceCounter referenceCounter) + { + return new Array(referenceCounter, new StackItem[] { Id, (int)UpdateCounter, Hash.ToArray(), Script, Manifest.ToString() }); + } + } +} diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 6abbaa11ff..6358b8e0f4 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -1,6 +1,5 @@ using Neo.Cryptography; using Neo.Cryptography.ECC; -using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract.Native; @@ -173,7 +172,7 @@ internal static bool VerifyWitness(this IVerifiable verifiable, StoreView snapsh if (verification.Length == 0) { - ContractState cs = snapshot.Contracts.TryGet(hash); + ContractState cs = NativeContract.Management.GetContract(snapshot, hash); if (cs is null) return false; if (engine.LoadContract(cs, "verify", callFlags, true) is null) return false; diff --git a/src/neo/SmartContract/Native/Designate/DesignateContract.cs b/src/neo/SmartContract/Native/Designate/DesignateContract.cs index 45842ad6c1..af04563bf1 100644 --- a/src/neo/SmartContract/Native/Designate/DesignateContract.cs +++ b/src/neo/SmartContract/Native/Designate/DesignateContract.cs @@ -18,6 +18,7 @@ public sealed class DesignateContract : NativeContract { public override string Name => "Designation"; public override int Id => -5; + public override uint ActiveBlockIndex => 0; internal DesignateContract() { diff --git a/src/neo/SmartContract/Native/ManagementContract.cs b/src/neo/SmartContract/Native/ManagementContract.cs new file mode 100644 index 0000000000..a4c5071366 --- /dev/null +++ b/src/neo/SmartContract/Native/ManagementContract.cs @@ -0,0 +1,141 @@ +#pragma warning disable IDE0051 + +using Neo.IO; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract.Manifest; +using System; +using System.Numerics; + +namespace Neo.SmartContract.Native +{ + public sealed class ManagementContract : NativeContract + { + public override string Name => "Neo Contract Management"; + public override int Id => 0; + public override uint ActiveBlockIndex => 0; + + private const byte Prefix_NextAvailableId = 15; + private const byte Prefix_Contract = 8; + + private int GetNextAvailableId(StoreView snapshot) + { + StorageItem item = snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_NextAvailableId), () => new StorageItem(1)); + int value = (int)(BigInteger)item; + item.Add(1); + return value; + } + + internal override void OnPersist(ApplicationEngine engine) + { + foreach (NativeContract contract in Contracts) + { + if (contract.ActiveBlockIndex != engine.Snapshot.PersistingBlock.Index) + continue; + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_Contract).Add(contract.Hash), new StorageItem(new ContractState + { + Id = contract.Id, + Script = contract.Script, + Hash = contract.Hash, + Manifest = contract.Manifest + })); + contract.Initialize(engine); + } + } + + [ContractMethod(0_01000000, CallFlags.ReadStates)] + public ContractState GetContract(StoreView snapshot, UInt160 hash) + { + return snapshot.Storages.TryGet(CreateStorageKey(Prefix_Contract).Add(hash))?.GetInteroperable(); + } + + [ContractMethod(0, CallFlags.WriteStates)] + private ContractState Deploy(ApplicationEngine engine, byte[] nefFile, byte[] manifest) + { + if (!(engine.ScriptContainer is Transaction tx)) + throw new InvalidOperationException(); + if (nefFile.Length == 0) + throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}"); + if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) + throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}"); + + engine.AddGas(ApplicationEngine.StoragePrice * (nefFile.Length + manifest.Length)); + + NefFile nef = nefFile.AsSerializable(); + UInt160 hash = Helper.GetContractHash(tx.Sender, nef.Script); + StorageKey key = CreateStorageKey(Prefix_Contract).Add(hash); + if (engine.Snapshot.Storages.Contains(key)) + throw new InvalidOperationException($"Contract Already Exists: {hash}"); + ContractState contract = new ContractState + { + Id = GetNextAvailableId(engine.Snapshot), + UpdateCounter = 0, + Script = nef.Script, + Hash = hash, + Manifest = ContractManifest.Parse(manifest) + }; + + if (!contract.Manifest.IsValid(hash)) throw new InvalidOperationException($"Invalid Manifest Hash: {hash}"); + + engine.Snapshot.Storages.Add(key, new StorageItem(contract)); + + // Execute _deploy + + ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy"); + if (md != null) + engine.CallFromNativeContract(null, hash, md.Name, false); + + return contract; + } + + [ContractMethod(0, CallFlags.WriteStates)] + private void Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest) + { + if (nefFile is null && manifest is null) throw new ArgumentException(); + + engine.AddGas(ApplicationEngine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0))); + + var contract = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Contract).Add(engine.CallingScriptHash))?.GetInteroperable(); + if (contract is null) throw new InvalidOperationException($"Updating Contract Does Not Exist: {engine.CallingScriptHash}"); + + if (nefFile != null) + { + if (nefFile.Length == 0) + throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}"); + + NefFile nef = nefFile.AsSerializable(); + + // Update script + contract.Script = nef.Script; + } + if (manifest != null) + { + if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) + throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}"); + contract.Manifest = ContractManifest.Parse(manifest); + if (!contract.Manifest.IsValid(contract.Hash)) + throw new InvalidOperationException($"Invalid Manifest Hash: {contract.Hash}"); + } + contract.UpdateCounter++; // Increase update counter + if (nefFile != null) + { + ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy"); + if (md != null) + engine.CallFromNativeContract(null, contract.Hash, md.Name, true); + } + } + + [ContractMethod(0_01000000, CallFlags.WriteStates)] + private void Destroy(ApplicationEngine engine) + { + UInt160 hash = engine.CallingScriptHash; + StorageKey ckey = CreateStorageKey(Prefix_Contract).Add(hash); + ContractState contract = engine.Snapshot.Storages.TryGet(ckey)?.GetInteroperable(); + if (contract is null) return; + engine.Snapshot.Storages.Delete(ckey); + foreach (var (key, _) in engine.Snapshot.Storages.Find(BitConverter.GetBytes(contract.Id))) + engine.Snapshot.Storages.Delete(key); + } + } +} diff --git a/src/neo/SmartContract/Native/NativeContract.cs b/src/neo/SmartContract/Native/NativeContract.cs index 5bd1cbc114..d457bb8a59 100644 --- a/src/neo/SmartContract/Native/NativeContract.cs +++ b/src/neo/SmartContract/Native/NativeContract.cs @@ -22,6 +22,7 @@ public abstract class NativeContract private readonly Dictionary methods = new Dictionary(); public static IReadOnlyCollection Contracts { get; } = contractsList; + public static ManagementContract Management { get; } = new ManagementContract(); public static NeoToken NEO { get; } = new NeoToken(); public static GasToken GAS { get; } = new GasToken(); public static PolicyContract Policy { get; } = new PolicyContract(); @@ -33,16 +34,17 @@ public abstract class NativeContract public UInt160 Hash { get; } public abstract int Id { get; } public ContractManifest Manifest { get; } + public abstract uint ActiveBlockIndex { get; } protected NativeContract() { using (ScriptBuilder sb = new ScriptBuilder()) { sb.EmitPush(Name); - sb.EmitSysCall(ApplicationEngine.Neo_Native_Call); + sb.EmitSysCall(ApplicationEngine.System_Contract_CallNative); this.Script = sb.ToArray(); } - this.Hash = Helper.GetContractHash((new[] { (byte)OpCode.PUSH1 }).ToScriptHash(), Script); + this.Hash = Helper.GetContractHash(UInt160.Zero, Script); List descriptors = new List(); List safeMethods = new List(); foreach (MemberInfo member in GetType().GetMembers(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) @@ -136,18 +138,12 @@ internal virtual void Initialize(ApplicationEngine engine) { } - [ContractMethod(0, CallFlags.WriteStates)] - protected virtual void OnPersist(ApplicationEngine engine) + internal virtual void OnPersist(ApplicationEngine engine) { - if (engine.Trigger != TriggerType.OnPersist) - throw new InvalidOperationException(); } - [ContractMethod(0, CallFlags.WriteStates)] - protected virtual void PostPersist(ApplicationEngine engine) + internal virtual void PostPersist(ApplicationEngine engine) { - if (engine.Trigger != TriggerType.PostPersist) - throw new InvalidOperationException(); } public ApplicationEngine TestCall(string operation, params object[] args) diff --git a/src/neo/SmartContract/Native/Oracle/OracleContract.cs b/src/neo/SmartContract/Native/Oracle/OracleContract.cs index 4e24f91181..374218a86f 100644 --- a/src/neo/SmartContract/Native/Oracle/OracleContract.cs +++ b/src/neo/SmartContract/Native/Oracle/OracleContract.cs @@ -31,6 +31,7 @@ public sealed class OracleContract : NativeContract public override int Id => -4; public override string Name => "Oracle"; + public override uint ActiveBlockIndex => 0; internal OracleContract() { @@ -135,9 +136,8 @@ internal override void Initialize(ApplicationEngine engine) engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_RequestId), new StorageItem(BitConverter.GetBytes(0ul))); } - protected override void PostPersist(ApplicationEngine engine) + internal override void PostPersist(ApplicationEngine engine) { - base.PostPersist(engine); (UInt160 Account, BigInteger GAS)[] nodes = null; foreach (Transaction tx in engine.Snapshot.PersistingBlock.Transactions) { @@ -194,7 +194,7 @@ private void Request(ApplicationEngine engine, string url, string filter, string item_id.Value = BitConverter.GetBytes(id); //Put the request to storage - if (engine.Snapshot.Contracts.TryGet(engine.CallingScriptHash) is null) + if (Management.GetContract(engine.Snapshot, engine.CallingScriptHash) is null) throw new InvalidOperationException(); engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_Request).Add(item_id.Value), new StorageItem(new OracleRequest { diff --git a/src/neo/SmartContract/Native/PolicyContract.cs b/src/neo/SmartContract/Native/PolicyContract.cs index da44d04652..c5a64a94d1 100644 --- a/src/neo/SmartContract/Native/PolicyContract.cs +++ b/src/neo/SmartContract/Native/PolicyContract.cs @@ -13,6 +13,7 @@ public sealed class PolicyContract : NativeContract { public override string Name => "Policy"; public override int Id => -3; + public override uint ActiveBlockIndex => 0; 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 d00c54f0db..8ee59c9a12 100644 --- a/src/neo/SmartContract/Native/Tokens/GasToken.cs +++ b/src/neo/SmartContract/Native/Tokens/GasToken.cs @@ -8,6 +8,7 @@ public sealed class GasToken : Nep17Token { public override int Id => -2; public override string Name => "GAS"; + public override uint ActiveBlockIndex => 0; public override string Symbol => "gas"; public override byte Decimals => 8; @@ -21,9 +22,8 @@ internal override void Initialize(ApplicationEngine engine) Mint(engine, account, 30_000_000 * Factor, false); } - protected override void OnPersist(ApplicationEngine engine) + internal override void OnPersist(ApplicationEngine engine) { - base.OnPersist(engine); long totalNetworkFee = 0; foreach (Transaction tx in engine.Snapshot.PersistingBlock.Transactions) { diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 6d141a45aa..4c8b0fefa3 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -19,6 +19,7 @@ public sealed class NeoToken : Nep17Token { public override int Id => -1; public override string Name => "NEO"; + public override uint ActiveBlockIndex => 0; public override string Symbol => "neo"; public override byte Decimals => 0; public BigInteger TotalAmount { get; } @@ -130,10 +131,8 @@ internal override void Initialize(ApplicationEngine engine) Mint(engine, Blockchain.GetConsensusAddress(Blockchain.StandbyValidators), TotalAmount, false); } - protected override void OnPersist(ApplicationEngine engine) + internal override void OnPersist(ApplicationEngine engine) { - base.OnPersist(engine); - // Set next committee if (ShouldRefreshCommittee(engine.Snapshot.PersistingBlock.Index)) { @@ -144,10 +143,8 @@ protected override void OnPersist(ApplicationEngine engine) } } - protected override void PostPersist(ApplicationEngine engine) + internal override void PostPersist(ApplicationEngine engine) { - base.PostPersist(engine); - // Distribute GAS for committee int m = ProtocolSettings.Default.CommitteeMembersCount; diff --git a/src/neo/SmartContract/Native/Tokens/Nep17Token.cs b/src/neo/SmartContract/Native/Tokens/Nep17Token.cs index a96c493e29..1c7d9af880 100644 --- a/src/neo/SmartContract/Native/Tokens/Nep17Token.cs +++ b/src/neo/SmartContract/Native/Tokens/Nep17Token.cs @@ -160,7 +160,7 @@ private void PostTransfer(ApplicationEngine engine, UInt160 from, UInt160 to, Bi // Check if it's a wallet or smart contract - if (!callOnPayment || to is null || engine.Snapshot.Contracts.TryGet(to) is null) return; + if (!callOnPayment || to is null || Management.GetContract(engine.Snapshot, to) is null) return; // Call onPayment method (NEP-17) diff --git a/src/neo/SmartContract/NefFile.cs b/src/neo/SmartContract/NefFile.cs index 3420f0597d..76d3d94dc2 100644 --- a/src/neo/SmartContract/NefFile.cs +++ b/src/neo/SmartContract/NefFile.cs @@ -45,7 +45,7 @@ public class NefFile : ISerializable /// public uint CheckSum { get; set; } - public const int MaxScriptLength = 1024 * 1024; + public const int MaxScriptLength = 512 * 1024; private const int HeaderSize = sizeof(uint) + // Magic diff --git a/src/neo/Wallets/AssetDescriptor.cs b/src/neo/Wallets/AssetDescriptor.cs index 35c80ea82c..5df14f1a0a 100644 --- a/src/neo/Wallets/AssetDescriptor.cs +++ b/src/neo/Wallets/AssetDescriptor.cs @@ -1,6 +1,7 @@ using Neo.Ledger; using Neo.Persistence; using Neo.SmartContract; +using Neo.SmartContract.Native; using Neo.VM; using System; @@ -15,7 +16,7 @@ public class AssetDescriptor public AssetDescriptor(UInt160 asset_id) { using SnapshotView snapshot = Blockchain.Singleton.GetSnapshot(); - var contract = snapshot.Contracts.TryGet(asset_id); + var contract = NativeContract.Management.GetContract(snapshot, asset_id); if (contract is null) throw new ArgumentException(); byte[] script; diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 1800bf2382..56fd839483 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -388,7 +388,7 @@ public long CalculateNetworkFee(StoreView snapshot, Transaction tx) if (witness_script is null) { - var contract = snapshot.Contracts.TryGet(hash); + var contract = NativeContract.Management.GetContract(snapshot, hash); if (contract is null) continue; // Empty invocation and verification scripts @@ -470,7 +470,7 @@ public bool Sign(ContractParametersContext context) // Try Smart contract verification using var snapshot = Blockchain.Singleton.GetSnapshot(); - var contract = snapshot.Contracts.TryGet(scriptHash); + var contract = NativeContract.Management.GetContract(snapshot, scriptHash); if (contract != null) { diff --git a/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs b/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs index 678f3dc3e4..5cc56999a8 100644 --- a/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs +++ b/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs @@ -10,6 +10,85 @@ namespace Neo.UnitTests.Extensions { public static class NativeContractExtensions { + public static ContractState DeployContract(this StoreView snapshot, UInt160 sender, byte[] nefFile, byte[] manifest, long gas = ApplicationEngine.TestModeGas) + { + var script = new ScriptBuilder(); + script.EmitAppCall(NativeContract.Management.Hash, "deploy", nefFile, manifest); + + var engine = ApplicationEngine.Create(TriggerType.Application, + sender != null ? new Transaction() { Signers = new Signer[] { new Signer() { Account = sender } } } : null, snapshot, gas); + engine.LoadScript(script.ToArray()); + + if (engine.Execute() != VMState.HALT) + { + Exception exception = engine.FaultException; + while (exception?.InnerException != null) exception = exception.InnerException; + throw exception ?? new InvalidOperationException(); + } + + var ret = new ContractState(); + ((IInteroperable)ret).FromStackItem(engine.ResultStack.Pop()); + return ret; + } + + public static void UpdateContract(this StoreView snapshot, UInt160 callingScriptHash, byte[] nefFile, byte[] manifest) + { + var script = new ScriptBuilder(); + script.EmitAppCall(NativeContract.Management.Hash, "update", nefFile, manifest); + + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + engine.LoadScript(script.ToArray()); + + // Fake calling script hash + if (callingScriptHash != null) + { + engine.CurrentContext.GetState().CallingScriptHash = callingScriptHash; + engine.CurrentContext.GetState().ScriptHash = callingScriptHash; + } + + if (engine.Execute() != VMState.HALT) + { + Exception exception = engine.FaultException; + while (exception?.InnerException != null) exception = exception.InnerException; + throw exception ?? new InvalidOperationException(); + } + } + + public static void DestroyContract(this StoreView snapshot, UInt160 callingScriptHash) + { + var script = new ScriptBuilder(); + script.EmitAppCall(NativeContract.Management.Hash, "destroy"); + + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + engine.LoadScript(script.ToArray()); + + // Fake calling script hash + if (callingScriptHash != null) + { + engine.CurrentContext.GetState().CallingScriptHash = callingScriptHash; + engine.CurrentContext.GetState().ScriptHash = callingScriptHash; + } + + if (engine.Execute() != VMState.HALT) + { + Exception exception = engine.FaultException; + while (exception?.InnerException != null) exception = exception.InnerException; + throw exception ?? new InvalidOperationException(); + } + } + + public static void AddContract(this StoreView snapshot, UInt160 hash, ContractState state) + { + var key = new KeyBuilder(NativeContract.Management.Id, 8).Add(hash); + snapshot.Storages.Add(key, new Neo.Ledger.StorageItem(state, false)); + } + + public static void DeleteContract(this StoreView snapshot, UInt160 hash) + { + var key = new KeyBuilder(NativeContract.Management.Id, 8).Add(hash); + snapshot.Storages.Delete(key); + } + public static StackItem Call(this NativeContract contract, StoreView snapshot, string method, params ContractParameter[] args) { return Call(contract, snapshot, null, method, args); @@ -18,8 +97,10 @@ public static StackItem Call(this NativeContract contract, StoreView snapshot, s public static StackItem Call(this NativeContract contract, StoreView snapshot, IVerifiable container, string method, params ContractParameter[] args) { var engine = ApplicationEngine.Create(TriggerType.Application, container, snapshot); + var contractState = NativeContract.Management.GetContract(snapshot, contract.Hash); + if (contractState == null) throw new InvalidOperationException(); - engine.LoadContract(snapshot.Contracts[contract.Hash], method, CallFlags.All, true); + engine.LoadContract(contractState, method, CallFlags.All, true); var script = new ScriptBuilder(); diff --git a/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs b/tests/neo.UnitTests/Extensions/Nep17NativeContractExtensions.cs similarity index 96% rename from tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs rename to tests/neo.UnitTests/Extensions/Nep17NativeContractExtensions.cs index 8f38dbb7c8..6b87c22863 100644 --- a/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs +++ b/tests/neo.UnitTests/Extensions/Nep17NativeContractExtensions.cs @@ -9,7 +9,7 @@ namespace Neo.UnitTests.Extensions { - public static class Nep5NativeContractExtensions + public static class Nep17NativeContractExtensions { internal class ManualWitness : IVerifiable { @@ -104,9 +104,9 @@ public static BigInteger BalanceOf(this NativeContract contract, StoreView snaps return result.GetInteger(); } - public static BigInteger Decimals(this NativeContract contract) + public static BigInteger Decimals(this NativeContract contract, StoreView snapshot) { - var engine = ApplicationEngine.Create(TriggerType.Application, null, null); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(contract.Script, CallFlags.All, contract.Hash); @@ -124,9 +124,9 @@ public static BigInteger Decimals(this NativeContract contract) return result.GetInteger(); } - public static string Symbol(this NativeContract contract) + public static string Symbol(this NativeContract contract, StoreView snapshot) { - var engine = ApplicationEngine.Create(TriggerType.Application, null, null); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(contract.Script, CallFlags.All, contract.Hash); diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index e4bf204d47..b0017a432f 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -48,12 +48,19 @@ public static TestHeader Cast(Header input) public class UT_Blockchain : TestKit { private NeoSystem system; - Transaction txSample = Blockchain.GenesisBlock.Transactions[0]; + private Transaction txSample; [TestInitialize] public void Initialize() { system = TestBlockchain.TheNeoSystem; + txSample = new Transaction() + { + Attributes = Array.Empty(), + Script = Array.Empty(), + Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, + Witnesses = Array.Empty() + }; Blockchain.Singleton.MemPool.TryAdd(txSample, Blockchain.Singleton.GetSnapshot()); } @@ -67,19 +74,19 @@ public void TestContainsBlock() public void TestContainsTransaction() { Blockchain.Singleton.ContainsTransaction(UInt256.Zero).Should().BeFalse(); - Blockchain.Singleton.ContainsTransaction(txSample.Hash).Should().BeTrue(); + Blockchain.Singleton.ContainsTransaction(txSample.Hash).Should().BeFalse(); } [TestMethod] public void TestGetCurrentBlockHash() { - Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0xecaee33262f1bc7c7c28f2b25b54a5d61d50670871f45c0c6fe755a40cbde4a8")); + Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0x00c6803707b564153d444bfcdf3a13325fc96dda55cc8a740bbd543a1d752fda")); } [TestMethod] public void TestGetCurrentHeaderHash() { - Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0xecaee33262f1bc7c7c28f2b25b54a5d61d50670871f45c0c6fe755a40cbde4a8")); + Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0x00c6803707b564153d444bfcdf3a13325fc96dda55cc8a740bbd543a1d752fda")); } [TestMethod] @@ -91,7 +98,7 @@ public void TestGetBlock() [TestMethod] public void TestGetBlockHash() { - Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0xecaee33262f1bc7c7c28f2b25b54a5d61d50670871f45c0c6fe755a40cbde4a8")); + Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0x00c6803707b564153d444bfcdf3a13325fc96dda55cc8a740bbd543a1d752fda")); Blockchain.Singleton.GetBlockHash(10).Should().BeNull(); } @@ -99,7 +106,7 @@ public void TestGetBlockHash() public void TestGetTransaction() { Blockchain.Singleton.GetTransaction(UInt256.Zero).Should().BeNull(); - Blockchain.Singleton.GetTransaction(txSample.Hash).Should().NotBeNull(); + Blockchain.Singleton.GetTransaction(txSample.Hash).Should().BeNull(); } [TestMethod] diff --git a/tests/neo.UnitTests/Ledger/UT_ContractIdState.cs b/tests/neo.UnitTests/Ledger/UT_ContractIdState.cs deleted file mode 100644 index d6300eb13b..0000000000 --- a/tests/neo.UnitTests/Ledger/UT_ContractIdState.cs +++ /dev/null @@ -1,48 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.IO; -using Neo.Ledger; -using System; - -namespace Neo.UnitTests.Ledger -{ - [TestClass] - public class UT_ContractIdState - { - [TestMethod] - public void Size_Get() - { - var test = new ContractIdState() { NextId = 1 }; - ((ISerializable)test).Size.Should().Be(4); - - test = new ContractIdState() { NextId = int.MaxValue }; - ((ISerializable)test).Size.Should().Be(4); - } - - [TestMethod] - public void Clone() - { - var test = new ContractIdState() { NextId = 1 }; - var clone = ((ICloneable)test).Clone(); - - Assert.AreEqual(test.NextId, clone.NextId); - - clone = new ContractIdState() { NextId = 2 }; - ((ICloneable)clone).FromReplica(test); - - Assert.AreEqual(test.NextId, clone.NextId); - } - - [TestMethod] - public void DeserializeAndSerialize() - { - var test = new ContractIdState() { NextId = int.MaxValue }; - var clone = test.ToArray().AsSerializable(); - - Assert.AreEqual(test.NextId, clone.NextId); - - test = new ContractIdState() { NextId = -1 }; - Assert.ThrowsException(() => test.ToArray().AsSerializable()); - } - } -} diff --git a/tests/neo.UnitTests/Ledger/UT_TransactionState.cs b/tests/neo.UnitTests/Ledger/UT_TransactionState.cs index e30416a136..cfb3f84d2d 100644 --- a/tests/neo.UnitTests/Ledger/UT_TransactionState.cs +++ b/tests/neo.UnitTests/Ledger/UT_TransactionState.cs @@ -2,6 +2,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO; using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using System; using System.IO; namespace Neo.UnitTests.Ledger @@ -18,7 +20,16 @@ public void Initialize() { BlockIndex = 1, VMState = VM.VMState.NONE, - Transaction = Blockchain.GenesisBlock.Transactions[0] + Transaction = new Neo.Network.P2P.Payloads.Transaction() + { + Attributes = Array.Empty(), + Script = new byte[] { 0x01 }, + Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, + Witnesses = new Witness[] { new Witness() { + InvocationScript=Array.Empty(), + VerificationScript=Array.Empty() + } } + } }; } @@ -54,14 +65,14 @@ public void TestDeserialize() ((ISerializable)dest).Deserialize(reader); dest.BlockIndex.Should().Be(origin.BlockIndex); dest.VMState.Should().Be(origin.VMState); - dest.Transaction.Should().Be(origin.Transaction); + dest.Transaction.Hash.Should().Be(origin.Transaction.Hash); } } [TestMethod] public void TestGetSize() { - ((ISerializable)origin).Size.Should().Be(63); + ((ISerializable)origin).Size.Should().Be(58); } } } diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_MerkleBlockPayload.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_MerkleBlockPayload.cs index eb8cae51ed..146a272f04 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_MerkleBlockPayload.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_MerkleBlockPayload.cs @@ -20,10 +20,10 @@ public void TestSetup() public void Size_Get() { var test = MerkleBlockPayload.Create(Blockchain.GenesisBlock, new BitArray(1024, false)); - test.Size.Should().Be(302); + test.Size.Should().Be(270); test = MerkleBlockPayload.Create(Blockchain.GenesisBlock, new BitArray(0, false)); - test.Size.Should().Be(174); + test.Size.Should().Be(142); } [TestMethod] diff --git a/tests/neo.UnitTests/Persistence/UT_ReadOnlyView.cs b/tests/neo.UnitTests/Persistence/UT_ReadOnlyView.cs index 40a0fe8a70..4e7921cb00 100644 --- a/tests/neo.UnitTests/Persistence/UT_ReadOnlyView.cs +++ b/tests/neo.UnitTests/Persistence/UT_ReadOnlyView.cs @@ -24,10 +24,8 @@ public void Stores() Assert.AreEqual(UInt256.Zero, r.BlockHashIndex.Get().Hash); Assert.AreEqual(uint.MaxValue, r.HeaderHashIndex.Get().Index); Assert.AreEqual(UInt256.Zero, r.HeaderHashIndex.Get().Hash); - Assert.AreEqual(0, r.ContractId.Get().NextId); Assert.AreEqual(0, r.Blocks.Find().Count()); Assert.AreEqual(0, r.Transactions.Find().Count()); - Assert.AreEqual(0, r.Contracts.Find().Count()); Assert.AreEqual(0, r.Storages.Find().Count()); Assert.AreEqual(0, r.HeaderHashList.Find().Count()); } diff --git a/tests/neo.UnitTests/SmartContract/Callbacks/UT_MethodCallback.cs b/tests/neo.UnitTests/SmartContract/Callbacks/UT_MethodCallback.cs index 2a79250bbf..b2becae5ae 100644 --- a/tests/neo.UnitTests/SmartContract/Callbacks/UT_MethodCallback.cs +++ b/tests/neo.UnitTests/SmartContract/Callbacks/UT_MethodCallback.cs @@ -3,6 +3,7 @@ using Neo.SmartContract; using Neo.SmartContract.Callbacks; using Neo.SmartContract.Manifest; +using Neo.UnitTests.Extensions; using System; namespace Neo.UnitTests.SmartContract.Callbacks @@ -44,7 +45,7 @@ public void GetHashData() Hash = new byte[] { 1, 2, 3 }.ToScriptHash() }; engine.LoadScript(contract.Script); - snapshot.Contracts.Add(contract.Hash, contract); + engine.Snapshot.AddContract(contract.Hash, contract); Assert.ThrowsException(() => new MethodCallback(engine, contract.Hash, "test")); diff --git a/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs b/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs index fe2e03bc37..48d2e90cd3 100644 --- a/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs +++ b/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs @@ -1,6 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography.ECC; -using Neo.Ledger; +using Neo.SmartContract; using Neo.SmartContract.Manifest; using System; diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index 9720cf1f52..a7564ea8b0 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -3,6 +3,7 @@ using Neo.IO; using Neo.Ledger; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Extensions; @@ -16,25 +17,30 @@ namespace Neo.UnitTests.SmartContract.Native.Tokens [TestClass] public class UT_GasToken { + private StoreView _snapshot; + [TestInitialize] public void TestSetup() { TestBlockchain.InitializeMockNeoSystem(); + + _snapshot = Blockchain.Singleton.GetSnapshot(); + _snapshot.PersistingBlock = new Block() { Index = 0 }; } [TestMethod] public void Check_Name() => NativeContract.GAS.Name.Should().Be("GAS"); [TestMethod] - public void Check_Symbol() => NativeContract.GAS.Symbol().Should().Be("gas"); + public void Check_Symbol() => NativeContract.GAS.Symbol(_snapshot).Should().Be("gas"); [TestMethod] - public void Check_Decimals() => NativeContract.GAS.Decimals().Should().Be(8); + public void Check_Decimals() => NativeContract.GAS.Decimals(_snapshot).Should().Be(8); [TestMethod] public void Check_BalanceOfTransferAndBurn() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); snapshot.PersistingBlock = new Block() { Index = 1000 }; byte[] from = Blockchain.GetConsensusAddress(Blockchain.StandbyValidators).ToArray(); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 7bcfd50cad..c281034c21 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -22,25 +22,29 @@ namespace Neo.UnitTests.SmartContract.Native.Tokens [TestClass] public class UT_NeoToken { + private StoreView _snapshot; + [TestInitialize] public void TestSetup() { TestBlockchain.InitializeMockNeoSystem(); + _snapshot = Blockchain.Singleton.GetSnapshot(); + _snapshot.PersistingBlock = new Block() { Index = 0, Transactions = Array.Empty(), ConsensusData = new ConsensusData() }; } [TestMethod] public void Check_Name() => NativeContract.NEO.Name.Should().Be("NEO"); [TestMethod] - public void Check_Symbol() => NativeContract.NEO.Symbol().Should().Be("neo"); + public void Check_Symbol() => NativeContract.NEO.Symbol(_snapshot).Should().Be("neo"); [TestMethod] - public void Check_Decimals() => NativeContract.NEO.Decimals().Should().Be(0); + public void Check_Decimals() => NativeContract.NEO.Decimals(_snapshot).Should().Be(0); [TestMethod] public void Check_Vote() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); snapshot.PersistingBlock = new Block() { Index = 1000 }; byte[] from = Blockchain.GetConsensusAddress(Blockchain.StandbyValidators).ToArray(); @@ -94,7 +98,7 @@ public void Check_Vote() [TestMethod] public void Check_Vote_Sameaccounts() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); snapshot.PersistingBlock = new Block() { Index = 1000 }; byte[] from = Blockchain.GetConsensusAddress(Blockchain.StandbyValidators).ToArray(); @@ -121,7 +125,7 @@ public void Check_Vote_Sameaccounts() [TestMethod] public void Check_Vote_ChangeVote() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); snapshot.PersistingBlock = new Block() { Index = 1000 }; //from vote to G byte[] from = Blockchain.StandbyValidators[0].ToArray(); @@ -152,7 +156,7 @@ public void Check_Vote_ChangeVote() [TestMethod] public void Check_Vote_VoteToNull() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); snapshot.PersistingBlock = new Block() { Index = 1000 }; byte[] from = Blockchain.StandbyValidators[0].ToArray(); @@ -182,7 +186,7 @@ public void Check_Vote_VoteToNull() [TestMethod] public void Check_UnclaimedGas() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); snapshot.PersistingBlock = new Block() { Index = 1000 }; byte[] from = Blockchain.GetConsensusAddress(Blockchain.StandbyValidators).ToArray(); @@ -199,7 +203,7 @@ public void Check_UnclaimedGas() [TestMethod] public void Check_RegisterValidator() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); var keyCount = snapshot.Storages.GetChangeSet().Count(); var point = Blockchain.StandbyValidators[0].EncodePoint(true).Clone() as byte[]; @@ -227,7 +231,7 @@ public void Check_RegisterValidator() [TestMethod] public void Check_UnregisterCandidate() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); var keyCount = snapshot.Storages.GetChangeSet().Count(); var point = Blockchain.StandbyValidators[0].EncodePoint(true); @@ -285,7 +289,7 @@ public void Check_UnregisterCandidate() [TestMethod] public void Check_GetCommittee() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); var keyCount = snapshot.Storages.GetChangeSet().Count(); var point = Blockchain.StandbyValidators[0].EncodePoint(true); @@ -309,24 +313,19 @@ public void Check_GetCommittee() committeemembers[i].Should().Be(defaultCommittee[i]); } - //register more candidates,committee member change - snapshot.PersistingBlock = new Block { Index = 0 }; + //register more candidates, committee member change + snapshot.PersistingBlock = new Block + { + Index = (uint)ProtocolSettings.Default.CommitteeMembersCount, + Transactions = Array.Empty(), + ConsensusData = new ConsensusData() + }; for (int i = 0; i < ProtocolSettings.Default.CommitteeMembersCount - 1; i++) { Check_RegisterValidator(snapshot, Blockchain.StandbyCommittee[i].ToArray()); - var currentCandidates = NativeContract.NEO.GetCandidates(snapshot); } - Script onPersistScript; - using (ScriptBuilder sb = new ScriptBuilder()) - { - sb.EmitAppCall(NativeContract.NEO.Hash, "onPersist"); - sb.Emit(OpCode.DROP); - onPersistScript = sb.ToArray(); - } - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.OnPersist, null, snapshot); - engine.LoadScript(onPersistScript); - Assert.AreEqual(engine.Execute(), VMState.HALT); + Check_OnPersist(snapshot); committeemembers = NativeContract.NEO.GetCommittee(snapshot); committeemembers.Length.Should().Be(ProtocolSettings.Default.CommitteeMembersCount); @@ -341,7 +340,7 @@ public void Check_GetCommittee() [TestMethod] public void Check_Transfer() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); snapshot.PersistingBlock = new Block() { Index = 1000 }; byte[] from = Blockchain.GetConsensusAddress(Blockchain.StandbyValidators).ToArray(); @@ -392,7 +391,7 @@ public void Check_Transfer() [TestMethod] public void Check_BalanceOf() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); byte[] account = Blockchain.GetConsensusAddress(Blockchain.StandbyValidators).ToArray(); NativeContract.NEO.BalanceOf(snapshot, account).Should().Be(100_000_000); @@ -405,29 +404,21 @@ public void Check_BalanceOf() [TestMethod] public void Check_CommitteeBonus() { - var snapshot = Blockchain.Singleton.GetSnapshot(); - snapshot.PersistingBlock = new Block { Index = 1 }; + var snapshot = _snapshot.Clone(); + snapshot.PersistingBlock = new Block { Index = 1, Transactions = Array.Empty() }; - using (ScriptBuilder sb = new ScriptBuilder()) - { - sb.EmitAppCall(NativeContract.NEO.Hash, "postPersist"); - sb.Emit(OpCode.RET); - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.PostPersist, null, snapshot, (long)(20 * NativeContract.GAS.Factor)); - engine.LoadScript(sb.ToArray()); - engine.Execute(); - engine.State.Should().Be(VM.VMState.HALT); - - var committee = Blockchain.StandbyCommittee; - NativeContract.GAS.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[0]).ScriptHash.ToArray()).Should().Be(50000000); - NativeContract.GAS.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[1]).ScriptHash.ToArray()).Should().Be(50000000); - NativeContract.GAS.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[2]).ScriptHash.ToArray()).Should().Be(0); - } + Check_PostPersist(snapshot); + + var committee = Blockchain.StandbyCommittee; + NativeContract.GAS.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[0]).ScriptHash.ToArray()).Should().Be(50000000); + NativeContract.GAS.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[1]).ScriptHash.ToArray()).Should().Be(50000000); + NativeContract.GAS.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[2]).ScriptHash.ToArray()).Should().Be(0); } [TestMethod] public void Check_Initialize() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); // StandbyValidators @@ -449,7 +440,7 @@ public void Check_BadScript() [TestMethod] public void TestCalculateBonus() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); snapshot.PersistingBlock = new Block { Index = 0 }; StorageKey key = CreateStorageKey(20, UInt160.Zero.ToArray()); @@ -536,7 +527,7 @@ public void TestGetNextBlockValidators1() [TestMethod] public void TestGetNextBlockValidators2() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); var result = NativeContract.NEO.GetNextBlockValidators(snapshot); result.Length.Should().Be(7); result[0].ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); @@ -559,7 +550,7 @@ public void TestGetCandidates1() [TestMethod] public void TestGetCandidates2() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); var result = NativeContract.NEO.GetCandidates(snapshot); result.Length.Should().Be(0); @@ -571,7 +562,7 @@ public void TestGetCandidates2() [TestMethod] public void TestCheckCandidate() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); var committee = NativeContract.NEO.GetCommittee(snapshot); var point = committee[0].EncodePoint(true); @@ -587,7 +578,7 @@ public void TestCheckCandidate() snapshot.Storages.Find(storageKey.ToArray()).ToArray().Length.Should().Be(1); // Pre-persist - snapshot.PersistingBlock = new Block { Index = 21 }; + snapshot.PersistingBlock = new Block { Index = 21, Transactions = Array.Empty() }; Check_OnPersist(snapshot); // Clear votes @@ -644,7 +635,7 @@ public void TestGetCommittee() [TestMethod] public void TestGetValidators() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); var result = NativeContract.NEO.ComputeNextBlockValidators(snapshot); result[0].ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); result[1].ToArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); @@ -674,14 +665,14 @@ public void TestOnBalanceChanging() [TestMethod] public void TestTotalSupply() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); NativeContract.NEO.TotalSupply(snapshot).Should().Be(new BigInteger(100000000)); } [TestMethod] public void TestEconomicParameter() { - var snapshot = Blockchain.Singleton.GetSnapshot().Clone(); + var snapshot = _snapshot.Clone(); snapshot.PersistingBlock = new Block { Index = 0 }; (BigInteger, bool) result = Check_GetGasPerBlock(snapshot); @@ -709,7 +700,7 @@ public void TestEconomicParameter() [TestMethod] public void TestClaimGas() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); // Initialize block snapshot.Storages.Add(CreateStorageKey(1), new StorageItem(new BigInteger(30000000))); @@ -731,7 +722,7 @@ public void TestClaimGas() var item = snapshot.Storages.GetAndChange(new KeyBuilder(-1, 1), () => new StorageItem()); item.Value = ((BigInteger)2100 * 10000L).ToByteArray(); - snapshot.PersistingBlock = new Block { Index = 0 }; + snapshot.PersistingBlock = new Block { Index = 0, Transactions = Array.Empty() }; Check_PostPersist(snapshot).Should().BeTrue(); var committee = Blockchain.StandbyCommittee.OrderBy(p => p).ToArray(); @@ -746,7 +737,7 @@ public void TestClaimGas() // Next block - snapshot.PersistingBlock = new Block { Index = 1 }; + snapshot.PersistingBlock = new Block { Index = 1, Transactions = Array.Empty() }; Check_PostPersist(snapshot).Should().BeTrue(); NativeContract.NEO.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[1]).ScriptHash).Should().Be(0); @@ -756,7 +747,7 @@ public void TestClaimGas() // Next block - snapshot.PersistingBlock = new Block { Index = 21 }; + snapshot.PersistingBlock = new Block { Index = 21, Transactions = Array.Empty() }; Check_PostPersist(snapshot).Should().BeTrue(); accountA = Blockchain.StandbyCommittee.OrderBy(p => p).ToArray()[2]; @@ -765,7 +756,6 @@ public void TestClaimGas() storageItem = snapshot.Storages.TryGet(new KeyBuilder(-1, 23).Add(committee[2]).AddBigEndian(22)); new BigInteger(storageItem.Value).Should().Be(30000000000 * 2); - // Claim GAS var account = Contract.CreateSignatureContract(committee[2]).ScriptHash; @@ -783,7 +773,7 @@ public void TestClaimGas() [TestMethod] public void TestUnclaimedGas() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); snapshot.Storages.Add(CreateStorageKey(20, UInt160.Zero.ToArray()), new StorageItem(new NeoAccountState())); NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); @@ -792,7 +782,7 @@ public void TestUnclaimedGas() [TestMethod] public void TestVote() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); UInt160 account = UInt160.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4"); StorageKey keyAccount = CreateStorageKey(20, account.ToArray()); StorageKey keyValidator = CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()); @@ -822,7 +812,7 @@ public void TestVote() internal (bool State, bool Result) Transfer4TesingOnBalanceChanging(BigInteger amount, bool addVotes) { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); snapshot.PersistingBlock = Blockchain.GenesisBlock; var engine = ApplicationEngine.Create(TriggerType.Application, Blockchain.GenesisBlock, snapshot); ScriptBuilder sb = new ScriptBuilder(); @@ -855,17 +845,9 @@ public void TestVote() internal static bool Check_OnPersist(StoreView snapshot) { - ECPoint[] committees = NativeContract.NEO.GetCommittee(snapshot); - UInt160 committeesMultisign = Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash(); - var engine = ApplicationEngine.Create(TriggerType.OnPersist, - new Nep5NativeContractExtensions.ManualWitness(committeesMultisign), snapshot); - - engine.LoadScript(NativeContract.NEO.Script, CallFlags.All, NativeContract.NEO.Hash); - var script = new ScriptBuilder(); - script.EmitPush(0); - script.Emit(OpCode.PACK); - script.EmitPush("onPersist"); + script.EmitSysCall(ApplicationEngine.System_Contract_NativeOnPersist); + var engine = ApplicationEngine.Create(TriggerType.OnPersist, null, snapshot); engine.LoadScript(script.ToArray()); return engine.Execute() == VMState.HALT; @@ -873,17 +855,9 @@ internal static bool Check_OnPersist(StoreView snapshot) internal static bool Check_PostPersist(StoreView snapshot) { - ECPoint[] committees = NativeContract.NEO.GetCommittee(snapshot); - UInt160 committeesMultisign = Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash(); - var engine = ApplicationEngine.Create(TriggerType.PostPersist, - new Nep5NativeContractExtensions.ManualWitness(committeesMultisign), snapshot); - - engine.LoadScript(NativeContract.NEO.Script, CallFlags.All, NativeContract.NEO.Hash); - var script = new ScriptBuilder(); - script.EmitPush(0); - script.Emit(OpCode.PACK); - script.EmitPush("postPersist"); + script.EmitSysCall(ApplicationEngine.System_Contract_NativePostPersist); + var engine = ApplicationEngine.Create(TriggerType.PostPersist, null, snapshot); engine.LoadScript(script.ToArray()); return engine.Execute() == VMState.HALT; @@ -915,7 +889,7 @@ internal static (BigInteger Value, bool State) Check_GetGasPerBlock(StoreView sn internal static (VM.Types.Boolean Value, bool State) Check_SetGasPerBlock(StoreView snapshot, BigInteger gasPerBlock) { UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); - var engine = ApplicationEngine.Create(TriggerType.Application, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), snapshot); + var engine = ApplicationEngine.Create(TriggerType.Application, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), snapshot); engine.LoadScript(NativeContract.NEO.Script, CallFlags.All, NativeContract.NEO.Hash); @@ -940,7 +914,7 @@ internal static (VM.Types.Boolean Value, bool State) Check_SetGasPerBlock(StoreV internal static (bool State, bool Result) Check_Vote(StoreView snapshot, byte[] account, byte[] pubkey, bool signAccount) { var engine = ApplicationEngine.Create(TriggerType.Application, - new Nep5NativeContractExtensions.ManualWitness(signAccount ? new UInt160(account) : UInt160.Zero), snapshot); + new Nep17NativeContractExtensions.ManualWitness(signAccount ? new UInt160(account) : UInt160.Zero), snapshot); engine.LoadScript(NativeContract.NEO.Script, CallFlags.All, NativeContract.NEO.Hash); @@ -970,7 +944,7 @@ internal static (bool State, bool Result) Check_Vote(StoreView snapshot, byte[] internal static (bool State, bool Result) Check_RegisterValidator(StoreView snapshot, byte[] pubkey) { var engine = ApplicationEngine.Create(TriggerType.Application, - new Nep5NativeContractExtensions.ManualWitness(Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubkey, ECCurve.Secp256r1)).ToScriptHash()), snapshot); + new Nep17NativeContractExtensions.ManualWitness(Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubkey, ECCurve.Secp256r1)).ToScriptHash()), snapshot); engine.LoadScript(NativeContract.NEO.Script, CallFlags.All, NativeContract.NEO.Hash); @@ -1076,7 +1050,7 @@ internal static StorageKey CreateStorageKey(byte prefix, byte[] key = null) internal static (bool State, bool Result) Check_UnregisterCandidate(StoreView snapshot, byte[] pubkey) { var engine = ApplicationEngine.Create(TriggerType.Application, - new Nep5NativeContractExtensions.ManualWitness(Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubkey, ECCurve.Secp256r1)).ToScriptHash()), snapshot); + new Nep17NativeContractExtensions.ManualWitness(Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubkey, ECCurve.Secp256r1)).ToScriptHash()), snapshot); engine.LoadScript(NativeContract.NEO.Script, CallFlags.All, NativeContract.NEO.Hash); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep17Token.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep17Token.cs index 0728f5d50a..6434731ae8 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep17Token.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_Nep17Token.cs @@ -80,11 +80,9 @@ public StorageKey CreateStorageKey(byte prefix, byte[] key = null) public class TestNep17Token : Nep17Token { public override int Id => 0x10000005; - public override string Name => "testNep17Token"; - public override string Symbol => throw new NotImplementedException(); - public override byte Decimals => 8; + public override uint ActiveBlockIndex => 0; } } diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_DesignateContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_DesignateContract.cs index abda200797..bde4ee6cb3 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_DesignateContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_DesignateContract.cs @@ -4,6 +4,7 @@ using Neo.IO; using Neo.Ledger; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.SmartContract.Native.Designate; @@ -16,16 +17,20 @@ namespace Neo.UnitTests.SmartContract.Native [TestClass] public class UT_DesignateContract { + private StoreView _snapshot; + [TestInitialize] public void TestSetup() { TestBlockchain.InitializeMockNeoSystem(); + _snapshot = Blockchain.Singleton.GetSnapshot(); + _snapshot.PersistingBlock = new Block() { Index = 0 }; } [TestMethod] public void TestSetAndGet() { - using var snapshot1 = Blockchain.Singleton.GetSnapshot(); + var snapshot1 = _snapshot.Clone(); snapshot1.PersistingBlock = new Block { Index = 0, @@ -34,13 +39,13 @@ public void TestSetAndGet() ECPoint[] validators = NativeContract.NEO.ComputeNextBlockValidators(snapshot1); var ret = NativeContract.Designate.Call( snapshot1, - new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), + new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "designateAsRole", new ContractParameter(ContractParameterType.Integer) { Value = new BigInteger((int)Role.StateValidator) }, new ContractParameter(ContractParameterType.Array) { Value = validators.Select(p => new ContractParameter(ContractParameterType.ByteArray) { Value = p.ToArray() }).ToList() } ); snapshot1.Commit(); - using var snapshot2 = Blockchain.Singleton.GetSnapshot(); + var snapshot2 = _snapshot.Clone(); ret = NativeContract.Designate.Call( snapshot2, "getDesignatedByRole", diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 263d9a85df..28f568a895 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -34,6 +34,7 @@ private class DummyNative : NativeContract { public override string Name => "Dummy"; public override int Id => 1; + public override uint ActiveBlockIndex => 0; [ContractMethod(0, CallFlags.None)] public void NetTypes( @@ -108,7 +109,7 @@ public void TestInvoke() engine.CurrentContext.EvaluationStack.Push(method1); Assert.ThrowsException(() => testNativeContract.Invoke(engine)); - ByteString method2 = new ByteString(System.Text.Encoding.Default.GetBytes("onPersist")); + ByteString method2 = new ByteString(System.Text.Encoding.Default.GetBytes("helloWorld")); VMArray args2 = new VMArray(); engine.CurrentContext.EvaluationStack.Push(args2); engine.CurrentContext.EvaluationStack.Push(method2); @@ -116,15 +117,15 @@ public void TestInvoke() } [TestMethod] - public void TestOnPersistWithArgs() + public void TestTrigger() { var snapshot = Blockchain.Singleton.GetSnapshot(); ApplicationEngine engine1 = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0); - Assert.ThrowsException(() => testNativeContract.TestOnPersist(engine1)); + Assert.ThrowsException(() => testNativeContract.TestTrigger(engine1)); ApplicationEngine engine2 = ApplicationEngine.Create(TriggerType.OnPersist, null, snapshot, 0); - testNativeContract.TestOnPersist(engine2); + testNativeContract.TestTrigger(engine2); } [TestMethod] @@ -138,12 +139,15 @@ public void TestTestCall() public class TestNativeContract : NativeContract { public override string Name => "test"; - public override int Id => 0x10000006; + public override uint ActiveBlockIndex => 0; + + [ContractMethod(0, CallFlags.None)] + public string HelloWorld => "hello world"; - public void TestOnPersist(ApplicationEngine engine) + public void TestTrigger(ApplicationEngine engine) { - OnPersist(engine); + if (engine.Trigger != TriggerType.OnPersist) throw new InvalidOperationException(); } } } diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 16e2ae9efd..c59121a7c3 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -3,6 +3,7 @@ using Neo.IO; using Neo.Ledger; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Extensions; @@ -14,16 +15,23 @@ namespace Neo.UnitTests.SmartContract.Native [TestClass] public class UT_PolicyContract { + private StoreView _snapshot; + [TestInitialize] public void TestSetup() { TestBlockchain.InitializeMockNeoSystem(); + _snapshot = Blockchain.Singleton.GetSnapshot(); + _snapshot.PersistingBlock = new Block() { Index = 0 }; + + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.OnPersist, _snapshot.PersistingBlock, _snapshot, 0); + NativeContract.Management.OnPersist(engine); } [TestMethod] public void Check_Default() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); var ret = NativeContract.Policy.Call(snapshot, "getMaxTransactionsPerBlock"); ret.Should().BeOfType(); @@ -45,7 +53,7 @@ public void Check_Default() [TestMethod] public void Check_SetMaxBlockSize() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); // Fake blockchain @@ -54,11 +62,9 @@ public void Check_SetMaxBlockSize() UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); - NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0)); - // Without signature - var ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(null), + var ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(null), "setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = 1024 }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeFalse(); @@ -71,7 +77,7 @@ public void Check_SetMaxBlockSize() Assert.ThrowsException(() => { - NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), + NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = Neo.Network.P2P.Message.PayloadMaxSize + 1 }); }); @@ -81,7 +87,7 @@ public void Check_SetMaxBlockSize() // With signature - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), + ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = 1024 }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeTrue(); @@ -94,7 +100,7 @@ public void Check_SetMaxBlockSize() [TestMethod] public void Check_SetMaxBlockSystemFee() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); // Fake blockchain @@ -103,11 +109,9 @@ public void Check_SetMaxBlockSystemFee() UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); - NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0)); - // Without signature - var ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(null), + var ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(null), "setMaxBlockSystemFee", new ContractParameter(ContractParameterType.Integer) { Value = 1024 * (long)NativeContract.GAS.Factor }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeFalse(); @@ -120,7 +124,7 @@ public void Check_SetMaxBlockSystemFee() Assert.ThrowsException(() => { - NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), + NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setMaxBlockSystemFee", new ContractParameter(ContractParameterType.Integer) { Value = -1000 }); }); @@ -130,7 +134,7 @@ public void Check_SetMaxBlockSystemFee() // With signature - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), + ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setMaxBlockSystemFee", new ContractParameter(ContractParameterType.Integer) { Value = 1024 * (long)NativeContract.GAS.Factor }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeTrue(); @@ -143,18 +147,16 @@ public void Check_SetMaxBlockSystemFee() [TestMethod] public void Check_SetMaxTransactionsPerBlock() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); // Fake blockchain snapshot.PersistingBlock = new Block() { Index = 1000, PrevHash = UInt256.Zero }; - snapshot.Blocks.Add(UInt256.Zero, new Neo.Ledger.TrimmedBlock() { NextConsensus = UInt160.Zero }); - - NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0)); + snapshot.Blocks.Add(UInt256.Zero, new TrimmedBlock() { NextConsensus = UInt160.Zero }); // Without signature - var ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(), + var ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(), "setMaxTransactionsPerBlock", new ContractParameter(ContractParameterType.Integer) { Value = 1 }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeFalse(); @@ -165,7 +167,7 @@ public void Check_SetMaxTransactionsPerBlock() // With signature - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(NativeContract.NEO.GetCommitteeAddress(snapshot)), + ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(NativeContract.NEO.GetCommitteeAddress(snapshot)), "setMaxTransactionsPerBlock", new ContractParameter(ContractParameterType.Integer) { Value = 1 }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeTrue(); @@ -178,18 +180,16 @@ public void Check_SetMaxTransactionsPerBlock() [TestMethod] public void Check_SetFeePerByte() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); // Fake blockchain snapshot.PersistingBlock = new Block() { Index = 1000, PrevHash = UInt256.Zero }; - snapshot.Blocks.Add(UInt256.Zero, new Neo.Ledger.TrimmedBlock() { NextConsensus = UInt160.Zero }); - - NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0)); + snapshot.Blocks.Add(UInt256.Zero, new TrimmedBlock() { NextConsensus = UInt160.Zero }); // Without signature - var ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(), + var ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(), "setFeePerByte", new ContractParameter(ContractParameterType.Integer) { Value = 1 }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeFalse(); @@ -200,7 +200,7 @@ public void Check_SetFeePerByte() // With signature UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), + ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setFeePerByte", new ContractParameter(ContractParameterType.Integer) { Value = 1 }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeTrue(); @@ -213,18 +213,16 @@ public void Check_SetFeePerByte() [TestMethod] public void Check_BlockAccount() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); // Fake blockchain snapshot.PersistingBlock = new Block() { Index = 1000, PrevHash = UInt256.Zero }; - snapshot.Blocks.Add(UInt256.Zero, new Neo.Ledger.TrimmedBlock() { NextConsensus = UInt160.Zero }); - - NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0)); + snapshot.Blocks.Add(UInt256.Zero, new TrimmedBlock() { NextConsensus = UInt160.Zero }); // Without signature - var ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(UInt160.Zero), + var ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(UInt160.Zero), "blockAccount", new ContractParameter(ContractParameterType.ByteArray) { Value = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01").ToArray() }); ret.Should().BeOfType(); @@ -233,14 +231,14 @@ public void Check_BlockAccount() // With signature UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), + ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "blockAccount", new ContractParameter(ContractParameterType.ByteArray) { Value = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01").ToArray() }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeTrue(); // Same account - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), + ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "blockAccount", new ContractParameter(ContractParameterType.ByteArray) { Value = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01").ToArray() }); ret.Should().BeOfType(); @@ -248,7 +246,7 @@ public void Check_BlockAccount() // Account B - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), + ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "blockAccount", new ContractParameter(ContractParameterType.ByteArray) { Value = UInt160.Parse("0xb400ff00ff00ff00ff00ff00ff00ff00ff00ff01").ToArray() }); ret.Should().BeOfType(); @@ -264,20 +262,18 @@ public void Check_BlockAccount() [TestMethod] public void Check_Block_UnblockAccount() { - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = _snapshot.Clone(); // Fake blockchain snapshot.PersistingBlock = new Block() { Index = 1000, PrevHash = UInt256.Zero }; - snapshot.Blocks.Add(UInt256.Zero, new Neo.Ledger.TrimmedBlock() { NextConsensus = UInt160.Zero }); + snapshot.Blocks.Add(UInt256.Zero, new TrimmedBlock() { NextConsensus = UInt160.Zero }); UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); - NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0)); - // Block without signature - var ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(), + var ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(), "blockAccount", new ContractParameter(ContractParameterType.Hash160) { Value = UInt160.Zero }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeFalse(); @@ -286,7 +282,7 @@ public void Check_Block_UnblockAccount() // Block with signature - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), + ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "blockAccount", new ContractParameter(ContractParameterType.Hash160) { Value = UInt160.Zero }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeTrue(); @@ -295,7 +291,7 @@ public void Check_Block_UnblockAccount() // Unblock without signature - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(), + ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(), "unblockAccount", new ContractParameter(ContractParameterType.Hash160) { Value = UInt160.Zero }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeFalse(); @@ -304,7 +300,7 @@ public void Check_Block_UnblockAccount() // Unblock with signature - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), + ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "unblockAccount", new ContractParameter(ContractParameterType.Hash160) { Value = UInt160.Zero }); ret.Should().BeOfType(); ret.GetBoolean().Should().BeTrue(); diff --git a/tests/neo.UnitTests/Ledger/UT_ContractState.cs b/tests/neo.UnitTests/SmartContract/UT_ContractState.cs similarity index 60% rename from tests/neo.UnitTests/Ledger/UT_ContractState.cs rename to tests/neo.UnitTests/SmartContract/UT_ContractState.cs index 47c8ee52cb..e6fddcdeae 100644 --- a/tests/neo.UnitTests/Ledger/UT_ContractState.cs +++ b/tests/neo.UnitTests/SmartContract/UT_ContractState.cs @@ -1,13 +1,10 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.IO; using Neo.IO.Json; -using Neo.Ledger; using Neo.SmartContract; using Neo.SmartContract.Manifest; -using System.IO; -namespace Neo.UnitTests.Ledger +namespace Neo.UnitTests.SmartContract { [TestClass] public class UT_ContractState @@ -38,44 +35,14 @@ public void TestGetScriptHash() } [TestMethod] - public void TestClone() + public void TestIInteroperable() { - ICloneable cloneable = contract; - ContractState clone = cloneable.Clone(); - clone.ToJson().ToString().Should().Be(contract.ToJson().ToString()); - } - - [TestMethod] - public void TestFromReplica() - { - ICloneable cloneable = new ContractState(); - cloneable.FromReplica(contract); - ((ContractState)cloneable).ToJson().ToString().Should().Be(contract.ToJson().ToString()); - } - - [TestMethod] - public void TestDeserialize() - { - ISerializable newContract = new ContractState(); - using (MemoryStream ms = new MemoryStream(1024)) - using (BinaryWriter writer = new BinaryWriter(ms)) - using (BinaryReader reader = new BinaryReader(ms)) - { - ((ISerializable)contract).Serialize(writer); - ms.Seek(0, SeekOrigin.Begin); - newContract.Deserialize(reader); - } + IInteroperable newContract = new ContractState(); + newContract.FromStackItem(contract.ToStackItem(null)); ((ContractState)newContract).Manifest.ToJson().ToString().Should().Be(contract.Manifest.ToJson().ToString()); ((ContractState)newContract).Script.Should().BeEquivalentTo(contract.Script); } - [TestMethod] - public void TestGetSize() - { - ISerializable newContract = contract; - newContract.Size.Should().Be(210); - } - [TestMethod] public void TestCanCall() { diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs index fbea2b839d..489340ee21 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs @@ -2,6 +2,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Ledger; using Neo.SmartContract; +using Neo.UnitTests.Extensions; using Neo.VM; namespace Neo.UnitTests.SmartContract @@ -61,7 +62,7 @@ public void ApplicationEngineRegularPut() var snapshot = Blockchain.Singleton.GetSnapshot(); snapshot.Storages.Add(skey, sItem); - snapshot.Contracts.Add(script.ToScriptHash(), contractState); + snapshot.AddContract(script.ToScriptHash(), contractState); using (ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, snapshot)) { @@ -94,7 +95,7 @@ public void ApplicationEngineReusedStorage_FullReuse() var snapshot = Blockchain.Singleton.GetSnapshot(); snapshot.Storages.Add(skey, sItem); - snapshot.Contracts.Add(script.ToScriptHash(), contractState); + snapshot.AddContract(script.ToScriptHash(), contractState); using (ApplicationEngine applicationEngine = ApplicationEngine.Create(TriggerType.Application, null, snapshot)) { @@ -129,7 +130,7 @@ public void ApplicationEngineReusedStorage_PartialReuse() var snapshot = Blockchain.Singleton.GetSnapshot(); snapshot.Storages.Add(skey, sItem); - snapshot.Contracts.Add(script.ToScriptHash(), contractState); + snapshot.AddContract(script.ToScriptHash(), contractState); using (ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, snapshot)) { @@ -165,7 +166,7 @@ public void ApplicationEngineReusedStorage_PartialReuseTwice() var snapshot = Blockchain.Singleton.GetSnapshot(); snapshot.Storages.Add(skey, sItem); - snapshot.Contracts.Add(script.ToScriptHash(), contractState); + snapshot.AddContract(script.ToScriptHash(), contractState); using (ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, snapshot)) { diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index bd6175cc60..571f08ff00 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -9,6 +9,8 @@ using Neo.SmartContract; using Neo.SmartContract.Iterators; using Neo.SmartContract.Manifest; +using Neo.SmartContract.Native; +using Neo.UnitTests.Extensions; using Neo.VM.Types; using Neo.Wallets; using System; @@ -114,7 +116,7 @@ public void TestAccount_IsStandard() var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); - snapshot.Contracts.Add(state.Hash, state); + snapshot.AddContract(state.Hash, state); engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(new byte[] { 0x01 }); engine.IsStandardContract(state.Hash).Should().BeFalse(); @@ -128,20 +130,20 @@ public void TestAccount_IsStandard() [TestMethod] public void TestContract_Create() { + var snapshot = Blockchain.Singleton.GetSnapshot().Clone(); + snapshot.PersistingBlock = new Block() { }; var nef = new NefFile() { - Script = new byte[0x01], + Script = new byte[byte.MaxValue], Compiler = "", Version = new Version(1, 2, 3, 4).ToString() }; nef.CheckSum = NefFile.ComputeChecksum(nef); var nefFile = nef.ToArray(); var manifest = TestUtils.CreateDefaultManifest(); - var engine = GetEngine(false, true); - Assert.ThrowsException(() => engine.CreateContract(nefFile, manifest.ToJson().ToByteArray(false))); - - engine = GetEngine(true, true); - Assert.ThrowsException(() => engine.CreateContract(nefFile, new byte[ContractManifest.MaxLength + 1])); + Assert.ThrowsException(() => snapshot.DeployContract(null, nefFile, manifest.ToJson().ToByteArray(false))); + Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, nefFile, new byte[ContractManifest.MaxLength + 1])); + Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, nefFile, manifest.ToJson().ToByteArray(true), 10000000)); var script_exceedMaxLength = new NefFile() { @@ -150,32 +152,31 @@ public void TestContract_Create() Version = new Version(1, 2, 3, 4).ToString() }; script_exceedMaxLength.CheckSum = NefFile.ComputeChecksum(nef); - Assert.ThrowsException(() => engine.CreateContract(script_exceedMaxLength.ToArray(), manifest.ToJson().ToByteArray(true))); - engine = GetEngine(true, true, gas: 2000_00000000); - Assert.ThrowsException(() => engine.CreateContract(script_exceedMaxLength.ToArray(), manifest.ToJson().ToByteArray(true))); + Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, script_exceedMaxLength.ToArray(), manifest.ToJson().ToByteArray(true))); var script_zeroLength = new byte[] { }; - Assert.ThrowsException(() => engine.CreateContract(script_zeroLength, manifest.ToJson().ToByteArray(true))); + Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, script_zeroLength, manifest.ToJson().ToByteArray(true))); var manifest_zeroLength = new byte[] { }; - Assert.ThrowsException(() => engine.CreateContract(nefFile, manifest_zeroLength)); + Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, nefFile, manifest_zeroLength)); manifest = TestUtils.CreateDefaultManifest(); - engine.CreateContract(nefFile, manifest.ToJson().ToByteArray(false)); + var ret = snapshot.DeployContract(UInt160.Zero, nefFile, manifest.ToJson().ToByteArray(false)); + ret.Hash.ToString().Should().Be("0x5756874a149b9de89c7b5d34f9c37db3762f88a2"); + Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, nefFile, manifest.ToJson().ToByteArray(false))); - var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); - snapshot.Contracts.Add(state.Hash, state); - engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0); - engine.LoadScript(new byte[] { 0x01 }); + snapshot.AddContract(state.Hash, state); - Assert.ThrowsException(() => engine.CreateContract(nefFile, manifest.ToJson().ToByteArray(false))); + Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, nefFile, manifest.ToJson().ToByteArray(false))); } [TestMethod] public void TestContract_Update() { - var engine = GetEngine(false, true); + var snapshot = Blockchain.Singleton.GetSnapshot().Clone(); + snapshot.PersistingBlock = new Block() { }; + var nef = new NefFile() { Script = new byte[] { 0x01 }, @@ -183,15 +184,13 @@ public void TestContract_Update() Version = new Version(1, 2, 3, 4).ToString() }; nef.CheckSum = NefFile.ComputeChecksum(nef); - var nefFile = nef.ToArray(); - Assert.ThrowsException(() => engine.UpdateContract(nefFile, new byte[0])); + Assert.ThrowsException(() => snapshot.UpdateContract(null, nef.ToArray(), new byte[0])); var manifest = TestUtils.CreateDefaultManifest(); byte[] privkey = { 0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; KeyPair key = new KeyPair(privkey); ECPoint pubkey = key.PublicKey; - var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); byte[] signature = Crypto.Sign(state.Hash.ToArray(), privkey, pubkey.EncodePoint(false).Skip(1).ToArray()); manifest.Groups = new ContractGroup[] @@ -214,12 +213,16 @@ public void TestContract_Update() Id = state.Id, Key = new byte[] { 0x01 } }; - snapshot.Contracts.Add(state.Hash, state); + snapshot.AddContract(state.Hash, state); snapshot.Storages.Add(storageKey, storageItem); - engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); - engine.LoadScript(state.Script); - engine.UpdateContract(nefFile, manifest.ToJson().ToByteArray(false)); - engine.Snapshot.Storages.Find(BitConverter.GetBytes(state.Id)).ToList().Count().Should().Be(1); + state.UpdateCounter.Should().Be(0); + snapshot.UpdateContract(state.Hash, nef.ToArray(), manifest.ToJson().ToByteArray(false)); + var ret = NativeContract.Management.GetContract(snapshot, state.Hash); + snapshot.Storages.Find(BitConverter.GetBytes(state.Id)).ToList().Count().Should().Be(1); + ret.UpdateCounter.Should().Be(1); + ret.Id.Should().Be(state.Id); + ret.Manifest.ToJson().ToString().Should().Be(manifest.ToJson().ToString()); + ret.Script.ToHexString().Should().Be(nef.Script.ToHexString().ToString()); } [TestMethod] @@ -232,12 +235,13 @@ public void TestContract_Update_Invalid() Compiler = "" }; nefFile.CheckSum = NefFile.ComputeChecksum(nefFile); - var nef = nefFile.ToArray(); - var engine = GetEngine(false, true); - Assert.ThrowsException(() => engine.UpdateContract(null, new byte[] { 0x01 })); - Assert.ThrowsException(() => engine.UpdateContract(nef, null)); - Assert.ThrowsException(() => engine.UpdateContract(null, null)); + var snapshot = Blockchain.Singleton.GetSnapshot().Clone(); + snapshot.PersistingBlock = new Block(); + + Assert.ThrowsException(() => snapshot.UpdateContract(null, null, new byte[] { 0x01 })); + Assert.ThrowsException(() => snapshot.UpdateContract(null, nefFile.ToArray(), null)); + Assert.ThrowsException(() => snapshot.UpdateContract(null, null, null)); nefFile = new NefFile() { @@ -246,10 +250,9 @@ public void TestContract_Update_Invalid() Compiler = "" }; nefFile.CheckSum = NefFile.ComputeChecksum(nefFile); - nef = nefFile.ToArray(); - Assert.ThrowsException(() => engine.UpdateContract(nef, new byte[] { 0x01 })); - Assert.ThrowsException(() => engine.UpdateContract(nef, new byte[0])); + Assert.ThrowsException(() => snapshot.UpdateContract(null, nefFile.ToArray(), new byte[] { 0x01 })); + Assert.ThrowsException(() => snapshot.UpdateContract(null, nefFile.ToArray(), new byte[0])); } [TestMethod] @@ -268,7 +271,7 @@ public void TestStorage_Find() Id = state.Id, Key = new byte[] { 0x01 } }; - snapshot.Contracts.Add(state.Hash, state); + snapshot.AddContract(state.Hash, state); snapshot.Storages.Add(storageKey, storageItem); var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(new byte[] { 0x01 }); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 72e0cc2bec..1b0bad9314 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -8,6 +8,7 @@ using Neo.Network.P2P.Payloads; using Neo.SmartContract; using Neo.SmartContract.Manifest; +using Neo.UnitTests.Extensions; using Neo.VM; using Neo.VM.Types; using Neo.Wallets; @@ -48,8 +49,8 @@ public void Runtime_GetNotifications_Test() scriptHash2 = script.ToArray().ToScriptHash(); - snapshot.Contracts.Delete(scriptHash2); - snapshot.Contracts.Add(scriptHash2, new ContractState() + snapshot.DeleteContract(scriptHash2); + snapshot.AddContract(scriptHash2, new ContractState() { Script = script.ToArray(), Hash = script.ToArray().ToScriptHash(), @@ -179,7 +180,7 @@ public void Runtime_GetNotifications_Test() // Clean storage - snapshot.Contracts.Delete(scriptHash2); + snapshot.DeleteContract(scriptHash2); } private void AssertNotification(StackItem stackItem, UInt160 scriptHash, string notification) @@ -220,7 +221,7 @@ public void TestExecutionEngine_GetCallingScriptHash() Hash = scriptA.ToArray().ToScriptHash() }; engine = GetEngine(true, true, false); - engine.Snapshot.Contracts.Add(contract.Hash, contract); + engine.Snapshot.AddContract(contract.Hash, contract); using ScriptBuilder scriptB = new ScriptBuilder(); scriptB.EmitAppCall(contract.Hash, "test", 0, 1); @@ -387,14 +388,14 @@ public void TestBlockchain_GetContract() 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; - engine.GetContract(new UInt160(data1)).Should().BeNull(); + Neo.SmartContract.Native.NativeContract.Management.GetContract(engine.Snapshot, new UInt160(data1)).Should().BeNull(); var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); - snapshot.Contracts.Add(state.Hash, state); + snapshot.AddContract(state.Hash, state); engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(new byte[] { 0x01 }); - engine.GetContract(state.Hash).Should().BeSameAs(state); + Neo.SmartContract.Native.NativeContract.Management.GetContract(engine.Snapshot, state.Hash).Should().BeSameAs(state); } [TestMethod] @@ -402,7 +403,7 @@ public void TestStorage_GetContext() { var engine = GetEngine(false, true); var state = TestUtils.GetContract(); - engine.Snapshot.Contracts.Add(state.Hash, state); + engine.Snapshot.AddContract(state.Hash, state); engine.LoadScript(state.Script); engine.GetStorageContext().IsReadOnly.Should().BeFalse(); } @@ -412,7 +413,7 @@ public void TestStorage_GetReadOnlyContext() { var engine = GetEngine(false, true); var state = TestUtils.GetContract(); - engine.Snapshot.Contracts.Add(state.Hash, state); + engine.Snapshot.AddContract(state.Hash, state); engine.LoadScript(state.Script); engine.GetReadOnlyContext().IsReadOnly.Should().BeTrue(); } @@ -434,7 +435,7 @@ public void TestStorage_Get() Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, IsConstant = true }; - snapshot.Contracts.Add(state.Hash, state); + snapshot.AddContract(state.Hash, state); snapshot.Storages.Add(storageKey, storageItem); var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(new byte[] { 0x01 }); @@ -491,7 +492,7 @@ public void TestStorage_Put() Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, IsConstant = true }; - snapshot.Contracts.Add(state.Hash, state); + snapshot.AddContract(state.Hash, state); snapshot.Storages.Add(storageKey, storageItem); engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(new byte[] { 0x01 }); @@ -525,7 +526,7 @@ public void TestStorage_PutEx() Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, IsConstant = false }; - snapshot.Contracts.Add(state.Hash, state); + snapshot.AddContract(state.Hash, state); snapshot.Storages.Add(storageKey, storageItem); var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(new byte[] { 0x01 }); @@ -555,7 +556,7 @@ public void TestStorage_Delete() Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, IsConstant = false }; - snapshot.Contracts.Add(state.Hash, state); + snapshot.AddContract(state.Hash, state); snapshot.Storages.Add(storageKey, storageItem); engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(new byte[] { 0x01 }); @@ -593,7 +594,7 @@ public void TestContract_Call() var args = new VM.Types.Array { 0, 1 }; var state = TestUtils.GetContract(method, args.Count); - snapshot.Contracts.Add(state.Hash, state); + snapshot.AddContract(state.Hash, state); var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(new byte[] { 0x01 }); @@ -618,8 +619,7 @@ public void TestContract_CallEx() string method = "method"; var args = new VM.Types.Array { 0, 1 }; var state = TestUtils.GetContract(method, args.Count); - snapshot.Contracts.Add(state.Hash, state); - + snapshot.AddContract(state.Hash, state); foreach (var flags in new CallFlags[] { CallFlags.None, CallFlags.AllowCall, CallFlags.WriteStates, CallFlags.All }) { @@ -643,10 +643,9 @@ public void TestContract_CallEx() [TestMethod] public void TestContract_Destroy() { - var engine = GetEngine(false, true); - engine.DestroyContract(); + var snapshot = Blockchain.Singleton.GetSnapshot().Clone(); + snapshot.PersistingBlock = new Block(); - var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); var scriptHash = UInt160.Parse("0xcb9f3b7c6fb1cf2c13a40637c189bdd066a272b4"); var storageItem = new StorageItem @@ -660,21 +659,16 @@ public void TestContract_Destroy() Id = 0x43000000, Key = new byte[] { 0x01 } }; - snapshot.Contracts.Add(scriptHash, state); + snapshot.AddContract(scriptHash, state); snapshot.Storages.Add(storageKey, storageItem); - engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); - engine.LoadScript(new byte[0]); - engine.DestroyContract(); - engine.Snapshot.Storages.Find(BitConverter.GetBytes(0x43000000)).Any().Should().BeFalse(); + snapshot.DestroyContract(scriptHash); + snapshot.Storages.Find(BitConverter.GetBytes(0x43000000)).Any().Should().BeFalse(); //storages are removed - snapshot = Blockchain.Singleton.GetSnapshot(); state = TestUtils.GetContract(); - snapshot.Contracts.Add(scriptHash, state); - engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); - engine.LoadScript(new byte[0]); - engine.DestroyContract(); - engine.Snapshot.Storages.Find(BitConverter.GetBytes(0x43000000)).Any().Should().BeFalse(); + snapshot.AddContract(scriptHash, state); + snapshot.DestroyContract(scriptHash); + snapshot.Storages.Find(BitConverter.GetBytes(0x43000000)).Any().Should().BeFalse(); } [TestMethod] diff --git a/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs index e007b4c1d9..1dbd8e2f4a 100644 --- a/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs +++ b/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -2,6 +2,7 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.SmartContract; +using Neo.UnitTests.Extensions; using Neo.Wallets; using System; using System.Linq; @@ -128,8 +129,8 @@ public void TestVerifyWitnesses() snapshot2.Blocks.Add(index2, block2); Header header2 = new Header() { PrevHash = index2, Witness = new Witness { VerificationScript = new byte[0] } }; - snapshot2.Contracts.Add(UInt160.Zero, new ContractState()); - snapshot2.Contracts.Delete(UInt160.Zero); + snapshot2.AddContract(UInt160.Zero, new ContractState()); + snapshot2.DeleteContract(UInt160.Zero); Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header2, snapshot2, 100)); var snapshot3 = Blockchain.Singleton.GetSnapshot(); @@ -146,7 +147,7 @@ public void TestVerifyWitnesses() VerificationScript = Array.Empty() } }; - snapshot3.Contracts.Add(UInt160.Zero, new ContractState() + snapshot3.AddContract(UInt160.Zero, new ContractState() { Script = Array.Empty(), Hash = Array.Empty().ToScriptHash(), @@ -162,8 +163,8 @@ public void TestVerifyWitnesses() Hash = "11".HexToBytes().ToScriptHash(), Manifest = TestUtils.CreateManifest("verify", ContractParameterType.Boolean, ContractParameterType.Signature), // Offset = 0 }; - snapshot3.Contracts.Add(contract.Hash, contract); - var tx = new Extensions.Nep5NativeContractExtensions.ManualWitness(contract.Hash) + snapshot3.AddContract(contract.Hash, contract); + var tx = new Extensions.Nep17NativeContractExtensions.ManualWitness(contract.Hash) { Witnesses = new Witness[] { new Witness() { InvocationScript = new byte[0], VerificationScript = new byte[0] } } }; diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index 13b559cc15..9af0cddd87 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -3,6 +3,7 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.SmartContract; +using Neo.UnitTests.Extensions; using Neo.VM; using Neo.VM.Types; using System.Linq; @@ -316,7 +317,6 @@ public void System_Runtime_GetInvocationCounter() { ContractState contractA, contractB, contractC; var snapshot = Blockchain.Singleton.GetSnapshot().Clone(); - var contracts = snapshot.Contracts; // Create dummy contracts @@ -334,15 +334,15 @@ public void System_Runtime_GetInvocationCounter() // Init A,B,C contracts // First two drops is for drop method and arguments - contracts.Delete(contractA.Hash); - contracts.Delete(contractB.Hash); - contracts.Delete(contractC.Hash); + snapshot.DeleteContract(contractA.Hash); + snapshot.DeleteContract(contractB.Hash); + snapshot.DeleteContract(contractC.Hash); contractA.Manifest = TestUtils.CreateManifest("dummyMain", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer); contractB.Manifest = TestUtils.CreateManifest("dummyMain", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer); contractC.Manifest = TestUtils.CreateManifest("dummyMain", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer); - contracts.Add(contractA.Hash, contractA); - contracts.Add(contractB.Hash, contractB); - contracts.Add(contractC.Hash, contractC); + snapshot.AddContract(contractA.Hash, contractA); + snapshot.AddContract(contractB.Hash, contractB); + snapshot.AddContract(contractC.Hash, contractC); } // Call A,B,B,C diff --git a/tests/neo.UnitTests/VM/UT_Helper.cs b/tests/neo.UnitTests/VM/UT_Helper.cs index 52da42361c..52b6e97c58 100644 --- a/tests/neo.UnitTests/VM/UT_Helper.cs +++ b/tests/neo.UnitTests/VM/UT_Helper.cs @@ -117,7 +117,7 @@ public void TestMakeScript() { byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", UInt160.Zero); - Assert.AreEqual("0c14000000000000000000000000000000000000000011c00c0962616c616e63654f660c14ddeb7e9e9bf7ad8bf773c538c464d936d819a03641627d5b52", + Assert.AreEqual("0c14000000000000000000000000000000000000000011c00c0962616c616e63654f660c14320a42d054e0b20985f84e1e7af38c7751c099b341627d5b52", testScript.ToHexString()); }