diff --git a/src/neo/VM/Helper.cs b/src/neo/VM/Helper.cs
index 49a5a78f4b..c719acde11 100644
--- a/src/neo/VM/Helper.cs
+++ b/src/neo/VM/Helper.cs
@@ -278,48 +278,105 @@ public static byte[] MakeScript(this UInt160 scriptHash, string method, params o
/// Converts the to a JSON object.
///
/// The to convert.
+ /// The maximum size in bytes of the result.
/// The represented by a JSON object.
- public static JObject ToJson(this StackItem item)
+ public static JObject ToJson(this StackItem item, int maxSize = int.MaxValue)
{
- return ToJson(item, null);
+ return ToJson(item, null, ref maxSize);
}
- private static JObject ToJson(StackItem item, HashSet context)
+ ///
+ /// Converts the to a JSON object.
+ ///
+ /// The to convert.
+ /// The maximum size in bytes of the result.
+ /// The represented by a JSON object.
+ public static JArray ToJson(this EvaluationStack stack, int maxSize = int.MaxValue)
+ {
+ if (maxSize <= 0) throw new ArgumentOutOfRangeException(nameof(maxSize));
+ maxSize -= 2/*[]*/+ Math.Max(0, (stack.Count - 1))/*,*/;
+ JArray result = new();
+ foreach (var item in stack)
+ result.Add(ToJson(item, null, ref maxSize));
+ if (maxSize < 0) throw new InvalidOperationException("Max size reached.");
+ return result;
+ }
+
+ private static JObject ToJson(StackItem item, HashSet context, ref int maxSize)
{
- JObject json = new();
- json["type"] = item.Type;
+ JObject json = new()
+ {
+ ["type"] = item.Type
+ };
+ JObject value = null;
+ maxSize -= 11/*{"type":""}*/+ item.Type.ToString().Length;
switch (item)
{
case Array array:
- context ??= new HashSet(ReferenceEqualityComparer.Instance);
- if (!context.Add(array)) throw new InvalidOperationException();
- json["value"] = new JArray(array.Select(p => ToJson(p, context)));
- break;
+ {
+ context ??= new HashSet(ReferenceEqualityComparer.Instance);
+ if (!context.Add(array)) throw new InvalidOperationException();
+ maxSize -= 2/*[]*/+ Math.Max(0, (array.Count - 1))/*,*/;
+ JArray a = new();
+ foreach (StackItem stackItem in array)
+ a.Add(ToJson(stackItem, context, ref maxSize));
+ value = a;
+ break;
+ }
case Boolean boolean:
- json["value"] = boolean.GetBoolean();
- break;
+ {
+ bool b = boolean.GetBoolean();
+ maxSize -= b ? 4/*true*/: 5/*false*/;
+ value = b;
+ break;
+ }
case Buffer _:
case ByteString _:
- json["value"] = Convert.ToBase64String(item.GetSpan());
- break;
+ {
+ string s = Convert.ToBase64String(item.GetSpan());
+ maxSize -= 2/*""*/+ s.Length;
+ value = s;
+ break;
+ }
case Integer integer:
- json["value"] = integer.GetInteger().ToString();
- break;
+ {
+ string s = integer.GetInteger().ToString();
+ maxSize -= 2/*""*/+ s.Length;
+ value = s;
+ break;
+ }
case Map map:
- context ??= new HashSet(ReferenceEqualityComparer.Instance);
- if (!context.Add(map)) throw new InvalidOperationException();
- json["value"] = new JArray(map.Select(p =>
{
- JObject item = new();
- item["key"] = ToJson(p.Key, context);
- item["value"] = ToJson(p.Value, context);
- return item;
- }));
- break;
+ context ??= new HashSet(ReferenceEqualityComparer.Instance);
+ if (!context.Add(map)) throw new InvalidOperationException();
+ maxSize -= 2/*[]*/+ Math.Max(0, (map.Count - 1))/*,*/;
+ JArray a = new();
+ foreach (var (k, v) in map)
+ {
+ maxSize -= 17/*{"key":,"value":}*/;
+ JObject i = new()
+ {
+ ["key"] = ToJson(k, context, ref maxSize),
+ ["value"] = ToJson(v, context, ref maxSize)
+ };
+ a.Add(i);
+ }
+ value = a;
+ break;
+ }
case Pointer pointer:
- json["value"] = pointer.Position;
- break;
+ {
+ maxSize -= pointer.Position.ToString().Length;
+ value = pointer.Position;
+ break;
+ }
+ }
+ if (value is not null)
+ {
+ maxSize -= 9/*,"value":*/;
+ json["value"] = value;
}
+ if (maxSize < 0) throw new InvalidOperationException("Max size reached.");
return json;
}