Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to iterate a byte array inside the smart contract #1281

Merged
merged 11 commits into from
Nov 27, 2019
Merged
20 changes: 15 additions & 5 deletions src/neo/SmartContract/InteropService.NEO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,20 @@ private static bool Storage_Find(ApplicationEngine engine)

private static bool Enumerator_Create(ApplicationEngine engine)
{
if (engine.CurrentContext.EvaluationStack.Pop() is VMArray array)
IEnumerator enumerator;
switch (engine.CurrentContext.EvaluationStack.Pop())
{
IEnumerator enumerator = new ArrayWrapper(array);
engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(enumerator));
return true;
case VMArray array:
enumerator = new ArrayWrapper(array);
break;
case PrimitiveType primitive:
enumerator = new ByteArrayWrapper(primitive);
break;
default:
return false;
}
return false;
engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(enumerator));
return true;
}

private static bool Enumerator_Next(ApplicationEngine engine)
Expand Down Expand Up @@ -312,6 +319,9 @@ private static bool Iterator_Create(ApplicationEngine engine)
case Map map:
iterator = new MapWrapper(map);
break;
case PrimitiveType primitive:
iterator = new ByteArrayWrapper(primitive);
break;
default:
return false;
}
Expand Down
41 changes: 41 additions & 0 deletions src/neo/SmartContract/Iterators/ByteArrayWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Neo.VM.Types;
using System;

namespace Neo.SmartContract.Iterators
{
internal class ByteArrayWrapper : IIterator
{
private readonly byte[] array;
private int index = -1;

public ByteArrayWrapper(PrimitiveType value)
{
this.array = value.ToByteArray().ToArray();
}

public void Dispose() { }

public PrimitiveType Key()
{
if (index < 0)
throw new InvalidOperationException();
return index;
}

public bool Next()
{
int next = index + 1;
if (next >= array.Length)
return false;
index = next;
return true;
}

public StackItem Value()
{
if (index < 0)
throw new InvalidOperationException();
return new Integer(array[index]);
}
}
}
49 changes: 49 additions & 0 deletions tests/neo.UnitTests/SmartContract/Iterators/UT_PrimitiveWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.SmartContract.Iterators;
using Neo.VM;
using Neo.VM.Types;
using System;

namespace Neo.UnitTests.SmartContract.Iterators
{
[TestClass]
public class UT_PrimitiveWrapper
{
[TestMethod]
public void TestGeneratorAndDispose()
{
ByteArrayWrapper arrayWrapper = new ByteArrayWrapper(new ByteArray(new byte[0]));
Assert.IsNotNull(arrayWrapper);
Action action = () => arrayWrapper.Dispose();
action.Should().NotThrow<Exception>();
}

[TestMethod]
public void TestKeyAndValue()
{
ByteArrayWrapper arrayWrapper = new ByteArrayWrapper(new byte[] { 0x01, 0x02 });
Action action1 = () => arrayWrapper.Key();
action1.Should().Throw<InvalidOperationException>();
Action action2 = () => arrayWrapper.Value();
action2.Should().Throw<InvalidOperationException>();
arrayWrapper.Next();
Assert.AreEqual(0x00, arrayWrapper.Key().GetBigInteger());
Assert.AreEqual(0x01, arrayWrapper.Value());
arrayWrapper.Next();
Assert.AreEqual(0x01, arrayWrapper.Key().GetBigInteger());
Assert.AreEqual(0x02, arrayWrapper.Value());
}

[TestMethod]
public void TestNext()
{
ByteArrayWrapper arrayWrapper = new ByteArrayWrapper(new byte[] { 0x01, 0x02 });
Assert.AreEqual(true, arrayWrapper.Next());
Assert.AreEqual(0x01, arrayWrapper.Value());
Assert.AreEqual(true, arrayWrapper.Next());
Assert.AreEqual(0x02, arrayWrapper.Value());
Assert.AreEqual(false, arrayWrapper.Next());
}
}
}
8 changes: 6 additions & 2 deletions tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ public void TestEnumerator_Create()
.Should().Be(new byte[] { 0x01 }.ToHexString());

engine.CurrentContext.EvaluationStack.Push(1);
InteropService.Invoke(engine, InteropService.Neo_Enumerator_Create).Should().BeFalse();
InteropService.Invoke(engine, InteropService.Neo_Enumerator_Create).Should().BeTrue();
}

[TestMethod]
Expand Down Expand Up @@ -380,6 +380,10 @@ public void TestIterator_Create()
ret.GetInterface<IIterator>().Value().GetSpan().ToHexString()
.Should().Be(new byte[] { 0x01 }.ToHexString());

var interop = new InteropInterface<object>(1);
engine.CurrentContext.EvaluationStack.Push(interop);
InteropService.Invoke(engine, InteropService.Neo_Iterator_Create).Should().BeFalse();

var map = new Map
{
{ new Integer(1), new Integer(2) },
Expand All @@ -393,7 +397,7 @@ public void TestIterator_Create()
ret.GetInterface<IIterator>().Value().GetBigInteger().Should().Be(2);

engine.CurrentContext.EvaluationStack.Push(1);
InteropService.Invoke(engine, InteropService.Neo_Iterator_Create).Should().BeFalse();
InteropService.Invoke(engine, InteropService.Neo_Iterator_Create).Should().BeTrue();
}

[TestMethod]
Expand Down