diff --git a/neo/SmartContract/ApplicationEngine.cs b/neo/SmartContract/ApplicationEngine.cs index 2f904f330b..71673ab78a 100644 --- a/neo/SmartContract/ApplicationEngine.cs +++ b/neo/SmartContract/ApplicationEngine.cs @@ -1,6 +1,7 @@ using Neo.Core; using Neo.IO.Caching; using Neo.VM; +using Neo.VM.Types; using System.Numerics; using System.Text; @@ -223,8 +224,10 @@ private bool CheckStackSize(OpCode nextInstruction) break; case OpCode.UNPACK: StackItem item = EvaluationStack.Peek(); - if (!item.IsArray) return false; - size = item.GetArray().Count; + if (item is Array array) + size = array.Count; + else + return false; break; } if (size == 0) return true; diff --git a/neo/SmartContract/StackItemType.cs b/neo/SmartContract/StackItemType.cs new file mode 100644 index 0000000000..576f7c1d62 --- /dev/null +++ b/neo/SmartContract/StackItemType.cs @@ -0,0 +1,12 @@ +namespace Neo.SmartContract +{ + internal enum StackItemType : byte + { + ByteArray = 0x00, + Boolean = 0x01, + Integer = 0x02, + InteropInterface = 0x40, + Array = 0x80, + Struct = 0x81, + } +} diff --git a/neo/SmartContract/StateMachine.cs b/neo/SmartContract/StateMachine.cs index 43d6f05f88..f2137e4c03 100644 --- a/neo/SmartContract/StateMachine.cs +++ b/neo/SmartContract/StateMachine.cs @@ -2,6 +2,7 @@ using Neo.Cryptography.ECC; using Neo.IO.Caching; using Neo.VM; +using Neo.VM.Types; using System; using System.Collections.Generic; using System.Linq; @@ -148,22 +149,26 @@ private bool Asset_Create(ExecutionEngine engine) private bool Asset_Renew(ExecutionEngine engine) { - AssetState asset = engine.EvaluationStack.Pop().GetInterface(); - if (asset == null) return false; - byte years = (byte)engine.EvaluationStack.Pop().GetBigInteger(); - asset = assets.GetAndChange(asset.AssetId); - if (asset.Expiration < Blockchain.Default.Height + 1) - asset.Expiration = Blockchain.Default.Height + 1; - try - { - asset.Expiration = checked(asset.Expiration + years * 2000000u); - } - catch (OverflowException) + if (engine.EvaluationStack.Pop() is InteropInterface _interface) { - asset.Expiration = uint.MaxValue; + AssetState asset = _interface.GetInterface(); + if (asset == null) return false; + byte years = (byte)engine.EvaluationStack.Pop().GetBigInteger(); + asset = assets.GetAndChange(asset.AssetId); + if (asset.Expiration < Blockchain.Default.Height + 1) + asset.Expiration = Blockchain.Default.Height + 1; + try + { + asset.Expiration = checked(asset.Expiration + years * 2000000u); + } + catch (OverflowException) + { + asset.Expiration = uint.MaxValue; + } + engine.EvaluationStack.Push(asset.Expiration); + return true; } - engine.EvaluationStack.Push(asset.Expiration); - return true; + return false; } private bool Contract_Create(ExecutionEngine engine) @@ -264,14 +269,18 @@ private bool Contract_Migrate(ExecutionEngine engine) private bool Contract_GetStorageContext(ExecutionEngine engine) { - ContractState contract = engine.EvaluationStack.Pop().GetInterface(); - if (!contracts_created.TryGetValue(contract.ScriptHash, out UInt160 created)) return false; - if (!created.Equals(new UInt160(engine.CurrentContext.ScriptHash))) return false; - engine.EvaluationStack.Push(StackItem.FromInterface(new StorageContext + if (engine.EvaluationStack.Pop() is InteropInterface _interface) { - ScriptHash = contract.ScriptHash - })); - return true; + ContractState contract = _interface.GetInterface(); + if (!contracts_created.TryGetValue(contract.ScriptHash, out UInt160 created)) return false; + if (!created.Equals(new UInt160(engine.CurrentContext.ScriptHash))) return false; + engine.EvaluationStack.Push(StackItem.FromInterface(new StorageContext + { + ScriptHash = contract.ScriptHash + })); + return true; + } + return false; } private bool Contract_Destroy(ExecutionEngine engine) @@ -288,44 +297,56 @@ private bool Contract_Destroy(ExecutionEngine engine) protected override bool Storage_Get(ExecutionEngine engine) { - StorageContext context = engine.EvaluationStack.Pop().GetInterface(); - if (!CheckStorageContext(context)) return false; - byte[] key = engine.EvaluationStack.Pop().GetByteArray(); - StorageItem item = storages.TryGet(new StorageKey + if (engine.EvaluationStack.Pop() is InteropInterface _interface) { - ScriptHash = context.ScriptHash, - Key = key - }); - engine.EvaluationStack.Push(item?.Value ?? new byte[0]); - return true; + StorageContext context = _interface.GetInterface(); + if (!CheckStorageContext(context)) return false; + byte[] key = engine.EvaluationStack.Pop().GetByteArray(); + StorageItem item = storages.TryGet(new StorageKey + { + ScriptHash = context.ScriptHash, + Key = key + }); + engine.EvaluationStack.Push(item?.Value ?? new byte[0]); + return true; + } + return false; } private bool Storage_Put(ExecutionEngine engine) { - StorageContext context = engine.EvaluationStack.Pop().GetInterface(); - if (!CheckStorageContext(context)) return false; - byte[] key = engine.EvaluationStack.Pop().GetByteArray(); - if (key.Length > 1024) return false; - byte[] value = engine.EvaluationStack.Pop().GetByteArray(); - storages.GetAndChange(new StorageKey + if (engine.EvaluationStack.Pop() is InteropInterface _interface) { - ScriptHash = context.ScriptHash, - Key = key - }, () => new StorageItem()).Value = value; - return true; + StorageContext context = _interface.GetInterface(); + if (!CheckStorageContext(context)) return false; + byte[] key = engine.EvaluationStack.Pop().GetByteArray(); + if (key.Length > 1024) return false; + byte[] value = engine.EvaluationStack.Pop().GetByteArray(); + storages.GetAndChange(new StorageKey + { + ScriptHash = context.ScriptHash, + Key = key + }, () => new StorageItem()).Value = value; + return true; + } + return false; } private bool Storage_Delete(ExecutionEngine engine) { - StorageContext context = engine.EvaluationStack.Pop().GetInterface(); - if (!CheckStorageContext(context)) return false; - byte[] key = engine.EvaluationStack.Pop().GetByteArray(); - storages.Delete(new StorageKey + if (engine.EvaluationStack.Pop() is InteropInterface _interface) { - ScriptHash = context.ScriptHash, - Key = key - }); - return true; + StorageContext context = _interface.GetInterface(); + if (!CheckStorageContext(context)) return false; + byte[] key = engine.EvaluationStack.Pop().GetByteArray(); + storages.Delete(new StorageKey + { + ScriptHash = context.ScriptHash, + Key = key + }); + return true; + } + return false; } } } diff --git a/neo/SmartContract/StateReader.cs b/neo/SmartContract/StateReader.cs index c4c1d71d4b..dc74488d59 100644 --- a/neo/SmartContract/StateReader.cs +++ b/neo/SmartContract/StateReader.cs @@ -1,10 +1,15 @@ using Neo.Core; using Neo.Cryptography.ECC; +using Neo.IO; using Neo.VM; +using Neo.VM.Types; using System; +using System.IO; using System.Linq; using System.Numerics; using System.Text; +using VMArray = Neo.VM.Types.Array; +using VMBoolean = Neo.VM.Types.Boolean; namespace Neo.SmartContract { @@ -22,6 +27,8 @@ public StateReader() Register("Neo.Runtime.Notify", Runtime_Notify); Register("Neo.Runtime.Log", Runtime_Log); Register("Neo.Runtime.GetTime", Runtime_GetTime); + Register("Neo.Runtime.Serialize", Runtime_Serialize); + Register("Neo.Runtime.Deserialize", Runtime_Deserialize); Register("Neo.Blockchain.GetHeight", Blockchain_GetHeight); Register("Neo.Blockchain.GetHeader", Blockchain_GetHeader); Register("Neo.Blockchain.GetBlock", Blockchain_GetBlock); @@ -176,6 +183,91 @@ protected virtual bool Runtime_GetTime(ExecutionEngine engine) return true; } + private void SerializeStackItem(StackItem item, BinaryWriter writer) + { + switch (item) + { + case ByteArray _: + writer.Write((byte)StackItemType.ByteArray); + writer.WriteVarBytes(item.GetByteArray()); + break; + case VMBoolean _: + writer.Write((byte)StackItemType.Boolean); + writer.Write(item.GetBoolean()); + break; + case Integer _: + writer.Write((byte)StackItemType.Integer); + writer.WriteVarBytes(item.GetByteArray()); + break; + case InteropInterface _: + throw new NotSupportedException(); + case VMArray array: + if (array is Struct) + writer.Write((byte)StackItemType.Struct); + else + writer.Write((byte)StackItemType.Array); + writer.WriteVarInt(array.Count); + foreach (StackItem subitem in array) + SerializeStackItem(subitem, writer); + break; + } + } + + protected virtual bool Runtime_Serialize(ExecutionEngine engine) + { + using (MemoryStream ms = new MemoryStream()) + using (BinaryWriter writer = new BinaryWriter(ms)) + { + try + { + SerializeStackItem(engine.EvaluationStack.Pop(), writer); + } + catch (NotSupportedException) + { + return false; + } + writer.Flush(); + engine.EvaluationStack.Push(ms.ToArray()); + } + return true; + } + + private StackItem DeserializeStackItem(BinaryReader reader) + { + StackItemType type = (StackItemType)reader.ReadByte(); + switch (type) + { + case StackItemType.ByteArray: + return new ByteArray(reader.ReadVarBytes()); + case StackItemType.Boolean: + return new VMBoolean(reader.ReadBoolean()); + case StackItemType.Integer: + return new Integer(new BigInteger(reader.ReadVarBytes())); + case StackItemType.Array: + case StackItemType.Struct: + VMArray array = type == StackItemType.Struct ? new Struct() : new VMArray(); + ulong count = reader.ReadVarInt(); + while (count-- > 0) + array.Add(DeserializeStackItem(reader)); + return array; + default: + return null; + } + } + + protected virtual bool Runtime_Deserialize(ExecutionEngine engine) + { + byte[] data = engine.EvaluationStack.Pop().GetByteArray(); + using (MemoryStream ms = new MemoryStream(data, false)) + using (BinaryReader reader = new BinaryReader(ms)) + { + StackItem item = DeserializeStackItem(reader); + if (item == null) return false; + engine.EvaluationStack.Push(item); + } + return true; + } + protected virtual bool Blockchain_GetHeight(ExecutionEngine engine) { if (Blockchain.Default == null) @@ -291,303 +383,451 @@ protected virtual bool Blockchain_GetContract(ExecutionEngine engine) protected virtual bool Header_GetIndex(ExecutionEngine engine) { - BlockBase header = engine.EvaluationStack.Pop().GetInterface(); - if (header == null) return false; - engine.EvaluationStack.Push(header.Index); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + BlockBase header = _interface.GetInterface(); + if (header == null) return false; + engine.EvaluationStack.Push(header.Index); + return true; + } + return false; } protected virtual bool Header_GetHash(ExecutionEngine engine) { - BlockBase header = engine.EvaluationStack.Pop().GetInterface(); - if (header == null) return false; - engine.EvaluationStack.Push(header.Hash.ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + BlockBase header = _interface.GetInterface(); + if (header == null) return false; + engine.EvaluationStack.Push(header.Hash.ToArray()); + return true; + } + return false; } protected virtual bool Header_GetVersion(ExecutionEngine engine) { - BlockBase header = engine.EvaluationStack.Pop().GetInterface(); - if (header == null) return false; - engine.EvaluationStack.Push(header.Version); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + BlockBase header = _interface.GetInterface(); + if (header == null) return false; + engine.EvaluationStack.Push(header.Version); + return true; + } + return false; } protected virtual bool Header_GetPrevHash(ExecutionEngine engine) { - BlockBase header = engine.EvaluationStack.Pop().GetInterface(); - if (header == null) return false; - engine.EvaluationStack.Push(header.PrevHash.ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + BlockBase header = _interface.GetInterface(); + if (header == null) return false; + engine.EvaluationStack.Push(header.PrevHash.ToArray()); + return true; + } + return false; } protected virtual bool Header_GetMerkleRoot(ExecutionEngine engine) { - BlockBase header = engine.EvaluationStack.Pop().GetInterface(); - if (header == null) return false; - engine.EvaluationStack.Push(header.MerkleRoot.ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + BlockBase header = _interface.GetInterface(); + if (header == null) return false; + engine.EvaluationStack.Push(header.MerkleRoot.ToArray()); + return true; + } + return false; } protected virtual bool Header_GetTimestamp(ExecutionEngine engine) { - BlockBase header = engine.EvaluationStack.Pop().GetInterface(); - if (header == null) return false; - engine.EvaluationStack.Push(header.Timestamp); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + BlockBase header = _interface.GetInterface(); + if (header == null) return false; + engine.EvaluationStack.Push(header.Timestamp); + return true; + } + return false; } protected virtual bool Header_GetConsensusData(ExecutionEngine engine) { - BlockBase header = engine.EvaluationStack.Pop().GetInterface(); - if (header == null) return false; - engine.EvaluationStack.Push(header.ConsensusData); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + BlockBase header = _interface.GetInterface(); + if (header == null) return false; + engine.EvaluationStack.Push(header.ConsensusData); + return true; + } + return false; } protected virtual bool Header_GetNextConsensus(ExecutionEngine engine) { - BlockBase header = engine.EvaluationStack.Pop().GetInterface(); - if (header == null) return false; - engine.EvaluationStack.Push(header.NextConsensus.ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + BlockBase header = _interface.GetInterface(); + if (header == null) return false; + engine.EvaluationStack.Push(header.NextConsensus.ToArray()); + return true; + } + return false; } protected virtual bool Block_GetTransactionCount(ExecutionEngine engine) { - Block block = engine.EvaluationStack.Pop().GetInterface(); - if (block == null) return false; - engine.EvaluationStack.Push(block.Transactions.Length); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + Block block = _interface.GetInterface(); + if (block == null) return false; + engine.EvaluationStack.Push(block.Transactions.Length); + return true; + } + return false; } protected virtual bool Block_GetTransactions(ExecutionEngine engine) { - Block block = engine.EvaluationStack.Pop().GetInterface(); - if (block == null) return false; - engine.EvaluationStack.Push(block.Transactions.Select(p => StackItem.FromInterface(p)).ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + Block block = _interface.GetInterface(); + if (block == null) return false; + engine.EvaluationStack.Push(block.Transactions.Select(p => StackItem.FromInterface(p)).ToArray()); + return true; + } + return false; } protected virtual bool Block_GetTransaction(ExecutionEngine engine) { - Block block = engine.EvaluationStack.Pop().GetInterface(); - int index = (int)engine.EvaluationStack.Pop().GetBigInteger(); - if (block == null) return false; - if (index < 0 || index >= block.Transactions.Length) return false; - Transaction tx = block.Transactions[index]; - engine.EvaluationStack.Push(StackItem.FromInterface(tx)); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + Block block = _interface.GetInterface(); + int index = (int)engine.EvaluationStack.Pop().GetBigInteger(); + if (block == null) return false; + if (index < 0 || index >= block.Transactions.Length) return false; + Transaction tx = block.Transactions[index]; + engine.EvaluationStack.Push(StackItem.FromInterface(tx)); + return true; + } + return false; } protected virtual bool Transaction_GetHash(ExecutionEngine engine) { - Transaction tx = engine.EvaluationStack.Pop().GetInterface(); - if (tx == null) return false; - engine.EvaluationStack.Push(tx.Hash.ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + Transaction tx = _interface.GetInterface(); + if (tx == null) return false; + engine.EvaluationStack.Push(tx.Hash.ToArray()); + return true; + } + return false; } protected virtual bool Transaction_GetType(ExecutionEngine engine) { - Transaction tx = engine.EvaluationStack.Pop().GetInterface(); - if (tx == null) return false; - engine.EvaluationStack.Push((int)tx.Type); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + Transaction tx = _interface.GetInterface(); + if (tx == null) return false; + engine.EvaluationStack.Push((int)tx.Type); + return true; + } + return false; } protected virtual bool Transaction_GetAttributes(ExecutionEngine engine) { - Transaction tx = engine.EvaluationStack.Pop().GetInterface(); - if (tx == null) return false; - engine.EvaluationStack.Push(tx.Attributes.Select(p => StackItem.FromInterface(p)).ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + Transaction tx = _interface.GetInterface(); + if (tx == null) return false; + engine.EvaluationStack.Push(tx.Attributes.Select(p => StackItem.FromInterface(p)).ToArray()); + return true; + } + return false; } protected virtual bool Transaction_GetInputs(ExecutionEngine engine) { - Transaction tx = engine.EvaluationStack.Pop().GetInterface(); - if (tx == null) return false; - engine.EvaluationStack.Push(tx.Inputs.Select(p => StackItem.FromInterface(p)).ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + Transaction tx = _interface.GetInterface(); + if (tx == null) return false; + engine.EvaluationStack.Push(tx.Inputs.Select(p => StackItem.FromInterface(p)).ToArray()); + return true; + } + return false; } protected virtual bool Transaction_GetOutputs(ExecutionEngine engine) { - Transaction tx = engine.EvaluationStack.Pop().GetInterface(); - if (tx == null) return false; - engine.EvaluationStack.Push(tx.Outputs.Select(p => StackItem.FromInterface(p)).ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + Transaction tx = _interface.GetInterface(); + if (tx == null) return false; + engine.EvaluationStack.Push(tx.Outputs.Select(p => StackItem.FromInterface(p)).ToArray()); + return true; + } + return false; } protected virtual bool Transaction_GetReferences(ExecutionEngine engine) { - Transaction tx = engine.EvaluationStack.Pop().GetInterface(); - if (tx == null) return false; - engine.EvaluationStack.Push(tx.Inputs.Select(p => StackItem.FromInterface(tx.References[p])).ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + Transaction tx = _interface.GetInterface(); + if (tx == null) return false; + engine.EvaluationStack.Push(tx.Inputs.Select(p => StackItem.FromInterface(tx.References[p])).ToArray()); + return true; + } + return false; } protected virtual bool Transaction_GetUnspentCoins(ExecutionEngine engine) { - Transaction tx = engine.EvaluationStack.Pop().GetInterface(); - if (tx == null) return false; - engine.EvaluationStack.Push(Blockchain.Default.GetUnspent(tx.Hash).Select(p => StackItem.FromInterface(p)).ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + Transaction tx = _interface.GetInterface(); + if (tx == null) return false; + engine.EvaluationStack.Push(Blockchain.Default.GetUnspent(tx.Hash).Select(p => StackItem.FromInterface(p)).ToArray()); + return true; + } + return false; } protected virtual bool Attribute_GetUsage(ExecutionEngine engine) { - TransactionAttribute attr = engine.EvaluationStack.Pop().GetInterface(); - if (attr == null) return false; - engine.EvaluationStack.Push((int)attr.Usage); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + TransactionAttribute attr = _interface.GetInterface(); + if (attr == null) return false; + engine.EvaluationStack.Push((int)attr.Usage); + return true; + } + return false; } protected virtual bool Attribute_GetData(ExecutionEngine engine) { - TransactionAttribute attr = engine.EvaluationStack.Pop().GetInterface(); - if (attr == null) return false; - engine.EvaluationStack.Push(attr.Data); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + TransactionAttribute attr = _interface.GetInterface(); + if (attr == null) return false; + engine.EvaluationStack.Push(attr.Data); + return true; + } + return false; } protected virtual bool Input_GetHash(ExecutionEngine engine) { - CoinReference input = engine.EvaluationStack.Pop().GetInterface(); - if (input == null) return false; - engine.EvaluationStack.Push(input.PrevHash.ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + CoinReference input = _interface.GetInterface(); + if (input == null) return false; + engine.EvaluationStack.Push(input.PrevHash.ToArray()); + return true; + } + return false; } protected virtual bool Input_GetIndex(ExecutionEngine engine) { - CoinReference input = engine.EvaluationStack.Pop().GetInterface(); - if (input == null) return false; - engine.EvaluationStack.Push((int)input.PrevIndex); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + CoinReference input = _interface.GetInterface(); + if (input == null) return false; + engine.EvaluationStack.Push((int)input.PrevIndex); + return true; + } + return false; } protected virtual bool Output_GetAssetId(ExecutionEngine engine) { - TransactionOutput output = engine.EvaluationStack.Pop().GetInterface(); - if (output == null) return false; - engine.EvaluationStack.Push(output.AssetId.ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + TransactionOutput output = _interface.GetInterface(); + if (output == null) return false; + engine.EvaluationStack.Push(output.AssetId.ToArray()); + return true; + } + return false; } protected virtual bool Output_GetValue(ExecutionEngine engine) { - TransactionOutput output = engine.EvaluationStack.Pop().GetInterface(); - if (output == null) return false; - engine.EvaluationStack.Push(output.Value.GetData()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + TransactionOutput output = _interface.GetInterface(); + if (output == null) return false; + engine.EvaluationStack.Push(output.Value.GetData()); + return true; + } + return false; } protected virtual bool Output_GetScriptHash(ExecutionEngine engine) { - TransactionOutput output = engine.EvaluationStack.Pop().GetInterface(); - if (output == null) return false; - engine.EvaluationStack.Push(output.ScriptHash.ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + TransactionOutput output = _interface.GetInterface(); + if (output == null) return false; + engine.EvaluationStack.Push(output.ScriptHash.ToArray()); + return true; + } + return false; } protected virtual bool Account_GetScriptHash(ExecutionEngine engine) { - AccountState account = engine.EvaluationStack.Pop().GetInterface(); - if (account == null) return false; - engine.EvaluationStack.Push(account.ScriptHash.ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + AccountState account = _interface.GetInterface(); + if (account == null) return false; + engine.EvaluationStack.Push(account.ScriptHash.ToArray()); + return true; + } + return false; } protected virtual bool Account_GetVotes(ExecutionEngine engine) { - AccountState account = engine.EvaluationStack.Pop().GetInterface(); - if (account == null) return false; - engine.EvaluationStack.Push(account.Votes.Select(p => (StackItem)p.EncodePoint(true)).ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + AccountState account = _interface.GetInterface(); + if (account == null) return false; + engine.EvaluationStack.Push(account.Votes.Select(p => (StackItem)p.EncodePoint(true)).ToArray()); + return true; + } + return false; } protected virtual bool Account_GetBalance(ExecutionEngine engine) { - AccountState account = engine.EvaluationStack.Pop().GetInterface(); - UInt256 asset_id = new UInt256(engine.EvaluationStack.Pop().GetByteArray()); - if (account == null) return false; - Fixed8 balance = account.Balances.TryGetValue(asset_id, out Fixed8 value) ? value : Fixed8.Zero; - engine.EvaluationStack.Push(balance.GetData()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + AccountState account = _interface.GetInterface(); + UInt256 asset_id = new UInt256(engine.EvaluationStack.Pop().GetByteArray()); + if (account == null) return false; + Fixed8 balance = account.Balances.TryGetValue(asset_id, out Fixed8 value) ? value : Fixed8.Zero; + engine.EvaluationStack.Push(balance.GetData()); + return true; + } + return false; } protected virtual bool Asset_GetAssetId(ExecutionEngine engine) { - AssetState asset = engine.EvaluationStack.Pop().GetInterface(); - if (asset == null) return false; - engine.EvaluationStack.Push(asset.AssetId.ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + AssetState asset = _interface.GetInterface(); + if (asset == null) return false; + engine.EvaluationStack.Push(asset.AssetId.ToArray()); + return true; + } + return false; } protected virtual bool Asset_GetAssetType(ExecutionEngine engine) { - AssetState asset = engine.EvaluationStack.Pop().GetInterface(); - if (asset == null) return false; - engine.EvaluationStack.Push((int)asset.AssetType); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + AssetState asset = _interface.GetInterface(); + if (asset == null) return false; + engine.EvaluationStack.Push((int)asset.AssetType); + return true; + } + return false; } protected virtual bool Asset_GetAmount(ExecutionEngine engine) { - AssetState asset = engine.EvaluationStack.Pop().GetInterface(); - if (asset == null) return false; - engine.EvaluationStack.Push(asset.Amount.GetData()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + AssetState asset = _interface.GetInterface(); + if (asset == null) return false; + engine.EvaluationStack.Push(asset.Amount.GetData()); + return true; + } + return false; } protected virtual bool Asset_GetAvailable(ExecutionEngine engine) { - AssetState asset = engine.EvaluationStack.Pop().GetInterface(); - if (asset == null) return false; - engine.EvaluationStack.Push(asset.Available.GetData()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + AssetState asset = _interface.GetInterface(); + if (asset == null) return false; + engine.EvaluationStack.Push(asset.Available.GetData()); + return true; + } + return false; } protected virtual bool Asset_GetPrecision(ExecutionEngine engine) { - AssetState asset = engine.EvaluationStack.Pop().GetInterface(); - if (asset == null) return false; - engine.EvaluationStack.Push((int)asset.Precision); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + AssetState asset = _interface.GetInterface(); + if (asset == null) return false; + engine.EvaluationStack.Push((int)asset.Precision); + return true; + } + return false; } protected virtual bool Asset_GetOwner(ExecutionEngine engine) { - AssetState asset = engine.EvaluationStack.Pop().GetInterface(); - if (asset == null) return false; - engine.EvaluationStack.Push(asset.Owner.EncodePoint(true)); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + AssetState asset = _interface.GetInterface(); + if (asset == null) return false; + engine.EvaluationStack.Push(asset.Owner.EncodePoint(true)); + return true; + } + return false; } protected virtual bool Asset_GetAdmin(ExecutionEngine engine) { - AssetState asset = engine.EvaluationStack.Pop().GetInterface(); - if (asset == null) return false; - engine.EvaluationStack.Push(asset.Admin.ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + AssetState asset = _interface.GetInterface(); + if (asset == null) return false; + engine.EvaluationStack.Push(asset.Admin.ToArray()); + return true; + } + return false; } protected virtual bool Asset_GetIssuer(ExecutionEngine engine) { - AssetState asset = engine.EvaluationStack.Pop().GetInterface(); - if (asset == null) return false; - engine.EvaluationStack.Push(asset.Issuer.ToArray()); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + AssetState asset = _interface.GetInterface(); + if (asset == null) return false; + engine.EvaluationStack.Push(asset.Issuer.ToArray()); + return true; + } + return false; } protected virtual bool Contract_GetScript(ExecutionEngine engine) { - ContractState contract = engine.EvaluationStack.Pop().GetInterface(); - if (contract == null) return false; - engine.EvaluationStack.Push(contract.Script); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + ContractState contract = _interface.GetInterface(); + if (contract == null) return false; + engine.EvaluationStack.Push(contract.Script); + return true; + } + return false; } protected virtual bool Storage_GetContext(ExecutionEngine engine) @@ -601,18 +841,22 @@ protected virtual bool Storage_GetContext(ExecutionEngine engine) protected virtual bool Storage_Get(ExecutionEngine engine) { - StorageContext context = engine.EvaluationStack.Pop().GetInterface(); - ContractState contract = Blockchain.Default.GetContract(context.ScriptHash); - if (contract == null) return false; - if (!contract.HasStorage) return false; - byte[] key = engine.EvaluationStack.Pop().GetByteArray(); - StorageItem item = Blockchain.Default.GetStorageItem(new StorageKey - { - ScriptHash = context.ScriptHash, - Key = key - }); - engine.EvaluationStack.Push(item?.Value ?? new byte[0]); - return true; + if (engine.EvaluationStack.Pop() is InteropInterface _interface) + { + StorageContext context = _interface.GetInterface(); + ContractState contract = Blockchain.Default.GetContract(context.ScriptHash); + if (contract == null) return false; + if (!contract.HasStorage) return false; + byte[] key = engine.EvaluationStack.Pop().GetByteArray(); + StorageItem item = Blockchain.Default.GetStorageItem(new StorageKey + { + ScriptHash = context.ScriptHash, + Key = key + }); + engine.EvaluationStack.Push(item?.Value ?? new byte[0]); + return true; + } + return false; } } } diff --git a/neo/VM/Helper.cs b/neo/VM/Helper.cs index 09056b89e8..f0bb2b4220 100644 --- a/neo/VM/Helper.cs +++ b/neo/VM/Helper.cs @@ -1,10 +1,13 @@ using Neo.Cryptography.ECC; using Neo.IO; using Neo.SmartContract; +using Neo.VM.Types; using System; using System.Collections.Generic; using System.Linq; using System.Numerics; +using VMArray = Neo.VM.Types.Array; +using VMBoolean = Neo.VM.Types.Boolean; namespace Neo.VM { @@ -169,34 +172,33 @@ public static ScriptBuilder EmitSysCall(this ScriptBuilder sb, string api, param public static ContractParameter ToParameter(this StackItem item) { - switch (item.GetType().Name) + switch (item) { - case "Array": - case "Struct": + case VMArray array: return new ContractParameter { Type = ContractParameterType.Array, - Value = item.GetArray().Select(p => p.ToParameter()).ToArray() + Value = array.Select(p => p.ToParameter()).ToArray() }; - case "Boolean": + case VMBoolean _: return new ContractParameter { Type = ContractParameterType.Boolean, Value = item.GetBoolean() }; - case "ByteArray": + case ByteArray _: return new ContractParameter { Type = ContractParameterType.ByteArray, Value = item.GetByteArray() }; - case "Integer": + case Integer _: return new ContractParameter { Type = ContractParameterType.Integer, Value = item.GetBigInteger() }; - case "InteropInterface": + case InteropInterface _: return new ContractParameter { Type = ContractParameterType.InteropInterface diff --git a/neo/Wallets/Wallet.cs b/neo/Wallets/Wallet.cs index adbe0ee586..e5ed1a1efa 100644 --- a/neo/Wallets/Wallet.cs +++ b/neo/Wallets/Wallet.cs @@ -10,6 +10,7 @@ using System.Security.Cryptography.X509Certificates; using System.Text; using ECPoint = Neo.Cryptography.ECC.ECPoint; +using VMArray = Neo.VM.Types.Array; namespace Neo.Wallets { @@ -104,7 +105,7 @@ public BigDecimal GetAvailable(UIntBase asset_id) } ApplicationEngine engine = ApplicationEngine.Run(script); byte decimals = (byte)engine.EvaluationStack.Pop().GetBigInteger(); - BigInteger amount = engine.EvaluationStack.Pop().GetArray().Aggregate(BigInteger.Zero, (x, y) => x + y.GetBigInteger()); + BigInteger amount = ((VMArray)engine.EvaluationStack.Pop()).Aggregate(BigInteger.Zero, (x, y) => x + y.GetBigInteger()); return new BigDecimal(amount, decimals); } else @@ -304,7 +305,7 @@ public virtual WalletAccount Import(string nep2, string passphrase) } ApplicationEngine engine = ApplicationEngine.Run(script); if (engine.State.HasFlag(VMState.FAULT)) return null; - var balances = engine.EvaluationStack.Pop().GetArray().Reverse().Zip(accounts, (i, a) => new + var balances = ((IEnumerable)(VMArray)engine.EvaluationStack.Pop()).Reverse().Zip(accounts, (i, a) => new { Account = a, Value = i.GetBigInteger() diff --git a/neo/neo.csproj b/neo/neo.csproj index e3af0b7302..004d9db2f2 100644 --- a/neo/neo.csproj +++ b/neo/neo.csproj @@ -3,7 +3,7 @@ 2015-2017 The Neo Project Neo - 2.7.1 + 2.7.2 The Neo Project netstandard2.0;net47 true @@ -37,7 +37,7 @@ - +