From 49aea699505e60df23315b893c38dcf8ac4a0218 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 20 Sep 2024 09:54:53 -0400 Subject: [PATCH 1/2] Added `CreateStruct`, Fixed CreateMap --- src/Neo/VM/Helper.cs | 56 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/src/Neo/VM/Helper.cs b/src/Neo/VM/Helper.cs index c6423ac1f1..b00e5db9ab 100644 --- a/src/Neo/VM/Helper.cs +++ b/src/Neo/VM/Helper.cs @@ -54,18 +54,50 @@ public static ScriptBuilder CreateArray(this ScriptBuilder builder, IReadOnly /// The to be used. /// The key/value pairs of the map. /// The same instance as . - public static ScriptBuilder CreateMap(this ScriptBuilder builder, IEnumerable> map = null) + public static ScriptBuilder CreateMap(this ScriptBuilder builder, IEnumerable> map) + where TKey : notnull + where TValue : notnull { - builder.Emit(OpCode.NEWMAP); - if (map != null) - foreach (var p in map) - { - builder.Emit(OpCode.DUP); - builder.EmitPush(p.Key); - builder.EmitPush(p.Value); - builder.Emit(OpCode.SETITEM); - } - return builder; + var count = map.Count(); + + if (count == 0) + return builder.Emit(OpCode.NEWMAP); + + foreach (var (key, value) in map) + { + builder.EmitPush(value); + builder.EmitPush(key); + } + builder.EmitPush(count); + return builder.Emit(OpCode.PACKMAP); + } + + public static ScriptBuilder CreateMap(this ScriptBuilder builder, IReadOnlyDictionary map) + where TKey : notnull + where TValue : notnull + { + if (map.Count == 0) + return builder.Emit(OpCode.NEWMAP); + + foreach (var (key, value) in map) + { + builder.EmitPush(value); + builder.EmitPush(key); + } + builder.EmitPush(map.Count); + return builder.Emit(OpCode.PACKMAP); + } + + + public static ScriptBuilder CreateStruct(this ScriptBuilder builder, IReadOnlyList array) + where T : notnull + { + if (array.Count == 0) + return builder.Emit(OpCode.NEWSTRUCT0); + for (var i = array.Count - 1; i >= 0; i--) + builder.EmitPush(array[i]); + builder.EmitPush(array.Count); + return builder.Emit(OpCode.PACKSTRUCT); } /// @@ -218,7 +250,7 @@ public static ScriptBuilder EmitPush(this ScriptBuilder builder, object obj) builder.EmitPush(data); break; case char data: - builder.EmitPush((ushort)data); + builder.EmitPush(data); break; case ushort data: builder.EmitPush(data); From 792968d0335f9689695a6610e924cd14e42c7656 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 20 Sep 2024 13:21:49 -0400 Subject: [PATCH 2/2] Added test and comments --- src/Neo/VM/Helper.cs | 20 +++++++++++++++++--- tests/Neo.UnitTests/VM/UT_Helper.cs | 24 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/Neo/VM/Helper.cs b/src/Neo/VM/Helper.cs index b00e5db9ab..26d0fa132a 100644 --- a/src/Neo/VM/Helper.cs +++ b/src/Neo/VM/Helper.cs @@ -63,7 +63,7 @@ public static ScriptBuilder CreateMap(this ScriptBuilder builder, if (count == 0) return builder.Emit(OpCode.NEWMAP); - foreach (var (key, value) in map) + foreach (var (key, value) in map.Reverse()) { builder.EmitPush(value); builder.EmitPush(key); @@ -72,6 +72,14 @@ public static ScriptBuilder CreateMap(this ScriptBuilder builder, return builder.Emit(OpCode.PACKMAP); } + /// + /// Emits the opcodes for creating a map. + /// + /// The type of the key of the map. + /// The type of the value of the map. + /// The to be used. + /// The key/value pairs of the map. + /// The same instance as . public static ScriptBuilder CreateMap(this ScriptBuilder builder, IReadOnlyDictionary map) where TKey : notnull where TValue : notnull @@ -79,7 +87,7 @@ public static ScriptBuilder CreateMap(this ScriptBuilder builder, if (map.Count == 0) return builder.Emit(OpCode.NEWMAP); - foreach (var (key, value) in map) + foreach (var (key, value) in map.Reverse()) { builder.EmitPush(value); builder.EmitPush(key); @@ -88,7 +96,13 @@ public static ScriptBuilder CreateMap(this ScriptBuilder builder, return builder.Emit(OpCode.PACKMAP); } - + /// + /// Emits the opcodes for creating a struct. + /// + /// The type of the property. + /// The to be used. + /// The list of properties. + /// The same instance as . public static ScriptBuilder CreateStruct(this ScriptBuilder builder, IReadOnlyList array) where T : notnull { diff --git a/tests/Neo.UnitTests/VM/UT_Helper.cs b/tests/Neo.UnitTests/VM/UT_Helper.cs index 3e83256669..db47555dbd 100644 --- a/tests/Neo.UnitTests/VM/UT_Helper.cs +++ b/tests/Neo.UnitTests/VM/UT_Helper.cs @@ -106,6 +106,30 @@ public void TestEmitArray() Assert.AreEqual(0, engine2.ResultStack.Pop().Count); } + [TestMethod] + public void TestEmitStruct() + { + var expected = new BigInteger[] { 1, 2, 3 }; + var sb = new ScriptBuilder(); + sb.CreateStruct(expected); + + using var engine = ApplicationEngine.Create(TriggerType.Application, null, null); + engine.LoadScript(sb.ToArray()); + Assert.AreEqual(VMState.HALT, engine.Execute()); + + CollectionAssert.AreEqual(expected, engine.ResultStack.Pop().Select(u => u.GetInteger()).ToArray()); + + expected = new BigInteger[] { }; + sb = new ScriptBuilder(); + sb.CreateStruct(expected); + + using var engine2 = ApplicationEngine.Create(TriggerType.Application, null, null); + engine2.LoadScript(sb.ToArray()); + Assert.AreEqual(VMState.HALT, engine2.Execute()); + + Assert.AreEqual(0, engine2.ResultStack.Pop().Count); + } + [TestMethod] public void TestEmitMap() {