diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bce1dc7c79..aa935fd2d3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,6 +38,44 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: ./coverage/lcov.net7.0.info + PublishGithub: + if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') + needs: Test + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Set Version + run: git rev-list --count HEAD | xargs printf 'CI%05d' | xargs -I{} echo 'VERSION_SUFFIX={}' >> $GITHUB_ENV + + - name : Pack (Neo) + run: | + dotnet pack \ + --configuration Release \ + --output ./out \ + --version-suffix ${{ env.VERSION_SUFFIX }} + + - name: Remove Unwanted Files + working-directory: ./out + run: | + rm -v Neo.CLI* + rm -v Neo.GUI* + + - name: Publish to Github Packages + working-directory: ./out + run: | + dotnet nuget push * \ + --source https://nuget.pkg.github.com/neo-project/index.json \ + --api-key "${{ secrets.GITHUB_TOKEN }}" \ + --disable-buffering \ + --no-service-endpoint; + # MyGet isn't working # PublishMyGet: # if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') @@ -113,6 +151,18 @@ jobs: dotnet pack ./src/Neo \ --configuration Release \ --output ./out + - name : Pack (Neo.IO) + if: steps.check_tag.outputs.statusCode == '404' + run: | + dotnet pack ./src/Neo.IO \ + --configuration Release \ + --output ./out + - name : Pack (Neo.Extensions) + if: steps.check_tag.outputs.statusCode == '404' + run: | + dotnet pack ./src/Neo.Extensions \ + --configuration Release \ + --output ./out - name : Pack (Neo.Json) if: steps.check_tag.outputs.statusCode == '404' run: | diff --git a/.github/workflows/pkgs-delete.yml b/.github/workflows/pkgs-delete.yml new file mode 100644 index 0000000000..16855f1070 --- /dev/null +++ b/.github/workflows/pkgs-delete.yml @@ -0,0 +1,51 @@ +name: Nuget Package Cleanup (github) + +on: + schedule: + - cron: '0 0 * * *' # Run every day at 24:00 + +jobs: + delete-pkgs: + name: Delete Old Nuget Packages + runs-on: ubuntu-latest + + steps: + - name: Delete Neo Package + uses: actions/delete-package-versions@v4 + with: + package-name: Neo + package-type: nuget + min-versions-to-keep: 3 + token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Delete Neo.ConsoleService Package + uses: actions/delete-package-versions@v4 + with: + package-name: Neo.ConsoleService + package-type: nuget + min-versions-to-keep: 3 + token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Delete Neo.ConsoleService Package + uses: actions/delete-package-versions@v4 + with: + package-name: Neo.ConsoleService + package-type: nuget + min-versions-to-keep: 3 + token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Delete Neo.Json Package + uses: actions/delete-package-versions@v4 + with: + package-name: Neo.Json + package-type: nuget + min-versions-to-keep: 3 + token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Delete Neo.VM Package + uses: actions/delete-package-versions@v4 + with: + package-name: Neo.VM + package-type: nuget + min-versions-to-keep: 3 + token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/NuGet.Config b/NuGet.Config index 5922e754af..f7ce69db29 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -2,6 +2,7 @@ + diff --git a/neo.sln b/neo.sln index dc50d0f4d7..b62de06a6e 100644 --- a/neo.sln +++ b/neo.sln @@ -24,18 +24,22 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM", "src\Neo.VM\Neo.VM EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM.Tests", "tests\Neo.VM.Tests\Neo.VM.Tests.csproj", "{005F84EB-EA2E-449F-930A-7B4173DDC7EC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.ConsoleService", "src\Neo.ConsoleService\Neo.ConsoleService.csproj", "{9E886812-7243-48D8-BEAF-47AADC11C054}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.ConsoleService", "src\Neo.ConsoleService\Neo.ConsoleService.csproj", "{9E886812-7243-48D8-BEAF-47AADC11C054}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.GUI", "src\Neo.GUI\Neo.GUI.csproj", "{02ABDE42-9880-43B4-B6F7-8D618602A277}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.GUI", "src\Neo.GUI\Neo.GUI.csproj", "{02ABDE42-9880-43B4-B6F7-8D618602A277}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.CLI", "src\Neo.CLI\Neo.CLI.csproj", "{BDFBE455-4C1F-4FC4-B5FC-1387B93A8687}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.CLI", "src\Neo.CLI\Neo.CLI.csproj", "{BDFBE455-4C1F-4FC4-B5FC-1387B93A8687}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.ConsoleService.Tests", "tests\Neo.ConsoleService.Tests\Neo.ConsoleService.Tests.csproj", "{B40F8584-5AFB-452C-AEFA-009C80CC23A9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.ConsoleService.Tests", "tests\Neo.ConsoleService.Tests\Neo.ConsoleService.Tests.csproj", "{B40F8584-5AFB-452C-AEFA-009C80CC23A9}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381", "src\Neo.Cryptography.BLS12_381\Neo.Cryptography.BLS12_381.csproj", "{D48C1FAB-3471-4CA0-8688-25E6F43F2C25}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381.Tests", "tests\Neo.Cryptography.BLS12_381.Tests\Neo.Cryptography.BLS12_381.Tests.csproj", "{387CCF6C-9A26-43F6-A639-0A82E91E10D8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.IO", "src\Neo.IO\Neo.IO.csproj", "{4CDAC1AA-45C6-4157-8D8E-199050433048}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.Extensions", "src\Neo.Extensions\Neo.Extensions.csproj", "{9C5213D6-3833-4570-8AE2-47E9F9017A8F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -98,6 +102,14 @@ Global {387CCF6C-9A26-43F6-A639-0A82E91E10D8}.Debug|Any CPU.Build.0 = Debug|Any CPU {387CCF6C-9A26-43F6-A639-0A82E91E10D8}.Release|Any CPU.ActiveCfg = Release|Any CPU {387CCF6C-9A26-43F6-A639-0A82E91E10D8}.Release|Any CPU.Build.0 = Release|Any CPU + {4CDAC1AA-45C6-4157-8D8E-199050433048}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CDAC1AA-45C6-4157-8D8E-199050433048}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4CDAC1AA-45C6-4157-8D8E-199050433048}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4CDAC1AA-45C6-4157-8D8E-199050433048}.Release|Any CPU.Build.0 = Release|Any CPU + {9C5213D6-3833-4570-8AE2-47E9F9017A8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C5213D6-3833-4570-8AE2-47E9F9017A8F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C5213D6-3833-4570-8AE2-47E9F9017A8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C5213D6-3833-4570-8AE2-47E9F9017A8F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -117,6 +129,8 @@ Global {B40F8584-5AFB-452C-AEFA-009C80CC23A9} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} {D48C1FAB-3471-4CA0-8688-25E6F43F2C25} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} {387CCF6C-9A26-43F6-A639-0A82E91E10D8} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} + {4CDAC1AA-45C6-4157-8D8E-199050433048} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} + {9C5213D6-3833-4570-8AE2-47E9F9017A8F} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BCBA19D9-F868-4C6D-8061-A2B91E06E3EC} diff --git a/src/Neo/LogLevel.cs b/src/Neo.Extensions/LogLevel.cs similarity index 100% rename from src/Neo/LogLevel.cs rename to src/Neo.Extensions/LogLevel.cs diff --git a/src/Neo.Extensions/Neo.Extensions.csproj b/src/Neo.Extensions/Neo.Extensions.csproj new file mode 100644 index 0000000000..7552a56311 --- /dev/null +++ b/src/Neo.Extensions/Neo.Extensions.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.1;net7.0 + enable + NEO;Blockchain;Extensions + + + + + + + + + + + + + diff --git a/src/Neo/Utility.cs b/src/Neo.Extensions/Utility.cs similarity index 97% rename from src/Neo/Utility.cs rename to src/Neo.Extensions/Utility.cs index 6883c69a26..fca164a4f2 100644 --- a/src/Neo/Utility.cs +++ b/src/Neo.Extensions/Utility.cs @@ -31,7 +31,7 @@ public Logger() } } - public static event LogEventHandler Logging; + public static event LogEventHandler? Logging; /// /// A strict UTF8 encoding used in NEO system. diff --git a/src/Neo/IO/ByteArrayComparer.cs b/src/Neo.IO/ByteArrayComparer.cs similarity index 62% rename from src/Neo/IO/ByteArrayComparer.cs rename to src/Neo.IO/ByteArrayComparer.cs index 872052095c..f9d44e24d6 100644 --- a/src/Neo/IO/ByteArrayComparer.cs +++ b/src/Neo.IO/ByteArrayComparer.cs @@ -20,27 +20,32 @@ internal class ByteArrayComparer : IComparer public static readonly ByteArrayComparer Default = new(1); public static readonly ByteArrayComparer Reverse = new(-1); - private readonly int direction; + private readonly int _direction; private ByteArrayComparer(int direction) { - this.direction = direction; + _direction = direction; } - public int Compare(byte[] x, byte[] y) + public int Compare(byte[]? x, byte[]? y) { - return direction > 0 - ? CompareInternal(x, y) - : -CompareInternal(x, y); + if (x == y) return 0; + if (x is null && y is not null) + return _direction > 0 ? -y.Length : y.Length; + if (y is null && x is not null) + return _direction > 0 ? x.Length : -x.Length; + return _direction > 0 ? + CompareInternal(x!, y!) : + -CompareInternal(x!, y!); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int CompareInternal(byte[] x, byte[] y) { - int length = Math.Min(x.Length, y.Length); - for (int i = 0; i < length; i++) + var length = Math.Min(x.Length, y.Length); + for (var i = 0; i < length; i++) { - int r = x[i].CompareTo(y[i]); + var r = x[i].CompareTo(y[i]); if (r != 0) return r; } return x.Length.CompareTo(y.Length); diff --git a/src/Neo/IO/ByteArrayEqualityComparer.cs b/src/Neo.IO/ByteArrayEqualityComparer.cs similarity index 90% rename from src/Neo/IO/ByteArrayEqualityComparer.cs rename to src/Neo.IO/ByteArrayEqualityComparer.cs index ffb5ad0e63..2b6f01491c 100644 --- a/src/Neo/IO/ByteArrayEqualityComparer.cs +++ b/src/Neo.IO/ByteArrayEqualityComparer.cs @@ -17,11 +17,11 @@ internal class ByteArrayEqualityComparer : IEqualityComparer { public static readonly ByteArrayEqualityComparer Default = new(); - public unsafe bool Equals(byte[] x, byte[] y) + public unsafe bool Equals(byte[]? x, byte[]? y) { if (ReferenceEquals(x, y)) return true; if (x is null || y is null) return false; - int len = x.Length; + var len = x.Length; if (len != y.Length) return false; if (len == 0) return true; fixed (byte* xp = x, yp = y) @@ -48,8 +48,8 @@ public int GetHashCode(byte[] obj) { unchecked { - int hash = 17; - foreach (byte element in obj) + var hash = 17; + foreach (var element in obj) hash = hash * 31 + element; return hash; } diff --git a/src/Neo/IO/ISerializable.cs b/src/Neo.IO/ISerializable.cs similarity index 100% rename from src/Neo/IO/ISerializable.cs rename to src/Neo.IO/ISerializable.cs diff --git a/src/Neo/IO/MemoryReader.cs b/src/Neo.IO/MemoryReader.cs similarity index 73% rename from src/Neo/IO/MemoryReader.cs rename to src/Neo.IO/MemoryReader.cs index ece7cb56be..df8afbb3d3 100644 --- a/src/Neo/IO/MemoryReader.cs +++ b/src/Neo.IO/MemoryReader.cs @@ -17,29 +17,29 @@ namespace Neo.IO { public ref struct MemoryReader { - private readonly ReadOnlyMemory memory; - private readonly ReadOnlySpan span; - private int pos = 0; + private readonly ReadOnlyMemory _memory; + private readonly ReadOnlySpan _span; + private int _pos = 0; - public readonly int Position => pos; + public readonly int Position => _pos; public MemoryReader(ReadOnlyMemory memory) { - this.memory = memory; - this.span = memory.Span; + _memory = memory; + _span = memory.Span; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private readonly void EnsurePosition(int move) { - if (pos + move > span.Length) throw new FormatException(); + if (_pos + move > _span.Length) throw new FormatException(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly byte Peek() { EnsurePosition(1); - return span[pos]; + return _span[_pos]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -57,7 +57,7 @@ public bool ReadBoolean() public sbyte ReadSByte() { EnsurePosition(1); - byte b = span[pos++]; + var b = _span[_pos++]; return unchecked((sbyte)b); } @@ -65,15 +65,15 @@ public sbyte ReadSByte() public byte ReadByte() { EnsurePosition(1); - return span[pos++]; + return _span[_pos++]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public short ReadInt16() { EnsurePosition(sizeof(short)); - var result = BinaryPrimitives.ReadInt16LittleEndian(span[pos..]); - pos += sizeof(short); + var result = BinaryPrimitives.ReadInt16LittleEndian(_span[_pos..]); + _pos += sizeof(short); return result; } @@ -81,8 +81,8 @@ public short ReadInt16() public short ReadInt16BigEndian() { EnsurePosition(sizeof(short)); - var result = BinaryPrimitives.ReadInt16BigEndian(span[pos..]); - pos += sizeof(short); + var result = BinaryPrimitives.ReadInt16BigEndian(_span[_pos..]); + _pos += sizeof(short); return result; } @@ -90,8 +90,8 @@ public short ReadInt16BigEndian() public ushort ReadUInt16() { EnsurePosition(sizeof(ushort)); - var result = BinaryPrimitives.ReadUInt16LittleEndian(span[pos..]); - pos += sizeof(ushort); + var result = BinaryPrimitives.ReadUInt16LittleEndian(_span[_pos..]); + _pos += sizeof(ushort); return result; } @@ -99,8 +99,8 @@ public ushort ReadUInt16() public ushort ReadUInt16BigEndian() { EnsurePosition(sizeof(ushort)); - var result = BinaryPrimitives.ReadUInt16BigEndian(span[pos..]); - pos += sizeof(ushort); + var result = BinaryPrimitives.ReadUInt16BigEndian(_span[_pos..]); + _pos += sizeof(ushort); return result; } @@ -108,8 +108,8 @@ public ushort ReadUInt16BigEndian() public int ReadInt32() { EnsurePosition(sizeof(int)); - var result = BinaryPrimitives.ReadInt32LittleEndian(span[pos..]); - pos += sizeof(int); + var result = BinaryPrimitives.ReadInt32LittleEndian(_span[_pos..]); + _pos += sizeof(int); return result; } @@ -117,8 +117,8 @@ public int ReadInt32() public int ReadInt32BigEndian() { EnsurePosition(sizeof(int)); - var result = BinaryPrimitives.ReadInt32BigEndian(span[pos..]); - pos += sizeof(int); + var result = BinaryPrimitives.ReadInt32BigEndian(_span[_pos..]); + _pos += sizeof(int); return result; } @@ -126,8 +126,8 @@ public int ReadInt32BigEndian() public uint ReadUInt32() { EnsurePosition(sizeof(uint)); - var result = BinaryPrimitives.ReadUInt32LittleEndian(span[pos..]); - pos += sizeof(uint); + var result = BinaryPrimitives.ReadUInt32LittleEndian(_span[_pos..]); + _pos += sizeof(uint); return result; } @@ -135,8 +135,8 @@ public uint ReadUInt32() public uint ReadUInt32BigEndian() { EnsurePosition(sizeof(uint)); - var result = BinaryPrimitives.ReadUInt32BigEndian(span[pos..]); - pos += sizeof(uint); + var result = BinaryPrimitives.ReadUInt32BigEndian(_span[_pos..]); + _pos += sizeof(uint); return result; } @@ -144,8 +144,8 @@ public uint ReadUInt32BigEndian() public long ReadInt64() { EnsurePosition(sizeof(long)); - var result = BinaryPrimitives.ReadInt64LittleEndian(span[pos..]); - pos += sizeof(long); + var result = BinaryPrimitives.ReadInt64LittleEndian(_span[_pos..]); + _pos += sizeof(long); return result; } @@ -153,8 +153,8 @@ public long ReadInt64() public long ReadInt64BigEndian() { EnsurePosition(sizeof(long)); - var result = BinaryPrimitives.ReadInt64BigEndian(span[pos..]); - pos += sizeof(long); + var result = BinaryPrimitives.ReadInt64BigEndian(_span[_pos..]); + _pos += sizeof(long); return result; } @@ -162,8 +162,8 @@ public long ReadInt64BigEndian() public ulong ReadUInt64() { EnsurePosition(sizeof(ulong)); - var result = BinaryPrimitives.ReadUInt64LittleEndian(span[pos..]); - pos += sizeof(ulong); + var result = BinaryPrimitives.ReadUInt64LittleEndian(_span[_pos..]); + _pos += sizeof(ulong); return result; } @@ -171,16 +171,16 @@ public ulong ReadUInt64() public ulong ReadUInt64BigEndian() { EnsurePosition(sizeof(ulong)); - var result = BinaryPrimitives.ReadUInt64BigEndian(span[pos..]); - pos += sizeof(ulong); + var result = BinaryPrimitives.ReadUInt64BigEndian(_span[_pos..]); + _pos += sizeof(ulong); return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ulong ReadVarInt(ulong max = ulong.MaxValue) { - byte b = ReadByte(); - ulong value = b switch + var b = ReadByte(); + var value = b switch { 0xfd => ReadUInt16(), 0xfe => ReadUInt32(), @@ -195,24 +195,24 @@ public ulong ReadVarInt(ulong max = ulong.MaxValue) public string ReadFixedString(int length) { EnsurePosition(length); - int end = pos + length; - int i = pos; - while (i < end && span[i] != 0) i++; - ReadOnlySpan data = span[pos..i]; + var end = _pos + length; + var i = _pos; + while (i < end && _span[i] != 0) i++; + var data = _span[_pos..i]; for (; i < end; i++) - if (span[i] != 0) + if (_span[i] != 0) throw new FormatException(); - pos = end; + _pos = end; return Utility.StrictUTF8.GetString(data); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadVarString(int max = 0x1000000) { - int length = (int)ReadVarInt((ulong)max); + var length = (int)ReadVarInt((ulong)max); EnsurePosition(length); - ReadOnlySpan data = span.Slice(pos, length); - pos += length; + var data = _span.Slice(_pos, length); + _pos += length; return Utility.StrictUTF8.GetString(data); } @@ -220,22 +220,20 @@ public string ReadVarString(int max = 0x1000000) public ReadOnlyMemory ReadMemory(int count) { EnsurePosition(count); - ReadOnlyMemory result = memory.Slice(pos, count); - pos += count; + var result = _memory.Slice(_pos, count); + _pos += count; return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlyMemory ReadVarMemory(int max = 0x1000000) - { - return ReadMemory((int)ReadVarInt((ulong)max)); - } + public ReadOnlyMemory ReadVarMemory(int max = 0x1000000) => + ReadMemory((int)ReadVarInt((ulong)max)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlyMemory ReadToEnd() { - ReadOnlyMemory result = memory[pos..]; - pos = memory.Length; + var result = _memory[_pos..]; + _pos = _memory.Length; return result; } } diff --git a/src/Neo.IO/Neo.IO.csproj b/src/Neo.IO/Neo.IO.csproj new file mode 100644 index 0000000000..05bc305a67 --- /dev/null +++ b/src/Neo.IO/Neo.IO.csproj @@ -0,0 +1,20 @@ + + + + netstandard2.1;net7.0 + true + enable + NEO;Blockchain;IO + + + + + + + + + + + + + diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 130ff2a570..75541f9091 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -18,6 +18,8 @@ + + diff --git a/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs b/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs index fb3835e14d..16a0a95944 100644 --- a/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs +++ b/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.VM; +using System; using System.Collections.Generic; namespace Neo.SmartContract @@ -19,6 +20,7 @@ partial class ApplicationEngine /// /// The prices of all the opcodes. /// + [Obsolete("You should use OpCodePriceTable")] public static readonly IReadOnlyDictionary OpCodePrices = new Dictionary { [OpCode.PUSHINT8] = 1 << 0, @@ -218,5 +220,20 @@ partial class ApplicationEngine [OpCode.ISTYPE] = 1 << 1, [OpCode.CONVERT] = 1 << 13, }; + + public static readonly long[] OpCodePriceTable = new long[byte.MaxValue]; + + /// + /// Init OpCodePrices + /// + static ApplicationEngine() + { +#pragma warning disable CS0618 // Type or member is obsolete + foreach (var entry in OpCodePrices) +#pragma warning restore CS0618 // Type or member is obsolete + { + OpCodePriceTable[(byte)entry.Key] = entry.Value; + } + } } } diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 8f30723d48..1331ff2608 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -570,7 +570,7 @@ protected virtual void OnSysCall(InteropDescriptor descriptor) protected override void PreExecuteInstruction(Instruction instruction) { Diagnostic?.PreExecuteInstruction(instruction); - AddGas(ExecFeeFactor * OpCodePrices[instruction.OpCode]); + AddGas(ExecFeeFactor * OpCodePriceTable[(byte)instruction.OpCode]); } protected override void PostExecuteInstruction(Instruction instruction) diff --git a/src/Neo/SmartContract/Helper.cs b/src/Neo/SmartContract/Helper.cs index 5045c74717..333ef77d7b 100644 --- a/src/Neo/SmartContract/Helper.cs +++ b/src/Neo/SmartContract/Helper.cs @@ -39,8 +39,8 @@ public static class Helper /// /// The calculated cost. public static long SignatureContractCost() => - ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * 2 + - ApplicationEngine.OpCodePrices[OpCode.SYSCALL] + + ApplicationEngine.OpCodePriceTable[(byte)OpCode.PUSHDATA1] * 2 + + ApplicationEngine.OpCodePriceTable[(byte)OpCode.SYSCALL] + ApplicationEngine.CheckSigPrice; /// @@ -51,12 +51,12 @@ public static long SignatureContractCost() => /// The calculated cost. public static long MultiSignatureContractCost(int m, int n) { - long fee = ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * (m + n); + long fee = ApplicationEngine.OpCodePriceTable[(byte)OpCode.PUSHDATA1] * (m + n); using (ScriptBuilder sb = new()) - fee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(m).ToArray()[0]]; + fee += ApplicationEngine.OpCodePriceTable[(byte)(OpCode)sb.EmitPush(m).ToArray()[0]]; using (ScriptBuilder sb = new()) - fee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(n).ToArray()[0]]; - fee += ApplicationEngine.OpCodePrices[OpCode.SYSCALL]; + fee += ApplicationEngine.OpCodePriceTable[(byte)(OpCode)sb.EmitPush(n).ToArray()[0]]; + fee += ApplicationEngine.OpCodePriceTable[(byte)OpCode.SYSCALL]; fee += ApplicationEngine.CheckSigPrice * n; return fee; } diff --git a/tests/Neo.UnitTests/IO/UT_ByteArrayComparer.cs b/tests/Neo.UnitTests/IO/UT_ByteArrayComparer.cs index 5efba80cb3..19c3fafcd6 100644 --- a/tests/Neo.UnitTests/IO/UT_ByteArrayComparer.cs +++ b/tests/Neo.UnitTests/IO/UT_ByteArrayComparer.cs @@ -12,6 +12,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO; +using System; namespace Neo.UnitTests.IO { @@ -22,10 +23,23 @@ public class UT_ByteArrayComparer public void TestCompare() { ByteArrayComparer comparer = ByteArrayComparer.Default; - byte[] x = new byte[0], y = new byte[0]; + byte[] x = null, y = null; comparer.Compare(x, y).Should().Be(0); + x = new byte[] { 1, 2, 3, 4, 5 }; + y = x; + comparer.Compare(x, y).Should().Be(0); + comparer.Compare(x, x).Should().Be(0); + + y = null; + comparer.Compare(x, y).Should().Be(5); + + y = x; + x = null; + comparer.Compare(x, y).Should().Be(-5); + x = new byte[] { 1 }; + y = Array.Empty(); comparer.Compare(x, y).Should().Be(1); y = x; comparer.Compare(x, y).Should().Be(0); diff --git a/tests/Neo.UnitTests/SmartContract/UT_Contract.cs b/tests/Neo.UnitTests/SmartContract/UT_Contract.cs index faf3c1fde4..a263779282 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Contract.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Contract.cs @@ -164,7 +164,7 @@ public void TestSignatureRedeemScriptFee() byte[] verification = Contract.CreateSignatureRedeemScript(key.PublicKey); byte[] invocation = new ScriptBuilder().EmitPush(UInt160.Zero).ToArray(); - var fee = PolicyContract.DefaultExecFeeFactor * (ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * 2 + ApplicationEngine.OpCodePrices[OpCode.SYSCALL] + ApplicationEngine.CheckSigPrice); + var fee = PolicyContract.DefaultExecFeeFactor * (ApplicationEngine.OpCodePriceTable[(byte)OpCode.PUSHDATA1] * 2 + ApplicationEngine.OpCodePriceTable[(byte)OpCode.SYSCALL] + ApplicationEngine.CheckSigPrice); using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, new Transaction { Signers = Array.Empty(), Attributes = Array.Empty() }, null, settings: TestBlockchain.TheNeoSystem.Settings)) { @@ -192,7 +192,7 @@ public void TestCreateMultiSigRedeemScriptFee() byte[] verification = Contract.CreateMultiSigRedeemScript(2, publicKeys); byte[] invocation = new ScriptBuilder().EmitPush(UInt160.Zero).EmitPush(UInt160.Zero).ToArray(); - long fee = PolicyContract.DefaultExecFeeFactor * (ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * (2 + 2) + ApplicationEngine.OpCodePrices[OpCode.PUSHINT8] * 2 + ApplicationEngine.OpCodePrices[OpCode.SYSCALL] + ApplicationEngine.CheckSigPrice * 2); + long fee = PolicyContract.DefaultExecFeeFactor * (ApplicationEngine.OpCodePriceTable[(byte)OpCode.PUSHDATA1] * (2 + 2) + ApplicationEngine.OpCodePriceTable[(byte)OpCode.PUSHINT8] * 2 + ApplicationEngine.OpCodePriceTable[(byte)OpCode.SYSCALL] + ApplicationEngine.CheckSigPrice * 2); using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, new Transaction { Signers = Array.Empty(), Attributes = Array.Empty() }, null, settings: TestBlockchain.TheNeoSystem.Settings)) { diff --git a/tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs b/tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs index 13209618e3..c373930c6e 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs @@ -23,7 +23,20 @@ public class UT_OpCodePrices public void AllOpcodePriceAreSet() { foreach (OpCode opcode in Enum.GetValues(typeof(OpCode))) - Assert.IsTrue(ApplicationEngine.OpCodePrices.ContainsKey(opcode), opcode.ToString()); + { +#pragma warning disable CS0618 // Type or member is obsolete + Assert.IsTrue(ApplicationEngine.OpCodePrices.ContainsKey(opcode), opcode.ToString(), $"{opcode} without price"); + Assert.AreEqual(ApplicationEngine.OpCodePrices[opcode], ApplicationEngine.OpCodePriceTable[(byte)opcode], $"{opcode} price mismatch"); +#pragma warning restore CS0618 // Type or member is obsolete + + if (opcode == OpCode.RET || + opcode == OpCode.SYSCALL || + opcode == OpCode.ABORT || + opcode == OpCode.ABORTMSG) + continue; + + Assert.AreNotEqual(0, ApplicationEngine.OpCodePriceTable[(byte)opcode], $"{opcode} without price"); + } } } }