diff --git a/src/Neo/SmartContract/ContractState.cs b/src/Neo/SmartContract/ContractState.cs
index 83ac9d3353..5b413c41a4 100644
--- a/src/Neo/SmartContract/ContractState.cs
+++ b/src/Neo/SmartContract/ContractState.cs
@@ -23,7 +23,7 @@ namespace Neo.SmartContract
///
/// Represents a deployed contract.
///
- public class ContractState : IInteroperable
+ public class ContractState : IInteroperableVerifiable
{
///
/// The id of the contract.
@@ -69,7 +69,7 @@ IInteroperable IInteroperable.Clone()
void IInteroperable.FromReplica(IInteroperable replica)
{
- ContractState from = (ContractState)replica;
+ var from = (ContractState)replica;
Id = from.Id;
UpdateCounter = from.UpdateCounter;
Hash = from.Hash;
@@ -79,11 +79,16 @@ void IInteroperable.FromReplica(IInteroperable replica)
void IInteroperable.FromStackItem(StackItem stackItem)
{
- Array array = (Array)stackItem;
+ ((IInteroperableVerifiable)this).FromStackItem(stackItem, true);
+ }
+
+ void IInteroperableVerifiable.FromStackItem(StackItem stackItem, bool verify)
+ {
+ var array = (Array)stackItem;
Id = (int)array[0].GetInteger();
UpdateCounter = (ushort)array[1].GetInteger();
Hash = new UInt160(array[2].GetSpan());
- Nef = ((ByteString)array[3]).Memory.AsSerializable();
+ Nef = NefFile.Parse(((ByteString)array[3]).Memory, verify);
Manifest = array[4].ToInteroperable();
}
diff --git a/src/Neo/SmartContract/IInteroperableVerifiable.cs b/src/Neo/SmartContract/IInteroperableVerifiable.cs
new file mode 100644
index 0000000000..c8af7b8a5e
--- /dev/null
+++ b/src/Neo/SmartContract/IInteroperableVerifiable.cs
@@ -0,0 +1,29 @@
+// Copyright (C) 2015-2024 The Neo Project.
+//
+// IInteroperableVerifiable.cs file belongs to the neo project and is free
+// software distributed under the MIT software license, see the
+// accompanying file LICENSE in the main directory of the
+// repository or http://www.opensource.org/licenses/mit-license.php
+// for more details.
+//
+// Redistribution and use in source and binary forms with or without
+// modifications are permitted.
+
+using Neo.VM.Types;
+
+namespace Neo.SmartContract
+{
+ ///
+ /// Represents the object that can be converted to and from
+ /// and allows you to specify whether a verification is required.
+ ///
+ public interface IInteroperableVerifiable : IInteroperable
+ {
+ ///
+ /// Convert a to the current object.
+ ///
+ /// The to convert.
+ /// Verify the content
+ void FromStackItem(StackItem stackItem, bool verify = true);
+ }
+}
diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs
index 3347163a6c..28642a2db1 100644
--- a/src/Neo/SmartContract/Native/ContractManagement.cs
+++ b/src/Neo/SmartContract/Native/ContractManagement.cs
@@ -84,7 +84,7 @@ internal override async ContractTask OnPersist(ApplicationEngine engine)
else
{
// Parse old contract
- var oldContract = state.GetInteroperable();
+ var oldContract = state.GetInteroperable(false);
// Increase the update counter
oldContract.UpdateCounter++;
// Modify nef and manifest
@@ -122,7 +122,7 @@ private void SetMinimumDeploymentFee(ApplicationEngine engine, BigInteger value)
[ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)]
public ContractState GetContract(DataCache snapshot, UInt160 hash)
{
- return snapshot.TryGet(CreateStorageKey(Prefix_Contract).Add(hash))?.GetInteroperable();
+ return snapshot.TryGet(CreateStorageKey(Prefix_Contract).Add(hash))?.GetInteroperable(false);
}
///
@@ -183,7 +183,7 @@ public bool HasMethod(DataCache snapshot, UInt160 hash, string method, int pcoun
public IEnumerable ListContracts(DataCache snapshot)
{
byte[] listContractsPrefix = CreateStorageKey(Prefix_Contract).ToArray();
- return snapshot.Find(listContractsPrefix).Select(kvp => kvp.Value.GetInteroperable());
+ return snapshot.Find(listContractsPrefix).Select(kvp => kvp.Value.GetInteroperable(false));
}
[ContractMethod(RequiredCallFlags = CallFlags.All)]
@@ -250,7 +250,7 @@ private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] man
engine.AddGas(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0)));
- var contract = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Contract).Add(engine.CallingScriptHash))?.GetInteroperable();
+ var contract = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Contract).Add(engine.CallingScriptHash))?.GetInteroperable(false);
if (contract is null) throw new InvalidOperationException($"Updating Contract Does Not Exist: {engine.CallingScriptHash}");
if (contract.UpdateCounter == ushort.MaxValue) throw new InvalidOperationException($"The contract reached the maximum number of updates.");
@@ -283,7 +283,7 @@ private void Destroy(ApplicationEngine engine)
{
UInt160 hash = engine.CallingScriptHash;
StorageKey ckey = CreateStorageKey(Prefix_Contract).Add(hash);
- ContractState contract = engine.Snapshot.TryGet(ckey)?.GetInteroperable();
+ ContractState contract = engine.Snapshot.TryGet(ckey)?.GetInteroperable(false);
if (contract is null) return;
engine.Snapshot.Delete(ckey);
engine.Snapshot.Delete(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id));
diff --git a/src/Neo/SmartContract/NefFile.cs b/src/Neo/SmartContract/NefFile.cs
index 1ffa7baf20..3e343d3be2 100644
--- a/src/Neo/SmartContract/NefFile.cs
+++ b/src/Neo/SmartContract/NefFile.cs
@@ -86,6 +86,20 @@ public class NefFile : ISerializable
Script.GetVarSize() + // Script
sizeof(uint); // Checksum
+ ///
+ /// Parse NefFile from memory
+ ///
+ /// Memory
+ /// Do checksum and MaxItemSize checks
+ /// NefFile
+ public static NefFile Parse(ReadOnlyMemory memory, bool verify = true)
+ {
+ var reader = new MemoryReader(memory);
+ var nef = new NefFile();
+ nef.Deserialize(ref reader, verify);
+ return nef;
+ }
+
public void Serialize(BinaryWriter writer)
{
SerializeHeader(writer);
@@ -103,7 +117,9 @@ private void SerializeHeader(BinaryWriter writer)
writer.WriteFixedString(Compiler, 64);
}
- public void Deserialize(ref MemoryReader reader)
+ public void Deserialize(ref MemoryReader reader) => Deserialize(ref reader, true);
+
+ public void Deserialize(ref MemoryReader reader, bool verify = true)
{
long startPosition = reader.Position;
if (reader.ReadUInt32() != Magic) throw new FormatException("Wrong magic");
@@ -115,8 +131,11 @@ public void Deserialize(ref MemoryReader reader)
Script = reader.ReadVarMemory((int)ExecutionEngineLimits.Default.MaxItemSize);
if (Script.Length == 0) throw new ArgumentException($"Script can't be empty");
CheckSum = reader.ReadUInt32();
- if (CheckSum != ComputeChecksum(this)) throw new FormatException("CRC verification fail");
- if (reader.Position - startPosition > ExecutionEngineLimits.Default.MaxItemSize) throw new FormatException("Max vm item size exceed");
+ if (verify)
+ {
+ if (CheckSum != ComputeChecksum(this)) throw new FormatException("CRC verification fail");
+ if (reader.Position - startPosition > ExecutionEngineLimits.Default.MaxItemSize) throw new FormatException("Max vm item size exceed");
+ }
}
///
diff --git a/src/Neo/SmartContract/StorageItem.cs b/src/Neo/SmartContract/StorageItem.cs
index 41486997de..350e95e70a 100644
--- a/src/Neo/SmartContract/StorageItem.cs
+++ b/src/Neo/SmartContract/StorageItem.cs
@@ -145,6 +145,24 @@ public void FromReplica(StorageItem replica)
return (T)cache;
}
+ ///
+ /// Gets an from the storage.
+ ///
+ /// Verify deserialization
+ /// The type of the .
+ /// The in the storage.
+ public T GetInteroperable(bool verify = true) where T : IInteroperableVerifiable, new()
+ {
+ if (cache is null)
+ {
+ var interoperable = new T();
+ interoperable.FromStackItem(BinarySerializer.Deserialize(value, ExecutionEngineLimits.Default), verify);
+ cache = interoperable;
+ }
+ value = null;
+ return (T)cache;
+ }
+
public void Serialize(BinaryWriter writer)
{
writer.Write(Value.Span);