diff --git a/neo.UnitTests/UT_SpentCointState.cs b/neo.UnitTests/UT_SpentCointState.cs index bb28ebecf3..e71e93fb4d 100644 --- a/neo.UnitTests/UT_SpentCointState.cs +++ b/neo.UnitTests/UT_SpentCointState.cs @@ -1,5 +1,6 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; using Neo.Ledger; using System.Collections.Generic; using System.IO; @@ -24,6 +25,31 @@ public void TransactionHash_Get() uut.TransactionHash.Should().BeNull(); } + [TestMethod] + public void TestFromReplica() + { + uut.Items = new Dictionary(); + uut.Items.Add(1, 3); + + var a = ((ICloneable)uut).Clone(); + var b = new SpentCoinState(); + + ((ICloneable)b).FromReplica(uut); + + CollectionAssert.AreEqual(a.Items.Keys, uut.Items.Keys); + CollectionAssert.AreEqual(a.Items.Values, uut.Items.Values); + CollectionAssert.AreEqual(b.Items.Keys, uut.Items.Keys); + CollectionAssert.AreEqual(b.Items.Values, uut.Items.Values); + + a.Items.Clear(); + b.Items.Clear(); + + CollectionAssert.AreNotEqual(a.Items.Keys, uut.Items.Keys); + CollectionAssert.AreNotEqual(b.Items.Keys, uut.Items.Keys); + CollectionAssert.AreNotEqual(a.Items.Values, uut.Items.Values); + CollectionAssert.AreNotEqual(b.Items.Values, uut.Items.Values); + } + [TestMethod] public void TransactionHash_Set() { @@ -98,8 +124,8 @@ private void setupSpentCoinStateWithValues(SpentCoinState spentCoinState, out UI [TestMethod] public void DeserializeSCS() { - byte[] dataArray = new byte[] { 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, 3, 44, 45, 1, 42, 0, 0, 0, 0, 0 }; - + byte[] dataArray = new byte[] { 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, 3, 44, 45, 1, 42, 0, 0, 0, 0, 0 }; + using (Stream stream = new MemoryStream(dataArray)) { using (BinaryReader reader = new BinaryReader(stream)) diff --git a/neo/Ledger/SpentCoinState.cs b/neo/Ledger/SpentCoinState.cs index 62443c28d6..eef553b867 100644 --- a/neo/Ledger/SpentCoinState.cs +++ b/neo/Ledger/SpentCoinState.cs @@ -42,7 +42,7 @@ void ICloneable.FromReplica(SpentCoinState replica) { TransactionHash = replica.TransactionHash; TransactionHeight = replica.TransactionHeight; - Items = replica.Items; + Items = new Dictionary(replica.Items); } public override void Serialize(BinaryWriter writer) diff --git a/neo/Network/RPC/RpcServer.cs b/neo/Network/RPC/RpcServer.cs index 0bcba6bc0a..52dbf474af 100644 --- a/neo/Network/RPC/RpcServer.cs +++ b/neo/Network/RPC/RpcServer.cs @@ -30,6 +30,48 @@ namespace Neo.Network.RPC { public sealed class RpcServer : IDisposable { + private class CheckWitnessHashes : IVerifiable + { + private readonly UInt160[] _scriptHashesForVerifying; + public Witness[] Witnesses { get; set; } + public int Size { get; } + + public CheckWitnessHashes(UInt160[] scriptHashesForVerifying) + { + _scriptHashesForVerifying = scriptHashesForVerifying; + } + + public void Serialize(BinaryWriter writer) + { + throw new NotImplementedException(); + } + + public void Deserialize(BinaryReader reader) + { + throw new NotImplementedException(); + } + + public void DeserializeUnsigned(BinaryReader reader) + { + throw new NotImplementedException(); + } + + public UInt160[] GetScriptHashesForVerifying(Snapshot snapshot) + { + return _scriptHashesForVerifying; + } + + public void SerializeUnsigned(BinaryWriter writer) + { + throw new NotImplementedException(); + } + + public byte[] GetMessage() + { + throw new NotImplementedException(); + } + } + public Wallet Wallet { get; set; } public Fixed8 MaxGasInvoke { get; } public int MaxConcurrentConnections { get; } @@ -73,9 +115,9 @@ public void Dispose() } } - private JObject GetInvokeResult(byte[] script) + private JObject GetInvokeResult(byte[] script, IVerifiable checkWitnessHashes = null) { - using (ApplicationEngine engine = ApplicationEngine.Run(script, extraGAS: MaxGasInvoke)) + using (ApplicationEngine engine = ApplicationEngine.Run(script, checkWitnessHashes, extraGAS: MaxGasInvoke)) { JObject json = new JObject(); json["script"] = script.ToHexString(); @@ -89,6 +131,7 @@ private JObject GetInvokeResult(byte[] script) { json["stack"] = "error: recursive reference"; } + return json; } } @@ -211,19 +254,37 @@ private JObject Process(string method, JArray _params) { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); ContractParameter[] parameters = ((JArray)_params[1]).Select(p => ContractParameter.FromJson(p)).ToArray(); - return Invoke(script_hash, parameters); + CheckWitnessHashes checkWitnessHashes = null; + if (_params.Count > 2) + { + UInt160[] scriptHashesForVerifying = _params.Skip(2).Select(u => UInt160.Parse(u.AsString())).ToArray(); + checkWitnessHashes = new CheckWitnessHashes(scriptHashesForVerifying); + } + return Invoke(script_hash, parameters, checkWitnessHashes); } case "invokefunction": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); string operation = _params[1].AsString(); ContractParameter[] args = _params.Count >= 3 ? ((JArray)_params[2]).Select(p => ContractParameter.FromJson(p)).ToArray() : new ContractParameter[0]; - return InvokeFunction(script_hash, operation, args); + CheckWitnessHashes checkWitnessHashes = null; + if (_params.Count > 3) + { + UInt160[] scriptHashesForVerifying = _params.Skip(3).Select(u => UInt160.Parse(u.AsString())).ToArray(); + checkWitnessHashes = new CheckWitnessHashes(scriptHashesForVerifying); + } + return InvokeFunction(script_hash, operation, args, checkWitnessHashes); } case "invokescript": { byte[] script = _params[0].AsString().HexToBytes(); - return InvokeScript(script); + CheckWitnessHashes checkWitnessHashes = null; + if (_params.Count > 1) + { + UInt160[] scriptHashesForVerifying = _params.Skip(1).Select(u => UInt160.Parse(u.AsString())).ToArray(); + checkWitnessHashes = new CheckWitnessHashes(scriptHashesForVerifying); + } + return InvokeScript(script, checkWitnessHashes); } case "listplugins": { @@ -620,29 +681,29 @@ private JObject GetVersion() return json; } - private JObject Invoke(UInt160 script_hash, ContractParameter[] parameters) + private JObject Invoke(UInt160 script_hash, ContractParameter[] parameters, IVerifiable checkWitnessHashes = null) { byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { script = sb.EmitAppCall(script_hash, parameters).ToArray(); } - return GetInvokeResult(script); + return GetInvokeResult(script, checkWitnessHashes); } - private JObject InvokeFunction(UInt160 script_hash, string operation, ContractParameter[] args) + private JObject InvokeFunction(UInt160 script_hash, string operation, ContractParameter[] args, IVerifiable checkWitnessHashes = null) { byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { script = sb.EmitAppCall(script_hash, operation, args).ToArray(); } - return GetInvokeResult(script); + return GetInvokeResult(script, checkWitnessHashes); } - private JObject InvokeScript(byte[] script) + private JObject InvokeScript(byte[] script, IVerifiable checkWitnessHashes = null) { - return GetInvokeResult(script); + return GetInvokeResult(script, checkWitnessHashes); } private JObject ListPlugins()