Skip to content

Commit 6bc7d19

Browse files
Wi1l-B0tshargon
andauthored
[Optimize]: show native contract is active or not (#3922)
* optimize: show native contract net active yet * Update src/Neo.CLI/CLI/MainService.Native.cs * style: move BigInteger extensions from Utility to BigIntegerExtensions (#3916) --------- Co-authored-by: Shargon <[email protected]>
1 parent 0a60b93 commit 6bc7d19

File tree

11 files changed

+184
-188
lines changed

11 files changed

+184
-188
lines changed

src/Neo.CLI/CLI/MainService.Blockchain.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,20 +208,27 @@ public void OnShowContractCommand(string nameOrHash)
208208
lock (syncRoot)
209209
{
210210
ContractState? contract = null;
211-
212-
if (UInt160.TryParse(nameOrHash, out var scriptHash))
211+
NativeContract? nativeContract = null;
212+
var isHash = UInt160.TryParse(nameOrHash, out var scriptHash);
213+
if (isHash)
214+
{
213215
contract = NativeContract.ContractManagement.GetContract(NeoSystem.StoreView, scriptHash);
216+
if (contract is null)
217+
nativeContract = NativeContract.Contracts.SingleOrDefault(s => s.Hash == scriptHash);
218+
}
214219
else
215220
{
216-
var nativeContract = NativeContract.Contracts.SingleOrDefault(s => s.Name.Equals(nameOrHash, StringComparison.InvariantCultureIgnoreCase));
217-
221+
nativeContract = NativeContract.Contracts.SingleOrDefault(s => s.Name.Equals(nameOrHash, StringComparison.InvariantCultureIgnoreCase));
218222
if (nativeContract != null)
219223
contract = NativeContract.ContractManagement.GetContract(NeoSystem.StoreView, nativeContract.Hash);
220224
}
221225

222226
if (contract is null)
223227
{
224-
ConsoleHelper.Error($"Contract {nameOrHash} doesn't exist.");
228+
var state = nativeContract is null
229+
? "doesn't exist"
230+
: isHash ? $"({nativeContract.Name}) not active yet" : "not active yet";
231+
ConsoleHelper.Error($"Contract {nameOrHash} {state}.");
225232
return;
226233
}
227234

src/Neo.CLI/CLI/MainService.Native.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ partial class MainService
2323
[ConsoleCommand("list nativecontract", Category = "Native Contract")]
2424
private void OnListNativeContract()
2525
{
26-
NativeContract.Contracts.ToList().ForEach(p => ConsoleHelper.Info($"\t{p.Name,-20}", $"{p.Hash}"));
26+
var currentIndex = NativeContract.Ledger.CurrentIndex(NeoSystem.StoreView);
27+
NativeContract.Contracts.ToList().ForEach(contract =>
28+
{
29+
var active = contract.IsActive(NeoSystem.Settings, currentIndex) ? "" : " not active yet";
30+
ConsoleHelper.Info($"\t{contract.Name,-20}", $"{contract.Hash}{active}");
31+
});
2732
}
2833
}
2934
}

src/Neo.Extensions/BigIntegerExtensions.cs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,77 @@ public static BigInteger Sum(this IEnumerable<BigInteger> source)
117117
[MethodImpl(MethodImplOptions.AggressiveInlining)]
118118
public static byte[] ToByteArrayStandard(this BigInteger value)
119119
{
120-
if (value.IsZero) return Array.Empty<byte>();
120+
if (value.IsZero) return [];
121121
return value.ToByteArray();
122122
}
123+
124+
public static BigInteger Sqrt(this BigInteger value)
125+
{
126+
if (value < 0) throw new InvalidOperationException($"value {value} can not be negative for '{nameof(Sqrt)}'.");
127+
if (value.IsZero) return BigInteger.Zero;
128+
if (value < 4) return BigInteger.One;
129+
130+
var z = value;
131+
var x = BigInteger.One << (int)(((value - 1).GetBitLength() + 1) >> 1);
132+
while (x < z)
133+
{
134+
z = x;
135+
x = (value / x + x) / 2;
136+
}
137+
138+
return z;
139+
}
140+
141+
/// <summary>
142+
/// Gets the number of bits required for shortest two's complement representation of the current instance without the sign bit.
143+
/// Note: This method is imprecise and might not work as expected with integers larger than 256 bits if less than .NET5.
144+
/// </summary>
145+
/// <returns>The minimum non-negative number of bits in two's complement notation without the sign bit.</returns>
146+
/// <remarks>
147+
/// This method returns 0 if the value of current object is equal to
148+
/// <see cref="BigInteger.Zero"/> or <see cref="BigInteger.MinusOne"/>.
149+
/// For positive integers the return value is equal to the ordinary binary representation string length.
150+
/// </remarks>
151+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
152+
public static long GetBitLength(this BigInteger value)
153+
{
154+
#if NET5_0_OR_GREATER
155+
return value.GetBitLength();
156+
#else
157+
return BitLength(value);
158+
#endif
159+
}
160+
161+
/// <summary>
162+
/// GetBitLength for earlier than .NET5.0
163+
/// </summary>
164+
internal static long BitLength(this BigInteger value)
165+
{
166+
if (value == 0 || value == BigInteger.MinusOne) return 0;
167+
168+
var b = value.ToByteArray();
169+
if (b.Length == 1 || (b.Length == 2 && b[1] == 0))
170+
{
171+
return BitCount(value.Sign > 0 ? b[0] : (byte)(255 - b[0]));
172+
}
173+
return (b.Length - 1) * 8 + BitCount(value.Sign > 0 ? b[^1] : (byte)(255 - b[^1]));
174+
}
175+
176+
private static int BitCount(int w)
177+
{
178+
return w < 1 << 15 ? (w < 1 << 7
179+
? (w < 1 << 3 ? (w < 1 << 1
180+
? (w < 1 << 0 ? (w < 0 ? 32 : 0) : 1)
181+
: (w < 1 << 2 ? 2 : 3)) : (w < 1 << 5
182+
? (w < 1 << 4 ? 4 : 5)
183+
: (w < 1 << 6 ? 6 : 7)))
184+
: (w < 1 << 11
185+
? (w < 1 << 9 ? (w < 1 << 8 ? 8 : 9) : (w < 1 << 10 ? 10 : 11))
186+
: (w < 1 << 13 ? (w < 1 << 12 ? 12 : 13) : (w < 1 << 14 ? 14 : 15)))) : (w < 1 << 23 ? (w < 1 << 19
187+
? (w < 1 << 17 ? (w < 1 << 16 ? 16 : 17) : (w < 1 << 18 ? 18 : 19))
188+
: (w < 1 << 21 ? (w < 1 << 20 ? 20 : 21) : (w < 1 << 22 ? 22 : 23))) : (w < 1 << 27
189+
? (w < 1 << 25 ? (w < 1 << 24 ? 24 : 25) : (w < 1 << 26 ? 26 : 27))
190+
: (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31))));
191+
}
123192
}
124193
}

src/Neo.Extensions/Neo.Extensions.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<InternalsVisibleTo Include="Neo" />
1717
<InternalsVisibleTo Include="Neo.IO" />
1818
<InternalsVisibleTo Include="Neo.UnitTests" />
19+
<InternalsVisibleTo Include="Neo.Extensions.Tests" />
1920
</ItemGroup>
2021

2122
</Project>

src/Neo.VM/Utility.cs

Lines changed: 0 additions & 80 deletions
This file was deleted.

src/Neo/Cryptography/ECC/ECCurve.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public class ECCurve
4646
private ECCurve(BigInteger Q, BigInteger A, BigInteger B, BigInteger N, byte[] G, string curveName)
4747
{
4848
this.Q = Q;
49-
ExpectedECPointLength = ((int)VM.Utility.GetBitLength(Q) + 7) / 8;
49+
ExpectedECPointLength = ((int)Q.GetBitLength() + 7) / 8;
5050
this.A = new ECFieldElement(A, this);
5151
this.B = new ECFieldElement(B, this);
5252
this.N = N;

src/Neo/Cryptography/ECC/ECFieldElement.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public bool Equals(ECFieldElement? other)
5353

5454
private static BigInteger[] FastLucasSequence(BigInteger p, BigInteger P, BigInteger Q, BigInteger k)
5555
{
56-
var n = (int)VM.Utility.GetBitLength(k);
56+
var n = (int)k.GetBitLength();
5757
var s = k.GetLowestSetBit();
5858

5959
BigInteger Uh = 1;
@@ -125,7 +125,7 @@ public override int GetHashCode()
125125
BigInteger P;
126126
do
127127
{
128-
P = rand.NextBigInteger((int)VM.Utility.GetBitLength(_curve.Q));
128+
P = rand.NextBigInteger((int)_curve.Q.GetBitLength());
129129
}
130130
while (P >= _curve.Q || BigInteger.ModPow(P * P - fourQ, legendreExponent, _curve.Q) != qMinusOne);
131131
var result = FastLucasSequence(_curve.Q, P, Q, k);

src/Neo/Cryptography/ECC/ECPoint.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ public override int GetHashCode()
234234
internal static ECPoint Multiply(ECPoint p, BigInteger k)
235235
{
236236
// floor(log2(k))
237-
var m = (int)VM.Utility.GetBitLength(k);
237+
var m = (int)k.GetBitLength();
238238

239239
// width of the Window NAF
240240
sbyte width;
@@ -397,7 +397,7 @@ internal ECPoint Twice()
397397

398398
private static sbyte[] WindowNaf(sbyte width, BigInteger k)
399399
{
400-
var wnaf = new sbyte[VM.Utility.GetBitLength(k) + 1];
400+
var wnaf = new sbyte[k.GetBitLength() + 1];
401401
var pow2wB = (short)(1 << width);
402402
var i = 0;
403403
var length = 0;

src/Neo/SmartContract/Native/NativeContract.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ internal bool IsInitializeBlock(ProtocolSettings settings, uint index, [NotNullW
330330
/// <param name="settings">The <see cref="ProtocolSettings"/> where the HardForks are configured.</param>
331331
/// <param name="blockHeight">Block height</param>
332332
/// <returns>True if the native contract is active</returns>
333-
internal bool IsActive(ProtocolSettings settings, uint blockHeight)
333+
public bool IsActive(ProtocolSettings settings, uint blockHeight)
334334
{
335335
if (ActiveIn is null) return true;
336336

tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,14 @@ public void TestToByteArrayStandard_EdgeCases()
6868
{
6969
CollectionAssert.AreEqual(new byte[] { 0xFF }, BigInteger.MinusOne.ToByteArrayStandard());
7070
CollectionAssert.AreEqual(new byte[] { 0xFF, 0x00 }, new BigInteger(byte.MaxValue).ToByteArrayStandard());
71-
CollectionAssert.AreEqual(new byte[] { 0xFF, 0xFF, 0x00 }, new BigInteger(ushort.MaxValue).ToByteArrayStandard());
72-
CollectionAssert.AreEqual(new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0 }, new BigInteger(JNumber.MIN_SAFE_INTEGER).ToByteArrayStandard());
71+
CollectionAssert.AreEqual(
72+
new byte[] { 0xFF, 0xFF, 0x00 },
73+
new BigInteger(ushort.MaxValue).ToByteArrayStandard()
74+
);
75+
CollectionAssert.AreEqual(
76+
new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0 },
77+
new BigInteger(JNumber.MIN_SAFE_INTEGER).ToByteArrayStandard()
78+
);
7379
}
7480

7581
[TestMethod]
@@ -181,6 +187,87 @@ public void TestSum_EdgeCases()
181187
Assert.AreEqual(JNumber.MAX_SAFE_INTEGER * 2, new List<BigInteger> { JNumber.MAX_SAFE_INTEGER, JNumber.MAX_SAFE_INTEGER }.Sum());
182188
}
183189

190+
[TestMethod]
191+
public void TestSqrtTest()
192+
{
193+
Assert.ThrowsExactly<InvalidOperationException>(() => _ = BigInteger.MinusOne.Sqrt());
194+
195+
Assert.AreEqual(BigInteger.Zero, BigInteger.Zero.Sqrt());
196+
Assert.AreEqual(new BigInteger(1), new BigInteger(1).Sqrt());
197+
Assert.AreEqual(new BigInteger(1), new BigInteger(2).Sqrt());
198+
Assert.AreEqual(new BigInteger(1), new BigInteger(3).Sqrt());
199+
Assert.AreEqual(new BigInteger(2), new BigInteger(4).Sqrt());
200+
Assert.AreEqual(new BigInteger(9), new BigInteger(81).Sqrt());
201+
}
202+
203+
private static byte[] GetRandomByteArray(Random random)
204+
{
205+
var byteValue = random.Next(0, 32);
206+
var value = new byte[byteValue];
207+
208+
random.NextBytes(value);
209+
return value;
210+
}
211+
212+
private void VerifyGetBitLength(BigInteger value, long expected)
213+
{
214+
var result = value.GetBitLength();
215+
Assert.AreEqual(expected, value.GetBitLength(), "Native method has not the expected result");
216+
Assert.AreEqual(result, BigIntegerExtensions.GetBitLength(value), "Result doesn't match");
217+
Assert.AreEqual(result, BigIntegerExtensions.BitLength(value), "Result doesn't match");
218+
}
219+
220+
[TestMethod]
221+
public void TestGetBitLength()
222+
{
223+
var random = new Random();
224+
225+
// Big Number (net standard didn't work)
226+
Assert.ThrowsExactly<OverflowException>(() => VerifyGetBitLength(BigInteger.One << 32 << int.MaxValue, 2147483680));
227+
228+
// Trivial cases
229+
// sign bit|shortest two's complement
230+
// string w/o sign bit
231+
VerifyGetBitLength(0, 0); // 0|
232+
VerifyGetBitLength(1, 1); // 0|1
233+
VerifyGetBitLength(-1, 0); // 1|
234+
VerifyGetBitLength(2, 2); // 0|10
235+
VerifyGetBitLength(-2, 1); // 1|0
236+
VerifyGetBitLength(3, 2); // 0|11
237+
VerifyGetBitLength(-3, 2); // 1|01
238+
VerifyGetBitLength(4, 3); // 0|100
239+
VerifyGetBitLength(-4, 2); // 1|00
240+
VerifyGetBitLength(5, 3); // 0|101
241+
VerifyGetBitLength(-5, 3); // 1|011
242+
VerifyGetBitLength(6, 3); // 0|110
243+
VerifyGetBitLength(-6, 3); // 1|010
244+
VerifyGetBitLength(7, 3); // 0|111
245+
VerifyGetBitLength(-7, 3); // 1|001
246+
VerifyGetBitLength(8, 4); // 0|1000
247+
VerifyGetBitLength(-8, 3); // 1|000
248+
249+
// Random cases
250+
for (uint i = 0; i < 1000; i++)
251+
{
252+
var b = new BigInteger(GetRandomByteArray(random));
253+
Assert.AreEqual(b.GetBitLength(), BigIntegerExtensions.GetBitLength(b), message: $"Error comparing: {b}");
254+
Assert.AreEqual(b.GetBitLength(), BigIntegerExtensions.BitLength(b), message: $"Error comparing: {b}");
255+
}
256+
257+
foreach (var bv in new[] { BigInteger.Zero, BigInteger.One, BigInteger.MinusOne, new(ulong.MaxValue), new(long.MinValue) })
258+
{
259+
Assert.AreEqual(bv.GetBitLength(), BigIntegerExtensions.GetBitLength(bv));
260+
Assert.AreEqual(bv.GetBitLength(), BigIntegerExtensions.BitLength(bv));
261+
}
262+
263+
for (var i = 0; i < 1000; i++)
264+
{
265+
var b = new BigInteger(i);
266+
Assert.AreEqual(b.GetBitLength(), BigIntegerExtensions.GetBitLength(b), message: $"Error comparing: {b}");
267+
Assert.AreEqual(b.GetBitLength(), BigIntegerExtensions.BitLength(b), message: $"Error comparing: {b}");
268+
}
269+
}
270+
184271
[TestMethod]
185272
public void TestModInverseTest()
186273
{

0 commit comments

Comments
 (0)