Skip to content

ExecutionEngine: collect parameters affecting opcode price#571

Open
Turalchik wants to merge 49 commits into
neo-project:masterfrom
Turalchik:dynamic-opcode-pricing
Open

ExecutionEngine: collect parameters affecting opcode price#571
Turalchik wants to merge 49 commits into
neo-project:masterfrom
Turalchik:dynamic-opcode-pricing

Conversation

@Turalchik

@Turalchik Turalchik commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

This PR adds collection of parameters in the OpcodePriceArgs struct (length, reference count changes, etc.) that affect opcode costs for dynamic pricing. The pricing is calculated in the related PR neo-project/neo#4536.

A partial port of nspcc-dev/neo-go#4087. Ref. nspcc-dev/neo-go#4043.

Signed-off-by: Tural Devrishev <tural@nspcc.ru>
@codecov

codecov Bot commented Apr 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.69231% with 40 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.39%. Comparing base (99095c2) to head (8d0a4d1).

Files with missing lines Patch % Lines
src/Neo.VM/JumpTable/JumpTable.Compound.cs 75.26% 22 Missing and 1 partial ⚠️
src/Neo.VM/JumpTable/JumpTable.Numeric.cs 58.62% 12 Missing ⚠️
src/Neo.VM/JumpTable/JumpTable.Control.cs 91.11% 4 Missing ⚠️
src/Neo.VM/JumpTable/JumpTable.Push.cs 96.77% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #571      +/-   ##
==========================================
- Coverage   85.47%   85.39%   -0.08%     
==========================================
  Files          41       42       +1     
  Lines        2720     2993     +273     
  Branches      345      349       +4     
==========================================
+ Hits         2325     2556     +231     
- Misses        304      345      +41     
- Partials       91       92       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@AnnaShaleva AnnaShaleva left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will submit detailed handlers review later.

Comment thread src/Neo.VM/OpCodePriceArgs.cs Outdated
Comment thread src/Neo.VM/ExecutionEngine.cs Outdated
Comment thread src/Neo.VM/ExecutionEngine.cs Outdated
Comment thread src/Neo.VM/Types/Struct.cs Outdated
Comment thread src/Neo.VM/OpCodePriceArgs.cs Outdated
@AnnaShaleva AnnaShaleva changed the title collect parameters that affect price of opcode ExecutionEngine: collect parameters affecting opcode price Apr 17, 2026
Tural Devrishev added 4 commits April 20, 2026 11:49
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
@Turalchik Turalchik requested a review from AnnaShaleva April 20, 2026 09:59

@AnnaShaleva AnnaShaleva left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will check it one more time together with neo-project/neo#4536.

Comment thread src/Neo.VM/JumpTable/JumpTable.Compound.cs Outdated
Comment thread src/Neo.VM/JumpTable/JumpTable.Compound.cs Outdated
Comment thread src/Neo.VM/JumpTable/JumpTable.Compound.cs Outdated
Comment thread src/Neo.VM/JumpTable/JumpTable.Push.cs Outdated
Comment thread src/Neo.VM/JumpTable/JumpTable.Types.cs
Comment thread src/Neo.VM/OpCodePriceParams.cs Outdated
Comment thread src/Neo.VM/JumpTable/JumpTable.Splice.cs
Tural Devrishev added 3 commits April 21, 2026 11:41
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Comment thread src/Neo.VM/OpCodePriceParams.cs Outdated

@AnnaShaleva AnnaShaleva left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to update parameters construction for Map-related opcodes (ref. nspcc-dev/neo-go#4222); other than that the PR looks legit, let's wait for the update.

Comment thread src/Neo.VM/Types/Struct.cs Outdated
Comment thread src/Neo.VM/JumpTable/JumpTable.Slot.cs Outdated
Tural Devrishev added 3 commits April 28, 2026 21:47
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
/// Typ specifies type of <see cref="StackItemType"/> which in most of the cases serves
/// as an operand of the given opcode.
/// </summary>
public StackItemType Type { get; internal set; }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this is not initialized every time? Is this required?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's required for some of opcodes. For other opcodes price doesn't depend on the operand type.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you give me an example please?

@AnnaShaleva AnnaShaleva Apr 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. CONVERT requires Type since it works differently for Array/Struct and ByteStrings:
https://github.com/Turalchik/neo/blob/f0699631792accf4cdd717073091199f0bd650a3/src/Neo/SmartContract/Fee.cs#L357

PICKITEM requires Type argument since its price depends on whether the operand is a compound type or not:
https://github.com/Turalchik/neo/blob/f0699631792accf4cdd717073091199f0bd650a3/src/Neo/SmartContract/Fee.cs#L368

And APPEND doesn't actually depend on the operand type. RefsDelta and NClonedItems arguments cover possible price fluctuations for different operand types:
https://github.com/Turalchik/neo/blob/f0699631792accf4cdd717073091199f0bd650a3/src/Neo/SmartContract/Fee.cs#L353

@AnnaShaleva AnnaShaleva Apr 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, different combinations of Type, RefsDelta, Length and NClonedItems are used for every opcode. The set of required parameters is defined separately for every opcode via opcode handler investigation and via benchmarks of edge cases in nspcc-dev/neo-go#4218.

@AnnaShaleva AnnaShaleva self-requested a review April 29, 2026 09:14
Comment thread src/Neo.VM/JumpTable/JumpTable.Compound.cs
Comment thread src/Neo.VM/JumpTable/JumpTable.Compound.cs
Comment thread src/Neo.VM/JumpTable/JumpTable.Stack.cs Outdated
Comment thread src/Neo.VM/JumpTable/JumpTable.Types.cs Outdated
Comment thread src/Neo.VM/JumpTable/JumpTable.Types.cs Outdated
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
@Turalchik Turalchik requested a review from shargon May 19, 2026 11:09
Jim8y
Jim8y previously approved these changes May 19, 2026

@Jim8y Jim8y left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me now. The latest update covers the two RunStats gaps I was concerned about.

Tural Devrishev added 3 commits May 19, 2026 16:58
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Tural Devrishev added 3 commits May 21, 2026 12:42
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
@Turalchik Turalchik requested a review from Jim8y May 22, 2026 08:21
@AnnaShaleva

Copy link
Copy Markdown
Member

@neo-project/core this PR does not depend on #576 and may be reviewed&merged in parallel with #576.

@Jim8y Jim8y left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One blocker remains around faulting dynamic-price paths. Because PostExecuteInstruction now runs from a finally block, opcodes that fault after doing work still reach the dynamic pricing hook, but some of them leave runStats null. I reproduced this with ASSERTMSG on a false condition and with an unhandled THROW: both call PostExecuteInstruction with null stats after consuming their operands. ASSERTMSG loses the message Length used by AssertGas, and THROW loses RefsDelta on the unhandled path. Please populate RunStats before throwing, or otherwise avoid charging these faulting executions with default stats.

@AnnaShaleva

Copy link
Copy Markdown
Member

Please populate RunStats before throwing, or otherwise avoid charging these faulting executions with default stats.

The execution is already FAULT-ed, and the exception is not catchable. From that point, further charging doesn't make sense, so populating RunStats before throwing is not an option to me. At the same time, avoiding charging with default stats requires an additional check in PostExecuteInstruction (check if an uncatchable exception was thrown). I'd prefer not to introduce this check because it complicates PostExecuteInstruction for no good reason.

So I'd leave it as it is.

Jim8y
Jim8y previously approved these changes May 23, 2026

@Jim8y Jim8y left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that makes sense. I agree this faulting path does not need to block the PR.

Signed-off-by: Tural Devrishev <tural@nspcc.ru>
@Wi1l-B0t

Wi1l-B0t commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Conflicts.

@Turalchik Turalchik requested a review from Jim8y June 2, 2026 12:20
Tural Devrishev added 2 commits June 3, 2026 00:07
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
if (value is Struct s) value = s.Clone(engine.Limits);
var nClonedItems = 0;
if (value is Struct s) value = s.Clone(engine.Limits, out nClonedItems);
var (r1, r2) = (engine.ReferenceCounter.Count, engine.ReferenceCounter.Count);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SETITEM still seems to miss the first value pop in RefsDelta. With a direct map SETITEM, ReferenceCounter goes 3 -> 0 but RunStats reports RefsDelta = 2; with a retained map it goes 4 -> 3 but reports 0. Should we capture r1 before popping value, or otherwise add that delta?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be fixed after the merge https://github.com/neo-project/neo-vm/pull/575/changes, in which the value is extracted using the PopNoRef() method:

var value = engine.PopNoRef();

Signed-off-by: Tural Devrishev <tural@nspcc.ru>
@Turalchik Turalchik requested a review from Jim8y June 4, 2026 16:26
Tural Devrishev added 3 commits June 5, 2026 14:54
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
Signed-off-by: Tural Devrishev <tural@nspcc.ru>
@AnnaShaleva AnnaShaleva mentioned this pull request Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants