diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 811db655a6..2d2fafab04 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -156,7 +156,7 @@ private static Transaction DeployNativeContracts() byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { - sb.EmitSysCall(InteropService.Native.Deploy); + sb.EmitSysCall(ApplicationEngine.Neo_Native_Deploy); script = sb.ToArray(); } return new Transaction diff --git a/src/neo/SmartContract/ApplicationEngine.Binary.cs b/src/neo/SmartContract/ApplicationEngine.Binary.cs new file mode 100644 index 0000000000..d5f86feefb --- /dev/null +++ b/src/neo/SmartContract/ApplicationEngine.Binary.cs @@ -0,0 +1,20 @@ +using Neo.VM.Types; + +namespace Neo.SmartContract +{ + partial class ApplicationEngine + { + public static readonly InteropDescriptor System_Binary_Serialize = Register("System.Binary.Serialize", nameof(BinarySerialize), 0_00100000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Binary_Deserialize = Register("System.Binary.Deserialize", nameof(BinaryDeserialize), 0_00500000, TriggerType.All, CallFlags.None); + + internal byte[] BinarySerialize(StackItem item) + { + return BinarySerializer.Serialize(item, MaxItemSize); + } + + internal StackItem BinaryDeserialize(byte[] data) + { + return BinarySerializer.Deserialize(data, MaxStackSize, MaxItemSize, ReferenceCounter); + } + } +} diff --git a/src/neo/SmartContract/ApplicationEngine.Blockchain.cs b/src/neo/SmartContract/ApplicationEngine.Blockchain.cs new file mode 100644 index 0000000000..025fae972a --- /dev/null +++ b/src/neo/SmartContract/ApplicationEngine.Blockchain.cs @@ -0,0 +1,103 @@ +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using System; +using System.Numerics; + +namespace Neo.SmartContract +{ + partial class ApplicationEngine + { + public const uint MaxTraceableBlocks = Transaction.MaxValidUntilBlockIncrement; + + public static readonly InteropDescriptor System_Blockchain_GetHeight = Register("System.Blockchain.GetHeight", nameof(GetBlockchainHeight), 0_00000400, TriggerType.Application, CallFlags.AllowStates); + public static readonly InteropDescriptor System_Blockchain_GetBlock = Register("System.Blockchain.GetBlock", nameof(GetBlock), 0_02500000, TriggerType.Application, CallFlags.AllowStates); + public static readonly InteropDescriptor System_Blockchain_GetTransaction = Register("System.Blockchain.GetTransaction", nameof(GetTransaction), 0_01000000, TriggerType.Application, CallFlags.AllowStates); + public static readonly InteropDescriptor System_Blockchain_GetTransactionHeight = Register("System.Blockchain.GetTransactionHeight", nameof(GetTransactionHeight), 0_01000000, TriggerType.Application, CallFlags.AllowStates); + public static readonly InteropDescriptor System_Blockchain_GetTransactionFromBlock = Register("System.Blockchain.GetTransactionFromBlock", nameof(GetTransactionFromBlock), 0_01000000, TriggerType.Application, CallFlags.AllowStates); + public static readonly InteropDescriptor System_Blockchain_GetContract = Register("System.Blockchain.GetContract", nameof(GetContract), 0_01000000, TriggerType.Application, CallFlags.AllowStates); + + internal uint GetBlockchainHeight() + { + return Snapshot.Height; + } + + internal Block GetBlock(byte[] indexOrHash) + { + UInt256 hash; + if (indexOrHash.Length < UInt256.Length) + { + BigInteger bi = new BigInteger(indexOrHash); + if (bi < uint.MinValue || bi > uint.MaxValue) + throw new ArgumentOutOfRangeException(nameof(indexOrHash)); + hash = Blockchain.Singleton.GetBlockHash((uint)bi); + } + else if (indexOrHash.Length == UInt256.Length) + { + hash = new UInt256(indexOrHash); + } + else + { + throw new ArgumentException(); + } + if (hash is null) return null; + Block block = Snapshot.GetBlock(hash); + if (block is null) return null; + if (!IsTraceableBlock(Snapshot, block.Index)) return null; + return block; + } + + internal Transaction GetTransaction(UInt256 hash) + { + TransactionState state = Snapshot.Transactions.TryGet(hash); + if (state != null && !IsTraceableBlock(Snapshot, state.BlockIndex)) state = null; + return state?.Transaction; + } + + internal int GetTransactionHeight(UInt256 hash) + { + TransactionState state = Snapshot.Transactions.TryGet(hash); + if (state is null) return -1; + if (!IsTraceableBlock(Snapshot, state.BlockIndex)) return -1; + return (int)state.BlockIndex; + } + + internal Transaction GetTransactionFromBlock(byte[] blockIndexOrHash, int txIndex) + { + UInt256 hash; + if (blockIndexOrHash.Length < UInt256.Length) + { + BigInteger bi = new BigInteger(blockIndexOrHash); + if (bi < uint.MinValue || bi > uint.MaxValue) + throw new ArgumentOutOfRangeException(nameof(blockIndexOrHash)); + hash = Blockchain.Singleton.GetBlockHash((uint)bi); + } + else if (blockIndexOrHash.Length == UInt256.Length) + { + hash = new UInt256(blockIndexOrHash); + } + else + { + throw new ArgumentException(); + } + if (hash is null) return null; + TrimmedBlock block = Snapshot.Blocks.TryGet(hash); + if (block is null) return null; + if (!IsTraceableBlock(Snapshot, block.Index)) return null; + if (txIndex < 0 || txIndex >= block.Hashes.Length - 1) + throw new ArgumentOutOfRangeException(nameof(txIndex)); + return Snapshot.GetTransaction(block.Hashes[txIndex + 1]); + } + + internal ContractState GetContract(UInt160 hash) + { + return Snapshot.Contracts.TryGet(hash); + } + + private static bool IsTraceableBlock(StoreView snapshot, uint index) + { + if (index > snapshot.Height) return false; + return index + MaxTraceableBlocks > snapshot.Height; + } + } +} diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs new file mode 100644 index 0000000000..31407a596c --- /dev/null +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -0,0 +1,181 @@ +using Neo.Cryptography.ECC; +using Neo.IO; +using Neo.Ledger; +using Neo.SmartContract.Manifest; +using Neo.SmartContract.Native; +using Neo.VM; +using System; +using System.Linq; +using Array = Neo.VM.Types.Array; + +namespace Neo.SmartContract +{ + partial class ApplicationEngine + { + public const int MaxContractLength = 1024 * 1024; + + public static readonly InteropDescriptor System_Contract_Create = Register("System.Contract.Create", nameof(CreateContract), 0, TriggerType.Application, CallFlags.AllowModifyStates); + public static readonly InteropDescriptor System_Contract_Update = Register("System.Contract.Update", nameof(UpdateContract), 0, TriggerType.Application, CallFlags.AllowModifyStates); + public static readonly InteropDescriptor System_Contract_Destroy = Register("System.Contract.Destroy", nameof(DestroyContract), 0_01000000, TriggerType.Application, CallFlags.AllowModifyStates); + public static readonly InteropDescriptor System_Contract_Call = Register("System.Contract.Call", nameof(CallContract), 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall); + public static readonly InteropDescriptor System_Contract_CallEx = Register("System.Contract.CallEx", nameof(CallContractEx), 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall); + public static readonly InteropDescriptor System_Contract_IsStandard = Register("System.Contract.IsStandard", nameof(IsStandardContract), 0_00030000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Contract_GetCallFlags = Register("System.Contract.GetCallFlags", nameof(GetCallFlags), 0_00030000, TriggerType.All, CallFlags.None); + /// + /// Calculate corresponding account scripthash for given public key + /// 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, TriggerType.All, CallFlags.None); + + internal ContractState CreateContract(byte[] script, byte[] manifest) + { + if (script.Length == 0 || script.Length > MaxContractLength || manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) + throw new ArgumentException(); + + if (!AddGas(StoragePrice * (script.Length + manifest.Length))) + throw new InvalidOperationException(); + + UInt160 hash = script.ToScriptHash(); + ContractState contract = Snapshot.Contracts.TryGet(hash); + if (contract != null) throw new InvalidOperationException(); + contract = new ContractState + { + Id = Snapshot.ContractId.GetAndChange().NextId++, + Script = script.ToArray(), + Manifest = ContractManifest.Parse(manifest) + }; + + if (!contract.Manifest.IsValid(hash)) throw new InvalidOperationException(); + + Snapshot.Contracts.Add(hash, contract); + return contract; + } + + internal void UpdateContract(byte[] script, byte[] manifest) + { + if (!AddGas(StoragePrice * (script?.Length ?? 0 + manifest?.Length ?? 0))) + throw new InvalidOperationException(); + + var contract = Snapshot.Contracts.TryGet(CurrentScriptHash); + if (contract is null) throw new InvalidOperationException(); + + if (script != null) + { + if (script.Length == 0 || script.Length > MaxContractLength) + throw new ArgumentException(); + UInt160 hash_new = script.ToScriptHash(); + if (hash_new.Equals(CurrentScriptHash) || Snapshot.Contracts.TryGet(hash_new) != null) + throw new InvalidOperationException(); + contract = new ContractState + { + Id = contract.Id, + Script = script.ToArray(), + Manifest = contract.Manifest + }; + contract.Manifest.Abi.Hash = hash_new; + Snapshot.Contracts.Add(hash_new, contract); + Snapshot.Contracts.Delete(CurrentScriptHash); + } + if (manifest != null) + { + if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) + throw new ArgumentException(); + contract = Snapshot.Contracts.GetAndChange(contract.ScriptHash); + contract.Manifest = ContractManifest.Parse(manifest); + if (!contract.Manifest.IsValid(contract.ScriptHash)) + throw new InvalidOperationException(); + if (!contract.HasStorage && Snapshot.Storages.Find(BitConverter.GetBytes(contract.Id)).Any()) + throw new InvalidOperationException(); + } + } + + internal void DestroyContract() + { + UInt160 hash = CurrentScriptHash; + ContractState contract = Snapshot.Contracts.TryGet(hash); + if (contract == null) return; + Snapshot.Contracts.Delete(hash); + if (contract.HasStorage) + foreach (var (key, _) in Snapshot.Storages.Find(BitConverter.GetBytes(contract.Id))) + Snapshot.Storages.Delete(key); + } + + internal void CallContract(UInt160 contractHash, string method, Array args) + { + CallContractInternal(contractHash, method, args, CallFlags.All); + } + + internal void CallContractEx(UInt160 contractHash, string method, Array args, CallFlags callFlags) + { + if ((callFlags & ~CallFlags.All) != 0) + throw new ArgumentOutOfRangeException(nameof(callFlags)); + CallContractInternal(contractHash, method, args, callFlags); + } + + private void CallContractInternal(UInt160 contractHash, string method, Array args, CallFlags flags) + { + if (method.StartsWith('_')) throw new ArgumentException(); + + ContractState contract = Snapshot.Contracts.TryGet(contractHash); + if (contract is null) throw new InvalidOperationException(); + + ContractManifest currentManifest = Snapshot.Contracts.TryGet(CurrentScriptHash)?.Manifest; + + if (currentManifest != null && !currentManifest.CanCall(contract.Manifest, method)) + throw new InvalidOperationException(); + + if (invocationCounter.TryGetValue(contract.ScriptHash, out var counter)) + { + invocationCounter[contract.ScriptHash] = counter + 1; + } + else + { + invocationCounter[contract.ScriptHash] = 1; + } + + ExecutionContextState state = CurrentContext.GetState(); + UInt160 callingScriptHash = state.ScriptHash; + CallFlags callingFlags = state.CallFlags; + + ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method); + if (md is null) throw new InvalidOperationException(); + int rvcount = md.ReturnType == ContractParameterType.Void ? 0 : 1; + ExecutionContext context_new = LoadScript(contract.Script, rvcount); + state = context_new.GetState(); + state.CallingScriptHash = callingScriptHash; + state.CallFlags = flags & callingFlags; + + if (NativeContract.IsNative(contractHash)) + { + context_new.EvaluationStack.Push(args); + context_new.EvaluationStack.Push(method); + } + else + { + for (int i = args.Count - 1; i >= 0; i--) + context_new.EvaluationStack.Push(args[i]); + context_new.InstructionPointer = md.Offset; + } + + md = contract.Manifest.Abi.GetMethod("_initialize"); + if (md != null) LoadClonedContext(md.Offset); + } + + internal bool IsStandardContract(UInt160 hash) + { + ContractState contract = Snapshot.Contracts.TryGet(hash); + return contract is null || contract.Script.IsStandardContract(); + } + + internal CallFlags GetCallFlags() + { + var state = CurrentContext.GetState(); + return state.CallFlags; + } + + internal UInt160 CreateStandardAccount(ECPoint pubKey) + { + return Contract.CreateSignatureRedeemScript(pubKey).ToScriptHash(); + } + } +} diff --git a/src/neo/SmartContract/ApplicationEngine.Crypto.cs b/src/neo/SmartContract/ApplicationEngine.Crypto.cs new file mode 100644 index 0000000000..9cb3a9abf4 --- /dev/null +++ b/src/neo/SmartContract/ApplicationEngine.Crypto.cs @@ -0,0 +1,99 @@ +using Neo.Cryptography; +using Neo.Cryptography.ECC; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.VM; +using Neo.VM.Types; +using System; + +namespace Neo.SmartContract +{ + partial class ApplicationEngine + { + public const long ECDsaVerifyPrice = 0_01000000; + + public static readonly InteropDescriptor Neo_Crypto_SHA256 = Register("Neo.Crypto.SHA256", nameof(Sha256), 0_01000000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor Neo_Crypto_VerifyWithECDsaSecp256r1 = Register("Neo.Crypto.VerifyWithECDsaSecp256r1", nameof(VerifyWithECDsaSecp256r1), ECDsaVerifyPrice, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor Neo_Crypto_VerifyWithECDsaSecp256k1 = Register("Neo.Crypto.VerifyWithECDsaSecp256k1", nameof(VerifyWithECDsaSecp256k1), ECDsaVerifyPrice, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor Neo_Crypto_CheckMultisigWithECDsaSecp256r1 = Register("Neo.Crypto.CheckMultisigWithECDsaSecp256r1", nameof(CheckMultisigWithECDsaSecp256r1), 0, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor Neo_Crypto_CheckMultisigWithECDsaSecp256k1 = Register("Neo.Crypto.CheckMultisigWithECDsaSecp256k1", nameof(CheckMultisigWithECDsaSecp256k1), 0, TriggerType.All, CallFlags.None); + + internal byte[] Sha256(StackItem item) + { + ReadOnlySpan value = item switch + { + InteropInterface _interface => _interface.GetInterface().GetHashData(), + Null _ => ScriptContainer.GetHashData(), + _ => item.GetSpan() + }; + return value.Sha256(); + } + + internal bool VerifyWithECDsaSecp256r1(StackItem item, byte[] pubkey, byte[] signature) + { + return VerifyWithECDsa(item, pubkey, signature, ECCurve.Secp256r1); + } + + internal bool VerifyWithECDsaSecp256k1(StackItem item, byte[] pubkey, byte[] signature) + { + return VerifyWithECDsa(item, pubkey, signature, ECCurve.Secp256k1); + } + + private bool VerifyWithECDsa(StackItem item, byte[] pubkey, byte[] signature, ECCurve curve) + { + ReadOnlySpan message = item switch + { + InteropInterface _interface => _interface.GetInterface().GetHashData(), + Null _ => ScriptContainer.GetHashData(), + _ => item.GetSpan() + }; + try + { + return Crypto.VerifySignature(message, signature, pubkey, curve); + } + catch (ArgumentException) + { + return false; + } + } + + internal bool CheckMultisigWithECDsaSecp256r1(StackItem item, byte[][] pubkeys, byte[][] signatures) + { + return CheckMultiSigWithECDsa(item, pubkeys, signatures, ECCurve.Secp256r1); + } + + internal bool CheckMultisigWithECDsaSecp256k1(StackItem item, byte[][] pubkeys, byte[][] signatures) + { + return CheckMultiSigWithECDsa(item, pubkeys, signatures, ECCurve.Secp256k1); + } + + private bool CheckMultiSigWithECDsa(StackItem item0, byte[][] pubkeys, byte[][] signatures, ECCurve curve) + { + int m = signatures.Length, n = pubkeys.Length; + ReadOnlySpan message = item0 switch + { + InteropInterface _interface => _interface.GetInterface().GetHashData(), + Null _ => ScriptContainer.GetHashData(), + _ => item0.GetSpan() + }; + if (n == 0 || m == 0 || m > n) throw new ArgumentException(); + if (!AddGas(ECDsaVerifyPrice * n)) throw new InvalidOperationException(); + try + { + for (int i = 0, j = 0; i < m && j < n;) + { + if (Crypto.VerifySignature(message, signatures[i], pubkeys[j], curve)) + i++; + j++; + if (m - i > n - j) + return false; + } + } + catch (ArgumentException) + { + return false; + } + return true; + } + } +} diff --git a/src/neo/SmartContract/ApplicationEngine.Enumerator.cs b/src/neo/SmartContract/ApplicationEngine.Enumerator.cs new file mode 100644 index 0000000000..7fdbbd8bf8 --- /dev/null +++ b/src/neo/SmartContract/ApplicationEngine.Enumerator.cs @@ -0,0 +1,41 @@ +using Neo.SmartContract.Enumerators; +using Neo.SmartContract.Iterators; +using Neo.VM.Types; +using System; +using Array = Neo.VM.Types.Array; + +namespace Neo.SmartContract +{ + partial class ApplicationEngine + { + public static readonly InteropDescriptor System_Enumerator_Create = Register("System.Enumerator.Create", nameof(CreateEnumerator), 0_00000400, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Enumerator_Next = Register("System.Enumerator.Next", nameof(EnumeratorNext), 0_01000000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Enumerator_Value = Register("System.Enumerator.Value", nameof(EnumeratorValue), 0_00000400, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Enumerator_Concat = Register("System.Enumerator.Concat", nameof(ConcatEnumerators), 0_00000400, TriggerType.All, CallFlags.None); + + internal IEnumerator CreateEnumerator(StackItem item) + { + return item switch + { + Array array => new ArrayWrapper(array), + PrimitiveType primitive => new ByteArrayWrapper(primitive), + _ => throw new ArgumentException() + }; + } + + internal bool EnumeratorNext(IEnumerator enumerator) + { + return enumerator.Next(); + } + + internal StackItem EnumeratorValue(IEnumerator enumerator) + { + return enumerator.Value(); + } + + internal IEnumerator ConcatEnumerators(IEnumerator first, IEnumerator second) + { + return new ConcatenatedEnumerator(first, second); + } + } +} diff --git a/src/neo/SmartContract/ApplicationEngine.Iterator.cs b/src/neo/SmartContract/ApplicationEngine.Iterator.cs new file mode 100644 index 0000000000..be3bde386b --- /dev/null +++ b/src/neo/SmartContract/ApplicationEngine.Iterator.cs @@ -0,0 +1,48 @@ +using Neo.SmartContract.Enumerators; +using Neo.SmartContract.Iterators; +using Neo.VM.Types; +using System; +using Array = Neo.VM.Types.Array; + +namespace Neo.SmartContract +{ + partial class ApplicationEngine + { + public static readonly InteropDescriptor System_Iterator_Create = Register("System.Iterator.Create", nameof(CreateIterator), 0_00000400, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Iterator_Key = Register("System.Iterator.Key", nameof(IteratorKey), 0_00000400, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Iterator_Keys = Register("System.Iterator.Keys", nameof(IteratorKeys), 0_00000400, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Iterator_Values = Register("System.Iterator.Values", nameof(IteratorValues), 0_00000400, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Iterator_Concat = Register("System.Iterator.Concat", nameof(ConcatIterators), 0_00000400, TriggerType.All, CallFlags.None); + + internal IIterator CreateIterator(StackItem item) + { + return item switch + { + Array array => new ArrayWrapper(array), + Map map => new MapWrapper(map), + PrimitiveType primitive => new ByteArrayWrapper(primitive), + _ => throw new ArgumentException() + }; + } + + internal PrimitiveType IteratorKey(IIterator iterator) + { + return iterator.Key(); + } + + internal IEnumerator IteratorKeys(IIterator iterator) + { + return new IteratorKeysWrapper(iterator); + } + + internal IEnumerator IteratorValues(IIterator iterator) + { + return new IteratorValuesWrapper(iterator); + } + + internal IIterator ConcatIterators(IIterator first, IIterator second) + { + return new ConcatenatedIterator(first, second); + } + } +} diff --git a/src/neo/SmartContract/ApplicationEngine.Json.cs b/src/neo/SmartContract/ApplicationEngine.Json.cs new file mode 100644 index 0000000000..d8f972c343 --- /dev/null +++ b/src/neo/SmartContract/ApplicationEngine.Json.cs @@ -0,0 +1,21 @@ +using Neo.IO.Json; +using Neo.VM.Types; + +namespace Neo.SmartContract +{ + partial class ApplicationEngine + { + public static readonly InteropDescriptor System_Json_Serialize = Register("System.Json.Serialize", nameof(JsonSerialize), 0_00100000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Json_Deserialize = Register("System.Json.Deserialize", nameof(JsonDeserialize), 0_00500000, TriggerType.All, CallFlags.None); + + internal byte[] JsonSerialize(StackItem item) + { + return JsonSerializer.SerializeToByteArray(item, MaxItemSize); + } + + internal StackItem JsonDeserialize(byte[] json) + { + return JsonSerializer.Deserialize(JObject.Parse(json, 10), ReferenceCounter); + } + } +} diff --git a/src/neo/SmartContract/ApplicationEngine.Native.cs b/src/neo/SmartContract/ApplicationEngine.Native.cs new file mode 100644 index 0000000000..e413df7b17 --- /dev/null +++ b/src/neo/SmartContract/ApplicationEngine.Native.cs @@ -0,0 +1,34 @@ +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, TriggerType.Application, CallFlags.AllowModifyStates); + public static readonly InteropDescriptor Neo_Native_Call = Register("Neo.Native.Call", nameof(CallNativeContract), 0, TriggerType.System | TriggerType.Application, CallFlags.None); + + 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, + Manifest = contract.Manifest + }); + contract.Initialize(this); + } + } + + internal void CallNativeContract(string name) + { + if (!NativeContract.GetContract(name).Invoke(this)) + throw new InvalidOperationException(); + } + } +} diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs new file mode 100644 index 0000000000..481e6fcfcb --- /dev/null +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -0,0 +1,173 @@ +using Neo.Cryptography.ECC; +using Neo.IO; +using Neo.Network.P2P.Payloads; +using Neo.VM.Types; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Array = Neo.VM.Types.Array; + +namespace Neo.SmartContract +{ + partial class ApplicationEngine + { + public const int MaxNotificationSize = 1024; + + public static readonly InteropDescriptor System_Runtime_Platform = Register("System.Runtime.Platform", nameof(GetPlatform), 0_00000250, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Runtime_GetTrigger = Register("System.Runtime.GetTrigger", nameof(Trigger), 0_00000250, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Runtime_GetTime = Register("System.Runtime.GetTime", nameof(GetTime), 0_00000250, TriggerType.Application, CallFlags.AllowStates); + public static readonly InteropDescriptor System_Runtime_GetScriptContainer = Register("System.Runtime.GetScriptContainer", nameof(GetScriptContainer), 0_00000250, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Runtime_GetExecutingScriptHash = Register("System.Runtime.GetExecutingScriptHash", nameof(CurrentScriptHash), 0_00000400, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Runtime_GetCallingScriptHash = Register("System.Runtime.GetCallingScriptHash", nameof(CallingScriptHash), 0_00000400, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Runtime_GetEntryScriptHash = Register("System.Runtime.GetEntryScriptHash", nameof(EntryScriptHash), 0_00000400, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Runtime_CheckWitness = Register("System.Runtime.CheckWitness", nameof(CheckWitness), 0_00030000, TriggerType.All, CallFlags.AllowStates); + public static readonly InteropDescriptor System_Runtime_GetInvocationCounter = Register("System.Runtime.GetInvocationCounter", nameof(GetInvocationCounter), 0_00000400, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Runtime_Log = Register("System.Runtime.Log", nameof(RuntimeLog), 0_01000000, TriggerType.All, CallFlags.AllowNotify); + public static readonly InteropDescriptor System_Runtime_Notify = Register("System.Runtime.Notify", nameof(RuntimeNotify), 0_01000000, TriggerType.All, CallFlags.AllowNotify); + public static readonly InteropDescriptor System_Runtime_GetNotifications = Register("System.Runtime.GetNotifications", nameof(GetNotifications), 0_00010000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor System_Runtime_GasLeft = Register("System.Runtime.GasLeft", nameof(GasLeft), 0_00000400, TriggerType.All, CallFlags.None); + + private static bool CheckItemForNotification(StackItem state) + { + int size = 0; + List items_checked = new List(); + Queue items_unchecked = new Queue(); + while (true) + { + switch (state) + { + case Struct array: + foreach (StackItem item in array) + items_unchecked.Enqueue(item); + break; + case Array array: + if (items_checked.All(p => !ReferenceEquals(p, array))) + { + items_checked.Add(array); + foreach (StackItem item in array) + items_unchecked.Enqueue(item); + } + break; + case PrimitiveType primitive: + size += primitive.Size; + break; + case Null _: + break; + case InteropInterface _: + return false; + case Map map: + if (items_checked.All(p => !ReferenceEquals(p, map))) + { + items_checked.Add(map); + foreach (var pair in map) + { + size += pair.Key.Size; + items_unchecked.Enqueue(pair.Value); + } + } + break; + } + if (size > MaxNotificationSize) return false; + if (items_unchecked.Count == 0) return true; + state = items_unchecked.Dequeue(); + } + } + + internal string GetPlatform() + { + return "NEO"; + } + + internal ulong GetTime() + { + return Snapshot.PersistingBlock.Timestamp; + } + + internal IInteroperable GetScriptContainer() + { + return ScriptContainer as IInteroperable; + } + + internal bool CheckWitness(byte[] hashOrPubkey) + { + UInt160 hash = hashOrPubkey.Length switch + { + 20 => new UInt160(hashOrPubkey), + 33 => Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(hashOrPubkey, ECCurve.Secp256r1)).ToScriptHash(), + _ => throw new ArgumentException() + }; + return CheckWitnessInternal(hash); + } + + internal bool CheckWitnessInternal(UInt160 hash) + { + if (ScriptContainer is Transaction tx) + { + Cosigner cosigner = tx.Cosigners.FirstOrDefault(p => p.Account.Equals(hash)); + if (cosigner is null) return false; + if (cosigner.Scopes == WitnessScope.Global) return true; + if (cosigner.Scopes.HasFlag(WitnessScope.CalledByEntry)) + { + if (CallingScriptHash == EntryScriptHash) + return true; + } + if (cosigner.Scopes.HasFlag(WitnessScope.CustomContracts)) + { + if (cosigner.AllowedContracts.Contains(CurrentScriptHash)) + return true; + } + if (cosigner.Scopes.HasFlag(WitnessScope.CustomGroups)) + { + var contract = Snapshot.Contracts[CallingScriptHash]; + // check if current group is the required one + if (contract.Manifest.Groups.Select(p => p.PubKey).Intersect(cosigner.AllowedGroups).Any()) + return true; + } + return false; + } + + // only for non-Transaction types (Block, etc) + + var hashes_for_verifying = ScriptContainer.GetScriptHashesForVerifying(Snapshot); + return hashes_for_verifying.Contains(hash); + } + + internal int GetInvocationCounter() + { + if (!invocationCounter.TryGetValue(CurrentScriptHash, out var counter)) + throw new InvalidOperationException(); + return counter; + } + + internal void RuntimeLog(byte[] state) + { + if (state.Length > MaxNotificationSize) throw new ArgumentException(); + string message = Encoding.UTF8.GetString(state); + Log?.Invoke(this, new LogEventArgs(ScriptContainer, CurrentScriptHash, message)); + } + + internal void RuntimeNotify(StackItem state) + { + if (!CheckItemForNotification(state)) throw new ArgumentException(); + SendNotification(CurrentScriptHash, state); + } + + internal void SendNotification(UInt160 script_hash, StackItem state) + { + NotifyEventArgs notification = new NotifyEventArgs(ScriptContainer, script_hash, state); + Notify?.Invoke(this, notification); + notifications.Add(notification); + } + + internal NotifyEventArgs[] GetNotifications(UInt160 hash) + { + IEnumerable notifications = Notifications; + if (hash != null) // must filter by scriptHash + notifications = notifications.Where(p => p.ScriptHash == hash); + NotifyEventArgs[] array = notifications.ToArray(); + if (array.Length > MaxStackSize) throw new InvalidOperationException(); + return array; + } + } +} diff --git a/src/neo/SmartContract/ApplicationEngine.Storage.cs b/src/neo/SmartContract/ApplicationEngine.Storage.cs new file mode 100644 index 0000000000..b579c5f37f --- /dev/null +++ b/src/neo/SmartContract/ApplicationEngine.Storage.cs @@ -0,0 +1,127 @@ +using Neo.Ledger; +using Neo.SmartContract.Iterators; +using System; +using System.Linq; + +namespace Neo.SmartContract +{ + partial class ApplicationEngine + { + public const long StoragePrice = 100000; + public const int MaxStorageKeySize = 64; + public const int MaxStorageValueSize = ushort.MaxValue; + + public static readonly InteropDescriptor System_Storage_GetContext = Register("System.Storage.GetContext", nameof(GetStorageContext), 0_00000400, TriggerType.Application, CallFlags.AllowStates); + public static readonly InteropDescriptor System_Storage_GetReadOnlyContext = Register("System.Storage.GetReadOnlyContext", nameof(GetReadOnlyContext), 0_00000400, TriggerType.Application, CallFlags.AllowStates); + public static readonly InteropDescriptor System_Storage_AsReadOnly = Register("System.Storage.AsReadOnly", nameof(AsReadOnly), 0_00000400, TriggerType.Application, CallFlags.AllowStates); + public static readonly InteropDescriptor System_Storage_Get = Register("System.Storage.Get", nameof(Get), 0_01000000, TriggerType.Application, CallFlags.AllowStates); + public static readonly InteropDescriptor System_Storage_Find = Register("System.Storage.Find", nameof(Find), 0_01000000, TriggerType.Application, CallFlags.AllowStates); + public static readonly InteropDescriptor System_Storage_Put = Register("System.Storage.Put", nameof(Put), 0, TriggerType.Application, CallFlags.AllowModifyStates); + public static readonly InteropDescriptor System_Storage_PutEx = Register("System.Storage.PutEx", nameof(PutEx), 0, TriggerType.Application, CallFlags.AllowModifyStates); + public static readonly InteropDescriptor System_Storage_Delete = Register("System.Storage.Delete", nameof(Delete), 1 * StoragePrice, TriggerType.Application, CallFlags.AllowModifyStates); + + internal StorageContext GetStorageContext() + { + ContractState contract = Snapshot.Contracts.TryGet(CurrentScriptHash); + if (!contract.HasStorage) throw new InvalidOperationException(); + return new StorageContext + { + Id = contract.Id, + IsReadOnly = false + }; + } + + internal StorageContext GetReadOnlyContext() + { + ContractState contract = Snapshot.Contracts.TryGet(CurrentScriptHash); + if (!contract.HasStorage) throw new InvalidOperationException(); + return new StorageContext + { + Id = contract.Id, + IsReadOnly = true + }; + } + + internal StorageContext AsReadOnly(StorageContext context) + { + if (!context.IsReadOnly) + context = new StorageContext + { + Id = context.Id, + IsReadOnly = true + }; + return context; + } + + internal byte[] Get(StorageContext context, byte[] key) + { + return Snapshot.Storages.TryGet(new StorageKey + { + Id = context.Id, + Key = key.ToArray() + })?.Value; + } + + internal IIterator Find(StorageContext context, byte[] prefix) + { + byte[] prefix_key = StorageKey.CreateSearchPrefix(context.Id, prefix); + StorageIterator iterator = new StorageIterator(Snapshot.Storages.Find(prefix_key).Where(p => p.Key.Key.AsSpan().StartsWith(prefix)).GetEnumerator()); + disposables.Add(iterator); + return iterator; + } + + internal void Put(StorageContext context, byte[] key, byte[] value) + { + PutExInternal(context, key, value, StorageFlags.None); + } + + internal void PutEx(StorageContext context, byte[] key, byte[] value, StorageFlags flags) + { + PutExInternal(context, key, value, flags); + } + + private void PutExInternal(StorageContext context, byte[] key, byte[] value, StorageFlags flags) + { + if (key.Length > MaxStorageKeySize || value.Length > MaxStorageValueSize || context.IsReadOnly) + throw new ArgumentException(); + + int newDataSize; + StorageKey skey = new StorageKey + { + Id = context.Id, + Key = key + }; + StorageItem item = Snapshot.Storages.GetAndChange(skey); + if (item is null) + { + newDataSize = key.Length + value.Length; + Snapshot.Storages.Add(skey, item = new StorageItem()); + } + else + { + if (item.IsConstant) throw new InvalidOperationException(); + if (value.Length <= item.Value.Length) + newDataSize = 1; + else + newDataSize = value.Length - item.Value.Length; + } + if (!AddGas(newDataSize * StoragePrice)) throw new InvalidOperationException(); + + item.Value = value; + item.IsConstant = flags.HasFlag(StorageFlags.Constant); + } + + internal void Delete(StorageContext context, byte[] key) + { + if (context.IsReadOnly) throw new ArgumentException(); + StorageKey skey = new StorageKey + { + Id = context.Id, + Key = key + }; + if (Snapshot.Storages.TryGet(skey)?.IsConstant == true) + throw new InvalidOperationException(); + Snapshot.Storages.Delete(skey); + } + } +} diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index bfec85c8f8..11708d9609 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -1,3 +1,4 @@ +using Neo.IO; using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; @@ -5,8 +6,12 @@ using Neo.VM.Types; using System; using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Reflection; using System.Text; using Array = System.Array; +using VMArray = Neo.VM.Types.Array; namespace Neo.SmartContract { @@ -16,22 +21,24 @@ public partial class ApplicationEngine : ExecutionEngine public static event EventHandler Log; public const long GasFree = 0; + + private static Dictionary services; private readonly long gas_amount; private readonly bool testMode; private readonly List notifications = new List(); private readonly List disposables = new List(); + private readonly Dictionary invocationCounter = new Dictionary(); + public static IEnumerable Services => services.Values; public TriggerType Trigger { get; } public IVerifiable ScriptContainer { get; } public StoreView Snapshot { get; } public long GasConsumed { get; private set; } = 0; public long GasLeft => testMode ? -1 : gas_amount - GasConsumed; - public UInt160 CurrentScriptHash => CurrentContext?.GetState().ScriptHash; public UInt160 CallingScriptHash => CurrentContext?.GetState().CallingScriptHash; public UInt160 EntryScriptHash => EntryContext?.GetState().ScriptHash; public IReadOnlyList Notifications => notifications; - internal Dictionary InvocationCounter { get; } = new Dictionary(); public ApplicationEngine(TriggerType trigger, IVerifiable container, StoreView snapshot, long gas, bool testMode = false) { @@ -42,12 +49,6 @@ public ApplicationEngine(TriggerType trigger, IVerifiable container, StoreView s this.Snapshot = snapshot; } - internal T AddDisposable(T disposable) where T : IDisposable - { - disposables.Add(disposable); - return disposable; - } - internal bool AddGas(long gas) { GasConsumed = checked(GasConsumed + gas); @@ -70,6 +71,32 @@ public ExecutionContext LoadScript(Script script, CallFlags callFlags, int rvcou return context; } + private StackItem ConvertReturnValue(object value) + { + return value switch + { + null => StackItem.Null, + bool b => b, + sbyte i => i, + byte i => (BigInteger)i, + short i => i, + ushort i => (BigInteger)i, + int i => i, + uint i => i, + long i => i, + ulong i => i, + Enum e => ConvertReturnValue(Convert.ChangeType(e, e.GetTypeCode())), + byte[] data => data, + string s => s, + UInt160 i => i.ToArray(), + UInt256 i => i.ToArray(), + IInteroperable interoperable => interoperable.ToStackItem(ReferenceCounter), + IInteroperable[] array => new VMArray(ReferenceCounter, array.Select(p => p.ToStackItem(ReferenceCounter))), + StackItem item => item, + _ => StackItem.FromInterface(value) + }; + } + public override void Dispose() { foreach (IDisposable disposable in disposables) @@ -80,7 +107,53 @@ public override void Dispose() protected override bool OnSysCall(uint method) { - return InteropService.Invoke(this, method); + if (!services.TryGetValue(method, out InteropDescriptor descriptor)) + return false; + if (!descriptor.AllowedTriggers.HasFlag(Trigger)) + return false; + ExecutionContextState state = CurrentContext.GetState(); + if (!state.CallFlags.HasFlag(descriptor.RequiredCallFlags)) + return false; + if (!AddGas(descriptor.FixedPrice)) + return false; + List parameters = descriptor.Parameters.Length > 0 + ? new List() + : null; + foreach (var pd in descriptor.Parameters) + { + StackItem item = Pop(); + object value; + if (pd.IsArray) + { + Array av; + if (item is VMArray array) + { + av = Array.CreateInstance(pd.Type.GetElementType(), array.Count); + for (int i = 0; i < av.Length; i++) + av.SetValue(pd.Converter(array[i]), i); + } + else + { + av = Array.CreateInstance(pd.Type.GetElementType(), (int)item.GetBigInteger()); + for (int i = 0; i < av.Length; i++) + av.SetValue(pd.Converter(Pop()), i); + } + value = av; + } + else + { + value = pd.Converter(item); + if (pd.IsEnum) + value = Convert.ChangeType(value, pd.Type); + else if (pd.IsInterface) + value = ((InteropInterface)value).GetInterface(); + } + parameters.Add(value); + } + object returnValue = descriptor.Handler.Invoke(this, parameters?.ToArray()); + if (descriptor.Handler.ReturnType != typeof(void)) + Push(ConvertReturnValue(returnValue)); + return true; } protected override bool PreExecuteInstruction() @@ -111,6 +184,16 @@ private static Block CreateDummyBlock(StoreView snapshot) }; } + private static InteropDescriptor Register(string name, string handler, long fixedPrice, TriggerType allowedTriggers, CallFlags requiredCallFlags) + { + MethodInfo method = typeof(ApplicationEngine).GetMethod(handler, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + ?? typeof(ApplicationEngine).GetProperty(handler, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).GetMethod; + InteropDescriptor descriptor = new InteropDescriptor(name, method, fixedPrice, allowedTriggers, requiredCallFlags); + services ??= new Dictionary(); + services.Add(descriptor.Hash, descriptor); + return descriptor; + } + public static ApplicationEngine Run(byte[] script, StoreView snapshot, IVerifiable container = null, Block persistingBlock = null, int offset = 0, bool testMode = false, long extraGAS = default) { @@ -129,19 +212,6 @@ public static ApplicationEngine Run(byte[] script, IVerifiable container = null, } } - internal void SendLog(UInt160 script_hash, string message) - { - LogEventArgs log = new LogEventArgs(ScriptContainer, script_hash, message); - Log?.Invoke(this, log); - } - - internal void SendNotification(UInt160 script_hash, StackItem state) - { - NotifyEventArgs notification = new NotifyEventArgs(ScriptContainer, script_hash, state); - Notify?.Invoke(this, notification); - notifications.Add(notification); - } - public bool TryPop(out string s) { if (TryPop(out ReadOnlySpan b)) diff --git a/src/neo/SmartContract/Contract.cs b/src/neo/SmartContract/Contract.cs index 32f409eab8..ca5a27b945 100644 --- a/src/neo/SmartContract/Contract.cs +++ b/src/neo/SmartContract/Contract.cs @@ -82,7 +82,7 @@ public static byte[] CreateMultiSigRedeemScript(int m, params ECPoint[] publicKe } sb.EmitPush(publicKeys.Length); sb.Emit(OpCode.PUSHNULL); - sb.EmitSysCall(InteropService.Crypto.CheckMultisigWithECDsaSecp256r1); + sb.EmitSysCall(ApplicationEngine.Neo_Crypto_CheckMultisigWithECDsaSecp256r1); return sb.ToArray(); } } @@ -102,7 +102,7 @@ public static byte[] CreateSignatureRedeemScript(ECPoint publicKey) { sb.EmitPush(publicKey.EncodePoint(true)); sb.Emit(OpCode.PUSHNULL); - sb.EmitSysCall(InteropService.Crypto.VerifyWithECDsaSecp256r1); + sb.EmitSysCall(ApplicationEngine.Neo_Crypto_VerifyWithECDsaSecp256r1); return sb.ToArray(); } } diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index c9ca603f68..fcab335b9d 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -91,7 +91,7 @@ private static bool IsMultiSigContract(byte[] script, out int m, out int n, List if (script[i++] != (byte)OpCode.PUSHNULL) return false; if (script[i++] != (byte)OpCode.SYSCALL) return false; if (script.Length != i + 4) return false; - if (BitConverter.ToUInt32(script, i) != InteropService.Crypto.CheckMultisigWithECDsaSecp256r1) + if (BitConverter.ToUInt32(script, i) != ApplicationEngine.Neo_Crypto_CheckMultisigWithECDsaSecp256r1) return false; return true; } @@ -103,7 +103,7 @@ public static bool IsSignatureContract(this byte[] script) || script[1] != 33 || script[35] != (byte)OpCode.PUSHNULL || script[36] != (byte)OpCode.SYSCALL - || BitConverter.ToUInt32(script, 37) != InteropService.Crypto.VerifyWithECDsaSecp256r1) + || BitConverter.ToUInt32(script, 37) != ApplicationEngine.Neo_Crypto_VerifyWithECDsaSecp256r1) return false; return true; } diff --git a/src/neo/SmartContract/InteropDescriptor.cs b/src/neo/SmartContract/InteropDescriptor.cs index b5efb42edd..86e4c6ba87 100644 --- a/src/neo/SmartContract/InteropDescriptor.cs +++ b/src/neo/SmartContract/InteropDescriptor.cs @@ -1,23 +1,27 @@ using Neo.Cryptography; using System; +using System.Linq; +using System.Reflection; using System.Text; namespace Neo.SmartContract { public class InteropDescriptor { - public string Method { get; } + public string Name { get; } public uint Hash { get; } - internal Func Handler { get; } + internal MethodInfo Handler { get; } + internal InteropParameterDescriptor[] Parameters { get; } public long FixedPrice { get; } public TriggerType AllowedTriggers { get; } public CallFlags RequiredCallFlags { get; } - internal InteropDescriptor(string method, Func handler, long fixedPrice, TriggerType allowedTriggers, CallFlags requiredCallFlags) + internal InteropDescriptor(string name, MethodInfo handler, long fixedPrice, TriggerType allowedTriggers, CallFlags requiredCallFlags) { - this.Method = method; - this.Hash = BitConverter.ToUInt32(Encoding.ASCII.GetBytes(method).Sha256(), 0); + this.Name = name; + this.Hash = BitConverter.ToUInt32(Encoding.ASCII.GetBytes(name).Sha256(), 0); this.Handler = handler; + this.Parameters = handler.GetParameters().Select(p => new InteropParameterDescriptor(p)).ToArray(); this.FixedPrice = fixedPrice; this.AllowedTriggers = allowedTriggers; this.RequiredCallFlags = requiredCallFlags; diff --git a/src/neo/SmartContract/InteropParameterDescriptor.cs b/src/neo/SmartContract/InteropParameterDescriptor.cs new file mode 100644 index 0000000000..e7ee51cf28 --- /dev/null +++ b/src/neo/SmartContract/InteropParameterDescriptor.cs @@ -0,0 +1,59 @@ +using Neo.Cryptography.ECC; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Neo.SmartContract +{ + internal class InteropParameterDescriptor + { + public Type Type { get; } + public Func Converter { get; } + public bool IsEnum => Type.IsEnum; + public bool IsArray => Type.IsArray && Type.GetElementType() != typeof(byte); + public bool IsInterface { get; } + + private static readonly Dictionary> converters = new Dictionary> + { + [typeof(StackItem)] = p => p, + [typeof(VM.Types.Array)] = p => p, + [typeof(InteropInterface)] = p => p, + [typeof(sbyte)] = p => (sbyte)p.GetBigInteger(), + [typeof(byte)] = p => (byte)p.GetBigInteger(), + [typeof(short)] = p => (short)p.GetBigInteger(), + [typeof(ushort)] = p => (ushort)p.GetBigInteger(), + [typeof(int)] = p => (int)p.GetBigInteger(), + [typeof(uint)] = p => (uint)p.GetBigInteger(), + [typeof(long)] = p => (long)p.GetBigInteger(), + [typeof(ulong)] = p => (ulong)p.GetBigInteger(), + [typeof(byte[])] = p => p.IsNull ? null : p.GetSpan().ToArray(), + [typeof(string)] = p => p.IsNull ? null : p.GetString(), + [typeof(UInt160)] = p => p.IsNull ? null : new UInt160(p.GetSpan()), + [typeof(UInt256)] = p => p.IsNull ? null : new UInt256(p.GetSpan()), + [typeof(ECPoint)] = p => p.IsNull ? null : ECPoint.DecodePoint(p.GetSpan(), ECCurve.Secp256r1), + }; + + public InteropParameterDescriptor(ParameterInfo parameterInfo) + { + Type = parameterInfo.ParameterType; + if (IsEnum) + { + Converter = converters[Type.GetEnumUnderlyingType()]; + } + else if (IsArray) + { + Converter = converters[Type.GetElementType()]; + } + else + { + IsInterface = !converters.TryGetValue(Type, out var converter); + if (IsInterface) + Converter = converters[typeof(InteropInterface)]; + else + Converter = converter; + } + } + } +} diff --git a/src/neo/SmartContract/InteropService.Binary.cs b/src/neo/SmartContract/InteropService.Binary.cs deleted file mode 100644 index 50d5946dbd..0000000000 --- a/src/neo/SmartContract/InteropService.Binary.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Neo.VM.Types; -using System; - -namespace Neo.SmartContract -{ - partial class InteropService - { - public static class Binary - { - public static readonly InteropDescriptor Serialize = Register("System.Binary.Serialize", Binary_Serialize, 0_00100000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor Deserialize = Register("System.Binary.Deserialize", Binary_Deserialize, 0_00500000, TriggerType.All, CallFlags.None); - - private static bool Binary_Serialize(ApplicationEngine engine) - { - if (!engine.TryPop(out StackItem item)) return false; - byte[] serialized = BinarySerializer.Serialize(item, engine.MaxItemSize); - engine.Push(serialized); - return true; - } - - private static bool Binary_Deserialize(ApplicationEngine engine) - { - if (!engine.TryPop(out ReadOnlySpan data)) return false; - StackItem item = BinarySerializer.Deserialize(data, engine.MaxStackSize, engine.MaxItemSize, engine.ReferenceCounter); - engine.CurrentContext.EvaluationStack.Push(item); - return true; - } - } - } -} diff --git a/src/neo/SmartContract/InteropService.Blockchain.cs b/src/neo/SmartContract/InteropService.Blockchain.cs deleted file mode 100644 index a8ada65f45..0000000000 --- a/src/neo/SmartContract/InteropService.Blockchain.cs +++ /dev/null @@ -1,120 +0,0 @@ -using Neo.Ledger; -using Neo.Network.P2P.Payloads; -using Neo.Persistence; -using Neo.VM; -using Neo.VM.Types; -using System; -using System.Numerics; - -namespace Neo.SmartContract -{ - partial class InteropService - { - public static class Blockchain - { - public const uint MaxTraceableBlocks = Transaction.MaxValidUntilBlockIncrement; - - public static readonly InteropDescriptor GetHeight = Register("System.Blockchain.GetHeight", Blockchain_GetHeight, 0_00000400, TriggerType.Application, CallFlags.AllowStates); - public static readonly InteropDescriptor GetBlock = Register("System.Blockchain.GetBlock", Blockchain_GetBlock, 0_02500000, TriggerType.Application, CallFlags.AllowStates); - public static readonly InteropDescriptor GetTransaction = Register("System.Blockchain.GetTransaction", Blockchain_GetTransaction, 0_01000000, TriggerType.Application, CallFlags.AllowStates); - public static readonly InteropDescriptor GetTransactionHeight = Register("System.Blockchain.GetTransactionHeight", Blockchain_GetTransactionHeight, 0_01000000, TriggerType.Application, CallFlags.AllowStates); - public static readonly InteropDescriptor GetTransactionFromBlock = Register("System.Blockchain.GetTransactionFromBlock", Blockchain_GetTransactionFromBlock, 0_01000000, TriggerType.Application, CallFlags.AllowStates); - public static readonly InteropDescriptor GetContract = Register("System.Blockchain.GetContract", Blockchain_GetContract, 0_01000000, TriggerType.Application, CallFlags.AllowStates); - - private static bool Blockchain_GetHeight(ApplicationEngine engine) - { - engine.CurrentContext.EvaluationStack.Push(engine.Snapshot.Height); - return true; - } - - private static bool Blockchain_GetBlock(ApplicationEngine engine) - { - UInt256 hash; - if (engine.TryPop(out uint height)) - { - hash = Ledger.Blockchain.Singleton.GetBlockHash(height); - } - else if (engine.TryPop(out ReadOnlySpan data)) - { - if (data.Length != 32) return false; - hash = new UInt256(data); - } - else - { - return false; - } - Block block = hash != null ? engine.Snapshot.GetBlock(hash) : null; - if (block != null && !IsTraceableBlock(engine.Snapshot, block.Index)) block = null; - engine.Push(block?.ToStackItem(engine.ReferenceCounter) ?? StackItem.Null); - return true; - } - - private static bool Blockchain_GetTransaction(ApplicationEngine engine) - { - if (!engine.TryPop(out ReadOnlySpan hash)) return false; - TransactionState state = engine.Snapshot.Transactions.TryGet(new UInt256(hash)); - if (state != null && !IsTraceableBlock(engine.Snapshot, state.BlockIndex)) state = null; - engine.Push(state?.Transaction.ToStackItem(engine.ReferenceCounter) ?? StackItem.Null); - return true; - } - - private static bool Blockchain_GetTransactionHeight(ApplicationEngine engine) - { - if (!engine.TryPop(out ReadOnlySpan hash)) return false; - TransactionState state = engine.Snapshot.Transactions.TryGet(new UInt256(hash)); - if (state != null && !IsTraceableBlock(engine.Snapshot, state.BlockIndex)) state = null; - engine.Push(state?.BlockIndex ?? BigInteger.MinusOne); - return true; - } - - private static bool Blockchain_GetTransactionFromBlock(ApplicationEngine engine) - { - UInt256 hash; - if (engine.TryPop(out uint height)) - { - hash = Ledger.Blockchain.Singleton.GetBlockHash(height); - } - else if (engine.TryPop(out ReadOnlySpan data)) - { - if (data.Length != 32) return false; - hash = new UInt256(data); - } - else - { - return false; - } - TrimmedBlock block = hash != null ? engine.Snapshot.Blocks.TryGet(hash) : null; - if (block != null && !IsTraceableBlock(engine.Snapshot, block.Index)) block = null; - if (block is null) - { - engine.Push(StackItem.Null); - } - else - { - if (!engine.TryPop(out int index)) return false; - if (index < 0 || index >= block.Hashes.Length - 1) return false; - Transaction tx = engine.Snapshot.GetTransaction(block.Hashes[index + 1]); - engine.Push(tx?.ToStackItem(engine.ReferenceCounter) ?? StackItem.Null); - } - return true; - } - - private static bool Blockchain_GetContract(ApplicationEngine engine) - { - UInt160 hash = new UInt160(engine.CurrentContext.EvaluationStack.Pop().GetSpan()); - ContractState contract = engine.Snapshot.Contracts.TryGet(hash); - if (contract == null) - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - else - engine.CurrentContext.EvaluationStack.Push(contract.ToStackItem(engine.ReferenceCounter)); - return true; - } - - private static bool IsTraceableBlock(StoreView snapshot, uint index) - { - if (index > snapshot.Height) return false; - return index + MaxTraceableBlocks > snapshot.Height; - } - } - } -} diff --git a/src/neo/SmartContract/InteropService.Contract.cs b/src/neo/SmartContract/InteropService.Contract.cs deleted file mode 100644 index fdcb7607be..0000000000 --- a/src/neo/SmartContract/InteropService.Contract.cs +++ /dev/null @@ -1,211 +0,0 @@ -using Neo.Cryptography.ECC; -using Neo.IO; -using Neo.Ledger; -using Neo.SmartContract.Manifest; -using Neo.SmartContract.Native; -using Neo.VM; -using Neo.VM.Types; -using System; -using System.Linq; -using Array = Neo.VM.Types.Array; - -namespace Neo.SmartContract -{ - partial class InteropService - { - public static class Contract - { - public const int MaxLength = 1024 * 1024; - - public static readonly InteropDescriptor Create = Register("System.Contract.Create", Contract_Create, 0, TriggerType.Application, CallFlags.AllowModifyStates); - public static readonly InteropDescriptor Update = Register("System.Contract.Update", Contract_Update, 0, TriggerType.Application, CallFlags.AllowModifyStates); - public static readonly InteropDescriptor Destroy = Register("System.Contract.Destroy", Contract_Destroy, 0_01000000, TriggerType.Application, CallFlags.AllowModifyStates); - public static readonly InteropDescriptor Call = Register("System.Contract.Call", Contract_Call, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall); - public static readonly InteropDescriptor CallEx = Register("System.Contract.CallEx", Contract_CallEx, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall); - public static readonly InteropDescriptor IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor GetCallFlags = Register("System.Contract.GetCallFlags", Contract_GetCallFlags, 0_00030000, TriggerType.All, CallFlags.None); - - /// - /// Calculate corresponding account scripthash for given public key - /// Warning: check first that input public key is valid, before creating the script. - /// - public static readonly InteropDescriptor CreateStandardAccount = Register("System.Contract.CreateStandardAccount", Contract_CreateStandardAccount, 0_00010000, TriggerType.All, CallFlags.None); - - private static bool Contract_GetCallFlags(ApplicationEngine engine) - { - var state = engine.CurrentContext.GetState(); - engine.Push((int)state.CallFlags); - return true; - } - - private static bool Contract_Create(ApplicationEngine engine) - { - if (!engine.TryPop(out ReadOnlySpan script)) return false; - if (script.Length == 0 || script.Length > MaxLength) return false; - - if (!engine.TryPop(out ReadOnlySpan manifest)) return false; - if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) return false; - - if (!engine.AddGas(Storage.GasPerByte * (script.Length + manifest.Length))) return false; - - UInt160 hash = script.ToScriptHash(); - ContractState contract = engine.Snapshot.Contracts.TryGet(hash); - if (contract != null) return false; - contract = new ContractState - { - Id = engine.Snapshot.ContractId.GetAndChange().NextId++, - Script = script.ToArray(), - Manifest = ContractManifest.Parse(manifest) - }; - - if (!contract.Manifest.IsValid(hash)) return false; - - engine.Snapshot.Contracts.Add(hash, contract); - engine.Push(StackItem.FromInterface(contract)); - return true; - } - - private static bool Contract_Update(ApplicationEngine engine) - { - if (!engine.TryPop(out StackItem item0)) return false; - if (!engine.TryPop(out StackItem item1)) return false; - - if (!engine.AddGas(Storage.GasPerByte * (item0.GetByteLength() + item1.GetByteLength()))) return false; - - var contract = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash); - if (contract is null) return false; - - if (!item0.IsNull) - { - ReadOnlySpan script = item0.GetSpan(); - if (script.Length == 0 || script.Length > MaxLength) return false; - UInt160 hash_new = script.ToScriptHash(); - if (hash_new.Equals(engine.CurrentScriptHash)) return false; - if (engine.Snapshot.Contracts.TryGet(hash_new) != null) return false; - contract = new ContractState - { - Id = contract.Id, - Script = script.ToArray(), - Manifest = contract.Manifest - }; - contract.Manifest.Abi.Hash = hash_new; - engine.Snapshot.Contracts.Add(hash_new, contract); - engine.Snapshot.Contracts.Delete(engine.CurrentScriptHash); - } - if (!item1.IsNull) - { - ReadOnlySpan manifest = item1.GetSpan(); - if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) return false; - contract = engine.Snapshot.Contracts.GetAndChange(contract.ScriptHash); - contract.Manifest = ContractManifest.Parse(manifest); - if (!contract.Manifest.IsValid(contract.ScriptHash)) return false; - if (!contract.HasStorage && engine.Snapshot.Storages.Find(BitConverter.GetBytes(contract.Id)).Any()) return false; - } - - return true; - } - - private static bool Contract_Destroy(ApplicationEngine engine) - { - UInt160 hash = engine.CurrentScriptHash; - ContractState contract = engine.Snapshot.Contracts.TryGet(hash); - if (contract == null) return true; - engine.Snapshot.Contracts.Delete(hash); - if (contract.HasStorage) - foreach (var (key, _) in engine.Snapshot.Storages.Find(BitConverter.GetBytes(contract.Id))) - engine.Snapshot.Storages.Delete(key); - return true; - } - - private static bool Contract_Call(ApplicationEngine engine) - { - if (!engine.TryPop(out ReadOnlySpan contractHash)) return false; - if (!engine.TryPop(out string method)) return false; - if (!engine.TryPop(out Array args)) return false; - - return Contract_CallEx(engine, new UInt160(contractHash), method, args, CallFlags.All); - } - - private static bool Contract_CallEx(ApplicationEngine engine) - { - if (!engine.TryPop(out ReadOnlySpan contractHash)) return false; - if (!engine.TryPop(out string method)) return false; - if (!engine.TryPop(out Array args)) return false; - if (!engine.TryPop(out int flagsValue)) return false; - - CallFlags flags = (CallFlags)flagsValue; - if ((flags & ~CallFlags.All) != 0) return false; - - return Contract_CallEx(engine, new UInt160(contractHash), method, args, flags); - } - - private static bool Contract_CallEx(ApplicationEngine engine, UInt160 contractHash, string method, Array args, CallFlags flags) - { - if (method.StartsWith('_')) return false; - - ContractState contract = engine.Snapshot.Contracts.TryGet(contractHash); - if (contract is null) return false; - - ContractManifest currentManifest = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash)?.Manifest; - - if (currentManifest != null && !currentManifest.CanCall(contract.Manifest, method)) - return false; - - if (engine.InvocationCounter.TryGetValue(contract.ScriptHash, out var counter)) - { - engine.InvocationCounter[contract.ScriptHash] = counter + 1; - } - else - { - engine.InvocationCounter[contract.ScriptHash] = 1; - } - - ExecutionContextState state = engine.CurrentContext.GetState(); - UInt160 callingScriptHash = state.ScriptHash; - CallFlags callingFlags = state.CallFlags; - - ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method); - if (md is null) return false; - int rvcount = md.ReturnType == ContractParameterType.Void ? 0 : 1; - ExecutionContext context_new = engine.LoadScript(contract.Script, rvcount); - state = context_new.GetState(); - state.CallingScriptHash = callingScriptHash; - state.CallFlags = flags & callingFlags; - - if (NativeContract.IsNative(contractHash)) - { - context_new.EvaluationStack.Push(args); - context_new.EvaluationStack.Push(method); - } - else - { - for (int i = args.Count - 1; i >= 0; i--) - context_new.EvaluationStack.Push(args[i]); - context_new.InstructionPointer = md.Offset; - } - - md = contract.Manifest.Abi.GetMethod("_initialize"); - if (md != null) engine.LoadClonedContext(md.Offset); - - return true; - } - - private static bool Contract_IsStandard(ApplicationEngine engine) - { - UInt160 hash = new UInt160(engine.CurrentContext.EvaluationStack.Pop().GetSpan()); - ContractState contract = engine.Snapshot.Contracts.TryGet(hash); - bool isStandard = contract is null || contract.Script.IsStandardContract(); - engine.CurrentContext.EvaluationStack.Push(isStandard); - return true; - } - - private static bool Contract_CreateStandardAccount(ApplicationEngine engine) - { - if (!engine.TryPop(out ReadOnlySpan pubKey)) return false; - UInt160 scriptHash = SmartContract.Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubKey, ECCurve.Secp256r1)).ToScriptHash(); - engine.Push(scriptHash.ToArray()); - return true; - } - } - } -} diff --git a/src/neo/SmartContract/InteropService.Crypto.cs b/src/neo/SmartContract/InteropService.Crypto.cs deleted file mode 100644 index 73fb99c3d2..0000000000 --- a/src/neo/SmartContract/InteropService.Crypto.cs +++ /dev/null @@ -1,144 +0,0 @@ -using Neo.Cryptography; -using Neo.Network.P2P; -using Neo.Network.P2P.Payloads; -using Neo.VM; -using Neo.VM.Types; -using System; -using System.Linq; -using Array = Neo.VM.Types.Array; - -namespace Neo.SmartContract -{ - partial class InteropService - { - public static class Crypto - { - public static readonly InteropDescriptor SHA256 = Register("Neo.Crypto.SHA256", Crypto_SHA256, 0_01000000, TriggerType.All, CallFlags.None); - - public static readonly InteropDescriptor VerifyWithECDsaSecp256r1 = Register("Neo.Crypto.ECDsa.Secp256r1.Verify", Crypto_ECDsaSecp256r1Verify, 0_01000000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor VerifyWithECDsaSecp256k1 = Register("Neo.Crypto.ECDsa.Secp256k1.Verify", Crypto_ECDsaSecp256k1Verify, 0_01000000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor CheckMultisigWithECDsaSecp256r1 = Register("Neo.Crypto.ECDsa.Secp256r1.CheckMultiSig", Crypto_ECDsaSecp256r1CheckMultiSig, 0, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor CheckMultisigWithECDsaSecp256k1 = Register("Neo.Crypto.ECDsa.Secp256k1.CheckMultiSig", Crypto_ECDsaSecp256k1CheckMultiSig, 0, TriggerType.All, CallFlags.None); - - private static bool Crypto_SHA256(ApplicationEngine engine) - { - StackItem item0 = engine.CurrentContext.EvaluationStack.Pop(); - ReadOnlySpan value = item0 switch - { - InteropInterface _interface => _interface.GetInterface().GetHashData(), - Null _ => engine.ScriptContainer.GetHashData(), - _ => item0.GetSpan() - }; - - engine.CurrentContext.EvaluationStack.Push(value.ToArray().Sha256()); - return true; - } - - private static bool Crypto_ECDsaSecp256r1Verify(ApplicationEngine engine) - { - return Crypto_ECDsaVerify(engine, Cryptography.ECC.ECCurve.Secp256r1); - } - - private static bool Crypto_ECDsaSecp256k1Verify(ApplicationEngine engine) - { - return Crypto_ECDsaVerify(engine, Cryptography.ECC.ECCurve.Secp256k1); - } - - private static bool Crypto_ECDsaVerify(ApplicationEngine engine, Cryptography.ECC.ECCurve curve) - { - StackItem item0 = engine.CurrentContext.EvaluationStack.Pop(); - ReadOnlySpan message = item0 switch - { - InteropInterface _interface => _interface.GetInterface().GetHashData(), - Null _ => engine.ScriptContainer.GetHashData(), - _ => item0.GetSpan() - }; - ReadOnlySpan pubkey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - ReadOnlySpan signature = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - try - { - engine.CurrentContext.EvaluationStack.Push(Cryptography.Crypto.VerifySignature(message, signature, pubkey, curve)); - } - catch (ArgumentException) - { - engine.CurrentContext.EvaluationStack.Push(false); - } - return true; - } - - private static bool Crypto_ECDsaSecp256r1CheckMultiSig(ApplicationEngine engine) - { - return Crypto_ECDsaCheckMultiSig(engine, Cryptography.ECC.ECCurve.Secp256r1); - } - - private static bool Crypto_ECDsaSecp256k1CheckMultiSig(ApplicationEngine engine) - { - return Crypto_ECDsaCheckMultiSig(engine, Cryptography.ECC.ECCurve.Secp256k1); - } - - private static bool Crypto_ECDsaCheckMultiSig(ApplicationEngine engine, Cryptography.ECC.ECCurve curve) - { - StackItem item0 = engine.CurrentContext.EvaluationStack.Pop(); - ReadOnlySpan message = item0 switch - { - InteropInterface _interface => _interface.GetInterface().GetHashData(), - Null _ => engine.ScriptContainer.GetHashData(), - _ => item0.GetSpan() - }; - int n; - byte[][] pubkeys; - StackItem item = engine.CurrentContext.EvaluationStack.Pop(); - if (item is Array array1) - { - pubkeys = array1.Select(p => p.GetSpan().ToArray()).ToArray(); - n = pubkeys.Length; - if (n == 0) return false; - } - else - { - n = (int)item.GetBigInteger(); - if (n < 1 || n > engine.CurrentContext.EvaluationStack.Count) return false; - pubkeys = new byte[n][]; - for (int i = 0; i < n; i++) - pubkeys[i] = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray(); - } - if (!engine.AddGas(VerifyWithECDsaSecp256r1.FixedPrice * n)) return false; - int m; - byte[][] signatures; - item = engine.CurrentContext.EvaluationStack.Pop(); - if (item is Array array2) - { - signatures = array2.Select(p => p.GetSpan().ToArray()).ToArray(); - m = signatures.Length; - if (m == 0 || m > n) return false; - } - else - { - m = (int)item.GetBigInteger(); - if (m < 1 || m > n || m > engine.CurrentContext.EvaluationStack.Count) return false; - signatures = new byte[m][]; - for (int i = 0; i < m; i++) - signatures[i] = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray(); - } - bool fSuccess = true; - try - { - for (int i = 0, j = 0; fSuccess && i < m && j < n;) - { - if (Cryptography.Crypto.VerifySignature(message, signatures[i], pubkeys[j], curve)) - i++; - j++; - if (m - i > n - j) - fSuccess = false; - } - } - catch (ArgumentException) - { - fSuccess = false; - } - engine.CurrentContext.EvaluationStack.Push(fSuccess); - return true; - } - } - } -} diff --git a/src/neo/SmartContract/InteropService.Enumerator.cs b/src/neo/SmartContract/InteropService.Enumerator.cs deleted file mode 100644 index 444dda80a2..0000000000 --- a/src/neo/SmartContract/InteropService.Enumerator.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Neo.SmartContract.Enumerators; -using Neo.SmartContract.Iterators; -using Neo.VM.Types; -using Array = Neo.VM.Types.Array; - -namespace Neo.SmartContract -{ - partial class InteropService - { - public static class Enumerator - { - public static readonly InteropDescriptor Create = Register("System.Enumerator.Create", Enumerator_Create, 0_00000400, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor Next = Register("System.Enumerator.Next", Enumerator_Next, 0_01000000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor Value = Register("System.Enumerator.Value", Enumerator_Value, 0_00000400, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor Concat = Register("System.Enumerator.Concat", Enumerator_Concat, 0_00000400, TriggerType.All, CallFlags.None); - - private static bool Enumerator_Create(ApplicationEngine engine) - { - IEnumerator enumerator; - switch (engine.CurrentContext.EvaluationStack.Pop()) - { - case Array array: - enumerator = new ArrayWrapper(array); - break; - case PrimitiveType primitive: - enumerator = new ByteArrayWrapper(primitive); - break; - default: - return false; - } - engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(enumerator)); - return true; - } - - private static bool Enumerator_Next(ApplicationEngine engine) - { - if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) - { - IEnumerator enumerator = _interface.GetInterface(); - engine.CurrentContext.EvaluationStack.Push(enumerator.Next()); - return true; - } - return false; - } - - private static bool Enumerator_Value(ApplicationEngine engine) - { - if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) - { - IEnumerator enumerator = _interface.GetInterface(); - engine.CurrentContext.EvaluationStack.Push(enumerator.Value()); - return true; - } - return false; - } - - private static bool Enumerator_Concat(ApplicationEngine engine) - { - if (!(engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface1)) return false; - if (!(engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface2)) return false; - IEnumerator first = _interface1.GetInterface(); - IEnumerator second = _interface2.GetInterface(); - IEnumerator result = new ConcatenatedEnumerator(first, second); - engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(result)); - return true; - } - } - } -} diff --git a/src/neo/SmartContract/InteropService.Iterator.cs b/src/neo/SmartContract/InteropService.Iterator.cs deleted file mode 100644 index 590b298eb0..0000000000 --- a/src/neo/SmartContract/InteropService.Iterator.cs +++ /dev/null @@ -1,84 +0,0 @@ -using Neo.SmartContract.Enumerators; -using Neo.SmartContract.Iterators; -using Neo.VM.Types; -using Array = Neo.VM.Types.Array; - -namespace Neo.SmartContract -{ - partial class InteropService - { - public static class Iterator - { - public static readonly InteropDescriptor Create = Register("System.Iterator.Create", Iterator_Create, 0_00000400, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor Key = Register("System.Iterator.Key", Iterator_Key, 0_00000400, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor Keys = Register("System.Iterator.Keys", Iterator_Keys, 0_00000400, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor Values = Register("System.Iterator.Values", Iterator_Values, 0_00000400, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor Concat = Register("System.Iterator.Concat", Iterator_Concat, 0_00000400, TriggerType.All, CallFlags.None); - - private static bool Iterator_Create(ApplicationEngine engine) - { - IIterator iterator; - switch (engine.CurrentContext.EvaluationStack.Pop()) - { - case Array array: - iterator = new ArrayWrapper(array); - break; - case Map map: - iterator = new MapWrapper(map); - break; - case PrimitiveType primitive: - iterator = new ByteArrayWrapper(primitive); - break; - default: - return false; - } - engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(iterator)); - return true; - } - - private static bool Iterator_Key(ApplicationEngine engine) - { - if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) - { - IIterator iterator = _interface.GetInterface(); - engine.CurrentContext.EvaluationStack.Push(iterator.Key()); - return true; - } - return false; - } - - private static bool Iterator_Keys(ApplicationEngine engine) - { - if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) - { - IIterator iterator = _interface.GetInterface(); - engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new IteratorKeysWrapper(iterator))); - return true; - } - return false; - } - - private static bool Iterator_Values(ApplicationEngine engine) - { - if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) - { - IIterator iterator = _interface.GetInterface(); - engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new IteratorValuesWrapper(iterator))); - return true; - } - return false; - } - - private static bool Iterator_Concat(ApplicationEngine engine) - { - if (!(engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface1)) return false; - if (!(engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface2)) return false; - IIterator first = _interface1.GetInterface(); - IIterator second = _interface2.GetInterface(); - IIterator result = new ConcatenatedIterator(first, second); - engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(result)); - return true; - } - } - } -} diff --git a/src/neo/SmartContract/InteropService.Json.cs b/src/neo/SmartContract/InteropService.Json.cs deleted file mode 100644 index 262fbe2e9a..0000000000 --- a/src/neo/SmartContract/InteropService.Json.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Neo.IO.Json; -using Neo.VM.Types; -using System; - -namespace Neo.SmartContract -{ - partial class InteropService - { - public static class Json - { - public static readonly InteropDescriptor Serialize = Register("System.Json.Serialize", Json_Serialize, 0_00100000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor Deserialize = Register("System.Json.Deserialize", Json_Deserialize, 0_00500000, TriggerType.All, CallFlags.None); - - private static bool Json_Serialize(ApplicationEngine engine) - { - if (!engine.TryPop(out StackItem item)) return false; - byte[] json = JsonSerializer.SerializeToByteArray(item, engine.MaxItemSize); - engine.Push(json); - return true; - } - - private static bool Json_Deserialize(ApplicationEngine engine) - { - if (!engine.TryPop(out ReadOnlySpan json)) return false; - StackItem item = JsonSerializer.Deserialize(JObject.Parse(json, 10), engine.ReferenceCounter); - engine.Push(item); - return true; - } - } - } -} diff --git a/src/neo/SmartContract/InteropService.Native.cs b/src/neo/SmartContract/InteropService.Native.cs deleted file mode 100644 index 62c3970647..0000000000 --- a/src/neo/SmartContract/InteropService.Native.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Neo.Ledger; -using Neo.SmartContract.Native; - -namespace Neo.SmartContract -{ - partial class InteropService - { - internal static class Native - { - public static readonly InteropDescriptor Deploy = Register("Neo.Native.Deploy", Native_Deploy, 0, TriggerType.Application, CallFlags.AllowModifyStates); - public static readonly InteropDescriptor Call = Register("Neo.Native.Call", Native_Call, 0, TriggerType.System | TriggerType.Application, CallFlags.None); - - private static bool Native_Deploy(ApplicationEngine engine) - { - if (engine.Snapshot.PersistingBlock.Index != 0) return false; - foreach (NativeContract contract in NativeContract.Contracts) - { - engine.Snapshot.Contracts.Add(contract.Hash, new ContractState - { - Id = contract.Id, - Script = contract.Script, - Manifest = contract.Manifest - }); - contract.Initialize(engine); - } - return true; - } - - private static bool Native_Call(ApplicationEngine engine) - { - if (!engine.TryPop(out string name)) return false; - NativeContract contract = NativeContract.GetContract(name); - if (contract is null) return false; - contract.Invoke(engine); - return true; - } - } - } -} diff --git a/src/neo/SmartContract/InteropService.Runtime.cs b/src/neo/SmartContract/InteropService.Runtime.cs deleted file mode 100644 index ff58e0a897..0000000000 --- a/src/neo/SmartContract/InteropService.Runtime.cs +++ /dev/null @@ -1,222 +0,0 @@ -using Neo.Cryptography.ECC; -using Neo.IO; -using Neo.Network.P2P.Payloads; -using Neo.VM; -using Neo.VM.Types; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Array = Neo.VM.Types.Array; - -namespace Neo.SmartContract -{ - partial class InteropService - { - public static class Runtime - { - public const int MaxNotificationSize = 1024; - - public static readonly InteropDescriptor Platform = Register("System.Runtime.Platform", Runtime_Platform, 0_00000250, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor GetTrigger = Register("System.Runtime.GetTrigger", Runtime_GetTrigger, 0_00000250, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor GetTime = Register("System.Runtime.GetTime", Runtime_GetTime, 0_00000250, TriggerType.Application, CallFlags.AllowStates); - public static readonly InteropDescriptor GetScriptContainer = Register("System.Runtime.GetScriptContainer", Runtime_GetScriptContainer, 0_00000250, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor GetExecutingScriptHash = Register("System.Runtime.GetExecutingScriptHash", Runtime_GetExecutingScriptHash, 0_00000400, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor GetCallingScriptHash = Register("System.Runtime.GetCallingScriptHash", Runtime_GetCallingScriptHash, 0_00000400, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor GetEntryScriptHash = Register("System.Runtime.GetEntryScriptHash", Runtime_GetEntryScriptHash, 0_00000400, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor CheckWitness = Register("System.Runtime.CheckWitness", Runtime_CheckWitness, 0_00030000, TriggerType.All, CallFlags.AllowStates); - public static readonly InteropDescriptor GetInvocationCounter = Register("System.Runtime.GetInvocationCounter", Runtime_GetInvocationCounter, 0_00000400, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor Log = Register("System.Runtime.Log", Runtime_Log, 0_01000000, TriggerType.All, CallFlags.AllowNotify); - public static readonly InteropDescriptor Notify = Register("System.Runtime.Notify", Runtime_Notify, 0_01000000, TriggerType.All, CallFlags.AllowNotify); - public static readonly InteropDescriptor GetNotifications = Register("System.Runtime.GetNotifications", Runtime_GetNotifications, 0_00010000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor GasLeft = Register("System.Runtime.GasLeft", Runtime_GasLeft, 0_00000400, TriggerType.All, CallFlags.None); - - private static bool CheckItemForNotification(StackItem state) - { - int size = 0; - List items_checked = new List(); - Queue items_unchecked = new Queue(); - while (true) - { - switch (state) - { - case Struct array: - foreach (StackItem item in array) - items_unchecked.Enqueue(item); - break; - case Array array: - if (items_checked.All(p => !ReferenceEquals(p, array))) - { - items_checked.Add(array); - foreach (StackItem item in array) - items_unchecked.Enqueue(item); - } - break; - case PrimitiveType primitive: - size += primitive.Size; - break; - case Null _: - break; - case InteropInterface _: - return false; - case Map map: - if (items_checked.All(p => !ReferenceEquals(p, map))) - { - items_checked.Add(map); - foreach (var pair in map) - { - size += pair.Key.Size; - items_unchecked.Enqueue(pair.Value); - } - } - break; - } - if (size > MaxNotificationSize) return false; - if (items_unchecked.Count == 0) return true; - state = items_unchecked.Dequeue(); - } - } - - internal static bool CheckWitnessInternal(ApplicationEngine engine, UInt160 hash) - { - if (engine.ScriptContainer is Transaction tx) - { - Cosigner cosigner = tx.Cosigners.FirstOrDefault(p => p.Account.Equals(hash)); - if (cosigner is null) return false; - if (cosigner.Scopes == WitnessScope.Global) return true; - if (cosigner.Scopes.HasFlag(WitnessScope.CalledByEntry)) - { - if (engine.CallingScriptHash == engine.EntryScriptHash) - return true; - } - if (cosigner.Scopes.HasFlag(WitnessScope.CustomContracts)) - { - if (cosigner.AllowedContracts.Contains(engine.CurrentScriptHash)) - return true; - } - if (cosigner.Scopes.HasFlag(WitnessScope.CustomGroups)) - { - var contract = engine.Snapshot.Contracts[engine.CallingScriptHash]; - // check if current group is the required one - if (contract.Manifest.Groups.Select(p => p.PubKey).Intersect(cosigner.AllowedGroups).Any()) - return true; - } - return false; - } - - // only for non-Transaction types (Block, etc) - - var hashes_for_verifying = engine.ScriptContainer.GetScriptHashesForVerifying(engine.Snapshot); - return hashes_for_verifying.Contains(hash); - } - - private static bool Runtime_Platform(ApplicationEngine engine) - { - engine.CurrentContext.EvaluationStack.Push(Encoding.ASCII.GetBytes("NEO")); - return true; - } - - private static bool Runtime_GetTrigger(ApplicationEngine engine) - { - engine.CurrentContext.EvaluationStack.Push((int)engine.Trigger); - return true; - } - - private static bool Runtime_GetTime(ApplicationEngine engine) - { - engine.CurrentContext.EvaluationStack.Push(engine.Snapshot.PersistingBlock.Timestamp); - return true; - } - - private static bool Runtime_GetScriptContainer(ApplicationEngine engine) - { - engine.CurrentContext.EvaluationStack.Push( - engine.ScriptContainer is IInteroperable value ? value.ToStackItem(engine.ReferenceCounter) : - StackItem.FromInterface(engine.ScriptContainer)); - return true; - } - - private static bool Runtime_GetExecutingScriptHash(ApplicationEngine engine) - { - engine.CurrentContext.EvaluationStack.Push(engine.CurrentScriptHash.ToArray()); - return true; - } - - private static bool Runtime_GetCallingScriptHash(ApplicationEngine engine) - { - engine.CurrentContext.EvaluationStack.Push(engine.CallingScriptHash?.ToArray() ?? StackItem.Null); - return true; - } - - private static bool Runtime_GetEntryScriptHash(ApplicationEngine engine) - { - engine.CurrentContext.EvaluationStack.Push(engine.EntryScriptHash.ToArray()); - return true; - } - - private static bool Runtime_CheckWitness(ApplicationEngine engine) - { - ReadOnlySpan hashOrPubkey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - UInt160 hash = hashOrPubkey.Length switch - { - 20 => new UInt160(hashOrPubkey), - 33 => SmartContract.Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(hashOrPubkey, ECCurve.Secp256r1)).ToScriptHash(), - _ => null - }; - if (hash is null) return false; - engine.CurrentContext.EvaluationStack.Push(CheckWitnessInternal(engine, hash)); - return true; - } - - private static bool Runtime_GasLeft(ApplicationEngine engine) - { - engine.Push(engine.GasLeft); - return true; - } - - private static bool Runtime_GetInvocationCounter(ApplicationEngine engine) - { - if (!engine.InvocationCounter.TryGetValue(engine.CurrentScriptHash, out var counter)) - { - return false; - } - - engine.CurrentContext.EvaluationStack.Push(counter); - return true; - } - - private static bool Runtime_Log(ApplicationEngine engine) - { - ReadOnlySpan state = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - if (state.Length > MaxNotificationSize) return false; - string message = Encoding.UTF8.GetString(state); - engine.SendLog(engine.CurrentScriptHash, message); - return true; - } - - private static bool Runtime_Notify(ApplicationEngine engine) - { - StackItem state = engine.CurrentContext.EvaluationStack.Pop(); - if (!CheckItemForNotification(state)) return false; - engine.SendNotification(engine.CurrentScriptHash, state); - return true; - } - - private static bool Runtime_GetNotifications(ApplicationEngine engine) - { - StackItem item = engine.CurrentContext.EvaluationStack.Pop(); - - IEnumerable notifications = engine.Notifications; - if (!item.IsNull) // must filter by scriptHash - { - var hash = new UInt160(item.GetSpan()); - notifications = notifications.Where(p => p.ScriptHash == hash); - } - - if (notifications.Count() > engine.MaxStackSize) return false; - engine.Push(new Array(engine.ReferenceCounter, notifications.Select(u => new Array(engine.ReferenceCounter, new[] { u.ScriptHash.ToArray(), u.State })))); - return true; - } - } - } -} diff --git a/src/neo/SmartContract/InteropService.Storage.cs b/src/neo/SmartContract/InteropService.Storage.cs deleted file mode 100644 index 0525b9a774..0000000000 --- a/src/neo/SmartContract/InteropService.Storage.cs +++ /dev/null @@ -1,175 +0,0 @@ -using Neo.Ledger; -using Neo.SmartContract.Iterators; -using Neo.VM; -using Neo.VM.Types; -using System; -using System.Linq; - -namespace Neo.SmartContract -{ - partial class InteropService - { - public static class Storage - { - public const long GasPerByte = 100000; - public const int MaxKeySize = 64; - public const int MaxValueSize = ushort.MaxValue; - - public static readonly InteropDescriptor GetContext = Register("System.Storage.GetContext", Storage_GetContext, 0_00000400, TriggerType.Application, CallFlags.AllowStates); - public static readonly InteropDescriptor GetReadOnlyContext = Register("System.Storage.GetReadOnlyContext", Storage_GetReadOnlyContext, 0_00000400, TriggerType.Application, CallFlags.AllowStates); - public static readonly InteropDescriptor AsReadOnly = Register("System.Storage.AsReadOnly", Storage_AsReadOnly, 0_00000400, TriggerType.Application, CallFlags.AllowStates); - public static readonly InteropDescriptor Get = Register("System.Storage.Get", Storage_Get, 0_01000000, TriggerType.Application, CallFlags.AllowStates); - public static readonly InteropDescriptor Find = Register("System.Storage.Find", Storage_Find, 0_01000000, TriggerType.Application, CallFlags.AllowStates); - public static readonly InteropDescriptor Put = Register("System.Storage.Put", Storage_Put, 0, TriggerType.Application, CallFlags.AllowModifyStates); - public static readonly InteropDescriptor PutEx = Register("System.Storage.PutEx", Storage_PutEx, 0, TriggerType.Application, CallFlags.AllowModifyStates); - public static readonly InteropDescriptor Delete = Register("System.Storage.Delete", Storage_Delete, 1 * GasPerByte, TriggerType.Application, CallFlags.AllowModifyStates); - - private static bool PutExInternal(ApplicationEngine engine, StorageContext context, byte[] key, byte[] value, StorageFlags flags) - { - if (key.Length > MaxKeySize) return false; - if (value.Length > MaxValueSize) return false; - if (context.IsReadOnly) return false; - - int newDataSize; - StorageKey skey = new StorageKey - { - Id = context.Id, - Key = key - }; - StorageItem item = engine.Snapshot.Storages.GetAndChange(skey); - if (item is null) - { - newDataSize = key.Length + value.Length; - engine.Snapshot.Storages.Add(skey, item = new StorageItem()); - } - else - { - if (item.IsConstant) return false; - if (value.Length <= item.Value.Length) - newDataSize = 1; - else - newDataSize = value.Length - item.Value.Length; - } - if (!engine.AddGas(newDataSize * GasPerByte)) return false; - - item.Value = value; - item.IsConstant = flags.HasFlag(StorageFlags.Constant); - - return true; - } - - private static bool Storage_GetContext(ApplicationEngine engine) - { - ContractState contract = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash); - if (contract == null) return false; - if (!contract.HasStorage) return false; - engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new StorageContext - { - Id = contract.Id, - IsReadOnly = false - })); - return true; - } - - private static bool Storage_GetReadOnlyContext(ApplicationEngine engine) - { - ContractState contract = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash); - if (contract == null) return false; - if (!contract.HasStorage) return false; - engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new StorageContext - { - Id = contract.Id, - IsReadOnly = true - })); - return true; - } - - private static bool Storage_AsReadOnly(ApplicationEngine engine) - { - if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) - { - StorageContext context = _interface.GetInterface(); - if (!context.IsReadOnly) - context = new StorageContext - { - Id = context.Id, - IsReadOnly = true - }; - engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(context)); - return true; - } - return false; - } - - private static bool Storage_Get(ApplicationEngine engine) - { - if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) - { - StorageContext context = _interface.GetInterface(); - byte[] key = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray(); - StorageItem item = engine.Snapshot.Storages.TryGet(new StorageKey - { - Id = context.Id, - Key = key - }); - engine.CurrentContext.EvaluationStack.Push(item?.Value ?? StackItem.Null); - return true; - } - return false; - } - - private static bool Storage_Find(ApplicationEngine engine) - { - if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) - { - StorageContext context = _interface.GetInterface(); - byte[] prefix = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray(); - byte[] prefix_key = StorageKey.CreateSearchPrefix(context.Id, prefix); - StorageIterator iterator = engine.AddDisposable(new StorageIterator(engine.Snapshot.Storages.Find(prefix_key).Where(p => p.Key.Key.AsSpan().StartsWith(prefix)).GetEnumerator())); - engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(iterator)); - return true; - } - return false; - } - - private static bool Storage_Put(ApplicationEngine engine) - { - if (!(engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface)) - return false; - StorageContext context = _interface.GetInterface(); - byte[] key = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray(); - byte[] value = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray(); - return PutExInternal(engine, context, key, value, StorageFlags.None); - } - - private static bool Storage_PutEx(ApplicationEngine engine) - { - if (!(engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface)) - return false; - StorageContext context = _interface.GetInterface(); - byte[] key = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray(); - byte[] value = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray(); - StorageFlags flags = (StorageFlags)(byte)engine.CurrentContext.EvaluationStack.Pop().GetBigInteger(); - return PutExInternal(engine, context, key, value, flags); - } - - private static bool Storage_Delete(ApplicationEngine engine) - { - if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) - { - StorageContext context = _interface.GetInterface(); - if (context.IsReadOnly) return false; - StorageKey key = new StorageKey - { - Id = context.Id, - Key = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray() - }; - if (engine.Snapshot.Storages.TryGet(key)?.IsConstant == true) return false; - engine.Snapshot.Storages.Delete(key); - return true; - } - return false; - } - } - } -} diff --git a/src/neo/SmartContract/InteropService.cs b/src/neo/SmartContract/InteropService.cs deleted file mode 100644 index e4a399bf94..0000000000 --- a/src/neo/SmartContract/InteropService.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace Neo.SmartContract -{ - public static partial class InteropService - { - private static readonly Dictionary methods = new Dictionary(); - - static InteropService() - { - foreach (Type t in typeof(InteropService).GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)) - t.GetFields()[0].GetValue(null); - } - - public static IEnumerable SupportedMethods() - { - return methods.Values; - } - - internal static bool Invoke(ApplicationEngine engine, uint method) - { - if (!methods.TryGetValue(method, out InteropDescriptor descriptor)) - return false; - if (!descriptor.AllowedTriggers.HasFlag(engine.Trigger)) - return false; - ExecutionContextState state = engine.CurrentContext.GetState(); - if (!state.CallFlags.HasFlag(descriptor.RequiredCallFlags)) - return false; - if (!engine.AddGas(descriptor.FixedPrice)) - return false; - return descriptor.Handler(engine); - } - - private static InteropDescriptor Register(string method, Func handler, long price, TriggerType allowedTriggers, CallFlags requiredCallFlags) - { - InteropDescriptor descriptor = new InteropDescriptor(method, handler, price, allowedTriggers, requiredCallFlags); - methods.Add(descriptor.Hash, descriptor); - return descriptor; - } - } -} diff --git a/src/neo/SmartContract/Native/NativeContract.cs b/src/neo/SmartContract/Native/NativeContract.cs index 81d8b499ab..c42d7eb439 100644 --- a/src/neo/SmartContract/Native/NativeContract.cs +++ b/src/neo/SmartContract/Native/NativeContract.cs @@ -38,7 +38,7 @@ protected NativeContract() using (ScriptBuilder sb = new ScriptBuilder()) { sb.EmitPush(Name); - sb.EmitSysCall(InteropService.Native.Call); + sb.EmitSysCall(ApplicationEngine.Neo_Native_Call); this.Script = sb.ToArray(); } this.Hash = Script.ToScriptHash(); @@ -135,11 +135,8 @@ public static bool IsNative(UInt160 hash) return contractsHashDictionary.ContainsKey(hash); } - internal virtual bool Initialize(ApplicationEngine engine) + internal virtual void Initialize(ApplicationEngine engine) { - if (engine.Trigger != TriggerType.Application) - throw new InvalidOperationException(); - return true; } [ContractMethod(0, ContractParameterType.Boolean, CallFlags.AllowModifyStates)] diff --git a/src/neo/SmartContract/Native/PolicyContract.cs b/src/neo/SmartContract/Native/PolicyContract.cs index 552227f7be..2bd2244a96 100644 --- a/src/neo/SmartContract/Native/PolicyContract.cs +++ b/src/neo/SmartContract/Native/PolicyContract.cs @@ -41,12 +41,11 @@ internal bool CheckPolicy(Transaction tx, StoreView snapshot) private bool CheckCommittees(ApplicationEngine engine) { UInt160 committeeMultiSigAddr = NEO.GetCommitteeAddress(engine.Snapshot); - return InteropService.Runtime.CheckWitnessInternal(engine, committeeMultiSigAddr); + return engine.CheckWitnessInternal(committeeMultiSigAddr); } - internal override bool Initialize(ApplicationEngine engine) + internal override void Initialize(ApplicationEngine engine) { - if (!base.Initialize(engine)) return false; engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_MaxBlockSize), new StorageItem { Value = BitConverter.GetBytes(1024u * 256u) @@ -63,7 +62,6 @@ internal override bool Initialize(ApplicationEngine engine) { Value = new UInt160[0].ToByteArray() }); - return true; } [ContractMethod(0_01000000, ContractParameterType.Integer, CallFlags.AllowStates)] diff --git a/src/neo/SmartContract/Native/Tokens/GasToken.cs b/src/neo/SmartContract/Native/Tokens/GasToken.cs index 09c2ab1127..4a8cd5e1bf 100644 --- a/src/neo/SmartContract/Native/Tokens/GasToken.cs +++ b/src/neo/SmartContract/Native/Tokens/GasToken.cs @@ -4,7 +4,6 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using System.Linq; -using System.Numerics; namespace Neo.SmartContract.Native.Tokens { @@ -19,13 +18,10 @@ internal GasToken() { } - internal override bool Initialize(ApplicationEngine engine) + internal override void Initialize(ApplicationEngine engine) { - if (!base.Initialize(engine)) return false; - if (TotalSupply(engine.Snapshot) != BigInteger.Zero) return false; UInt160 account = Blockchain.GetConsensusAddress(Blockchain.StandbyValidators); Mint(engine, account, 30_000_000 * Factor); - return true; } protected override bool OnPersist(ApplicationEngine engine) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 8005d054ba..1c63485b5c 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -87,10 +87,8 @@ private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint sta return value * amount * GAS.Factor / TotalAmount; } - internal override bool Initialize(ApplicationEngine engine) + internal override void Initialize(ApplicationEngine engine) { - if (!base.Initialize(engine)) return false; - if (base.TotalSupply(engine.Snapshot) != BigInteger.Zero) return false; BigInteger amount = TotalAmount; for (int i = 0; i < Blockchain.StandbyCommittee.Length; i++) { @@ -104,7 +102,6 @@ internal override bool Initialize(ApplicationEngine engine) amount -= balance; } Mint(engine, Blockchain.GetConsensusAddress(Blockchain.StandbyValidators), amount); - return true; } protected override bool OnPersist(ApplicationEngine engine) @@ -135,7 +132,7 @@ public BigInteger UnclaimedGas(StoreView snapshot, UInt160 account, uint end) private StackItem RegisterCandidate(ApplicationEngine engine, Array args) { ECPoint pubkey = args[0].GetSpan().AsSerializable(); - if (!InteropService.Runtime.CheckWitnessInternal(engine, Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) + if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) return false; return RegisterCandidate(engine.Snapshot, pubkey); } @@ -153,7 +150,7 @@ private bool RegisterCandidate(StoreView snapshot, ECPoint pubkey) private StackItem UnregisterCandidate(ApplicationEngine engine, Array args) { ECPoint pubkey = args[0].GetSpan().AsSerializable(); - if (!InteropService.Runtime.CheckWitnessInternal(engine, Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) + if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) return false; return UnregisterCandidate(engine.Snapshot, pubkey); } @@ -176,7 +173,7 @@ private StackItem Vote(ApplicationEngine engine, Array args) { UInt160 account = new UInt160(args[0].GetSpan()); ECPoint voteTo = args[1].IsNull ? null : args[1].GetSpan().AsSerializable(); - if (!InteropService.Runtime.CheckWitnessInternal(engine, account)) return false; + if (!engine.CheckWitnessInternal(account)) return false; return Vote(engine.Snapshot, account, voteTo); } diff --git a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs index 045db4e4b5..855d864c59 100644 --- a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs +++ b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs @@ -159,7 +159,7 @@ protected StackItem Transfer(ApplicationEngine engine, Array args) protected virtual bool Transfer(ApplicationEngine engine, UInt160 from, UInt160 to, BigInteger amount) { if (amount.Sign < 0) throw new ArgumentOutOfRangeException(nameof(amount)); - if (!from.Equals(engine.CallingScriptHash) && !InteropService.Runtime.CheckWitnessInternal(engine, from)) + if (!from.Equals(engine.CallingScriptHash) && !engine.CheckWitnessInternal(from)) return false; ContractState contract_to = engine.Snapshot.Contracts.TryGet(to); if (contract_to?.Payable == false) return false; diff --git a/src/neo/SmartContract/NotifyEventArgs.cs b/src/neo/SmartContract/NotifyEventArgs.cs index e1d3fd8c1e..7b52c2a570 100644 --- a/src/neo/SmartContract/NotifyEventArgs.cs +++ b/src/neo/SmartContract/NotifyEventArgs.cs @@ -1,10 +1,13 @@ +using Neo.IO; using Neo.Network.P2P.Payloads; +using Neo.VM; using Neo.VM.Types; using System; +using Array = Neo.VM.Types.Array; namespace Neo.SmartContract { - public class NotifyEventArgs : EventArgs + public class NotifyEventArgs : EventArgs, IInteroperable { public IVerifiable ScriptContainer { get; } public UInt160 ScriptHash { get; } @@ -16,5 +19,15 @@ public NotifyEventArgs(IVerifiable container, UInt160 script_hash, StackItem sta this.ScriptHash = script_hash; this.State = state; } + + public void FromStackItem(StackItem stackItem) + { + throw new NotSupportedException(); + } + + public StackItem ToStackItem(ReferenceCounter referenceCounter) + { + return new Array(referenceCounter, new[] { ScriptHash.ToArray(), State }); + } } } diff --git a/src/neo/VM/Helper.cs b/src/neo/VM/Helper.cs index eaed72fb31..c99ad135f2 100644 --- a/src/neo/VM/Helper.cs +++ b/src/neo/VM/Helper.cs @@ -29,7 +29,7 @@ public static ScriptBuilder EmitAppCall(this ScriptBuilder sb, UInt160 scriptHas sb.Emit(OpCode.NEWARRAY); sb.EmitPush(operation); sb.EmitPush(scriptHash); - sb.EmitSysCall(InteropService.Contract.Call); + sb.EmitSysCall(ApplicationEngine.System_Contract_Call); return sb; } @@ -41,7 +41,7 @@ public static ScriptBuilder EmitAppCall(this ScriptBuilder sb, UInt160 scriptHas sb.Emit(OpCode.PACK); sb.EmitPush(operation); sb.EmitPush(scriptHash); - sb.EmitSysCall(InteropService.Contract.Call); + sb.EmitSysCall(ApplicationEngine.System_Contract_Call); return sb; } @@ -53,7 +53,7 @@ public static ScriptBuilder EmitAppCall(this ScriptBuilder sb, UInt160 scriptHas sb.Emit(OpCode.PACK); sb.EmitPush(operation); sb.EmitPush(scriptHash); - sb.EmitSysCall(InteropService.Contract.Call); + sb.EmitSysCall(ApplicationEngine.System_Contract_Call); return sb; } diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 2d4f6167cf..def6977959 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -356,7 +356,7 @@ public static long CalculateNetworkFee(byte[] witness_script, ref int size) if (witness_script.IsSignatureContract()) { size += 67 + witness_script.GetVarSize(); - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.Crypto.VerifyWithECDsaSecp256r1.FixedPrice; + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + ApplicationEngine.ECDsaVerifyPrice; } else if (witness_script.IsMultiSigContract(out int m, out int n)) { @@ -368,7 +368,7 @@ public static long CalculateNetworkFee(byte[] witness_script, ref int size) networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * n; using (ScriptBuilder sb = new ScriptBuilder()) networkFee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(n).ToArray()[0]]; - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.Crypto.VerifyWithECDsaSecp256r1.FixedPrice * n; + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + ApplicationEngine.ECDsaVerifyPrice * n; } else { diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index ee26c3ca85..86eb6bc8c2 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -154,8 +154,8 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Contract originalContract = Contract.CreateMultiSigContract(mockContext.Object.M, mockContext.Object.Validators); Console.WriteLine($"\nORIGINAL Contract is: {originalContract.ScriptHash}"); Console.WriteLine($"ORIGINAL NextConsensus: {mockContext.Object.Block.NextConsensus}\nENSURING values..."); - originalContract.ScriptHash.Should().Be(UInt160.Parse("0x7ab841144dcdbf228ff57f7068f795e2afd1a3c1")); - mockContext.Object.Block.NextConsensus.Should().Be(UInt160.Parse("0x7ab841144dcdbf228ff57f7068f795e2afd1a3c1")); + originalContract.ScriptHash.Should().Be(UInt160.Parse("0xe239c7228fa6b46cc0cf43623b2f934301d0b4f7")); + mockContext.Object.Block.NextConsensus.Should().Be(UInt160.Parse("0xe239c7228fa6b46cc0cf43623b2f934301d0b4f7")); Console.WriteLine("\n=========================="); Console.WriteLine("will trigger OnPersistCompleted again with OnStart flag!"); @@ -176,7 +176,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine("will create template MakePrepareRequest..."); mockContext.Object.PrevHeader.Timestamp = defaultTimestamp; - mockContext.Object.PrevHeader.NextConsensus.Should().Be(UInt160.Parse("0x7ab841144dcdbf228ff57f7068f795e2afd1a3c1")); + mockContext.Object.PrevHeader.NextConsensus.Should().Be(UInt160.Parse("0xe239c7228fa6b46cc0cf43623b2f934301d0b4f7")); var prepReq = mockContext.Object.MakePrepareRequest(); var ppToSend = (PrepareRequest)prepReq.ConsensusMessage; // Forcing hashes to 0 because mempool is currently shared diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index f672c2a707..7e04dfe229 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -73,13 +73,13 @@ public void TestContainsTransaction() [TestMethod] public void TestGetCurrentBlockHash() { - Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0x557f5c9d0c865a211a749899681e5b4fbf745b3bcf0c395e6d6a7f1edb0d86f1")); + Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0x3843c6d0dd2082a801cf3da0fe0e847ba8d5571e0606c5018f9a35ce49c55e18")); } [TestMethod] public void TestGetCurrentHeaderHash() { - Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0x557f5c9d0c865a211a749899681e5b4fbf745b3bcf0c395e6d6a7f1edb0d86f1")); + Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0x3843c6d0dd2082a801cf3da0fe0e847ba8d5571e0606c5018f9a35ce49c55e18")); } [TestMethod] @@ -91,7 +91,7 @@ public void TestGetBlock() [TestMethod] public void TestGetBlockHash() { - Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0x557f5c9d0c865a211a749899681e5b4fbf745b3bcf0c395e6d6a7f1edb0d86f1")); + Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0x3843c6d0dd2082a801cf3da0fe0e847ba8d5571e0606c5018f9a35ce49c55e18")); Blockchain.Singleton.GetBlockHash(10).Should().BeNull(); } diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index aa478633c1..f7be52f9a6 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -46,7 +46,6 @@ public void Check_BalanceOfTransferAndBurn() var keyCount = snapshot.Storages.GetChangeSet().Count(); - NativeContract.NEO.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); var supply = NativeContract.GAS.TotalSupply(snapshot); supply.Should().Be(3000000000000000); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 37b5bc51e3..12b025400b 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -203,22 +203,7 @@ public void Check_Initialize() // StandbyValidators - var validators = Check_GetValidators(snapshot); - - for (var x = 0; x < Blockchain.StandbyValidators.Length; x++) - { - validators[x].Equals(Blockchain.StandbyValidators[x]); - } - - // Check double call - - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); - - engine.LoadScript(NativeContract.NEO.Script); - - var result = NativeContract.NEO.Initialize(engine); - - result.Should().Be(false); + Check_GetValidators(snapshot); } [TestMethod] @@ -375,23 +360,6 @@ public void TestGetValidators2() result[6].ToArray().ToHexString().Should().Be("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"); } - [TestMethod] - public void TestInitialize() - { - var snapshot = Blockchain.Singleton.GetSnapshot(); - var engine = new ApplicationEngine(TriggerType.System, null, snapshot, 0, true); - Action action = () => NativeContract.NEO.Initialize(engine); - action.Should().Throw(); - - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); - NativeContract.NEO.Initialize(engine).Should().BeFalse(); - - snapshot.Storages.Delete(CreateStorageKey(11)); - snapshot.PersistingBlock = Blockchain.GenesisBlock; - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); - NativeContract.NEO.Initialize(engine).Should().BeTrue(); - } - [TestMethod] public void TestOnBalanceChanging() { diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index b3d5da5cd2..656332aabc 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -24,12 +24,7 @@ public void TestSetup() public void TestInitialize() { ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0); - - testNativeContract.Initialize(ae).Should().BeTrue(); - - ae = new ApplicationEngine(TriggerType.System, null, null, 0); - Action action = () => testNativeContract.Initialize(ae); - action.Should().Throw(); + testNativeContract.Initialize(ae); } [TestMethod] diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 22442e08cf..1740495571 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -3,7 +3,6 @@ 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; @@ -30,7 +29,7 @@ public void Check_Initialize() var snapshot = Blockchain.Singleton.GetSnapshot(); var keyCount = snapshot.Storages.GetChangeSet().Count(); - NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)).Should().BeTrue(); + NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); (keyCount + 4).Should().Be(snapshot.Storages.GetChangeSet().Count()); @@ -63,7 +62,7 @@ public void Check_SetMaxBlockSize() UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); - NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)).Should().BeTrue(); + NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); // Without signature @@ -109,7 +108,7 @@ public void Check_SetMaxTransactionsPerBlock() snapshot.PersistingBlock = new Block() { Index = 1000, PrevHash = UInt256.Zero }; snapshot.Blocks.Add(UInt256.Zero, new Neo.Ledger.TrimmedBlock() { NextConsensus = UInt160.Zero }); - NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)).Should().BeTrue(); + NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); // Without signature @@ -144,7 +143,7 @@ public void Check_SetFeePerByte() snapshot.PersistingBlock = new Block() { Index = 1000, PrevHash = UInt256.Zero }; snapshot.Blocks.Add(UInt256.Zero, new Neo.Ledger.TrimmedBlock() { NextConsensus = UInt160.Zero }); - NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)).Should().BeTrue(); + NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); // Without signature @@ -181,7 +180,7 @@ public void Check_Block_UnblockAccount() UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); - NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)).Should().BeTrue(); + NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); // Block without signature diff --git a/tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs b/tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs index 71e8dfe759..a05a5e9f88 100644 --- a/tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs +++ b/tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs @@ -1,6 +1,5 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; using Neo.IO; using Neo.IO.Caching; using Neo.Ledger; @@ -8,7 +7,6 @@ using Neo.Persistence; using Neo.SmartContract; using Neo.VM.Types; -using System; namespace Neo.UnitTests.SmartContract { @@ -24,31 +22,6 @@ public void TestSetup() TestBlockchain.InitializeMockNeoSystem(); } - [TestMethod] - public void TestLog() - { - var snapshot = Blockchain.Singleton.GetSnapshot(); - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); - ApplicationEngine.Log += Test_Log1; - string logMessage = "TestMessage"; - - engine.SendLog(UInt160.Zero, logMessage); - message.Should().Be(logMessage); - - ApplicationEngine.Log += Test_Log2; - engine.SendLog(UInt160.Zero, logMessage); - message.Should().Be(null); - - message = logMessage; - ApplicationEngine.Log -= Test_Log1; - engine.SendLog(UInt160.Zero, logMessage); - message.Should().Be(null); - - ApplicationEngine.Log -= Test_Log2; - engine.SendLog(UInt160.Zero, logMessage); - message.Should().Be(null); - } - [TestMethod] public void TestNotify() { @@ -74,17 +47,6 @@ public void TestNotify() item.Should().Be(null); } - [TestMethod] - public void TestDisposable() - { - var snapshot = Blockchain.Singleton.GetSnapshot(); - var m = new Mock(); - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); - engine.AddDisposable(m.Object).Should().Be(m.Object); - Action action = () => engine.Dispose(); - action.Should().NotThrow(); - } - private void Test_Log1(object sender, LogEventArgs e) { message = e.Message; @@ -115,27 +77,6 @@ public void TestCreateDummyBlock() snapshot.PersistingBlock.PrevHash.Should().Be(Blockchain.GenesisBlock.Hash); snapshot.PersistingBlock.MerkleRoot.Should().Be(new UInt256()); } - - [TestMethod] - public void TestOnSysCall() - { - InteropDescriptor descriptor = new InteropDescriptor("System.Blockchain.GetHeight", Blockchain_GetHeight, 0_00000400, TriggerType.Application, CallFlags.None); - TestApplicationEngine engine = new TestApplicationEngine(TriggerType.Application, null, null, 0); - byte[] SyscallSystemRuntimeCheckWitnessHash = new byte[] { 0x68, 0xf8, 0x27, 0xec, 0x8c }; - engine.LoadScript(SyscallSystemRuntimeCheckWitnessHash); - engine.GetOnSysCall(descriptor.Hash).Should().BeFalse(); - - var snapshot = Blockchain.Singleton.GetSnapshot(); - engine = new TestApplicationEngine(TriggerType.Application, null, snapshot, 0, true); - engine.LoadScript(SyscallSystemRuntimeCheckWitnessHash); - engine.GetOnSysCall(descriptor.Hash).Should().BeTrue(); - } - - private static bool Blockchain_GetHeight(ApplicationEngine engine) - { - engine.CurrentContext.EvaluationStack.Push(engine.Snapshot.Height); - return true; - } } public class TestApplicationEngine : ApplicationEngine diff --git a/tests/neo.UnitTests/SmartContract/UT_Contract.cs b/tests/neo.UnitTests/SmartContract/UT_Contract.cs index ee943c6477..249018f69b 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Contract.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Contract.cs @@ -26,7 +26,7 @@ public void TestGetAddress() Array.Copy(key.PublicKey.EncodePoint(true), 0, expectedArray, 2, 33); expectedArray[35] = (byte)OpCode.PUSHNULL; expectedArray[36] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(InteropService.Crypto.VerifyWithECDsaSecp256r1), 0, expectedArray, 37, 4); + Array.Copy(BitConverter.GetBytes(ApplicationEngine.Neo_Crypto_VerifyWithECDsaSecp256r1), 0, expectedArray, 37, 4); Assert.AreEqual(expectedArray.ToScriptHash().ToAddress(), contract.Address); } @@ -44,7 +44,7 @@ public void TestGetScriptHash() Array.Copy(key.PublicKey.EncodePoint(true), 0, expectedArray, 2, 33); expectedArray[35] = (byte)OpCode.PUSHNULL; expectedArray[36] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(InteropService.Crypto.VerifyWithECDsaSecp256r1), 0, expectedArray, 37, 4); + Array.Copy(BitConverter.GetBytes(ApplicationEngine.Neo_Crypto_VerifyWithECDsaSecp256r1), 0, expectedArray, 37, 4); Assert.AreEqual(expectedArray.ToScriptHash(), contract.ScriptHash); } @@ -86,7 +86,7 @@ public void TestCreateMultiSigContract() expectedArray[71] = (byte)OpCode.PUSH2; expectedArray[72] = (byte)OpCode.PUSHNULL; expectedArray[73] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(InteropService.Crypto.CheckMultisigWithECDsaSecp256r1), 0, expectedArray, 74, 4); + Array.Copy(BitConverter.GetBytes(ApplicationEngine.Neo_Crypto_CheckMultisigWithECDsaSecp256r1), 0, expectedArray, 74, 4); CollectionAssert.AreEqual(expectedArray, contract.Script); Assert.AreEqual(2, contract.ParameterList.Length); Assert.AreEqual(ContractParameterType.Signature, contract.ParameterList[0]); @@ -122,7 +122,7 @@ public void TestCreateMultiSigRedeemScript() expectedArray[71] = (byte)OpCode.PUSH2; expectedArray[72] = (byte)OpCode.PUSHNULL; expectedArray[73] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(InteropService.Crypto.CheckMultisigWithECDsaSecp256r1), 0, expectedArray, 74, 4); + Array.Copy(BitConverter.GetBytes(ApplicationEngine.Neo_Crypto_CheckMultisigWithECDsaSecp256r1), 0, expectedArray, 74, 4); CollectionAssert.AreEqual(expectedArray, script); } @@ -140,7 +140,7 @@ public void TestCreateSignatureContract() Array.Copy(key.PublicKey.EncodePoint(true), 0, expectedArray, 2, 33); expectedArray[35] = (byte)OpCode.PUSHNULL; expectedArray[36] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(InteropService.Crypto.VerifyWithECDsaSecp256r1), 0, expectedArray, 37, 4); + Array.Copy(BitConverter.GetBytes(ApplicationEngine.Neo_Crypto_VerifyWithECDsaSecp256r1), 0, expectedArray, 37, 4); CollectionAssert.AreEqual(expectedArray, contract.Script); Assert.AreEqual(1, contract.ParameterList.Length); Assert.AreEqual(ContractParameterType.Signature, contract.ParameterList[0]); @@ -160,7 +160,7 @@ public void TestCreateSignatureRedeemScript() Array.Copy(key.PublicKey.EncodePoint(true), 0, expectedArray, 2, 33); expectedArray[35] = (byte)OpCode.PUSHNULL; expectedArray[36] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(InteropService.Crypto.VerifyWithECDsaSecp256r1), 0, expectedArray, 37, 4); + Array.Copy(BitConverter.GetBytes(ApplicationEngine.Neo_Crypto_VerifyWithECDsaSecp256r1), 0, expectedArray, 37, 4); CollectionAssert.AreEqual(expectedArray, script); } } diff --git a/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs b/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs index aaf6511997..23e474e4b8 100644 --- a/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs +++ b/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs @@ -72,7 +72,7 @@ public void TestAdd() var context1 = new ContractParametersContext(tx); context1.Add(contract, 0, new byte[] { 0x01 }).Should().BeFalse(); - tx.Sender = UInt160.Parse("0xcd4ced947d791e887559b3829c3bc08fe37b0a64"); + tx.Sender = UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0"); var context2 = new ContractParametersContext(tx); context2.Add(contract, 0, new byte[] { 0x01 }).Should().BeTrue(); //test repeatlly createItem @@ -83,7 +83,7 @@ public void TestAdd() public void TestGetParameter() { Transaction tx = TestUtils.GetTransaction(); - tx.Sender = UInt160.Parse("0xcd4ced947d791e887559b3829c3bc08fe37b0a64"); + tx.Sender = UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0"); var context = new ContractParametersContext(tx); context.GetParameter(tx.Sender, 0).Should().BeNull(); @@ -96,7 +96,7 @@ public void TestGetParameter() public void TestGetWitnesses() { Transaction tx = TestUtils.GetTransaction(); - tx.Sender = UInt160.Parse("0xcd4ced947d791e887559b3829c3bc08fe37b0a64"); + tx.Sender = UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0"); var context = new ContractParametersContext(tx); context.Add(contract, 0, new byte[] { 0x01 }); Witness[] witnesses = context.GetWitnesses(); @@ -109,7 +109,7 @@ public void TestGetWitnesses() public void TestAddSignature() { Transaction tx = TestUtils.GetTransaction(); - var singleSender = UInt160.Parse("0xcd4ced947d791e887559b3829c3bc08fe37b0a64"); + var singleSender = UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0"); tx.Sender = singleSender; //singleSign @@ -139,7 +139,7 @@ public void TestAddSignature() key.PublicKey, key2.PublicKey }); - var multiSender = UInt160.Parse("0x6bb1ea23cefb73dd959775c035a114018c2c1119"); + var multiSender = UInt160.Parse("0x3593816cc1085a6328fea2b899c24d78cd0ba372"); tx.Sender = multiSender; context = new ContractParametersContext(tx); context.AddSignature(multiSignContract, key.PublicKey, new byte[] { 0x01 }).Should().BeTrue(); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropDescriptor.cs b/tests/neo.UnitTests/SmartContract/UT_InteropDescriptor.cs deleted file mode 100644 index 1d2d59d5a2..0000000000 --- a/tests/neo.UnitTests/SmartContract/UT_InteropDescriptor.cs +++ /dev/null @@ -1,26 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.SmartContract; - -namespace Neo.UnitTests.SmartContract -{ - [TestClass] - public class UT_InteropDescriptor - { - [TestMethod] - public void TestGetMethod() - { - string method = @"System.ExecutionEngine.GetScriptContainer"; - long price = 0_00000250; - TriggerType allowedTriggers = TriggerType.All; - InteropDescriptor descriptor = new InteropDescriptor(method, TestHandler, price, allowedTriggers, CallFlags.None); - descriptor.Method.Should().Be(method); - descriptor.FixedPrice.Should().Be(price); - } - - private bool TestHandler(ApplicationEngine engine) - { - return true; - } - } -} diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs index 5329463ffe..cf93e5abb3 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs @@ -24,7 +24,7 @@ public void ApplicationEngineFixedPrices() using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0)) { ae.LoadScript(SyscallSystemRuntimeCheckWitnessHash); - InteropService.Runtime.CheckWitness.FixedPrice.Should().Be(0_00030000L); + ApplicationEngine.System_Runtime_CheckWitness.FixedPrice.Should().Be(0_00030000L); } // System.Storage.GetContext: 9bf667ce (price is 1) @@ -32,7 +32,7 @@ public void ApplicationEngineFixedPrices() using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0)) { ae.LoadScript(SyscallSystemStorageGetContextHash); - InteropService.Storage.GetContext.FixedPrice.Should().Be(0_00000400L); + ApplicationEngine.System_Storage_GetContext.FixedPrice.Should().Be(0_00000400L); } // System.Storage.Get: 925de831 (price is 100) @@ -40,7 +40,7 @@ public void ApplicationEngineFixedPrices() using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0)) { ae.LoadScript(SyscallSystemStorageGetHash); - InteropService.Storage.Get.FixedPrice.Should().Be(0_01000000L); + ApplicationEngine.System_Storage_Get.FixedPrice.Should().Be(0_01000000L); } } @@ -74,7 +74,7 @@ public void ApplicationEngineRegularPut() debugger.StepInto(); var setupPrice = ae.GasConsumed; debugger.Execute(); - (ae.GasConsumed - setupPrice).Should().Be(InteropService.Storage.GasPerByte * value.Length); + (ae.GasConsumed - setupPrice).Should().Be(ApplicationEngine.StoragePrice * value.Length); } } @@ -108,7 +108,7 @@ public void ApplicationEngineReusedStorage_FullReuse() debugger.StepInto(); var setupPrice = applicationEngine.GasConsumed; debugger.Execute(); - (applicationEngine.GasConsumed - setupPrice).Should().Be(1 * InteropService.Storage.GasPerByte); + (applicationEngine.GasConsumed - setupPrice).Should().Be(1 * ApplicationEngine.StoragePrice); } } @@ -145,7 +145,7 @@ public void ApplicationEngineReusedStorage_PartialReuse() var setupPrice = ae.GasConsumed; debugger.StepInto(); debugger.StepInto(); - (ae.GasConsumed - setupPrice).Should().Be(1 * InteropService.Storage.GasPerByte); + (ae.GasConsumed - setupPrice).Should().Be(1 * ApplicationEngine.StoragePrice); } } @@ -185,7 +185,7 @@ public void ApplicationEngineReusedStorage_PartialReuseTwice() debugger.StepInto(); //syscall Storage.GetContext var setupPrice = ae.GasConsumed; debugger.StepInto(); //syscall Storage.Put - (ae.GasConsumed - setupPrice).Should().Be(1 * InteropService.Storage.GasPerByte); // = PUT basic fee + (ae.GasConsumed - setupPrice).Should().Be(1 * ApplicationEngine.StoragePrice); // = PUT basic fee } } @@ -197,8 +197,8 @@ private byte[] CreateMultiplePutScript(byte[] key, byte[] value, int times = 2) { scriptBuilder.EmitPush(value); scriptBuilder.EmitPush(key); - scriptBuilder.EmitSysCall(InteropService.Storage.GetContext); - scriptBuilder.EmitSysCall(InteropService.Storage.Put); + scriptBuilder.EmitSysCall(ApplicationEngine.System_Storage_GetContext); + scriptBuilder.EmitSysCall(ApplicationEngine.System_Storage_Put); } return scriptBuilder.ToArray(); @@ -209,8 +209,8 @@ private byte[] CreatePutScript(byte[] key, byte[] value) var scriptBuilder = new ScriptBuilder(); scriptBuilder.EmitPush(value); scriptBuilder.EmitPush(key); - scriptBuilder.EmitSysCall(InteropService.Storage.GetContext); - scriptBuilder.EmitSysCall(InteropService.Storage.Put); + scriptBuilder.EmitSysCall(ApplicationEngine.System_Storage_GetContext); + scriptBuilder.EmitSysCall(ApplicationEngine.System_Storage_Put); return scriptBuilder.ToArray(); } } diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index 99beb32046..b0a2547107 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -7,7 +7,6 @@ using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.SmartContract; -using Neo.SmartContract.Enumerators; using Neo.SmartContract.Iterators; using Neo.SmartContract.Manifest; using Neo.VM; @@ -15,6 +14,7 @@ using Neo.Wallets; using System; using System.Linq; +using System.Text; using VMArray = Neo.VM.Types.Array; namespace Neo.UnitTests.SmartContract @@ -32,17 +32,8 @@ public void TestCheckSig() KeyPair keyPair = new KeyPair(privateKey); ECPoint pubkey = keyPair.PublicKey; byte[] signature = Crypto.Sign(message, privateKey, pubkey.EncodePoint(false).Skip(1).ToArray()); - engine.CurrentContext.EvaluationStack.Push(signature); - engine.CurrentContext.EvaluationStack.Push(pubkey.EncodePoint(false)); - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.VerifyWithECDsaSecp256r1).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeTrue(); - - engine.CurrentContext.EvaluationStack.Push(signature); - engine.CurrentContext.EvaluationStack.Push(new byte[70]); - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.VerifyWithECDsaSecp256r1).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); + engine.VerifyWithECDsaSecp256r1(StackItem.Null, pubkey.EncodePoint(false), signature).Should().BeTrue(); + engine.VerifyWithECDsaSecp256r1(StackItem.Null, new byte[70], signature).Should().BeFalse(); } [TestMethod] @@ -64,70 +55,52 @@ public void TestCrypto_CheckMultiSig() ECPoint pubkey2 = key2.PublicKey; byte[] signature2 = Crypto.Sign(message, privkey2, pubkey2.EncodePoint(false).Skip(1).ToArray()); - var pubkeys = new VMArray + var pubkeys = new[] { pubkey1.EncodePoint(false), pubkey2.EncodePoint(false) }; - var signatures = new VMArray + var signatures = new[] { signature1, signature2 }; - engine.CurrentContext.EvaluationStack.Push(signatures); - engine.CurrentContext.EvaluationStack.Push(pubkeys); - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.CheckMultisigWithECDsaSecp256r1).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeTrue(); - - pubkeys = new VMArray(); - engine.CurrentContext.EvaluationStack.Push(signatures); - engine.CurrentContext.EvaluationStack.Push(pubkeys); - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.CheckMultisigWithECDsaSecp256r1).Should().BeFalse(); - - pubkeys = new VMArray + engine.CheckMultisigWithECDsaSecp256r1(StackItem.Null, pubkeys, signatures).Should().BeTrue(); + + pubkeys = new byte[0][]; + Assert.ThrowsException(() => engine.CheckMultisigWithECDsaSecp256r1(StackItem.Null, pubkeys, signatures)); + + pubkeys = new[] { pubkey1.EncodePoint(false), pubkey2.EncodePoint(false) }; - signatures = new VMArray(); - engine.CurrentContext.EvaluationStack.Push(signatures); - engine.CurrentContext.EvaluationStack.Push(pubkeys); - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.CheckMultisigWithECDsaSecp256r1).Should().BeFalse(); + signatures = new byte[0][]; + Assert.ThrowsException(() => engine.CheckMultisigWithECDsaSecp256r1(StackItem.Null, pubkeys, signatures)); - pubkeys = new VMArray + pubkeys = new[] { pubkey1.EncodePoint(false), pubkey2.EncodePoint(false) }; - signatures = new VMArray + signatures = new[] { signature1, new byte[64] }; - engine.CurrentContext.EvaluationStack.Push(signatures); - engine.CurrentContext.EvaluationStack.Push(pubkeys); - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.CheckMultisigWithECDsaSecp256r1).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); + engine.CheckMultisigWithECDsaSecp256r1(StackItem.Null, pubkeys, signatures).Should().BeFalse(); - pubkeys = new VMArray + pubkeys = new[] { pubkey1.EncodePoint(false), new byte[70] }; - signatures = new VMArray + signatures = new[] { signature1, signature2 }; - engine.CurrentContext.EvaluationStack.Push(signatures); - engine.CurrentContext.EvaluationStack.Push(pubkeys); - engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.CheckMultisigWithECDsaSecp256r1).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); + engine.CheckMultisigWithECDsaSecp256r1(StackItem.Null, pubkeys, signatures).Should().BeFalse(); } [TestMethod] @@ -138,72 +111,43 @@ public void TestAccount_IsStandard() 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; - engine.CurrentContext.EvaluationStack.Push(hash); - InteropService.Invoke(engine, InteropService.Contract.IsStandard).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeTrue(); + engine.IsStandardContract(new UInt160(hash)).Should().BeTrue(); var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); snapshot.Contracts.Add(state.ScriptHash, state); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); - engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); - InteropService.Invoke(engine, InteropService.Contract.IsStandard).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); + engine.IsStandardContract(state.ScriptHash).Should().BeFalse(); } [TestMethod] public void TestContract_Create() { var engine = GetEngine(false, true); - var script = new byte[1024 * 1024 + 1]; - engine.CurrentContext.EvaluationStack.Push(script); - InteropService.Invoke(engine, InteropService.Contract.Create).Should().BeFalse(); - - string manifestStr = new string(new char[ContractManifest.MaxLength + 1]); - script = new byte[] { 0x01 }; - engine.CurrentContext.EvaluationStack.Push(manifestStr); - engine.CurrentContext.EvaluationStack.Push(script); - InteropService.Invoke(engine, InteropService.Contract.Create).Should().BeFalse(); + var script = new byte[] { 0x01 }; + Assert.ThrowsException(() => engine.CreateContract(script, new byte[ContractManifest.MaxLength + 1])); var manifest = TestUtils.CreateDefaultManifest(UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01")); - engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); - engine.CurrentContext.EvaluationStack.Push(script); - InteropService.Invoke(engine, InteropService.Contract.Create).Should().BeFalse(); + Assert.ThrowsException(() => engine.CreateContract(script, manifest.ToJson().ToByteArray(false))); manifest.Abi.Hash = script.ToScriptHash(); - engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); - engine.CurrentContext.EvaluationStack.Push(script); - InteropService.Invoke(engine, InteropService.Contract.Create).Should().BeTrue(); + engine.CreateContract(script, manifest.ToJson().ToByteArray(false)); var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); snapshot.Contracts.Add(state.ScriptHash, state); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[] { 0x01 }); - engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); - engine.CurrentContext.EvaluationStack.Push(state.Script); - InteropService.Invoke(engine, InteropService.Contract.Create).Should().BeFalse(); + Assert.ThrowsException(() => engine.CreateContract(state.Script, manifest.ToJson().ToByteArray(false))); } [TestMethod] public void TestContract_Update() { var engine = GetEngine(false, true); - var script = new byte[1024 * 1024 + 1]; - engine.CurrentContext.EvaluationStack.Push(script); - InteropService.Invoke(engine, InteropService.Contract.Update).Should().BeFalse(); - - string manifestStr = new string(new char[ContractManifest.MaxLength + 1]); - script = new byte[] { 0x01 }; - engine.CurrentContext.EvaluationStack.Push(manifestStr); - engine.CurrentContext.EvaluationStack.Push(script); - InteropService.Invoke(engine, InteropService.Contract.Update).Should().BeFalse(); - - manifestStr = ""; - engine.CurrentContext.EvaluationStack.Push(manifestStr); - engine.CurrentContext.EvaluationStack.Push(script); - InteropService.Invoke(engine, InteropService.Contract.Update).Should().BeFalse(); + var script = new byte[] { 0x01 }; + Assert.ThrowsException(() => engine.UpdateContract(script, new byte[0])); var manifest = TestUtils.CreateDefaultManifest(script.ToScriptHash()); byte[] privkey = { 0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, @@ -238,9 +182,7 @@ public void TestContract_Update() snapshot.Storages.Add(storageKey, storageItem); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(state.Script); - engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); - engine.CurrentContext.EvaluationStack.Push(script); - InteropService.Invoke(engine, InteropService.Contract.Update).Should().BeTrue(); + engine.UpdateContract(script, manifest.ToJson().ToByteArray(false)); engine.Snapshot.Storages.Find(BitConverter.GetBytes(state.Id)).ToList().Count().Should().Be(1); } @@ -266,20 +208,14 @@ public void TestStorage_Find() var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); - engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(new StorageContext + var iterator = engine.Find(new StorageContext { Id = state.Id, IsReadOnly = false - })); - InteropService.Invoke(engine, InteropService.Storage.Find).Should().BeTrue(); - var iterator = ((InteropInterface)engine.CurrentContext.EvaluationStack.Pop()).GetInterface(); + }, new byte[] { 0x01 }); iterator.Next(); var ele = iterator.Value(); ele.GetSpan().ToHexString().Should().Be(storageItem.Value.ToHexString()); - - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Storage.Find).Should().BeFalse(); } [TestMethod] @@ -290,15 +226,9 @@ public void TestEnumerator_Create() new byte[]{ 0x01 }, new byte[]{ 0x02 } }; - engine.CurrentContext.EvaluationStack.Push(arr); - InteropService.Invoke(engine, InteropService.Enumerator.Create).Should().BeTrue(); - var ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); - ret.GetInterface().Next(); - ret.GetInterface().Value().GetSpan().ToHexString() - .Should().Be(new byte[] { 0x01 }.ToHexString()); - - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Enumerator.Create).Should().BeTrue(); + var ret = engine.CreateEnumerator(arr); + ret.Next(); + ret.Value().GetSpan().ToHexString().Should().Be(new byte[] { 0x01 }.ToHexString()); } [TestMethod] @@ -309,12 +239,7 @@ public void TestEnumerator_Next() new byte[]{ 0x01 }, new byte[]{ 0x02 } }; - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(new ArrayWrapper(arr))); - InteropService.Invoke(engine, InteropService.Enumerator.Next).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeTrue(); - - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Enumerator.Next).Should().BeFalse(); + engine.EnumeratorNext(new ArrayWrapper(arr)).Should().BeTrue(); } [TestMethod] @@ -327,12 +252,7 @@ public void TestEnumerator_Value() }; var wrapper = new ArrayWrapper(arr); wrapper.Next(); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper)); - InteropService.Invoke(engine, InteropService.Enumerator.Value).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToHexString().Should().Be(new byte[] { 0x01 }.ToHexString()); - - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Enumerator.Value).Should().BeFalse(); + engine.EnumeratorValue(wrapper).GetSpan().ToHexString().Should().Be(new byte[] { 0x01 }.ToHexString()); } [TestMethod] @@ -349,10 +269,7 @@ public void TestEnumerator_Concat() }; var wrapper1 = new ArrayWrapper(arr1); var wrapper2 = new ArrayWrapper(arr2); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper2)); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper1)); - InteropService.Invoke(engine, InteropService.Enumerator.Concat).Should().BeTrue(); - var ret = ((InteropInterface)engine.CurrentContext.EvaluationStack.Pop()).GetInterface(); + var ret = engine.ConcatEnumerators(wrapper1, wrapper2); ret.Next().Should().BeTrue(); ret.Value().GetSpan().ToHexString().Should().Be(new byte[] { 0x01 }.ToHexString()); } @@ -365,31 +282,22 @@ public void TestIterator_Create() new byte[]{ 0x01 }, new byte[]{ 0x02 } }; - engine.CurrentContext.EvaluationStack.Push(arr); - InteropService.Invoke(engine, InteropService.Iterator.Create).Should().BeTrue(); - var ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); - ret.GetInterface().Next(); - ret.GetInterface().Value().GetSpan().ToHexString() - .Should().Be(new byte[] { 0x01 }.ToHexString()); + var ret = engine.CreateIterator(arr); + ret.Next(); + ret.Value().GetSpan().ToHexString().Should().Be(new byte[] { 0x01 }.ToHexString()); var interop = new InteropInterface(1); - engine.CurrentContext.EvaluationStack.Push(interop); - InteropService.Invoke(engine, InteropService.Iterator.Create).Should().BeFalse(); + Assert.ThrowsException(() => engine.CreateIterator(interop)); var map = new Map { [1] = 2, [3] = 4 }; - engine.CurrentContext.EvaluationStack.Push(map); - InteropService.Invoke(engine, InteropService.Iterator.Create).Should().BeTrue(); - ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); - ret.GetInterface().Next(); - ret.GetInterface().Key().GetBigInteger().Should().Be(1); - ret.GetInterface().Value().GetBigInteger().Should().Be(2); - - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Iterator.Create).Should().BeTrue(); + ret = engine.CreateIterator(map); + ret.Next(); + ret.Key().GetBigInteger().Should().Be(1); + ret.Value().GetBigInteger().Should().Be(2); } [TestMethod] @@ -402,12 +310,7 @@ public void TestIterator_Key() }; var wrapper = new ArrayWrapper(arr); wrapper.Next(); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper)); - InteropService.Invoke(engine, InteropService.Iterator.Key).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(0); - - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Iterator.Key).Should().BeFalse(); + engine.IteratorKey(wrapper).GetBigInteger().Should().Be(0); } [TestMethod] @@ -419,14 +322,9 @@ public void TestIterator_Keys() new byte[]{ 0x02 } }; var wrapper = new ArrayWrapper(arr); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper)); - InteropService.Invoke(engine, InteropService.Iterator.Keys).Should().BeTrue(); - var ret = ((InteropInterface)engine.CurrentContext.EvaluationStack.Pop()).GetInterface(); + var ret = engine.IteratorKeys(wrapper); ret.Next(); ret.Value().GetBigInteger().Should().Be(0); - - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Iterator.Keys).Should().BeFalse(); } [TestMethod] @@ -438,14 +336,9 @@ public void TestIterator_Values() new byte[]{ 0x02 } }; var wrapper = new ArrayWrapper(arr); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper)); - InteropService.Invoke(engine, InteropService.Iterator.Values).Should().BeTrue(); - var ret = ((InteropInterface)engine.CurrentContext.EvaluationStack.Pop()).GetInterface(); + var ret = engine.IteratorValues(wrapper); ret.Next(); ret.Value().GetSpan().ToHexString().Should().Be(new byte[] { 0x01 }.ToHexString()); - - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Iterator.Values).Should().BeFalse(); } [TestMethod] @@ -462,10 +355,7 @@ public void TestIterator_Concat() }; var wrapper1 = new ArrayWrapper(arr1); var wrapper2 = new ArrayWrapper(arr2); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper2)); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper1)); - InteropService.Invoke(engine, InteropService.Iterator.Concat).Should().BeTrue(); - var ret = ((InteropInterface)engine.CurrentContext.EvaluationStack.Pop()).GetInterface(); + var ret = engine.ConcatIterators(wrapper1, wrapper2); ret.Next().Should().BeTrue(); ret.Value().GetSpan().ToHexString().Should().Be(new byte[] { 0x01 }.ToHexString()); } @@ -473,21 +363,13 @@ public void TestIterator_Concat() [TestMethod] public void TestJson_Deserialize() { - var engine = GetEngine(); - engine.CurrentContext.EvaluationStack.Push("1"); - InteropService.Invoke(engine, InteropService.Json.Deserialize).Should().BeTrue(); - var ret = engine.CurrentContext.EvaluationStack.Pop(); - ret.GetBigInteger().Should().Be(1); + GetEngine().JsonDeserialize(new byte[] { (byte)'1' }).GetBigInteger().Should().Be(1); } [TestMethod] public void TestJson_Serialize() { - var engine = GetEngine(); - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Json.Serialize).Should().BeTrue(); - var ret = engine.CurrentContext.EvaluationStack.Pop(); - ret.GetString().Should().Be("1"); + Encoding.UTF8.GetString(GetEngine().JsonSerialize(1)).Should().Be("1"); } } } diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 1fa5689e7a..399f063ec7 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -40,7 +40,7 @@ public void Runtime_GetNotifications_Test() // Notify method - script.EmitSysCall(InteropService.Runtime.Notify); + script.EmitSysCall(ApplicationEngine.System_Runtime_Notify); // Add return @@ -67,7 +67,7 @@ public void Runtime_GetNotifications_Test() // Retrive script.EmitPush(1); - script.EmitSysCall(InteropService.Runtime.GetNotifications); + script.EmitSysCall(ApplicationEngine.System_Runtime_GetNotifications); // Execute @@ -84,7 +84,7 @@ public void Runtime_GetNotifications_Test() // Notification 1 -> 13 script.EmitPush(13); - script.EmitSysCall(InteropService.Runtime.Notify); + script.EmitSysCall(ApplicationEngine.System_Runtime_Notify); // Call script @@ -97,7 +97,7 @@ public void Runtime_GetNotifications_Test() // Receive all notifications script.Emit(OpCode.PUSHNULL); - script.EmitSysCall(InteropService.Runtime.GetNotifications); + script.EmitSysCall(ApplicationEngine.System_Runtime_GetNotifications); // Execute @@ -134,7 +134,7 @@ public void Runtime_GetNotifications_Test() // Notification 1 -> 13 script.EmitPush(13); - script.EmitSysCall(InteropService.Runtime.Notify); + script.EmitSysCall(ApplicationEngine.System_Runtime_Notify); // Call script @@ -147,7 +147,7 @@ public void Runtime_GetNotifications_Test() // Receive all notifications script.EmitPush(scriptHash2.ToArray()); - script.EmitSysCall(InteropService.Runtime.GetNotifications); + script.EmitSysCall(ApplicationEngine.System_Runtime_GetNotifications); // Execute @@ -203,20 +203,7 @@ private void AssertNotification(StackItem stackItem, UInt160 scriptHash, int not [TestMethod] public void TestExecutionEngine_GetScriptContainer() { - var engine = GetEngine(true); - InteropService.Invoke(engine, InteropService.Runtime.GetScriptContainer).Should().BeTrue(); - var stackItem = ((VM.Types.Array)engine.CurrentContext.EvaluationStack.Pop()).ToArray(); - stackItem.Length.Should().Be(8); - stackItem[0].GetSpan().ToHexString().Should().Be(TestUtils.GetTransaction().Hash.ToArray().ToHexString()); - } - - [TestMethod] - public void TestExecutionEngine_GetExecutingScriptHash() - { - var engine = GetEngine(); - InteropService.Invoke(engine, InteropService.Runtime.GetExecutingScriptHash).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToHexString() - .Should().Be(engine.CurrentScriptHash.ToArray().ToHexString()); + GetEngine(true).GetScriptContainer().Should().BeOfType(); } [TestMethod] @@ -225,15 +212,14 @@ public void TestExecutionEngine_GetCallingScriptHash() // Test without var engine = GetEngine(true); - InteropService.Invoke(engine, InteropService.Runtime.GetCallingScriptHash).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().Should().Be(StackItem.Null); + engine.CallingScriptHash.Should().BeNull(); // Test real using ScriptBuilder scriptA = new ScriptBuilder(); scriptA.Emit(OpCode.DROP); // Drop arguments scriptA.Emit(OpCode.DROP); // Drop method - scriptA.EmitSysCall(InteropService.Runtime.GetCallingScriptHash); + scriptA.EmitSysCall(ApplicationEngine.System_Runtime_GetCallingScriptHash); var contract = new ContractState() { @@ -252,40 +238,16 @@ public void TestExecutionEngine_GetCallingScriptHash() engine.ResultStack.Pop().GetSpan().ToHexString().Should().Be(scriptB.ToArray().ToScriptHash().ToArray().ToHexString()); } - [TestMethod] - public void TestExecutionEngine_GetEntryScriptHash() - { - var engine = GetEngine(); - InteropService.Invoke(engine, InteropService.Runtime.GetEntryScriptHash).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToHexString() - .Should().Be(engine.EntryScriptHash.ToArray().ToHexString()); - } - [TestMethod] public void TestContract_GetCallFlags() { - var engine = GetEngine(); - InteropService.Invoke(engine, InteropService.Contract.GetCallFlags).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetBigInteger() - .Should().Be(((int)CallFlags.All)); + GetEngine().GetCallFlags().Should().Be(CallFlags.All); } [TestMethod] public void TestRuntime_Platform() { - var engine = GetEngine(); - InteropService.Invoke(engine, InteropService.Runtime.Platform).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToHexString() - .Should().Be(Encoding.ASCII.GetBytes("NEO").ToHexString()); - } - - [TestMethod] - public void TestRuntime_GetTrigger() - { - var engine = GetEngine(); - InteropService.Invoke(engine, InteropService.Runtime.GetTrigger).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetBigInteger() - .Should().Be((int)engine.Trigger); + GetEngine().GetPlatform().Should().Be("NEO"); } [TestMethod] @@ -299,18 +261,11 @@ public void TestRuntime_CheckWitness() var engine = GetEngine(true); ((Transaction)engine.ScriptContainer).Sender = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); - engine.CurrentContext.EvaluationStack.Push(pubkey.EncodePoint(true)); - InteropService.Invoke(engine, InteropService.Runtime.CheckWitness).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Peek().GetType().Should().Be(typeof(Neo.VM.Types.Boolean)); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().Be(false); + engine.CheckWitness(pubkey.EncodePoint(true)).Should().BeFalse(); + engine.CheckWitness(((Transaction)engine.ScriptContainer).Sender.ToArray()).Should().BeFalse(); - engine.CurrentContext.EvaluationStack.Push(((Transaction)engine.ScriptContainer).Sender.ToArray()); - InteropService.Invoke(engine, InteropService.Runtime.CheckWitness).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Peek().GetType().Should().Be(typeof(Neo.VM.Types.Boolean)); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().Be(false); - - engine.CurrentContext.EvaluationStack.Push(new byte[0]); - InteropService.Invoke(engine, InteropService.Runtime.CheckWitness).Should().BeFalse(); + Action action = () => engine.CheckWitness(new byte[0]); + action.Should().Throw(); } [TestMethod] @@ -318,9 +273,8 @@ public void TestRuntime_Log() { var engine = GetEngine(true); string message = "hello"; - engine.CurrentContext.EvaluationStack.Push(Encoding.UTF8.GetBytes(message)); ApplicationEngine.Log += LogEvent; - InteropService.Invoke(engine, InteropService.Runtime.Log).Should().BeTrue(); + engine.RuntimeLog(Encoding.UTF8.GetBytes(message)); ((Transaction)engine.ScriptContainer).Script.ToHexString().Should().Be(new byte[] { 0x01, 0x02, 0x03 }.ToHexString()); ApplicationEngine.Log -= LogEvent; } @@ -329,51 +283,40 @@ public void TestRuntime_Log() public void TestRuntime_GetTime() { Block block = new Block(); - TestUtils.SetupBlockWithValues(block, UInt256.Zero, out var merkRootVal, out var val160, out var timestampVal, out var indexVal, out var scriptVal, out var transactionsVal, 0); + TestUtils.SetupBlockWithValues(block, UInt256.Zero, out _, out _, out _, out _, out _, out _, 0); var engine = GetEngine(true, true); engine.Snapshot.PersistingBlock = block; - - InteropService.Invoke(engine, InteropService.Runtime.GetTime).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(block.Timestamp); + engine.GetTime().Should().Be(block.Timestamp); } [TestMethod] public void TestRuntime_Serialize() { var engine = GetEngine(); - engine.CurrentContext.EvaluationStack.Push(100); - InteropService.Invoke(engine, InteropService.Binary.Serialize).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToHexString() - .Should().Be(new byte[] { 0x21, 0x01, 0x64 }.ToHexString()); + engine.BinarySerialize(100).ToHexString().Should().Be(new byte[] { 0x21, 0x01, 0x64 }.ToHexString()); - engine.CurrentContext.EvaluationStack.Push(new byte[1024 * 1024 * 2]); //Larger than MaxItemSize - Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Binary.Serialize)); + //Larger than MaxItemSize + Assert.ThrowsException(() => engine.BinarySerialize(new byte[1024 * 1024 * 2])); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(new object())); //NotSupportedException - Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Binary.Serialize)); + //NotSupportedException + Assert.ThrowsException(() => engine.BinarySerialize(new InteropInterface(new object()))); } [TestMethod] public void TestRuntime_Deserialize() { var engine = GetEngine(); - engine.CurrentContext.EvaluationStack.Push(100); - InteropService.Invoke(engine, InteropService.Binary.Serialize).Should().BeTrue(); - InteropService.Invoke(engine, InteropService.Binary.Deserialize).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(100); + engine.BinaryDeserialize(engine.BinarySerialize(100)).GetBigInteger().Should().Be(100); - engine.CurrentContext.EvaluationStack.Push(new byte[] { 0xfa, 0x01 }); //FormatException - Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Binary.Deserialize)); + //FormatException + Assert.ThrowsException(() => engine.BinaryDeserialize(new byte[] { 0xfa, 0x01 })); } [TestMethod] public void TestRuntime_GetInvocationCounter() { var engine = GetEngine(); - InteropService.Invoke(engine, InteropService.Runtime.GetInvocationCounter).Should().BeFalse(); - engine.InvocationCounter.TryAdd(engine.CurrentScriptHash, 10); - InteropService.Invoke(engine, InteropService.Runtime.GetInvocationCounter).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(10); + Assert.ThrowsException(() => engine.GetInvocationCounter()); } [TestMethod] @@ -387,28 +330,17 @@ public void TestCrypto_Verify() KeyPair keyPair = new KeyPair(privateKey); ECPoint pubkey = keyPair.PublicKey; byte[] signature = Crypto.Sign(message, privateKey, pubkey.EncodePoint(false).Skip(1).ToArray()); - - engine.CurrentContext.EvaluationStack.Push(signature); - engine.CurrentContext.EvaluationStack.Push(pubkey.EncodePoint(false)); - engine.CurrentContext.EvaluationStack.Push(message); - InteropService.Invoke(engine, InteropService.Crypto.VerifyWithECDsaSecp256r1).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeTrue(); + engine.VerifyWithECDsaSecp256r1(message, pubkey.EncodePoint(false), signature).Should().BeTrue(); byte[] wrongkey = pubkey.EncodePoint(false); wrongkey[0] = 5; - engine.CurrentContext.EvaluationStack.Push(signature); - engine.CurrentContext.EvaluationStack.Push(wrongkey); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(engine.ScriptContainer)); - InteropService.Invoke(engine, InteropService.Crypto.VerifyWithECDsaSecp256r1).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Peek().ToBoolean().Should().BeFalse(); + engine.VerifyWithECDsaSecp256r1(new InteropInterface(engine.ScriptContainer), wrongkey, signature).Should().BeFalse(); } [TestMethod] public void TestBlockchain_GetHeight() { - var engine = GetEngine(true, true); - InteropService.Invoke(engine, InteropService.Blockchain.GetHeight).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(0); + GetEngine(true, true).GetBlockchainHeight().Should().Be(0); } [TestMethod] @@ -416,21 +348,16 @@ public void TestBlockchain_GetBlock() { var engine = GetEngine(true, true); - engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); - InteropService.Invoke(engine, InteropService.Blockchain.GetBlock).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().Should().Be(StackItem.Null); + engine.GetBlock(new byte[] { 0x01 }).Should().BeNull(); byte[] data1 = new byte[] { 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}; - engine.CurrentContext.EvaluationStack.Push(data1); - InteropService.Invoke(engine, InteropService.Blockchain.GetBlock).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); + engine.GetBlock(data1).Should().BeNull(); byte[] data2 = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; - engine.CurrentContext.EvaluationStack.Push(data2); - InteropService.Invoke(engine, InteropService.Blockchain.GetBlock).Should().BeFalse(); + Assert.ThrowsException(() => engine.GetBlock(data2)); } [TestMethod] @@ -441,9 +368,7 @@ public void TestBlockchain_GetTransaction() 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; - engine.CurrentContext.EvaluationStack.Push(data1); - InteropService.Invoke(engine, InteropService.Blockchain.GetTransaction).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); + engine.GetTransaction(new UInt256(data1)).Should().BeNull(); } [TestMethod] @@ -454,9 +379,7 @@ public void TestBlockchain_GetTransactionHeight() 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; - engine.CurrentContext.EvaluationStack.Push(data1); - InteropService.Invoke(engine, InteropService.Blockchain.GetTransactionHeight).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(-1); + engine.GetTransactionHeight(new UInt256(data1)).Should().Be(-1); } [TestMethod] @@ -467,23 +390,14 @@ public void TestBlockchain_GetContract() 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; - engine.CurrentContext.EvaluationStack.Push(data1); - InteropService.Invoke(engine, InteropService.Blockchain.GetContract).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().Should().Be(StackItem.Null); + engine.GetContract(new UInt160(data1)).Should().BeNull(); var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); snapshot.Contracts.Add(state.ScriptHash, state); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); - engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); - InteropService.Invoke(engine, InteropService.Blockchain.GetContract).Should().BeTrue(); - var stackItems = ((VM.Types.Array)engine.CurrentContext.EvaluationStack.Pop()).ToArray(); - stackItems.Length.Should().Be(3); - stackItems[0].GetType().Should().Be(typeof(ByteString)); - stackItems[0].GetSpan().ToHexString().Should().Be(state.Script.ToHexString()); - stackItems[1].ToBoolean().Should().BeFalse(); - stackItems[2].ToBoolean().Should().BeFalse(); + engine.GetContract(state.ScriptHash).Should().BeSameAs(state); } [TestMethod] @@ -494,9 +408,7 @@ public void TestStorage_GetContext() state.Manifest.Features = ContractFeatures.HasStorage; engine.Snapshot.Contracts.Add(state.ScriptHash, state); engine.LoadScript(state.Script); - InteropService.Invoke(engine, InteropService.Storage.GetContext).Should().BeTrue(); - var ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); - ret.GetInterface().IsReadOnly.Should().BeFalse(); + engine.GetStorageContext().IsReadOnly.Should().BeFalse(); } [TestMethod] @@ -507,9 +419,7 @@ public void TestStorage_GetReadOnlyContext() state.Manifest.Features = ContractFeatures.HasStorage; engine.Snapshot.Contracts.Add(state.ScriptHash, state); engine.LoadScript(state.Script); - InteropService.Invoke(engine, InteropService.Storage.GetReadOnlyContext).Should().BeTrue(); - var ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); - ret.GetInterface().IsReadOnly.Should().BeTrue(); + engine.GetReadOnlyContext().IsReadOnly.Should().BeTrue(); } [TestMethod] @@ -535,61 +445,44 @@ public void TestStorage_Get() var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); - engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(new StorageContext + engine.Get(new StorageContext { Id = state.Id, IsReadOnly = false - })); - InteropService.Invoke(engine, InteropService.Storage.Get).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToHexString().Should().Be(storageItem.Value.ToHexString()); + }, new byte[] { 0x01 }).ToHexString().Should().Be(storageItem.Value.ToHexString()); } [TestMethod] public void TestStorage_Put() { var engine = GetEngine(false, true); - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Storage.Put).Should().BeFalse(); //CheckStorageContext fail var key = new byte[] { 0x01 }; var value = new byte[] { 0x02 }; - engine.CurrentContext.EvaluationStack.Push(value); - engine.CurrentContext.EvaluationStack.Push(key); var state = TestUtils.GetContract(); var storageContext = new StorageContext { Id = state.Id, IsReadOnly = false }; - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.Put).Should().BeTrue(); + engine.Put(storageContext, key, value); //key.Length > MaxStorageKeySize - key = new byte[InteropService.Storage.MaxKeySize + 1]; + key = new byte[ApplicationEngine.MaxStorageKeySize + 1]; value = new byte[] { 0x02 }; - engine.CurrentContext.EvaluationStack.Push(value); - engine.CurrentContext.EvaluationStack.Push(key); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.Put).Should().BeFalse(); + Assert.ThrowsException(() => engine.Put(storageContext, key, value)); //value.Length > MaxStorageValueSize key = new byte[] { 0x01 }; value = new byte[ushort.MaxValue + 1]; - engine.CurrentContext.EvaluationStack.Push(value); - engine.CurrentContext.EvaluationStack.Push(key); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.Put).Should().BeFalse(); + Assert.ThrowsException(() => engine.Put(storageContext, key, value)); //context.IsReadOnly key = new byte[] { 0x01 }; value = new byte[] { 0x02 }; storageContext.IsReadOnly = true; - engine.CurrentContext.EvaluationStack.Push(value); - engine.CurrentContext.EvaluationStack.Push(key); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.Put).Should().BeFalse(); + Assert.ThrowsException(() => engine.Put(storageContext, key, value)); //storage value is constant var snapshot = Blockchain.Singleton.GetSnapshot(); @@ -612,34 +505,22 @@ public void TestStorage_Put() key = new byte[] { 0x01 }; value = new byte[] { 0x02 }; storageContext.IsReadOnly = false; - engine.CurrentContext.EvaluationStack.Push(value); - engine.CurrentContext.EvaluationStack.Push(key); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.Put).Should().BeFalse(); + Assert.ThrowsException(() => engine.Put(storageContext, key, value)); //success storageItem.IsConstant = false; - engine.CurrentContext.EvaluationStack.Push(value); - engine.CurrentContext.EvaluationStack.Push(key); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.Put).Should().BeTrue(); + engine.Put(storageContext, key, value); //value length == 0 key = new byte[] { 0x01 }; value = new byte[0]; - engine.CurrentContext.EvaluationStack.Push(value); - engine.CurrentContext.EvaluationStack.Push(key); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.Put).Should().BeTrue(); + engine.Put(storageContext, key, value); } [TestMethod] public void TestStorage_PutEx() { var engine = GetEngine(false, true); - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Storage.PutEx).Should().BeFalse(); - var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); state.Manifest.Features = ContractFeatures.HasStorage; @@ -664,21 +545,13 @@ public void TestStorage_PutEx() Id = state.Id, IsReadOnly = false }; - engine.CurrentContext.EvaluationStack.Push((int)StorageFlags.None); - engine.CurrentContext.EvaluationStack.Push(value); - engine.CurrentContext.EvaluationStack.Push(key); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.PutEx).Should().BeTrue(); + engine.PutEx(storageContext, key, value, StorageFlags.None); } [TestMethod] public void TestStorage_Delete() { var engine = GetEngine(false, true); - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Storage.Delete).Should().BeFalse(); - - var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); state.Manifest.Features = ContractFeatures.HasStorage; @@ -703,42 +576,24 @@ public void TestStorage_Delete() Id = state.Id, IsReadOnly = false }; - engine.CurrentContext.EvaluationStack.Push(key); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.Delete).Should().BeTrue(); + engine.Delete(storageContext, key); //context is readonly storageContext.IsReadOnly = true; - engine.CurrentContext.EvaluationStack.Push(key); - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.Delete).Should().BeFalse(); + Assert.ThrowsException(() => engine.Delete(storageContext, key)); } [TestMethod] public void TestStorageContext_AsReadOnly() { var engine = GetEngine(); - engine.CurrentContext.EvaluationStack.Push(1); - InteropService.Invoke(engine, InteropService.Storage.AsReadOnly).Should().BeFalse(); - var state = TestUtils.GetContract(); var storageContext = new StorageContext { Id = state.Id, IsReadOnly = false }; - engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); - InteropService.Invoke(engine, InteropService.Storage.AsReadOnly).Should().BeTrue(); - var ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); - ret.GetInterface().IsReadOnly.Should().Be(true); - } - - [TestMethod] - public void TestInvoke() - { - var engine = new ApplicationEngine(TriggerType.Verification, null, null, 0); - InteropService.Invoke(engine, 10000).Should().BeFalse(); - InteropService.Invoke(engine, InteropService.Storage.AsReadOnly).Should().BeFalse(); + engine.AsReadOnly(storageContext).IsReadOnly.Should().BeTrue(); } [TestMethod] @@ -747,36 +602,24 @@ public void TestContract_Call() var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract("method"); state.Manifest.Features = ContractFeatures.HasStorage; - byte[] method = Encoding.UTF8.GetBytes("method"); + string method = "method"; var args = new VM.Types.Array { 0, 1 }; snapshot.Contracts.Add(state.ScriptHash, state); var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); - engine.CurrentContext.EvaluationStack.Push(args); - engine.CurrentContext.EvaluationStack.Push(method); - engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); - InteropService.Invoke(engine, InteropService.Contract.Call).Should().BeTrue(); + engine.CallContract(state.ScriptHash, method, args); engine.CurrentContext.EvaluationStack.Pop().Should().Be(args[0]); engine.CurrentContext.EvaluationStack.Pop().Should().Be(args[1]); state.Manifest.Permissions[0].Methods = WildcardContainer.Create("a"); - engine.CurrentContext.EvaluationStack.Push(args); - engine.CurrentContext.EvaluationStack.Push(method); - engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); - InteropService.Invoke(engine, InteropService.Contract.Call).Should().BeFalse(); - state.Manifest.Permissions[0].Methods = WildcardContainer.CreateWildcard(); + Assert.ThrowsException(() => engine.CallContract(state.ScriptHash, method, args)); - engine.CurrentContext.EvaluationStack.Push(args); - engine.CurrentContext.EvaluationStack.Push(method); - engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); - InteropService.Invoke(engine, InteropService.Contract.Call).Should().BeTrue(); + state.Manifest.Permissions[0].Methods = WildcardContainer.CreateWildcard(); + engine.CallContract(state.ScriptHash, method, args); - engine.CurrentContext.EvaluationStack.Push(args); - engine.CurrentContext.EvaluationStack.Push(method); - engine.CurrentContext.EvaluationStack.Push(UInt160.Zero.ToArray()); - InteropService.Invoke(engine, InteropService.Contract.Call).Should().BeFalse(); + Assert.ThrowsException(() => engine.CallContract(UInt160.Zero, method, args)); } [TestMethod] @@ -788,7 +631,7 @@ public void TestContract_CallEx() state.Manifest.Features = ContractFeatures.HasStorage; snapshot.Contracts.Add(state.ScriptHash, state); - byte[] method = Encoding.UTF8.GetBytes("method"); + string method = "method"; var args = new VM.Types.Array { 0, 1 }; foreach (var flags in new CallFlags[] { CallFlags.None, CallFlags.AllowCall, CallFlags.AllowModifyStates, CallFlags.All }) @@ -796,39 +639,17 @@ public void TestContract_CallEx() var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); - engine.CurrentContext.EvaluationStack.Push((int)CallFlags.All); - engine.CurrentContext.EvaluationStack.Push(args); - engine.CurrentContext.EvaluationStack.Push(method); - engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); - InteropService.Invoke(engine, InteropService.Contract.CallEx).Should().BeTrue(); + engine.CallContractEx(state.ScriptHash, method, args, CallFlags.All); engine.CurrentContext.EvaluationStack.Pop().Should().Be(args[0]); engine.CurrentContext.EvaluationStack.Pop().Should().Be(args[1]); // Contract doesn't exists - - engine.CurrentContext.EvaluationStack.Push((int)CallFlags.All); - engine.CurrentContext.EvaluationStack.Push(args); - engine.CurrentContext.EvaluationStack.Push(method); - engine.CurrentContext.EvaluationStack.Push(UInt160.Zero.ToArray()); - InteropService.Invoke(engine, InteropService.Contract.CallEx).Should().BeFalse(); + Assert.ThrowsException(() => engine.CallContractEx(UInt160.Zero, method, args, CallFlags.All)); // Call with rights - - engine.CurrentContext.EvaluationStack.Push((int)flags); - engine.CurrentContext.EvaluationStack.Push(args); - engine.CurrentContext.EvaluationStack.Push(method); - engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); - InteropService.Invoke(engine, InteropService.Contract.CallEx).Should().BeTrue(); + engine.CallContractEx(state.ScriptHash, method, args, flags); engine.CurrentContext.EvaluationStack.Pop().Should().Be(args[0]); engine.CurrentContext.EvaluationStack.Pop().Should().Be(args[1]); - - // Check rights - - engine.CurrentContext.EvaluationStack.Push((int)CallFlags.All); - engine.CurrentContext.EvaluationStack.Push(args); - engine.CurrentContext.EvaluationStack.Push(method); - engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); - InteropService.Invoke(engine, InteropService.Contract.CallEx).Should().Be(flags.HasFlag(CallFlags.AllowCall)); } } @@ -836,7 +657,7 @@ public void TestContract_CallEx() public void TestContract_Destroy() { var engine = GetEngine(false, true); - InteropService.Invoke(engine, InteropService.Contract.Destroy).Should().BeTrue(); + engine.DestroyContract(); var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); @@ -857,7 +678,7 @@ public void TestContract_Destroy() snapshot.Storages.Add(storageKey, storageItem); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[0]); - InteropService.Invoke(engine, InteropService.Contract.Destroy).Should().BeTrue(); + engine.DestroyContract(); engine.Snapshot.Storages.Find(BitConverter.GetBytes(0x43000000)).Any().Should().BeFalse(); //storages are removed @@ -866,48 +687,16 @@ public void TestContract_Destroy() snapshot.Contracts.Add(scriptHash, state); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[0]); - InteropService.Invoke(engine, InteropService.Contract.Destroy).Should().BeTrue(); + engine.DestroyContract(); engine.Snapshot.Storages.Find(BitConverter.GetBytes(0x43000000)).Any().Should().BeFalse(); - } [TestMethod] public void TestContract_CreateStandardAccount() { var engine = GetEngine(true, true); - byte[] data = "024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); - - engine.CurrentContext.EvaluationStack.Push(data); - InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().ToHexString().Should().Be("68f96a15748750cccd548feb71be766e8a2c2733"); - - data = "064b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); - engine.CurrentContext.EvaluationStack.Push(data); - Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Invalid point encoding 6"); - - data = "024b817ef37f2fc3d4a33fe36687e599f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); - engine.CurrentContext.EvaluationStack.Push(data); - Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Incorrect length for compressed encoding"); - - data = "02ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes(); - engine.CurrentContext.EvaluationStack.Push(data); - Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("x value too large in field element"); - - data = "020fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes(); - engine.CurrentContext.EvaluationStack.Push(data); - Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Invalid point compression"); - - data = "044b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); - engine.CurrentContext.EvaluationStack.Push(data); - Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Incorrect length for uncompressed/hybrid encoding"); - - data = "04ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes(); - engine.CurrentContext.EvaluationStack.Push(data); - Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("x value too large in field element"); - - data = "040fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes(); - engine.CurrentContext.EvaluationStack.Push(data); - Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("x value too large in field element"); + ECPoint pubkey = ECPoint.Parse("024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e", ECCurve.Secp256r1); + engine.CreateStandardAccount(pubkey).ToArray().ToHexString().Should().Be("a17e91aff4bb5e0ad54d7ce8de8472e17ce88bf1"); } public static void LogEvent(object sender, LogEventArgs args) diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index 0fc198f3d5..848079aef3 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -57,7 +57,7 @@ public void System_Blockchain_GetBlock() using (var script = new ScriptBuilder()) { script.EmitPush(block.Hash.ToArray()); - script.EmitSysCall(InteropService.Blockchain.GetBlock); + script.EmitSysCall(ApplicationEngine.System_Blockchain_GetBlock); // Without block @@ -89,7 +89,7 @@ public void System_Blockchain_GetBlock() height.Index = block.Index; - script.EmitSysCall(InteropService.Json.Serialize); + script.EmitSysCall(ApplicationEngine.System_Json_Serialize); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(script.ToArray()); @@ -115,9 +115,9 @@ public void Json_Deserialize() using (var script = new ScriptBuilder()) { script.EmitPush("123"); - script.EmitSysCall(InteropService.Json.Deserialize); + script.EmitSysCall(ApplicationEngine.System_Json_Deserialize); script.EmitPush("null"); - script.EmitSysCall(InteropService.Json.Deserialize); + script.EmitSysCall(ApplicationEngine.System_Json_Deserialize); using (var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, true)) { @@ -136,7 +136,7 @@ public void Json_Deserialize() using (var script = new ScriptBuilder()) { script.EmitPush("***"); - script.EmitSysCall(InteropService.Json.Deserialize); + script.EmitSysCall(ApplicationEngine.System_Json_Deserialize); using (var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, true)) { @@ -152,7 +152,7 @@ public void Json_Deserialize() using (var script = new ScriptBuilder()) { script.EmitPush("123.45"); - script.EmitSysCall(InteropService.Json.Deserialize); + script.EmitSysCall(ApplicationEngine.System_Json_Deserialize); using (var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, true)) { @@ -172,20 +172,20 @@ public void Json_Serialize() using (var script = new ScriptBuilder()) { script.EmitPush(5); - script.EmitSysCall(InteropService.Json.Serialize); + script.EmitSysCall(ApplicationEngine.System_Json_Serialize); script.Emit(OpCode.PUSH0); script.Emit(OpCode.NOT); - script.EmitSysCall(InteropService.Json.Serialize); + script.EmitSysCall(ApplicationEngine.System_Json_Serialize); script.EmitPush("test"); - script.EmitSysCall(InteropService.Json.Serialize); + script.EmitSysCall(ApplicationEngine.System_Json_Serialize); script.Emit(OpCode.PUSHNULL); - script.EmitSysCall(InteropService.Json.Serialize); + script.EmitSysCall(ApplicationEngine.System_Json_Serialize); script.Emit(OpCode.NEWMAP); script.Emit(OpCode.DUP); script.EmitPush("key"); script.EmitPush("value"); script.Emit(OpCode.SETITEM); - script.EmitSysCall(InteropService.Json.Serialize); + script.EmitSysCall(ApplicationEngine.System_Json_Serialize); using (var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, true)) { @@ -206,8 +206,8 @@ public void Json_Serialize() using (var script = new ScriptBuilder()) { - script.EmitSysCall(InteropService.Storage.GetContext); - script.EmitSysCall(InteropService.Json.Serialize); + script.EmitSysCall(ApplicationEngine.System_Storage_GetContext); + script.EmitSysCall(ApplicationEngine.System_Json_Serialize); using (var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, true)) { @@ -225,7 +225,7 @@ public void System_ExecutionEngine_GetScriptContainer() var snapshot = Blockchain.Singleton.GetSnapshot(); using (var script = new ScriptBuilder()) { - script.EmitSysCall(InteropService.Runtime.GetScriptContainer); + script.EmitSysCall(ApplicationEngine.System_Runtime_GetScriptContainer); // Without tx @@ -238,7 +238,7 @@ public void System_ExecutionEngine_GetScriptContainer() // With tx - script.EmitSysCall(InteropService.Json.Serialize); + script.EmitSysCall(ApplicationEngine.System_Json_Serialize); var tx = new Transaction() { @@ -273,13 +273,13 @@ public void System_Runtime_GasLeft() using (var script = new ScriptBuilder()) { script.Emit(OpCode.NOP); - script.EmitSysCall(InteropService.Runtime.GasLeft); + script.EmitSysCall(ApplicationEngine.System_Runtime_GasLeft); script.Emit(OpCode.NOP); - script.EmitSysCall(InteropService.Runtime.GasLeft); + script.EmitSysCall(ApplicationEngine.System_Runtime_GasLeft); script.Emit(OpCode.NOP); script.Emit(OpCode.NOP); script.Emit(OpCode.NOP); - script.EmitSysCall(InteropService.Runtime.GasLeft); + script.EmitSysCall(ApplicationEngine.System_Runtime_GasLeft); // Execute @@ -300,7 +300,7 @@ public void System_Runtime_GasLeft() using (var script = new ScriptBuilder()) { - script.EmitSysCall(InteropService.Runtime.GasLeft); + script.EmitSysCall(ApplicationEngine.System_Runtime_GasLeft); // Execute @@ -327,7 +327,7 @@ public void System_Runtime_GetInvocationCounter() using (var script = new ScriptBuilder()) { - script.EmitSysCall(InteropService.Runtime.GetInvocationCounter); + script.EmitSysCall(ApplicationEngine.System_Runtime_GetInvocationCounter); contractA = new ContractState() { Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP }.Concat(script.ToArray()).ToArray() }; contractB = new ContractState() { Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP, (byte)OpCode.NOP }.Concat(script.ToArray()).ToArray() }; diff --git a/tests/neo.UnitTests/VM/UT_Helper.cs b/tests/neo.UnitTests/VM/UT_Helper.cs index 428855d0ae..4c89fe09a5 100644 --- a/tests/neo.UnitTests/VM/UT_Helper.cs +++ b/tests/neo.UnitTests/VM/UT_Helper.cs @@ -62,7 +62,7 @@ public void TestEmitAppCall1() tempArray[9] = (byte)OpCode.PUSHDATA1; tempArray[10] = 0x14;//scriptHash.Length Array.Copy(UInt160.Zero.ToArray(), 0, tempArray, 11, 20);//operation.data - uint api = InteropService.Contract.Call; + uint api = ApplicationEngine.System_Contract_Call; tempArray[31] = (byte)OpCode.SYSCALL; Array.Copy(BitConverter.GetBytes(api), 0, tempArray, 32, 4);//api.data CollectionAssert.AreEqual(tempArray, sb.ToArray()); @@ -84,7 +84,7 @@ public void TestEmitAppCall2() tempArray[10] = (byte)OpCode.PUSHDATA1; tempArray[11] = 0x14;//scriptHash.Length Array.Copy(UInt160.Zero.ToArray(), 0, tempArray, 12, 20);//operation.data - uint api = InteropService.Contract.Call; + uint api = ApplicationEngine.System_Contract_Call; tempArray[32] = (byte)OpCode.SYSCALL; Array.Copy(BitConverter.GetBytes(api), 0, tempArray, 33, 4);//api.data CollectionAssert.AreEqual(tempArray, sb.ToArray()); @@ -106,7 +106,7 @@ public void TestEmitAppCall3() tempArray[10] = (byte)OpCode.PUSHDATA1; tempArray[11] = 0x14;//scriptHash.Length Array.Copy(UInt160.Zero.ToArray(), 0, tempArray, 12, 20);//operation.data - uint api = InteropService.Contract.Call; + uint api = ApplicationEngine.System_Contract_Call; tempArray[32] = (byte)OpCode.SYSCALL; Array.Copy(BitConverter.GetBytes(api), 0, tempArray, 33, 4);//api.data CollectionAssert.AreEqual(tempArray, sb.ToArray()); diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index 41069a5006..e63145ff5d 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -171,9 +171,9 @@ public void TestGetVersion() public void TestGetAccount1() { MyWallet wallet = new MyWallet(); - wallet.CreateAccount(UInt160.Parse("0xb3f1526d9f9670df1a21a5953d5296c3a9c9173c")); + wallet.CreateAccount(UInt160.Parse("0xf55f6873ae944cf4ec9626e8855b8554e798a7d1")); WalletAccount account = wallet.GetAccount(ECCurve.Secp256r1.G); - account.ScriptHash.Should().Be(UInt160.Parse("0xb3f1526d9f9670df1a21a5953d5296c3a9c9173c")); + account.ScriptHash.Should().Be(UInt160.Parse("0xf55f6873ae944cf4ec9626e8855b8554e798a7d1")); } [TestMethod]