diff --git a/neo.UnitTests/TestUtils.cs b/neo.UnitTests/TestUtils.cs index c8625a4e04..9bf06acbf7 100644 --- a/neo.UnitTests/TestUtils.cs +++ b/neo.UnitTests/TestUtils.cs @@ -92,7 +92,7 @@ public static Transaction CreateRandomHashTransaction() new Witness { InvocationScript = new byte[0], - VerificationScript = new byte[1] + VerificationScript = new byte[0] } } }; diff --git a/neo/Network/P2P/Payloads/Witness.cs b/neo/Network/P2P/Payloads/Witness.cs index b02d521dcc..237a954642 100644 --- a/neo/Network/P2P/Payloads/Witness.cs +++ b/neo/Network/P2P/Payloads/Witness.cs @@ -1,7 +1,7 @@ using Neo.IO; using Neo.IO.Json; using Neo.SmartContract; -using System; +using Neo.VM; using System.IO; namespace Neo.Network.P2P.Payloads @@ -30,8 +30,6 @@ void ISerializable.Deserialize(BinaryReader reader) { InvocationScript = reader.ReadVarBytes(65536); VerificationScript = reader.ReadVarBytes(65536); - if (VerificationScript.Length == 0) - throw new FormatException(); } void ISerializable.Serialize(BinaryWriter writer) diff --git a/neo/SmartContract/Helper.cs b/neo/SmartContract/Helper.cs index 3cf40a42d8..f40dad212e 100644 --- a/neo/SmartContract/Helper.cs +++ b/neo/SmartContract/Helper.cs @@ -262,10 +262,19 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, Snapshot snaps if (hashes.Length != verifiable.Witnesses.Length) return false; for (int i = 0; i < hashes.Length; i++) { - if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; + byte[] verification = verifiable.Witnesses[i].VerificationScript; + if (verification.Length == 0) + { + verification = snapshot.Contracts.TryGet(hashes[i])?.Script; + if (verification is null) return false; + } + else + { + if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; + } using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas)) { - engine.LoadScript(verifiable.Witnesses[i].VerificationScript); + engine.LoadScript(verification); engine.LoadScript(verifiable.Witnesses[i].InvocationScript); if (engine.Execute().HasFlag(VMState.FAULT)) return false; if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) return false; diff --git a/neo/SmartContract/InteropService.NEO.cs b/neo/SmartContract/InteropService.NEO.cs index 812a2d7155..5787cebdb4 100644 --- a/neo/SmartContract/InteropService.NEO.cs +++ b/neo/SmartContract/InteropService.NEO.cs @@ -214,7 +214,7 @@ private static bool Transaction_GetWitnesses(ApplicationEngine engine) if (tx == null) return false; if (tx.Witnesses.Length > engine.MaxArraySize) return false; - engine.CurrentContext.EvaluationStack.Push(tx.Witnesses.Select(p => StackItem.FromInterface(p)).ToArray()); + engine.CurrentContext.EvaluationStack.Push(WitnessWrapper.Create(tx, engine.Snapshot).Select(p => StackItem.FromInterface(p)).ToArray()); return true; } return false; @@ -224,7 +224,7 @@ private static bool Witness_GetVerificationScript(ApplicationEngine engine) { if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) { - Witness witness = _interface.GetInterface(); + WitnessWrapper witness = _interface.GetInterface(); if (witness == null) return false; engine.CurrentContext.EvaluationStack.Push(witness.VerificationScript); return true; diff --git a/neo/SmartContract/WitnessWrapper.cs b/neo/SmartContract/WitnessWrapper.cs new file mode 100644 index 0000000000..f67690cad5 --- /dev/null +++ b/neo/SmartContract/WitnessWrapper.cs @@ -0,0 +1,27 @@ +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using System.Linq; + +namespace Neo.SmartContract +{ + internal class WitnessWrapper + { + public byte[] VerificationScript; + + public static WitnessWrapper[] Create(IVerifiable verifiable, Snapshot snapshot) + { + WitnessWrapper[] wrappers = verifiable.Witnesses.Select(p => new WitnessWrapper + { + VerificationScript = p.VerificationScript + }).ToArray(); + if (wrappers.Any(p => p.VerificationScript.Length == 0)) + { + UInt160[] hashes = verifiable.GetScriptHashesForVerifying(snapshot); + for (int i = 0; i < wrappers.Length; i++) + if (wrappers[i].VerificationScript.Length == 0) + wrappers[i].VerificationScript = snapshot.Contracts[hashes[i]].Script; + } + return wrappers; + } + } +}