From cd27dbe4d519f3b201c71b6883cd42189bf442ce Mon Sep 17 00:00:00 2001 From: Cedric Decoster Date: Tue, 26 Nov 2024 23:21:57 +0100 Subject: [PATCH] refactored i128,u128,1256,u256 --- .../TypeConverters/BaseTypesTest.cs | 7 +- .../TypeConverters/PrimitiveRustTest.cs | 718 +++++++ .../TypeConverters/PrimitiveTypesTest.cs | 48 +- Substrate.NetApi/CompactInteger.cs | 57 +- .../Model/Types/Primitive/I128.cs | 31 +- .../Model/Types/Primitive/I256.cs | 30 +- .../Model/Types/Primitive/RustPrimitives.cs | 1752 +++++++++++++++++ .../Model/Types/Primitive/U128.cs | 43 +- .../Model/Types/Primitive/U256.cs | 48 +- Substrate.NetApi/Substrate.NetApi.csproj | 2 +- 10 files changed, 2642 insertions(+), 94 deletions(-) create mode 100644 Substrate.NetApi.Test/TypeConverters/PrimitiveRustTest.cs create mode 100644 Substrate.NetApi/Model/Types/Primitive/RustPrimitives.cs diff --git a/Substrate.NetApi.Test/TypeConverters/BaseTypesTest.cs b/Substrate.NetApi.Test/TypeConverters/BaseTypesTest.cs index 7dba339..1878a76 100644 --- a/Substrate.NetApi.Test/TypeConverters/BaseTypesTest.cs +++ b/Substrate.NetApi.Test/TypeConverters/BaseTypesTest.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using Newtonsoft.Json.Linq; using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using System.Numerics; namespace Substrate.NetApi.Test { @@ -248,9 +249,9 @@ public void BaseComTest() Assert.AreNotEqual(baseComFromValue.Value, new BaseCom(new CompactInteger(new U64(20))).Value); Assert.AreEqual(baseComFromValue.TypeSize, new BaseCom(new CompactInteger(new U64(20))).TypeSize); - Assert.AreEqual(baseComFromValue.Bytes, new BaseCom(new CompactInteger(new U128(10))).Bytes); - Assert.AreEqual(baseComFromValue.Value, new BaseCom(new CompactInteger(new U128(10))).Value); - Assert.AreEqual(baseComFromValue.TypeSize, new BaseCom(new CompactInteger(new U128(10))).TypeSize); + Assert.AreEqual(baseComFromValue.Bytes, new BaseCom(new CompactInteger((U128) new BigInteger(10))).Bytes); + Assert.AreEqual(baseComFromValue.Value, new BaseCom(new CompactInteger((U128)new BigInteger(10))).Value); + Assert.AreEqual(baseComFromValue.TypeSize, new BaseCom(new CompactInteger((U128)new BigInteger(10))).TypeSize); // Test explicit conversion from CompactInteger to BaseCom var compactInt = new CompactInteger(new U64(10)); diff --git a/Substrate.NetApi.Test/TypeConverters/PrimitiveRustTest.cs b/Substrate.NetApi.Test/TypeConverters/PrimitiveRustTest.cs new file mode 100644 index 0000000..fe2b6cd --- /dev/null +++ b/Substrate.NetApi.Test/TypeConverters/PrimitiveRustTest.cs @@ -0,0 +1,718 @@ +using NUnit.Framework; +using Substrate.NetApi.Model.Types.Primitive; +using System; +using System.Numerics; + +namespace Substrate.NetApi.Test +{ + [TestFixture] + public class u256Tests + { + [Test] + public void AdditionTest() + { + u256 a = u256.MaxValue; + u256 b = u256.One; + u256 result = a + b; + Assert.AreEqual(u256.Zero, result); // Wrap-around behavior + } + + [Test] + public void SubtractionTest() + { + u256 a = u256.Zero; + u256 b = u256.One; + u256 result = a - b; + Assert.AreEqual(u256.MaxValue, result); // Wrap-around behavior + } + + [Test] + public void MultiplicationTest() + { + u256 a = new u256(2, 0, 0, 0); + u256 b = new u256(3, 0, 0, 0); + u256 result = a * b; + Assert.AreEqual(new u256(6, 0, 0, 0), result); + } + + [Test] + public void DivisionTest() + { + u256 a = new u256(10, 0, 0, 0); + u256 b = new u256(2, 0, 0, 0); + u256 result = a / b; + Assert.AreEqual(new u256(5, 0, 0, 0), result); + } + + [Test] + public void ModuloTest() + { + u256 a = new u256(10, 0, 0, 0); + u256 b = new u256(3, 0, 0, 0); + u256 result = a % b; + Assert.AreEqual(new u256(1, 0, 0, 0), result); + } + + [Test] + public void BitwiseOperationsTest() + { + u256 a = new u256(0x0F0F0F0F0F0F0F0FUL, 0, 0, 0); + u256 b = new u256(0x00FF00FF00FF00FFUL, 0, 0, 0); + + u256 andResult = a & b; + u256 orResult = a | b; + u256 xorResult = a ^ b; + u256 notResult = ~a; + + Assert.AreEqual(new u256(0x000F000F000F000FUL, 0, 0, 0), andResult); + Assert.AreEqual(new u256(0x0FFF0FFF0FFF0FFFUL, 0, 0, 0), orResult); + Assert.AreEqual(new u256(0x0FF00FF00FF00FF0UL, 0, 0, 0), xorResult); + Assert.AreEqual(new u256(0xF0F0F0F0F0F0F0F0UL, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue), notResult); + } + + [Test] + public void ShiftOperationsTest() + { + u256 a = new u256(1, 0, 0, 0); + u256 leftShift = a << 64; + u256 rightShift = leftShift >> 64; + + Assert.AreEqual(new u256(0, 1, 0, 0), leftShift); + Assert.AreEqual(a, rightShift); + } + + [Test] + public void ComparisonOperatorsTest() + { + u256 a = new u256(1, 0, 0, 0); + u256 b = new u256(2, 0, 0, 0); + + Assert.IsTrue(a < b); + Assert.IsTrue(b > a); + Assert.IsTrue(a <= a); + Assert.IsTrue(b >= a); + Assert.IsTrue(a == a); + Assert.IsTrue(a != b); + } + + [Test] + public void ToBigIntegerTest() + { + u256 a = new u256(ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue); + BigInteger bigInt = a.ToBigInteger(); + + Assert.AreEqual(BigInteger.Pow(2, 256) - 1, bigInt); + } + + [Test] + public void FromBigIntegerTest() + { + BigInteger bigInt = BigInteger.Pow(2, 256) - 1; + u256 a = u256.FromBigInteger(bigInt); + + Assert.AreEqual(u256.MaxValue, a); + } + + [Test] + public void ParseTest() + { + BigInteger expectedValue = BigInteger.Pow(2, 256) - 1; + string value = expectedValue.ToString(); + u256 a = u256.Parse(value); + + Assert.AreEqual(expectedValue, a.ToBigInteger()); + } + + [Test] + public void TryParseTest() + { + string value = "NotANumber"; + bool success = u256.TryParse(value, out u256 result); + + Assert.IsFalse(success); + Assert.AreEqual(u256.Zero, result); + } + + [Test] + public void DivideByZeroTest() + { + u256 a = new u256(10, 0, 0, 0); + u256 b = u256.Zero; + + Assert.Throws(() => { var result = a / b; }); + Assert.Throws(() => { var result = a % b; }); + } + + [Test] + public void OverflowTest() + { + u256 a = u256.MaxValue; + u256 b = u256.One; + u256 result = a + b; + + Assert.AreEqual(u256.Zero, result); + } + + [Test] + public void ToStringTest() + { + u256 a = new u256(1234567890UL, 0, 0, 0); + string str = a.ToString(); + + Assert.AreEqual("1234567890", str); + } + + [Test] + public void EqualityTest() + { + u256 a = new u256(123, 456, 789, 101112); + u256 b = new u256(123, 456, 789, 101112); + u256 c = new u256(123, 456, 789, 0); + + Assert.IsTrue(a.Equals(b)); + Assert.IsFalse(a.Equals(c)); + Assert.IsTrue(a == b); + Assert.IsTrue(a != c); + } + + [Test] + public void HashCodeTest() + { + u256 a = new u256(123, 456, 789, 101112); + u256 b = new u256(123, 456, 789, 101112); + + Assert.AreEqual(a.GetHashCode(), b.GetHashCode()); + } + } + + [TestFixture] + public class i256Tests + { + [Test] + public void AdditionTest() + { + i256 a = i256.MaxValue; + i256 b = i256.One; + Assert.Throws(() => { var result = a + b; }); + } + + [Test] + public void SubtractionTest() + { + i256 a = i256.MinValue; + i256 b = i256.One; + Assert.Throws(() => { var result = a - b; }); + } + + [Test] + public void MultiplicationTest() + { + i256 a = new i256(2, 0, 0, 0); + i256 b = new i256(ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue); // Represents -1 in two's complement + i256 result = a * b; + i256 expected = new i256(ulong.MaxValue - 1, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue); // -2 in two's complement + Assert.AreEqual(expected, result); + } + + [Test] + public void DivisionTest() + { + i256 a = new i256(10, 0, 0, 0); + i256 b = new i256(2, 0, 0, 0); + i256 result = a / b; + Assert.AreEqual(new i256(5, 0, 0, 0), result); + } + + [Test] + public void ModuloTest() + { + i256 a = new i256(10, 0, 0, 0); + i256 b = new i256(3, 0, 0, 0); + i256 result = a % b; + Assert.AreEqual(new i256(1, 0, 0, 0), result); + } + + [Test] + public void BitwiseOperationsTest() + { + i256 a = new i256(0x0F0F0F0F0F0F0F0FUL, 0, 0, 0); + i256 b = new i256(0x00FF00FF00FF00FFUL, 0, 0, 0); + + i256 andResult = a & b; + i256 orResult = a | b; + i256 xorResult = a ^ b; + i256 notResult = ~a; + + Assert.AreEqual(new i256(0x000F000F000F000FUL, 0, 0, 0), andResult); + Assert.AreEqual(new i256(0x0FFF0FFF0FFF0FFFUL, 0, 0, 0), orResult); + Assert.AreEqual(new i256(0x0FF00FF00FF00FF0UL, 0, 0, 0), xorResult); + Assert.AreEqual(new i256(0xF0F0F0F0F0F0F0F0UL, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue), notResult); + } + + [Test] + public void ShiftOperationsTest() + { + i256 a = new i256(1, 0, 0, 0); + i256 leftShift = a << 64; + i256 rightShift = leftShift >> 64; + + Assert.AreEqual(new i256(0, 1, 0, 0), leftShift); + Assert.AreEqual(a, rightShift); + } + + [Test] + public void ComparisonOperatorsTest() + { + i256 a = new i256(1, 0, 0, 0); + i256 b = new i256(ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue); + + Assert.IsTrue(b < a); + Assert.IsTrue(a > b); + Assert.IsTrue(a >= a); + Assert.IsTrue(b <= a); + Assert.IsTrue(a != b); + } + + [Test] + public void ToBigIntegerTest() + { + i256 a = i256.MinValue; + BigInteger bigInt = a.ToBigInteger(); + + Assert.AreEqual(BigInteger.Pow(-2, 255), bigInt); + } + + [Test] + public void FromBigIntegerTest() + { + BigInteger bigInt = BigInteger.Pow(-2, 255); + i256 a = i256.FromBigInteger(bigInt); + + Assert.AreEqual(i256.MinValue, a); + } + + [Test] + public void ParseTest() + { + string value = "-1234567890123456789012345678901234567890"; + i256 a = i256.Parse(value); + + Assert.AreEqual(value, a.ToString()); + } + + [Test] + public void TryParseTest() + { + string value = "NotANumber"; + bool success = i256.TryParse(value, out i256 result); + + Assert.IsFalse(success); + Assert.AreEqual(i256.Zero, result); + } + + [Test] + public void DivideByZeroTest() + { + i256 a = new i256(10, 0, 0, 0); + i256 b = i256.Zero; + + Assert.Throws(() => { var result = a / b; }); + Assert.Throws(() => { var result = a % b; }); + } + + [Test] + public void OverflowTest() + { + i256 a = i256.MaxValue; + i256 b = i256.One; + + Assert.Throws(() => { var result = a + b; }); + } + + [Test] + public void ToStringTest() + { + i256 a = new i256(1234567890UL, 0, 0, 0); + string str = a.ToString(); + + Assert.AreEqual("1234567890", str); + } + + [Test] + public void EqualityTest() + { + i256 a = new i256(123, 456, 789, 101112); + i256 b = new i256(123, 456, 789, 101112); + i256 c = new i256(123, 456, 789, 0); + + Assert.IsTrue(a.Equals(b)); + Assert.IsFalse(a.Equals(c)); + Assert.IsTrue(a == b); + Assert.IsTrue(a != c); + } + + [Test] + public void HashCodeTest() + { + i256 a = new i256(123, 456, 789, 101112); + i256 b = new i256(123, 456, 789, 101112); + + Assert.AreEqual(a.GetHashCode(), b.GetHashCode()); + } + } + + [TestFixture] + public class u128Tests + { + [Test] + public void AdditionTest() + { + u128 a = u128.MaxValue; + u128 b = u128.One; + u128 result = a + b; + Assert.AreEqual(u128.Zero, result); + } + + [Test] + public void SubtractionTest() + { + u128 a = u128.Zero; + u128 b = u128.One; + u128 result = a - b; + Assert.AreEqual(u128.MaxValue, result); + } + + [Test] + public void MultiplicationTest() + { + u128 a = new u128(2, 0); + u128 b = new u128(3, 0); + u128 result = a * b; + Assert.AreEqual(new u128(6, 0), result); + } + + [Test] + public void DivisionTest() + { + u128 a = new u128(10, 0); + u128 b = new u128(2, 0); + u128 result = a / b; + Assert.AreEqual(new u128(5, 0), result); + } + + [Test] + public void ModuloTest() + { + u128 a = new u128(10, 0); + u128 b = new u128(3, 0); + u128 result = a % b; + Assert.AreEqual(new u128(1, 0), result); + } + + [Test] + public void BitwiseOperationsTest() + { + u128 a = new u128(0x0F0F0F0F0F0F0F0FUL, 0); + u128 b = new u128(0x00FF00FF00FF00FFUL, 0); + + u128 andResult = a & b; + u128 orResult = a | b; + u128 xorResult = a ^ b; + u128 notResult = ~a; + + Assert.AreEqual(new u128(0x000F000F000F000FUL, 0), andResult); + Assert.AreEqual(new u128(0x0FFF0FFF0FFF0FFFUL, 0), orResult); + Assert.AreEqual(new u128(0x0FF00FF00FF00FF0UL, 0), xorResult); + Assert.AreEqual(new u128(0xF0F0F0F0F0F0F0F0UL, ulong.MaxValue), notResult); + } + + [Test] + public void ShiftOperationsTest() + { + u128 a = new u128(1, 0); + u128 leftShift = a << 64; + u128 rightShift = leftShift >> 64; + + Assert.AreEqual(new u128(0, 1), leftShift); + Assert.AreEqual(a, rightShift); + } + + [Test] + public void ComparisonOperatorsTest() + { + u128 a = new u128(1, 0); + u128 b = new u128(2, 0); + + Assert.IsTrue(a < b); + Assert.IsTrue(b > a); + Assert.IsTrue(a <= a); + Assert.IsTrue(b >= a); + Assert.IsTrue(a == a); + Assert.IsTrue(a != b); + } + + [Test] + public void ToBigIntegerTest() + { + u128 a = u128.MaxValue; + BigInteger bigInt = a.ToBigInteger(); + + Assert.AreEqual(BigInteger.Pow(2, 128) - 1, bigInt); + } + + [Test] + public void FromBigIntegerTest() + { + BigInteger bigInt = BigInteger.Pow(2, 128) - 1; + u128 a = u128.FromBigInteger(bigInt); + + Assert.AreEqual(u128.MaxValue, a); + } + + [Test] + public void ParseTest() + { + string value = (BigInteger.Pow(2, 64) + 12345).ToString(); + u128 a = u128.Parse(value); + + Assert.AreEqual(new u128(12345, 1), a); + } + + [Test] + public void TryParseTest() + { + string value = "NotANumber"; + bool success = u128.TryParse(value, out u128 result); + + Assert.IsFalse(success); + Assert.AreEqual(u128.Zero, result); + } + + [Test] + public void DivideByZeroTest() + { + u128 a = new u128(10, 0); + u128 b = u128.Zero; + + Assert.Throws(() => { var result = a / b; }); + Assert.Throws(() => { var result = a % b; }); + } + + [Test] + public void OverflowTest() + { + u128 a = u128.MaxValue; + u128 b = u128.One; + u128 result = a + b; + + Assert.AreEqual(u128.Zero, result); + } + + [Test] + public void ToStringTest() + { + u128 a = new u128(1234567890UL, 0); + string str = a.ToString(); + + Assert.AreEqual("1234567890", str); + } + + [Test] + public void EqualityTest() + { + u128 a = new u128(123, 456); + u128 b = new u128(123, 456); + u128 c = new u128(123, 0); + + Assert.IsTrue(a.Equals(b)); + Assert.IsFalse(a.Equals(c)); + Assert.IsTrue(a == b); + Assert.IsTrue(a != c); + } + + [Test] + public void HashCodeTest() + { + u128 a = new u128(123, 456); + u128 b = new u128(123, 456); + + Assert.AreEqual(a.GetHashCode(), b.GetHashCode()); + } + } + + [TestFixture] + public class i128Tests + { + [Test] + public void AdditionTest() + { + i128 a = i128.MaxValue; + i128 b = i128.One; + Assert.Throws(() => { var result = a + b; }); + } + + [Test] + public void SubtractionTest() + { + i128 a = i128.MinValue; + i128 b = i128.One; + Assert.Throws(() => { var result = a - b; }); + } + + [Test] + public void MultiplicationTest() + { + i128 a = new i128(2, 0); + i128 b = new i128(ulong.MaxValue, ulong.MaxValue); // Represents -1 in two's complement + i128 result = a * b; + i128 expected = new i128(ulong.MaxValue - 1, ulong.MaxValue); // -2 in two's complement + Assert.AreEqual(expected, result); + } + + [Test] + public void DivisionTest() + { + i128 a = new i128(10, 0); + i128 b = new i128(2, 0); + i128 result = a / b; + Assert.AreEqual(new i128(5, 0), result); + } + + [Test] + public void ModuloTest() + { + i128 a = new i128(10, 0); + i128 b = new i128(3, 0); + i128 result = a % b; + Assert.AreEqual(new i128(1, 0), result); + } + + [Test] + public void BitwiseOperationsTest() + { + i128 a = new i128(0x0F0F0F0F0F0F0F0FUL, 0); + i128 b = new i128(0x00FF00FF00FF00FFUL, 0); + + i128 andResult = a & b; + i128 orResult = a | b; + i128 xorResult = a ^ b; + i128 notResult = ~a; + + Assert.AreEqual(new i128(0x000F000F000F000FUL, 0), andResult); + Assert.AreEqual(new i128(0x0FFF0FFF0FFF0FFFUL, 0), orResult); + Assert.AreEqual(new i128(0x0FF00FF00FF00FF0UL, 0), xorResult); + Assert.AreEqual(new i128(0xF0F0F0F0F0F0F0F0UL, ulong.MaxValue), notResult); + } + + [Test] + public void ShiftOperationsTest() + { + i128 a = new i128(1, 0); + i128 leftShift = a << 64; + i128 rightShift = leftShift >> 64; + + Assert.AreEqual(new i128(0, 1), leftShift); + Assert.AreEqual(a, rightShift); + } + + [Test] + public void ComparisonOperatorsTest() + { + i128 a = new i128(1, 0); + i128 b = new i128(ulong.MaxValue, ulong.MaxValue); + + Assert.IsTrue(b < a); + Assert.IsTrue(a > b); + Assert.IsTrue(a >= a); + Assert.IsTrue(b <= a); + Assert.IsTrue(a != b); + } + + [Test] + public void ToBigIntegerTest() + { + i128 a = i128.MinValue; + BigInteger bigInt = a.ToBigInteger(); + + Assert.AreEqual(BigInteger.Pow(-2, 127), bigInt); + } + + [Test] + public void FromBigIntegerTest() + { + BigInteger bigInt = BigInteger.Pow(-2, 127); + i128 a = i128.FromBigInteger(bigInt); + + Assert.AreEqual(i128.MinValue, a); + } + + [Test] + public void ParseTest() + { + string value = "-170141183460469231731687303715884105728"; // Min value for i128 + i128 a = i128.Parse(value); + + Assert.AreEqual(i128.MinValue, a); + } + + [Test] + public void TryParseTest() + { + string value = "NotANumber"; + bool success = i128.TryParse(value, out i128 result); + + Assert.IsFalse(success); + Assert.AreEqual(i128.Zero, result); + } + + [Test] + public void DivideByZeroTest() + { + i128 a = new i128(10, 0); + i128 b = i128.Zero; + + Assert.Throws(() => { var result = a / b; }); + Assert.Throws(() => { var result = a % b; }); + } + + [Test] + public void OverflowTest() + { + i128 a = i128.MaxValue; + i128 b = i128.One; + + Assert.Throws(() => { var result = a + b; }); + } + + [Test] + public void ToStringTest() + { + i128 a = new i128(1234567890UL, 0); + string str = a.ToString(); + + Assert.AreEqual("1234567890", str); + } + + [Test] + public void EqualityTest() + { + i128 a = new i128(123, 456); + i128 b = new i128(123, 456); + i128 c = new i128(123, 0); + + Assert.IsTrue(a.Equals(b)); + Assert.IsFalse(a.Equals(c)); + Assert.IsTrue(a == b); + Assert.IsTrue(a != c); + } + + [Test] + public void HashCodeTest() + { + i128 a = new i128(123, 456); + i128 b = new i128(123, 456); + + Assert.AreEqual(a.GetHashCode(), b.GetHashCode()); + } + } +} \ No newline at end of file diff --git a/Substrate.NetApi.Test/TypeConverters/PrimitiveTypesTest.cs b/Substrate.NetApi.Test/TypeConverters/PrimitiveTypesTest.cs index 6c554e9..735cafc 100644 --- a/Substrate.NetApi.Test/TypeConverters/PrimitiveTypesTest.cs +++ b/Substrate.NetApi.Test/TypeConverters/PrimitiveTypesTest.cs @@ -172,15 +172,15 @@ public void PrimU128Test() var prim = new U128(); prim.Create("0xffffff00ffffff00ffffff00ffffff00"); - Assert.AreEqual(value, prim.Value); + Assert.AreEqual(((U128)value).Value, prim.Value); - var primCtor = new U128(value); + var primCtor = (U128)value; Assert.AreEqual(prim.Value, primCtor.Value); U128 primExplicit = (U128)value; - Assert.AreEqual(value, primExplicit.Value); + Assert.AreEqual(((U128)value).Value, primExplicit.Value); - BigInteger primImplicit = new U128(value); + BigInteger primImplicit = (BigInteger) (U128) value; Assert.AreEqual(value, primImplicit); } @@ -194,23 +194,23 @@ public void PrimU128CreateTest() var prim2 = new U128(); prim2.Create("0x35820000000000000000000000000000"); - Assert.AreEqual(number, prim2.Value); + Assert.AreEqual(((U128)number).Value, prim2.Value); Assert.AreEqual(prim.Bytes, prim2.Bytes); - var primCtor = new U128(number); + var primCtor = (U128) number; Assert.AreEqual(prim.Value, primCtor.Value); // 0 is a valid input - var primZero = new U128(0); - Assert.That(primZero.Value, Is.EqualTo(BigInteger.Zero)); + var primZero = new U128(u128.FromBigInteger(0)); + Assert.That((BigInteger) primZero, Is.EqualTo(BigInteger.Zero)); } [Test] public void PrimU128_WithNegativeNumber_ShouldFail() { var number = new BigInteger(-1000); - Assert.Throws(() => new U128(number)); + Assert.Throws(() => new U128(u128.FromBigInteger(number))); } [Test] @@ -220,19 +220,19 @@ public void PrimU256Test() var prim = new U256(); prim.Create("0xffffff00ffffff00ffffff00ffffff00ffffff00ffffff00ffffff00ffffff00"); - Assert.AreEqual(value, prim.Value); + Assert.AreEqual(((U256)value).Value, prim.Value); - var primCtor = new U256(value); + var primCtor = (U256) value; Assert.AreEqual(prim.Value, primCtor.Value); // 0 is a valid input - var primZero = new U256(0); - Assert.That(primZero.Value, Is.EqualTo(BigInteger.Zero)); + var primZero = new U256(u256.FromBigInteger(0)); + Assert.That((BigInteger) primZero, Is.EqualTo(BigInteger.Zero)); U256 primExplicit = (U256)value; - Assert.AreEqual(value, primExplicit.Value); + Assert.AreEqual(((U256)value).Value, primExplicit.Value); - BigInteger primImplicit = new U256(value); + BigInteger primImplicit = (BigInteger) (U256) value; Assert.AreEqual(value, primImplicit); var testArray = Utils.GetPublicKeyFrom("unixuHLc4UoAjwLpkQHUWy2NpT5LV4tUqJFnFVNyLaeqBfq22").Reverse().ToArray(); @@ -248,7 +248,7 @@ public void PrimU256Test() public void PrimU256_WithNegativeNumber_ShouldFail() { var bigNumber = BigInteger.Parse("452312821728632006638659744032470891714787547825123743022878680681856106495") * (-1); - Assert.Throws(() => new U256(bigNumber)); + Assert.Throws(() => new U256(u256.FromBigInteger(bigNumber))); } [Test] @@ -334,15 +334,15 @@ public void PrimI128Test() var prim = new I128(); prim.Create("0xf5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5"); - Assert.AreEqual(value, prim.Value); + Assert.AreEqual(((I128)value).Value, prim.Value); - var primCtor = new I128(value); + var primCtor = (I128)value; Assert.AreEqual(prim.Value, primCtor.Value); I128 primExplicit = (I128)value; - Assert.AreEqual(value, primExplicit.Value); + Assert.AreEqual(((I128)value).Value, primExplicit.Value); - BigInteger primImplicit = new I128(value); + BigInteger primImplicit = (BigInteger) (I128) value; Assert.AreEqual(value, primImplicit); } @@ -353,15 +353,15 @@ public void PrimI256Test() var prim = new I256(); prim.Create("0xf5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5"); - Assert.AreEqual(value, prim.Value); + Assert.AreEqual(((I256)value).Value, prim.Value); - var primCtor = new I256(value); + var primCtor = (I256) value; Assert.AreEqual(prim.Value, primCtor.Value); I256 primExplicit = (I256)value; - Assert.AreEqual(value, primExplicit.Value); + Assert.AreEqual(((I256)value).Value, primExplicit.Value); - BigInteger primImplicit = new I256(value); + BigInteger primImplicit = (BigInteger) (I256) value; Assert.AreEqual(value, primImplicit); } diff --git a/Substrate.NetApi/CompactInteger.cs b/Substrate.NetApi/CompactInteger.cs index adc9fc2..d316b9f 100644 --- a/Substrate.NetApi/CompactInteger.cs +++ b/Substrate.NetApi/CompactInteger.cs @@ -43,13 +43,13 @@ public struct CompactInteger : IEncodable /// Value /// /// - public CompactInteger(I128 value) => Value = value.Value; + public CompactInteger(I128 value) => Value = value.Value.ToBigInteger(); /// /// Value /// /// - public CompactInteger(I256 value) => Value = value.Value; + public CompactInteger(I256 value) => Value = value.Value.ToBigInteger(); /// /// Value @@ -79,13 +79,13 @@ public struct CompactInteger : IEncodable /// Value /// /// - public CompactInteger(U128 value) => Value = value.Value; + public CompactInteger(U128 value) => Value = value.Value.ToBigInteger(); /// /// Value /// /// - public CompactInteger(U256 value) => Value = value.Value; + public CompactInteger(U256 value) => Value = value.Value.ToBigInteger(); /// Indicates whether this instance and a specified object are equal. /// 19.09.2020. @@ -96,7 +96,11 @@ public struct CompactInteger : IEncodable /// public override bool Equals(object obj) { - if (obj is CompactInteger i) return Value.Equals(i.Value); + if (obj is CompactInteger i) + { + return Value.Equals(i.Value); + } + return Value.Equals(obj); } @@ -414,6 +418,42 @@ public static implicit operator CompactInteger(ulong i) return new CompactInteger(i); } + /// + /// Implicit cast that converts the given I128 to a CompactInteger. + /// + /// + public static implicit operator CompactInteger(I128 i) + { + return new CompactInteger(i); + } + + /// + /// Implicit cast that converts the given U128 to a CompactInteger. + /// + /// + public static implicit operator CompactInteger(U128 i) + { + return new CompactInteger(i); + } + + /// + /// Implicit cast that converts the given I256 to a CompactInteger. + /// + /// + public static implicit operator CompactInteger(I256 i) + { + return new CompactInteger(i); + } + + /// + /// Implicit cast that converts the given U256 to a CompactInteger. + /// + /// + public static implicit operator CompactInteger(U256 i) + { + return new CompactInteger(i); + } + /// Gets the value. /// The value. public BigInteger Value { get; } @@ -496,14 +536,19 @@ public static CompactInteger Decode(byte[] m, ref int p) /// A byte[]. public byte[] Encode() { - if (this <= 63) return new byte[] { this << 2 }; + if (this <= 63) + { + return new byte[] { this << 2 }; + } if (this <= 0x3FFF) + { return new byte[] { ((this & 0x3F) << 2) | 0x01, (this & 0xFFC0) >> 6 }; + } if (this <= 0x3FFFFFFF) { diff --git a/Substrate.NetApi/Model/Types/Primitive/I128.cs b/Substrate.NetApi/Model/Types/Primitive/I128.cs index 60b8b16..0cf843f 100644 --- a/Substrate.NetApi/Model/Types/Primitive/I128.cs +++ b/Substrate.NetApi/Model/Types/Primitive/I128.cs @@ -6,19 +6,31 @@ namespace Substrate.NetApi.Model.Types.Primitive /// /// I128 Type /// - public class I128 : BasePrim + public class I128 : BasePrim { /// /// Explicit conversion to I128 /// /// - public static explicit operator I128(BigInteger p) => new I128(p); + public static explicit operator I128(i128 p) => new I128(p); + + /// + /// Explicitly cast a BigInteger to a I128 + /// + /// + public static explicit operator I128(BigInteger p) => new I128(i128.FromBigInteger(p)); + + /// + /// Implicit conversion to i128 + /// + /// + public static implicit operator i128(I128 p) => p.Value; /// /// Implicit conversion to BigInteger /// /// - public static implicit operator BigInteger(I128 p) => p.Value; + public static implicit operator BigInteger(I128 p) => p.Value.ToBigInteger(); /// /// I128 Constructor @@ -30,7 +42,7 @@ public I128() /// I128 Constructor /// /// - public I128(BigInteger value) + public I128(i128 value) { Create(value); } @@ -68,20 +80,17 @@ public override void Create(byte[] byteArray) } Bytes = byteArray; - Value = new BigInteger(byteArray); + Value = new i128(byteArray); } /// - public void Create(long value) + public void Create(BigInteger value) { - var bytes = new byte[TypeSize]; - BitConverter.GetBytes(value).CopyTo(bytes, 0); - Bytes = bytes; - Value = value; + Create(i128.FromBigInteger(value)); } /// - public override void Create(BigInteger value) + public override void Create(i128 value) { var byteArray = value.ToByteArray(); diff --git a/Substrate.NetApi/Model/Types/Primitive/I256.cs b/Substrate.NetApi/Model/Types/Primitive/I256.cs index 5cf5753..599f0f3 100644 --- a/Substrate.NetApi/Model/Types/Primitive/I256.cs +++ b/Substrate.NetApi/Model/Types/Primitive/I256.cs @@ -6,19 +6,31 @@ namespace Substrate.NetApi.Model.Types.Primitive /// /// I256 Type /// - public class I256 : BasePrim + public class I256 : BasePrim { /// /// Explicit conversion to I256 /// /// - public static explicit operator I256(BigInteger p) => new I256(p); + public static explicit operator I256(i256 p) => new I256(p); + + /// + /// Explicitly cast a BigInteger to a I256 + /// + /// + public static explicit operator I256(BigInteger p) => new I256(i256.FromBigInteger(p)); + + /// + /// Implicit conversion to i256 + /// + /// + public static implicit operator i256(I256 p) => p.Value; /// /// Implicit conversion to BigInteger /// /// - public static implicit operator BigInteger(I256 p) => p.Value; + public static implicit operator BigInteger(I256 p) => p.Value.ToBigInteger(); /// /// I256 Constructor @@ -30,13 +42,13 @@ public I256() /// I256 Constructor /// /// - public I256(BigInteger value) + public I256(i256 value) { Create(value); } /// - public override string TypeName() => "i128"; + public override string TypeName() => "i256"; /// public override int TypeSize => 32; @@ -68,17 +80,17 @@ public override void Create(byte[] byteArray) } Bytes = byteArray; - Value = new BigInteger(byteArray); + Value = new i256(byteArray); } /// - public void Create(long value) + public void Create(BigInteger value) { - Create(new BigInteger(value)); + Create(i256.FromBigInteger(value)); } /// - public override void Create(BigInteger value) + public override void Create(i256 value) { var byteArray = value.ToByteArray(); diff --git a/Substrate.NetApi/Model/Types/Primitive/RustPrimitives.cs b/Substrate.NetApi/Model/Types/Primitive/RustPrimitives.cs new file mode 100644 index 0000000..e0f3828 --- /dev/null +++ b/Substrate.NetApi/Model/Types/Primitive/RustPrimitives.cs @@ -0,0 +1,1752 @@ +using System; +using System.Numerics; + +namespace Substrate.NetApi.Model.Types.Primitive +{ + /// + /// u256 primitive mimic type + /// + public readonly struct u256 : IComparable, IEquatable + { + private readonly ulong _low; + private readonly ulong _midLow; + private readonly ulong _midHigh; + private readonly ulong _high; + + /// + /// Zero value + /// + public static readonly u256 Zero = new u256(0, 0, 0, 0); + + /// + /// One value + /// + public static readonly u256 One = new u256(1, 0, 0, 0); + + /// + /// Max value + /// + public static readonly u256 MaxValue = new u256(ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue); + + /// + /// u256 Constructor + /// + public u256(ulong low, ulong mid1, ulong mid2, ulong high) + { + _low = low; + _midLow = mid1; + _midHigh = mid2; + _high = high; + } + + /// + /// u256 Constructor from byte array (little-endian) + /// + public u256(byte[] bytes) + { + if (bytes.Length != 32) + { + throw new ArgumentException("Byte array must be 32 bytes to fit a u256."); + } + + _low = BitConverter.ToUInt64(bytes, 0); + _midLow = BitConverter.ToUInt64(bytes, 8); + _midHigh = BitConverter.ToUInt64(bytes, 16); + _high = BitConverter.ToUInt64(bytes, 24); + } + + /// + /// Convert to byte array (little-endian) + /// + public byte[] ToByteArray() + { + var bytes = new byte[32]; + BitConverter.GetBytes(_low).CopyTo(bytes, 0); + BitConverter.GetBytes(_midLow).CopyTo(bytes, 8); + BitConverter.GetBytes(_midHigh).CopyTo(bytes, 16); + BitConverter.GetBytes(_high).CopyTo(bytes, 24); + return bytes; + } + + /// + /// Addition operator + /// + public static u256 operator +(u256 a, u256 b) + { + ulong carry = 0; + ulong low = AddWithCarry(a._low, b._low, ref carry); + ulong midLow = AddWithCarry(a._midLow, b._midLow, ref carry); + ulong midHigh = AddWithCarry(a._midHigh, b._midHigh, ref carry); + ulong high = a._high + b._high + carry; + return new u256(low, midLow, midHigh, high); + } + + private static ulong AddWithCarry(ulong a, ulong b, ref ulong carry) + { + ulong tempSum = a + b + carry; + carry = ((tempSum < a) || (carry == 1 && tempSum == a)) ? 1UL : 0UL; + return tempSum; + } + + /// + /// Subtraction operator + /// + public static u256 operator -(u256 a, u256 b) + { + ulong borrow = 0; + ulong low = SubtractWithBorrow(a._low, b._low, ref borrow); + ulong midLow = SubtractWithBorrow(a._midLow, b._midLow, ref borrow); + ulong midHigh = SubtractWithBorrow(a._midHigh, b._midHigh, ref borrow); + ulong high = a._high - b._high - borrow; + return new u256(low, midLow, midHigh, high); + } + + private static ulong SubtractWithBorrow(ulong a, ulong b, ref ulong borrow) + { + ulong tempDiff = a - b - borrow; + borrow = (a < b + borrow) ? 1UL : 0UL; + return tempDiff; + } + + /// + /// Multiplication operator + /// + public static u256 operator *(u256 a, u256 b) + { + // Use BigInteger for multiplication and wrap around + BigInteger result = (a.ToBigInteger() * b.ToBigInteger()) & ((BigInteger.One << 256) - 1); + return FromBigInteger(result); + } + + /// + /// Division operator (integer division) + /// + public static u256 operator /(u256 a, u256 b) + { + if (b == Zero) + { + throw new DivideByZeroException(); + } + + BigInteger result = a.ToBigInteger() / b.ToBigInteger(); + return FromBigInteger(result); + } + + /// + /// Modulo operator + /// + public static u256 operator %(u256 a, u256 b) + { + if (b == Zero) + { + throw new DivideByZeroException(); + } + + BigInteger result = a.ToBigInteger() % b.ToBigInteger(); + return FromBigInteger(result); + } + + /// + /// Bitwise AND operator + /// + public static u256 operator &(u256 a, u256 b) + { + return new u256(a._low & b._low, a._midLow & b._midLow, a._midHigh & b._midHigh, a._high & b._high); + } + + /// + /// Bitwise OR operator + /// + public static u256 operator |(u256 a, u256 b) + { + return new u256(a._low | b._low, a._midLow | b._midLow, a._midHigh | b._midHigh, a._high | b._high); + } + + /// + /// Bitwise XOR operator + /// + public static u256 operator ^(u256 a, u256 b) + { + return new u256(a._low ^ b._low, a._midLow ^ b._midLow, a._midHigh ^ b._midHigh, a._high ^ b._high); + } + + /// + /// Bitwise NOT operator + /// + public static u256 operator ~(u256 a) + { + return new u256(~a._low, ~a._midLow, ~a._midHigh, ~a._high); + } + + /// + /// Left shift operator + /// + public static u256 operator <<(u256 value, int shift) + { + shift &= 255; // Modulo 256 + if (shift == 0) + { + return value; + } + + ulong[] parts = { value._low, value._midLow, value._midHigh, value._high }; + ulong[] result = new ulong[4]; + + int k = shift / 64; + int s = shift % 64; + + for (int i = 3; i >= 0; i--) + { + if (i - k >= 0) + { + result[i] = parts[i - k] << s; + if (s != 0 && i - k - 1 >= 0) + { + result[i] |= parts[i - k - 1] >> (64 - s); + } + } + } + return new u256(result[0], result[1], result[2], result[3]); + } + + /// + /// Right shift operator + /// + public static u256 operator >>(u256 value, int shift) + { + shift &= 255; // Modulo 256 + if (shift == 0) + { + return value; + } + + ulong[] parts = { value._low, value._midLow, value._midHigh, value._high }; + ulong[] result = new ulong[4]; + + int k = shift / 64; + int s = shift % 64; + + for (int i = 0; i < 4; i++) + { + if (i + k < 4) + { + result[i] = parts[i + k] >> s; + if (s != 0 && i + k + 1 < 4) + { + result[i] |= parts[i + k + 1] << (64 - s); + } + } + } + return new u256(result[0], result[1], result[2], result[3]); + } + + /// + /// Comparison operators + /// + public static bool operator ==(u256 left, u256 right) => left.Equals(right); + + /// + /// Unequality operator + /// + /// + /// + /// + public static bool operator !=(u256 left, u256 right) => !left.Equals(right); + + /// + /// Greater than + /// + /// + /// + /// + public static bool operator <(u256 left, u256 right) => left.CompareTo(right) < 0; + + /// + /// Less than + /// + /// + /// + /// + public static bool operator >(u256 left, u256 right) => left.CompareTo(right) > 0; + + /// + /// Greater than or equal + /// + /// + /// + /// + public static bool operator <=(u256 left, u256 right) => left.CompareTo(right) <= 0; + + /// + /// Smaller than or equal + /// + /// + /// + /// + public static bool operator >=(u256 left, u256 right) => left.CompareTo(right) >= 0; + + /// + /// Equals override + /// + public override bool Equals(object obj) => obj is u256 other && Equals(other); + + /// + /// Equals method + /// + /// + /// + public bool Equals(u256 other) => + _low == other._low && _midLow == other._midLow && _midHigh == other._midHigh && _high == other._high; + + /// + /// GetHashCode override + /// + /// + public override int GetHashCode() + { +#if NETSTANDARD2_0 + unchecked + { + int hash = 17; + hash = hash * 31 + _low.GetHashCode(); + hash = hash * 31 + _midLow.GetHashCode(); + hash = hash * 31 + _midHigh.GetHashCode(); + hash = hash * 31 + _high.GetHashCode(); + return hash; + } +#else + return HashCode.Combine(_low, _midLow, _midHigh, _high); +#endif + } + + /// + /// CompareTo implementation + /// + public int CompareTo(u256 other) + { + int cmp = _high.CompareTo(other._high); + if (cmp != 0) + { + return cmp; + } + + cmp = _midHigh.CompareTo(other._midHigh); + if (cmp != 0) + { + return cmp; + } + + cmp = _midLow.CompareTo(other._midLow); + if (cmp != 0) + { + return cmp; + } + + return _low.CompareTo(other._low); + } + + /// + /// ToString override + /// + public override string ToString() + { + // Use BigInteger for string representation + return ToBigInteger().ToString(); + } + + /// + /// Converts u256 to BigInteger + /// + public BigInteger ToBigInteger() + { + byte[] bytes = ToByteArray(); + + // Check if the most significant bit is set + if ((bytes[bytes.Length - 1] & 0x80) != 0) + { + // Append a zero byte to ensure positive interpretation + byte[] extendedBytes = new byte[bytes.Length + 1]; + Array.Copy(bytes, extendedBytes, bytes.Length); + bytes = extendedBytes; + } + + return new BigInteger(bytes); + } + + /// + /// Creates u256 from BigInteger + /// + public static u256 FromBigInteger(BigInteger value) + { + if (value < BigInteger.Zero) + throw new OverflowException("Value is out of range for u256."); + + byte[] bytes = value.ToByteArray(); + + // Remove any leading zeros that may have been added + if (bytes.Length > 32) + { + // Ensure that the extra bytes are all zeros + for (int i = 32; i < bytes.Length; i++) + { + if (bytes[i] != 0) + throw new OverflowException("Value is out of range for u256."); + } + } + + // Ensure array is exactly 32 bytes + Array.Resize(ref bytes, 32); + + return new u256(bytes); + } + + /// + /// Parses a string into u256 + /// + public static u256 Parse(string value) + { + BigInteger bigInt = BigInteger.Parse(value); + return FromBigInteger(bigInt); + } + + /// + /// TryParse method + /// + public static bool TryParse(string value, out u256 result) + { + result = Zero; + if (BigInteger.TryParse(value, out BigInteger bigInt)) + { + if (bigInt >= BigInteger.Zero && bigInt <= MaxValue.ToBigInteger()) + { + result = FromBigInteger(bigInt); + return true; + } + } + return false; + } + } + + /// + /// i256 primitive mimic type + /// + public struct i256 : IComparable, IEquatable + { + private readonly ulong _low; + private readonly ulong _midLow; + private readonly ulong _midHigh; + private readonly ulong _high; + + /// + /// Zero value + /// + public static readonly i256 Zero = new i256(0, 0, 0, 0); + + /// + /// One value + /// + public static readonly i256 One = new i256(1, 0, 0, 0); + + /// + /// Min value (-2^255) + /// + public static readonly i256 MinValue = new i256(0, 0, 0, 0x8000000000000000UL); + + /// + /// Max value (2^255 - 1) + /// + public static readonly i256 MaxValue = new i256(ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, 0x7FFFFFFFFFFFFFFFUL); + + /// + /// i256 Constructor + /// + public i256(ulong low, ulong mid1, ulong mid2, ulong high) + { + _low = low; + _midLow = mid1; + _midHigh = mid2; + _high = high; + } + + /// + /// i256 Constructor from byte array (little-endian) + /// + public i256(byte[] bytes) + { + if (bytes.Length != 32) + { + throw new ArgumentException("Byte array must be 32 bytes to fit an i256."); + } + + _low = BitConverter.ToUInt64(bytes, 0); + _midLow = BitConverter.ToUInt64(bytes, 8); + _midHigh = BitConverter.ToUInt64(bytes, 16); + _high = BitConverter.ToUInt64(bytes, 24); + } + + /// + /// Convert to byte array (little-endian) + /// + public byte[] ToByteArray() + { + var bytes = new byte[32]; + BitConverter.GetBytes(_low).CopyTo(bytes, 0); + BitConverter.GetBytes(_midLow).CopyTo(bytes, 8); + BitConverter.GetBytes(_midHigh).CopyTo(bytes, 16); + BitConverter.GetBytes(_high).CopyTo(bytes, 24); + return bytes; + } + + /// + /// Addition operator + /// + public static i256 operator +(i256 a, i256 b) + { + BigInteger result = a.ToBigInteger() + b.ToBigInteger(); + if (result < MinValue.ToBigInteger() || result > MaxValue.ToBigInteger()) + { + throw new OverflowException("Addition overflow in i256."); + } + + return FromBigInteger(result); + } + + private static ulong AddWithCarry(ulong a, ulong b, ref ulong carry) + { + ulong sum = a + b + carry; + carry = (sum < a || (carry == 1 && sum == a)) ? 1UL : 0UL; + return sum; + } + + /// + /// Subtraction operator + /// + public static i256 operator -(i256 a, i256 b) + { + BigInteger result = a.ToBigInteger() - b.ToBigInteger(); + if (result < MinValue.ToBigInteger() || result > MaxValue.ToBigInteger()) + { + throw new OverflowException("Subtraction overflow in i256."); + } + + return FromBigInteger(result); + } + + private static ulong SubtractWithBorrow(ulong a, ulong b, ref ulong borrow) + { + ulong diff = a - b - borrow; + borrow = (a < b || (borrow == 1 && a == b)) ? 1UL : 0UL; + return diff; + } + + /// + /// Multiplication operator + /// + public static i256 operator *(i256 a, i256 b) + { + BigInteger result = a.ToBigInteger() * b.ToBigInteger(); + if (result < MinValue.ToBigInteger() || result > MaxValue.ToBigInteger()) + { + throw new OverflowException("Multiplication overflow in i256."); + } + + return FromBigInteger(result); + } + + /// + /// Division operator (integer division) + /// + public static i256 operator /(i256 a, i256 b) + { + if (b == Zero) + { + throw new DivideByZeroException(); + } + + BigInteger result = a.ToBigInteger() / b.ToBigInteger(); + return FromBigInteger(result); + } + + /// + /// Modulo operator + /// + public static i256 operator %(i256 a, i256 b) + { + if (b == Zero) + { + throw new DivideByZeroException(); + } + + BigInteger result = a.ToBigInteger() % b.ToBigInteger(); + return FromBigInteger(result); + } + + /// + /// Bitwise AND operator + /// + public static i256 operator &(i256 a, i256 b) + { + return new i256(a._low & b._low, a._midLow & b._midLow, a._midHigh & b._midHigh, a._high & b._high); + } + + /// + /// Bitwise OR operator + /// + public static i256 operator |(i256 a, i256 b) + { + return new i256(a._low | b._low, a._midLow | b._midLow, a._midHigh | b._midHigh, a._high | b._high); + } + + /// + /// Bitwise XOR operator + /// + public static i256 operator ^(i256 a, i256 b) + { + return new i256(a._low ^ b._low, a._midLow ^ b._midLow, a._midHigh ^ b._midHigh, a._high ^ b._high); + } + + /// + /// Bitwise NOT operator + /// + public static i256 operator ~(i256 a) + { + return new i256(~a._low, ~a._midLow, ~a._midHigh, ~a._high); + } + + /// + /// Left shift operator + /// + public static i256 operator <<(i256 value, int shift) + { + shift &= 255; // Modulo 256 + if (shift == 0) + { + return value; + } + + ulong[] parts = { value._low, value._midLow, value._midHigh, value._high }; + ulong[] result = new ulong[4]; + + int k = shift / 64; + int s = shift % 64; + + for (int i = 3; i >= 0; i--) + { + if (i - k >= 0) + { + result[i] = parts[i - k] << s; + if (s != 0 && i - k - 1 >= 0) + { + result[i] |= parts[i - k - 1] >> (64 - s); + } + } + } + return new i256(result[0], result[1], result[2], result[3]); + } + + /// + /// Right shift operator + /// + public static i256 operator >>(i256 value, int shift) + { + shift &= 255; // Modulo 256 + if (shift == 0) + { + return value; + } + + ulong[] parts = { value._low, value._midLow, value._midHigh, value._high }; + ulong[] result = new ulong[4]; + + bool isNegative = (value._high & 0x8000000000000000UL) != 0; + + int k = shift / 64; + int s = shift % 64; + + for (int i = 0; i < 4; i++) + { + if (i + k < 4) + { + result[i] = parts[i + k] >> s; + if (s != 0 && i + k + 1 < 4) + { + result[i] |= parts[i + k + 1] << (64 - s); + } + } + else if (isNegative) + { + result[i] = ulong.MaxValue; + } + else + { + result[i] = 0; + } + } + + // Sign extension for arithmetic shift + if (isNegative) + { + for (int i = 3 - k; i >= 0; i--) + { + result[i] |= ulong.MaxValue << (64 - s); + } + } + + return new i256(result[0], result[1], result[2], result[3]); + } + + /// + /// Unary minus operator + /// + public static i256 operator -(i256 value) + { + return Zero - value; + } + + /// + /// Unary plus operator + /// + public static i256 operator +(i256 value) + { + return value; + } + + /// + /// Equality operators + /// + public static bool operator ==(i256 left, i256 right) => left.Equals(right); + + /// + /// Inequality operator + /// + /// + /// + /// + public static bool operator !=(i256 left, i256 right) => !left.Equals(right); + + /// + /// Greater than + /// + public static bool operator <(i256 left, i256 right) => left.CompareTo(right) < 0; + + /// + /// Less than + /// + /// + /// + /// + public static bool operator >(i256 left, i256 right) => left.CompareTo(right) > 0; + + /// + /// Greater than or equal + /// + /// + /// + /// + public static bool operator <=(i256 left, i256 right) => left.CompareTo(right) <= 0; + + /// + /// Less than or equal + /// + /// + /// + /// + public static bool operator >=(i256 left, i256 right) => left.CompareTo(right) >= 0; + + /// + /// Equals override + /// + public override bool Equals(object obj) => obj is i256 other && Equals(other); + + public bool Equals(i256 other) => + _low == other._low && _midLow == other._midLow && _midHigh == other._midHigh && _high == other._high; + + public override int GetHashCode() + { +#if NETSTANDARD2_0 + unchecked + { + int hash = 17; + hash = hash * 31 + _low.GetHashCode(); + hash = hash * 31 + _midLow.GetHashCode(); + hash = hash * 31 + _midHigh.GetHashCode(); + hash = hash * 31 + _high.GetHashCode(); + return hash; + } +#else + return HashCode.Combine(_low, _midLow, _midHigh, _high); +#endif + } + + /// + /// CompareTo implementation + /// + public int CompareTo(i256 other) + { + bool thisNegative = (_high & 0x8000000000000000UL) != 0; + bool otherNegative = (other._high & 0x8000000000000000UL) != 0; + + if (thisNegative && !otherNegative) + { + return -1; + } + + if (!thisNegative && otherNegative) + { + return 1; + } + + int cmp = _high.CompareTo(other._high); + if (cmp != 0) + { + return cmp; + } + + cmp = _midHigh.CompareTo(other._midHigh); + if (cmp != 0) + { + return cmp; + } + + cmp = _midLow.CompareTo(other._midLow); + if (cmp != 0) + { + return cmp; + } + + return _low.CompareTo(other._low); + } + + /// + /// ToString override + /// + public override string ToString() + { + return ToBigInteger().ToString(); + } + + /// + /// Converts i256 to BigInteger + /// + public BigInteger ToBigInteger() + { + byte[] bytes = ToByteArray(); + + // Check if the number is negative + bool isNegative = (_high & 0x8000000000000000UL) != 0; + + if (isNegative) + { + // Convert to two's complement representation + var complement = new byte[bytes.Length + 1]; // Extra byte for sign + for (int i = 0; i < bytes.Length; i++) + { + complement[i] = (byte)~bytes[i]; + } + // Add one + BigInteger temp = new BigInteger(complement) + 1; + // Make negative + return -temp; + } + else + { + return new BigInteger(bytes); + } + } + + /// + /// Creates i256 from BigInteger + /// + public static i256 FromBigInteger(BigInteger value) + { + if (value < MinValue.ToBigInteger() || value > MaxValue.ToBigInteger()) + { + throw new OverflowException("Value is out of range for i256."); + } + + byte[] bytes = value.ToByteArray(); + + // Ensure array is 32 bytes + if (bytes.Length > 32) + { + throw new OverflowException("Value is out of range for i256."); + } + else if (bytes.Length < 32) + { + Array.Resize(ref bytes, 32); + if (value.Sign < 0) + { + // Fill with 0xFF for negative numbers (sign extension) + for (int i = bytes.Length - 1; i >= 0; i--) + { + if (bytes[i] != 0) + { + break; + } + + bytes[i] = 0xFF; + } + } + } + + return new i256(bytes); + } + + /// + /// Parses a string into i256 + /// + public static i256 Parse(string value) + { + BigInteger bigInt = BigInteger.Parse(value); + return FromBigInteger(bigInt); + } + + /// + /// TryParse method + /// + public static bool TryParse(string value, out i256 result) + { + result = Zero; + if (BigInteger.TryParse(value, out BigInteger bigInt)) + { + if (bigInt >= MinValue.ToBigInteger() && bigInt <= MaxValue.ToBigInteger()) + { + result = FromBigInteger(bigInt); + return true; + } + } + return false; + } + } + + /// + /// u128 primitive mimic type + /// + public struct u128 : IComparable, IEquatable + { + private readonly ulong _low; + private readonly ulong _high; + + /// + /// Zero value + /// + public static readonly u128 Zero = new u128(0, 0); + + /// + /// One value + /// + public static readonly u128 One = new u128(1, 0); + + /// + /// Max value + /// + public static readonly u128 MaxValue = new u128(ulong.MaxValue, ulong.MaxValue); + + /// + /// u128 Constructor + /// + public u128(ulong low, ulong high) + { + _low = low; + _high = high; + } + + /// + /// u128 Constructor from byte array (little-endian) + /// + public u128(byte[] bytes) + { + if (bytes.Length != 16) + { + throw new ArgumentException("Byte array must be 16 bytes to fit a u128."); + } + + _low = BitConverter.ToUInt64(bytes, 0); + _high = BitConverter.ToUInt64(bytes, 8); + } + + /// + /// Convert to byte array (little-endian) + /// + public byte[] ToByteArray() + { + var bytes = new byte[16]; + BitConverter.GetBytes(_low).CopyTo(bytes, 0); + BitConverter.GetBytes(_high).CopyTo(bytes, 8); + return bytes; + } + + /// + /// Addition operator + /// + public static u128 operator +(u128 a, u128 b) + { + ulong carry = 0; + ulong low = AddWithCarry(a._low, b._low, ref carry); + ulong high = a._high + b._high + carry; + return new u128(low, high); + } + + private static ulong AddWithCarry(ulong a, ulong b, ref ulong carry) + { + ulong tempSum = a + b + carry; + carry = ((tempSum < a) || (carry == 1 && tempSum == a)) ? 1UL : 0UL; + return tempSum; + } + + /// + /// Subtraction operator + /// + public static u128 operator -(u128 a, u128 b) + { + ulong borrow = 0; + ulong low = SubtractWithBorrow(a._low, b._low, ref borrow); + ulong high = a._high - b._high - borrow; + return new u128(low, high); + } + + private static ulong SubtractWithBorrow(ulong a, ulong b, ref ulong borrow) + { + ulong tempDiff = a - b - borrow; + borrow = (a < b + borrow) ? 1UL : 0UL; + return tempDiff; + } + + /// + /// Multiplication operator + /// + public static u128 operator *(u128 a, u128 b) + { + // Perform multiplication using BigInteger and allow wrap-around + BigInteger result = (a.ToBigInteger() * b.ToBigInteger()) & ((BigInteger.One << 128) - 1); + return FromBigInteger(result); + } + + /// + /// Division operator (integer division) + /// + public static u128 operator /(u128 a, u128 b) + { + if (b == Zero) + { + throw new DivideByZeroException(); + } + + BigInteger result = a.ToBigInteger() / b.ToBigInteger(); + return FromBigInteger(result); + } + + /// + /// Modulo operator + /// + public static u128 operator %(u128 a, u128 b) + { + if (b == Zero) + { + throw new DivideByZeroException(); + } + + BigInteger result = a.ToBigInteger() % b.ToBigInteger(); + return FromBigInteger(result); + } + + /// + /// Bitwise AND operator + /// + public static u128 operator &(u128 a, u128 b) + { + return new u128(a._low & b._low, a._high & b._high); + } + + /// + /// Bitwise OR operator + /// + public static u128 operator |(u128 a, u128 b) + { + return new u128(a._low | b._low, a._high | b._high); + } + + /// + /// Bitwise XOR operator + /// + public static u128 operator ^(u128 a, u128 b) + { + return new u128(a._low ^ b._low, a._high ^ b._high); + } + + /// + /// Bitwise NOT operator + /// + public static u128 operator ~(u128 a) + { + return new u128(~a._low, ~a._high); + } + + /// + /// Left shift operator + /// + public static u128 operator <<(u128 value, int shift) + { + shift &= 127; // Modulo 128 + if (shift == 0) + { + return value; + } + + ulong[] parts = { value._low, value._high }; + ulong[] result = new ulong[2]; + + int k = shift / 64; + int s = shift % 64; + + if (k < 2) + { + result[1] = (k == 1 ? parts[0] : parts[1]) << s; + if (s != 0 && k == 0) + { + result[1] |= parts[0] >> (64 - s); + } + + result[0] = k == 0 ? parts[0] << s : 0UL; + } + return new u128(result[0], result[1]); + } + + /// + /// Right shift operator + /// + public static u128 operator >>(u128 value, int shift) + { + shift &= 127; // Modulo 128 + if (shift == 0) + { + return value; + } + + ulong[] parts = { value._low, value._high }; + ulong[] result = new ulong[2]; + + int k = shift / 64; + int s = shift % 64; + + if (k < 2) + { + result[0] = (k == 1 ? parts[1] : parts[0]) >> s; + if (s != 0 && k == 0) + { + result[0] |= parts[1] << (64 - s); + } + + result[1] = k == 0 ? parts[1] >> s : 0UL; + } + return new u128(result[0], result[1]); + } + + /// + /// Equality operators + /// + public static bool operator ==(u128 left, u128 right) => left.Equals(right); + + /// + /// Unequality operator + /// + /// + /// + /// + public static bool operator !=(u128 left, u128 right) => !left.Equals(right); + + /// + /// Greater than + /// + public static bool operator <(u128 left, u128 right) => left.CompareTo(right) < 0; + + /// + /// Lesser than + /// + /// + /// + /// + public static bool operator >(u128 left, u128 right) => left.CompareTo(right) > 0; + + /// + /// Greater than or equal + /// + /// + /// + /// + public static bool operator <=(u128 left, u128 right) => left.CompareTo(right) <= 0; + + /// + /// Lesser than or equal + /// + /// + /// + /// + public static bool operator >=(u128 left, u128 right) => left.CompareTo(right) >= 0; + + /// + /// Equals override + /// + public override bool Equals(object obj) => obj is u128 other && Equals(other); + + /// + /// Equals method + /// + /// + /// + public bool Equals(u128 other) => _low == other._low && _high == other._high; + + /// + /// GetHashCode override + /// + /// + public override int GetHashCode() + { +#if NETSTANDARD2_0 + unchecked + { + int hash = 17; + hash = hash * 31 + _low.GetHashCode(); + hash = hash * 31 + _high.GetHashCode(); + return hash; + } +#else + return HashCode.Combine(_low, _high); +#endif + } + + /// + /// CompareTo implementation + /// + public int CompareTo(u128 other) + { + int cmp = _high.CompareTo(other._high); + if (cmp != 0) + { + return cmp; + } + + return _low.CompareTo(other._low); + } + + /// + /// ToString override + /// + public override string ToString() + { + return ToBigInteger().ToString(); + } + + /// + /// Converts u128 to BigInteger + /// + public BigInteger ToBigInteger() + { + byte[] bytes = ToByteArray(); + + // Check if the most significant bit is set + if ((bytes[bytes.Length - 1] & 0x80) != 0) + { + // Append a zero byte to make it positive + byte[] extendedBytes = new byte[bytes.Length + 1]; + Array.Copy(bytes, extendedBytes, bytes.Length); + bytes = extendedBytes; + } + + return new BigInteger(bytes); + } + + /// + /// Creates u128 from BigInteger + /// + public static u128 FromBigInteger(BigInteger value) + { + if (value < BigInteger.Zero) + throw new OverflowException("Value is out of range for u128."); + + byte[] bytes = value.ToByteArray(); + + // Trim leading zeros if any + if (bytes.Length > 16) + { + for (int i = 16; i < bytes.Length; i++) + { + if (bytes[i] != 0) + throw new OverflowException("Value is out of range for u128."); + } + } + + // Ensure array is exactly 16 bytes + Array.Resize(ref bytes, 16); + + return new u128(bytes); + } + + /// + /// Parses a string into u128 + /// + public static u128 Parse(string value) + { + BigInteger bigInt = BigInteger.Parse(value); + return FromBigInteger(bigInt); + } + + /// + /// TryParse method + /// + public static bool TryParse(string value, out u128 result) + { + result = Zero; + if (BigInteger.TryParse(value, out BigInteger bigInt)) + { + if (bigInt >= BigInteger.Zero && bigInt <= MaxValue.ToBigInteger()) + { + result = FromBigInteger(bigInt); + return true; + } + } + return false; + } + } + + /// + /// i128 primitive mimic type + /// + public struct i128 : IComparable, IEquatable + { + private readonly ulong _low; + private readonly ulong _high; + + /// + /// Zero value + /// + public static readonly i128 Zero = new i128(0, 0); + + /// + /// One value + /// + public static readonly i128 One = new i128(1, 0); + + /// + /// Min value (-2^127) + /// + public static readonly i128 MinValue = new i128(0, 0x8000000000000000UL); + + /// + /// Max value (2^127 - 1) + /// + public static readonly i128 MaxValue = new i128(ulong.MaxValue, 0x7FFFFFFFFFFFFFFFUL); + + /// + /// i128 Constructor + /// + public i128(ulong low, ulong high) + { + _low = low; + _high = high; + } + + /// + /// i128 Constructor from byte array (little-endian) + /// + public i128(byte[] bytes) + { + if (bytes.Length != 16) + { + throw new ArgumentException("Byte array must be 16 bytes to fit an i128."); + } + + _low = BitConverter.ToUInt64(bytes, 0); + _high = BitConverter.ToUInt64(bytes, 8); + } + + /// + /// Convert to byte array (little-endian) + /// + public byte[] ToByteArray() + { + var bytes = new byte[16]; + BitConverter.GetBytes(_low).CopyTo(bytes, 0); + BitConverter.GetBytes(_high).CopyTo(bytes, 8); + return bytes; + } + + /// + /// Addition operator + /// + public static i128 operator +(i128 a, i128 b) + { + BigInteger result = a.ToBigInteger() + b.ToBigInteger(); + if (result < MinValue.ToBigInteger() || result > MaxValue.ToBigInteger()) + { + throw new OverflowException("Addition overflow in i128."); + } + + return FromBigInteger(result); + } + + private static ulong AddWithCarry(ulong a, ulong b, ref ulong carry) + { + ulong sum = a + b + carry; + carry = (sum < a || (carry == 1 && sum == a)) ? 1UL : 0UL; + return sum; + } + + /// + /// Subtraction operator + /// + public static i128 operator -(i128 a, i128 b) + { + BigInteger result = a.ToBigInteger() - b.ToBigInteger(); + if (result < MinValue.ToBigInteger() || result > MaxValue.ToBigInteger()) + { + throw new OverflowException("Subtraction overflow in i128."); + } + + return FromBigInteger(result); + } + + private static ulong SubtractWithBorrow(ulong a, ulong b, ref ulong borrow) + { + ulong diff = a - b - borrow; + borrow = (a < b || (borrow == 1 && a == b)) ? 1UL : 0UL; + return diff; + } + + /// + /// Multiplication operator + /// + public static i128 operator *(i128 a, i128 b) + { + BigInteger result = a.ToBigInteger() * b.ToBigInteger(); + if (result < MinValue.ToBigInteger() || result > MaxValue.ToBigInteger()) + { + throw new OverflowException("Multiplication overflow in i128."); + } + + return FromBigInteger(result); + } + + /// + /// Division operator (integer division) + /// + public static i128 operator /(i128 a, i128 b) + { + if (b == Zero) + { + throw new DivideByZeroException(); + } + + BigInteger result = a.ToBigInteger() / b.ToBigInteger(); + return FromBigInteger(result); + } + + /// + /// Modulo operator + /// + public static i128 operator %(i128 a, i128 b) + { + if (b == Zero) + { + throw new DivideByZeroException(); + } + + BigInteger result = a.ToBigInteger() % b.ToBigInteger(); + return FromBigInteger(result); + } + + /// + /// Bitwise AND operator + /// + public static i128 operator &(i128 a, i128 b) + { + return new i128(a._low & b._low, a._high & b._high); + } + + /// + /// Bitwise OR operator + /// + public static i128 operator |(i128 a, i128 b) + { + return new i128(a._low | b._low, a._high | b._high); + } + + /// + /// Bitwise XOR operator + /// + public static i128 operator ^(i128 a, i128 b) + { + return new i128(a._low ^ b._low, a._high ^ b._high); + } + + /// + /// Bitwise NOT operator + /// + public static i128 operator ~(i128 a) + { + return new i128(~a._low, ~a._high); + } + + /// + /// Left shift operator + /// + public static i128 operator <<(i128 value, int shift) + { + shift &= 127; // Modulo 128 + if (shift == 0) + { + return value; + } + + ulong[] parts = { value._low, value._high }; + ulong[] result = new ulong[2]; + + int k = shift / 64; + int s = shift % 64; + + if (k < 2) + { + result[1] = (k == 1 ? parts[0] : parts[1]) << s; + if (s != 0 && k == 0) + { + result[1] |= parts[0] >> (64 - s); + } + + result[0] = k == 0 ? parts[0] << s : 0UL; + } + return new i128(result[0], result[1]); + } + + /// + /// Right shift operator + /// + public static i128 operator >>(i128 value, int shift) + { + shift &= 127; // Modulo 128 + if (shift == 0) + { + return value; + } + + ulong[] parts = { value._low, value._high }; + ulong[] result = new ulong[2]; + + bool isNegative = (value._high & 0x8000000000000000UL) != 0; + + int k = shift / 64; + int s = shift % 64; + + if (k < 2) + { + result[0] = (k == 1 ? parts[1] : parts[0]) >> s; + if (s != 0 && k == 0) + { + result[0] |= parts[1] << (64 - s); + } + + result[1] = k == 0 ? parts[1] >> s : (isNegative ? ulong.MaxValue : 0UL); + } + + // Sign extension for arithmetic shift + if (isNegative) + { + for (int i = 1 - k; i >= 0; i--) + { + result[i] |= ulong.MaxValue << (64 - s); + } + } + + return new i128(result[0], result[1]); + } + + /// + /// Unary minus operator + /// + public static i128 operator -(i128 value) + { + return Zero - value; + } + + /// + /// Unary plus operator + /// + public static i128 operator +(i128 value) + { + return value; + } + + /// + /// Equality operators + /// + public static bool operator ==(i128 left, i128 right) => left.Equals(right); + + /// + /// Inequality operator + /// + /// + /// + /// + public static bool operator !=(i128 left, i128 right) => !left.Equals(right); + + /// + /// Comparison operators + /// + public static bool operator <(i128 left, i128 right) => left.CompareTo(right) < 0; + + public static bool operator >(i128 left, i128 right) => left.CompareTo(right) > 0; + + public static bool operator <=(i128 left, i128 right) => left.CompareTo(right) <= 0; + + public static bool operator >=(i128 left, i128 right) => left.CompareTo(right) >= 0; + + /// + /// Equals override + /// + public override bool Equals(object obj) => obj is i128 other && Equals(other); + + public bool Equals(i128 other) => _low == other._low && _high == other._high; + + public override int GetHashCode() + { +#if NETSTANDARD2_0 + unchecked + { + int hash = 17; + hash = hash * 31 + _low.GetHashCode(); + hash = hash * 31 + _high.GetHashCode(); + return hash; + } +#else + return HashCode.Combine(_low, _high); +#endif + } + + /// + /// CompareTo implementation + /// + public int CompareTo(i128 other) + { + bool thisNegative = (_high & 0x8000000000000000UL) != 0; + bool otherNegative = (other._high & 0x8000000000000000UL) != 0; + + if (thisNegative && !otherNegative) + { + return -1; + } + + if (!thisNegative && otherNegative) + { + return 1; + } + + int cmp = _high.CompareTo(other._high); + if (cmp != 0) + { + return cmp; + } + + return _low.CompareTo(other._low); + } + + /// + /// ToString override + /// + public override string ToString() + { + return ToBigInteger().ToString(); + } + + /// + /// Converts i128 to BigInteger + /// + public BigInteger ToBigInteger() + { + byte[] bytes = ToByteArray(); + + // Check if the number is negative + bool isNegative = (_high & 0x8000000000000000UL) != 0; + + if (isNegative) + { + // Convert to two's complement representation + var complement = new byte[bytes.Length + 1]; // Extra byte for sign + for (int i = 0; i < bytes.Length; i++) + { + complement[i] = (byte)~bytes[i]; + } + // Add one + BigInteger temp = new BigInteger(complement) + 1; + // Make negative + return -temp; + } + else + { + return new BigInteger(bytes); + } + } + + /// + /// Creates i128 from BigInteger + /// + public static i128 FromBigInteger(BigInteger value) + { + if (value < MinValue.ToBigInteger() || value > MaxValue.ToBigInteger()) + { + throw new OverflowException("Value is out of range for i128."); + } + + byte[] bytes = value.ToByteArray(); + + // Ensure array is 16 bytes + if (bytes.Length > 16) + { + Array.Resize(ref bytes, 16); + } + else if (bytes.Length < 16) + { + Array.Resize(ref bytes, 16); + if (value.Sign < 0) + { + // Fill with 0xFF for negative numbers (sign extension) + for (int i = bytes.Length - 1; i >= 0; i--) + { + if (bytes[i] != 0) + { + break; + } + + bytes[i] = 0xFF; + } + } + } + + return new i128(bytes); + } + + /// + /// Parses a string into i128 + /// + public static i128 Parse(string value) + { + BigInteger bigInt = BigInteger.Parse(value); + return FromBigInteger(bigInt); + } + + /// + /// TryParse method + /// + public static bool TryParse(string value, out i128 result) + { + result = Zero; + if (BigInteger.TryParse(value, out BigInteger bigInt)) + { + if (bigInt >= MinValue.ToBigInteger() && bigInt <= MaxValue.ToBigInteger()) + { + result = FromBigInteger(bigInt); + return true; + } + } + return false; + } + } +} \ No newline at end of file diff --git a/Substrate.NetApi/Model/Types/Primitive/U128.cs b/Substrate.NetApi/Model/Types/Primitive/U128.cs index 51e3ed2..181e6c8 100644 --- a/Substrate.NetApi/Model/Types/Primitive/U128.cs +++ b/Substrate.NetApi/Model/Types/Primitive/U128.cs @@ -6,19 +6,31 @@ namespace Substrate.NetApi.Model.Types.Primitive /// /// U128 /// - public class U128 : BasePrim + public class U128 : BasePrim { + /// + /// Explicitly cast a u128 to a U128 + /// + /// + public static explicit operator U128(u128 p) => new U128(p); + /// /// Explicitly cast a BigInteger to a U128 /// /// - public static explicit operator U128(BigInteger p) => new U128(p); + public static explicit operator U128(BigInteger p) => new U128(u128.FromBigInteger(p)); /// - /// Implicitly cast a U128 to a BigInteger + /// Implicitly cast a U128 to a u128 /// /// - public static implicit operator BigInteger(U128 p) => p.Value; + public static implicit operator u128(U128 p) => p.Value; + + /// + /// Implicit conversion to BigInteger + /// + /// + public static implicit operator BigInteger(U128 p) => p.Value.ToBigInteger(); /// /// U128 Constructor @@ -30,7 +42,7 @@ public U128() /// U128 Constructor /// /// - public U128(BigInteger value) + public U128(u128 value) { Create(value); } @@ -60,35 +72,30 @@ public override void CreateFromJson(string str) /// public override void Create(byte[] byteArray) { - // make sure it is unsigned we add 00 at the end if (byteArray.Length < TypeSize) { var newByteArray = new byte[TypeSize]; byteArray.CopyTo(newByteArray, 0); byteArray = newByteArray; } - else if (byteArray.Length == TypeSize) - { - byte[] newArray = new byte[byteArray.Length + 2]; - byteArray.CopyTo(newArray, 0); - newArray[byteArray.Length - 1] = 0x00; - } - else + else if(byteArray.Length > TypeSize) { throw new NotSupportedException($"Wrong byte array size for {TypeName()}, max. {TypeSize} bytes!"); } Bytes = byteArray; - Value = new BigInteger(byteArray); + Value = new u128(byteArray); } /// - public override void Create(BigInteger value) + public void Create(BigInteger value) { - // Ensure we have a positive number - if (value.Sign < 0) - throw new InvalidOperationException($"Unable to create a {nameof(U128)} instance while value is negative"); + Create(u128.FromBigInteger(value)); + } + /// + public override void Create(u128 value) + { var byteArray = value.ToByteArray(); if (byteArray.Length > TypeSize) diff --git a/Substrate.NetApi/Model/Types/Primitive/U256.cs b/Substrate.NetApi/Model/Types/Primitive/U256.cs index 633174c..83a01a9 100644 --- a/Substrate.NetApi/Model/Types/Primitive/U256.cs +++ b/Substrate.NetApi/Model/Types/Primitive/U256.cs @@ -3,22 +3,35 @@ namespace Substrate.NetApi.Model.Types.Primitive { + /// /// U256 /// - public class U256 : BasePrim + public class U256 : BasePrim { + /// + /// Explicitly cast a u256 to a U256 + /// + /// + public static explicit operator U256(u256 p) => new U256(p); + /// /// Explicitly cast a BigInteger to a U256 /// /// - public static explicit operator U256(BigInteger p) => new U256(p); + public static explicit operator U256(BigInteger p) => new U256(u256.FromBigInteger(p)); + + /// + /// Implicitly cast a U256 to a u256 + /// + /// + public static implicit operator u256(U256 p) => p.Value; /// - /// Implicitly cast a U256 to a BigInteger + /// Implicit conversion to BigInteger /// /// - public static implicit operator BigInteger(U256 p) => p.Value; + public static implicit operator BigInteger(U256 p) => p.Value.ToBigInteger(); /// /// U256 Constructor @@ -30,7 +43,7 @@ public U256() /// U256 Constructor /// /// - public U256(BigInteger value) + public U256(u256 value) { Create(value); } @@ -58,11 +71,9 @@ public override void CreateFromJson(string str) /// public override void Create(byte[] byteArray) { - byte[] newByteArray = new byte[32]; - // make sure it is unsigned we add 00 at the end if (byteArray.Length < TypeSize) { - newByteArray = new byte[TypeSize]; + var newByteArray = new byte[TypeSize]; byteArray.CopyTo(newByteArray, 0); byteArray = newByteArray; } @@ -71,26 +82,19 @@ public override void Create(byte[] byteArray) throw new NotSupportedException($"Wrong byte array size for {TypeName()}, max. {TypeSize} bytes!"); } - newByteArray = byteArray; - - if ((byteArray[TypeSize - 1] & 0x80) != 0) - { - newByteArray = new byte[byteArray.Length + 1]; - byteArray.CopyTo(newByteArray, 0); - //byteArray = newByteArray; // leaves us with a inconsistency. - } - Bytes = byteArray; - Value = new BigInteger(newByteArray); + Value = new u256(byteArray); } /// - public override void Create(BigInteger value) + public void Create(BigInteger value) { - // Ensure we have a positive number - if (value.Sign < 0) - throw new InvalidOperationException($"Unable to create a {nameof(U256)} instance while value is negative"); + Create(u256.FromBigInteger(value)); + } + /// + public override void Create(u256 value) + { var byteArray = value.ToByteArray(); if (byteArray.Length > TypeSize) diff --git a/Substrate.NetApi/Substrate.NetApi.csproj b/Substrate.NetApi/Substrate.NetApi.csproj index 053eb53..3f51853 100644 --- a/Substrate.NetApi/Substrate.NetApi.csproj +++ b/Substrate.NetApi/Substrate.NetApi.csproj @@ -3,7 +3,7 @@ Substrate.NET.API netstandard2.0;netstandard2.1;net6.0 - 0.9.24-rc8 + 0.9.24-rc9 Substrate Gaming Substrate Gaming true