Skip to content

Commit

Permalink
[Neo VM Style] Throw exception for Integer that is larger than 32 byt…
Browse files Browse the repository at this point in the history
…es (#3486)

* fix push integer

* Update src/Neo.VM/ScriptBuilder.cs

* Update tests/Neo.VM.Tests/UT_ScriptBuilder.cs

* Update tests/Neo.VM.Tests/UT_ScriptBuilder.cs
  • Loading branch information
Jim8y committed Sep 14, 2024
1 parent c6282cd commit 9946450
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 29 deletions.
3 changes: 2 additions & 1 deletion src/Neo.VM/ScriptBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ public ScriptBuilder EmitPush(BigInteger value)
<= 4 => Emit(OpCode.PUSHINT32, PadRight(buffer, bytesWritten, 4, value.Sign < 0)),
<= 8 => Emit(OpCode.PUSHINT64, PadRight(buffer, bytesWritten, 8, value.Sign < 0)),
<= 16 => Emit(OpCode.PUSHINT128, PadRight(buffer, bytesWritten, 16, value.Sign < 0)),
_ => Emit(OpCode.PUSHINT256, PadRight(buffer, bytesWritten, 32, value.Sign < 0)),
<= 32 => Emit(OpCode.PUSHINT256, PadRight(buffer, bytesWritten, 32, value.Sign < 0)),
_ => throw new ArgumentOutOfRangeException(nameof(value), "Invalid value: BigInteger is too large"),
};
}

Expand Down
78 changes: 50 additions & 28 deletions tests/Neo.VM.Tests/UT_ScriptBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,41 +143,63 @@ public void TestEmitJump()
[TestMethod]
public void TestEmitPushBigInteger()
{
using (ScriptBuilder script = new())
// Test small integers (-1 to 16)
for (var i = -1; i <= 16; i++)
{
script.EmitPush(BigInteger.MinusOne);
CollectionAssert.AreEqual(new byte[] { 0x0F }, script.ToArray());
using ScriptBuilder script = new();
script.EmitPush(new BigInteger(i));
CollectionAssert.AreEqual(new[] { (byte)(OpCode.PUSH0 + (byte)i) }, script.ToArray());
}

using (ScriptBuilder script = new())
{
script.EmitPush(BigInteger.Zero);
CollectionAssert.AreEqual(new byte[] { 0x10 }, script.ToArray());
}
// Test -1
Assert.AreEqual("0x0f", new ScriptBuilder().EmitPush(BigInteger.MinusOne).ToArray().ToHexString());

for (byte x = 1; x <= 16; x++)
{
using ScriptBuilder script = new();
script.EmitPush(new BigInteger(x));
CollectionAssert.AreEqual(new byte[] { (byte)(OpCode.PUSH0 + x) }, script.ToArray());
}
// Test edge cases for different sizes
// PUSHINT8
Assert.AreEqual("0x0080", new ScriptBuilder().EmitPush(sbyte.MinValue).ToArray().ToHexString());
Assert.AreEqual("0x007f", new ScriptBuilder().EmitPush(sbyte.MaxValue).ToArray().ToHexString());

// PUSHINT16
Assert.AreEqual("0x010080", new ScriptBuilder().EmitPush(short.MinValue).ToArray().ToHexString());
Assert.AreEqual("0x01ff7f", new ScriptBuilder().EmitPush(short.MaxValue).ToArray().ToHexString());

// PUSHINT32
Assert.AreEqual("0x0200000080", new ScriptBuilder().EmitPush(int.MinValue).ToArray().ToHexString());
Assert.AreEqual("0x02ffffff7f", new ScriptBuilder().EmitPush(int.MaxValue).ToArray().ToHexString());

// PUSHINT64
Assert.AreEqual("0x030000000000000080", new ScriptBuilder().EmitPush(long.MinValue).ToArray().ToHexString());
Assert.AreEqual("0x03ffffffffffffff7f", new ScriptBuilder().EmitPush(long.MaxValue).ToArray().ToHexString());

// PUSHINT128
Assert.AreEqual("0x04ffffffffffffffff0000000000000000", new ScriptBuilder().EmitPush(new BigInteger(ulong.MaxValue)).ToArray().ToHexString());
Assert.AreEqual("0x0400000000000000000100000000000000", new ScriptBuilder().EmitPush(new BigInteger(ulong.MaxValue) + 1).ToArray().ToHexString());

// PUSHINT256, case from https://en.wikipedia.org/wiki/256-bit_computing#:~:text=The%20range%20of%20a%20signed,%2C%E2%80%8B819%2C%E2%80%8B967.
Assert.AreEqual("0x050000000000000000000000000000000000000000000000000000000000000080",
new ScriptBuilder().EmitPush(BigInteger.Parse("-57896044618658097711785492504343953926634992332820282019728792003956564819968")).ToArray().ToHexString());

Assert.AreEqual("0x05ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
new ScriptBuilder().EmitPush(BigInteger.Parse("57896044618658097711785492504343953926634992332820282019728792003956564819967")).ToArray().ToHexString());

// Test exceeding 256-bit value (2^256)
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
new ScriptBuilder().EmitPush(BigInteger.Parse("115792089237316195423570985008687907853269984665640564039457584007913129639936")));

// Test negative numbers
Assert.AreEqual("0x00fe", new ScriptBuilder().EmitPush(new BigInteger(-2)).ToArray().ToHexString());
Assert.AreEqual("0x0100ff", new ScriptBuilder().EmitPush(new BigInteger(-256)).ToArray().ToHexString());

// Test numbers that are exactly at the boundary
Assert.AreEqual("0x04ffffffffffffffff0000000000000000", new ScriptBuilder().EmitPush(BigInteger.Parse("18446744073709551615")).ToArray().ToHexString());
Assert.AreEqual("0x0400000000000000000100000000000000", new ScriptBuilder().EmitPush(BigInteger.Parse("18446744073709551616")).ToArray().ToHexString());

CollectionAssert.AreEqual("0080".FromHexString(), new ScriptBuilder().EmitPush(sbyte.MinValue).ToArray());
CollectionAssert.AreEqual("007f".FromHexString(), new ScriptBuilder().EmitPush(sbyte.MaxValue).ToArray());
CollectionAssert.AreEqual("01ff00".FromHexString(), new ScriptBuilder().EmitPush(byte.MaxValue).ToArray());
CollectionAssert.AreEqual("010080".FromHexString(), new ScriptBuilder().EmitPush(short.MinValue).ToArray());
CollectionAssert.AreEqual("01ff7f".FromHexString(), new ScriptBuilder().EmitPush(short.MaxValue).ToArray());
CollectionAssert.AreEqual("02ffff0000".FromHexString(), new ScriptBuilder().EmitPush(ushort.MaxValue).ToArray());
CollectionAssert.AreEqual("0200000080".FromHexString(), new ScriptBuilder().EmitPush(int.MinValue).ToArray());
CollectionAssert.AreEqual("02ffffff7f".FromHexString(), new ScriptBuilder().EmitPush(int.MaxValue).ToArray());
CollectionAssert.AreEqual("03ffffffff00000000".FromHexString(), new ScriptBuilder().EmitPush(uint.MaxValue).ToArray());
CollectionAssert.AreEqual("030000000000000080".FromHexString(), new ScriptBuilder().EmitPush(long.MinValue).ToArray());
CollectionAssert.AreEqual("03ffffffffffffff7f".FromHexString(), new ScriptBuilder().EmitPush(long.MaxValue).ToArray());
CollectionAssert.AreEqual("04ffffffffffffffff0000000000000000".FromHexString(), new ScriptBuilder().EmitPush(ulong.MaxValue).ToArray());
CollectionAssert.AreEqual("050100000000000000feffffffffffffff00000000000000000000000000000000".FromHexString(), new ScriptBuilder().EmitPush(new BigInteger(ulong.MaxValue) * new BigInteger(ulong.MaxValue)).ToArray());
// Test very large negative number
Assert.AreEqual("0x040000000000000000ffffffffffffffff", new ScriptBuilder().EmitPush(BigInteger.Parse("-18446744073709551616")).ToArray().ToHexString());

// Test exception for too large BigInteger
Assert.ThrowsException<ArgumentOutOfRangeException>(() => new ScriptBuilder().EmitPush(
new BigInteger("050100000000000000feffffffffffffff0100000000000000feffffffffffffff00000000000000000000000000000000".FromHexString())));
BigInteger.Parse("115792089237316195423570985008687907853269984665640564039457584007913129639937")));
}

[TestMethod]
Expand Down

0 comments on commit 9946450

Please sign in to comment.