Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Optimize opcode price charging #3131

Merged
merged 9 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// modifications are permitted.

using Neo.VM;
using System;
using System.Collections.Generic;

namespace Neo.SmartContract
Expand All @@ -19,6 +20,7 @@ partial class ApplicationEngine
/// <summary>
/// The prices of all the opcodes.
/// </summary>
[Obsolete("You should use OpCodePriceTable")]
public static readonly IReadOnlyDictionary<OpCode, long> OpCodePrices = new Dictionary<OpCode, long>
{
[OpCode.PUSHINT8] = 1 << 0,
Expand Down Expand Up @@ -218,5 +220,20 @@ partial class ApplicationEngine
[OpCode.ISTYPE] = 1 << 1,
[OpCode.CONVERT] = 1 << 13,
};

public static readonly long[] OpCodePriceTable = new long[byte.MaxValue];

/// <summary>
/// Init OpCodePrices
/// </summary>
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;
}
}
}
}
2 changes: 1 addition & 1 deletion src/Neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,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)
Expand Down
12 changes: 6 additions & 6 deletions src/Neo/SmartContract/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ public static class Helper
/// </summary>
/// <returns>The calculated cost.</returns>
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;

/// <summary>
Expand All @@ -51,12 +51,12 @@ public static long SignatureContractCost() =>
/// <returns>The calculated cost.</returns>
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;
}
Expand Down
4 changes: 2 additions & 2 deletions tests/Neo.UnitTests/SmartContract/UT_Contract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Signer>(), Attributes = Array.Empty<TransactionAttribute>() }, null, settings: TestBlockchain.TheNeoSystem.Settings))
{
Expand Down Expand Up @@ -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<Signer>(), Attributes = Array.Empty<TransactionAttribute>() }, null, settings: TestBlockchain.TheNeoSystem.Settings))
{
Expand Down
15 changes: 14 additions & 1 deletion tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Jim8y marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}