-
Notifications
You must be signed in to change notification settings - Fork 1k
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
[Neo VM] Towards an Execution Time Determinastic VM: Dynamic OpCode Price #3600
Comments
The reason that i am not benchmark on single Opcode is becuause 1. DOS attack needs to be in a loop; 2. single OpCode execution time is related to its price, yet what we want is to have a dynamic price for it, thus setting up a benchmark env for single Opcode is way more complex than have a fixed GAS price. |
#3510, #3535, #3600, I'm counting...
Why not NOP? I've told about this many times (the last iteration: #3552 (comment)).
The script has NOP/PUSH/JMP per each REVERSEN, this affects executions with low number of elements and your "threshold" might as well be just that. You can have more accurate numbers (like in https://github.com/nspcc-dev/neo-go/blob/e89f9fe2a417c917d40d933c1b6a5f92804d6e2d/pkg/vm/opcodebench_test.go#L13) and accurate numbers is what we need here to make any decisions. Also, the model doesn't need to be perfect, I'd opt for simpler model that reflects the behavior reasonably ( |
Nop is basically the same, its 500 ms.
Yes, i have the same concern as well, the problem of this is what we want is to defend against DOS attack and have a worse case execution time expectation. Basically for all DOS attacks, loop is required. And aside from that, doing benchmark on single OpCode is way more complex than having a fixed GAS fee, the reason is we can not get the execution time until the benchmark is done, which means we need extra process on the value we get from the benchmark to know if the price is fairly set. i have tried that, need many days to collect tons of data to have a proper equation and reasonable parameters for a single OpCode. That is not the only problem, if you do benchmark on existing OpCode, you will find that even for OpCode that has the same price, their execution time is very very different, and you can not really find a baseline for that,,,,, But with a fixed GAS, i think loop itself took up most of the time, but this is not against our goal here. And as i said above, even if we did bench on single OpCode, it basically works the same as what we get from having a fixed GAS fee.
Having a threshold and a pricing factor at the same time is because i wish to introduce minumum influence to our existing price model, ordinary contract will still behave the same, even cheaper. If we only have one equation without a price factor, the final price can be too cheap or too expensive for different OpCode, for example, UNPACK and PACK need a factor of 1 and 0.5, while REVERSEN need a factor of 0.002 to limit their execution time to around 400-500 ms. otherwise it can be 2s or 30 ms. But this can be updated accordingly, I am open to any suggestions. |
Yeah, they're close, still this is the basic unit to measure everything against. At least if we're talking about price model adjustments and not complete rework. It's more or less balanced for a lot of opcodes, the only problematic are the ones that deal with a lot of elements.
That I agree with. Maybe we need to agree on a list of opcodes that we will not change first since they're considered to be perfectly aligned with execution time already. Then the assumption of "1 GAS executes in ~500ms" can be a good enough approximation. I still think that isolated numbers from NeoGo tests are better, but at the same time I know what you're talking about, Go benchmarks from above have to do a lot of iterations to get any reasonable numbers. Also, NeoGo test is easy to extend/reproduce.
That's exactly the point. Take
Because these are all wrong numbers, you know it, we need something that can be counted easily in integers. |
I get all your point above. Let me have a try on your methods. But different coefficients for different OpCode might be unavoidable, cause the execution time increase ratio can be different for different OpCodes, 0.5,and 0.002 are for that purpose. Some opcoe execution time increases sharply when the subitem number grows, while some grows more gentle. |
Sure, this of course depends on real benchmark data. |
@roman-khimov this is the benchmark with
With a threshold of 64, the result is:
|
I see your formula is a bit more accurate. But likely you're overoptimizing it for a particular CPU. These "thresholds" are very likely to be cache/pipeline effects and these are very different for different CPUs, you're using Maybe we can build this ladder with a step of 8 or 16, btw, can be tried, but I'd expect it to be good enough in the end.
And "expensive" or not should first of all be compared to the current price. And there I think we'd get a huge improvement anyway. Like paying 8 instead of 2048 is a much bigger difference than worrying that it takes 150ms per 1 GAS instead of 500ms. |
And I'm not even talking about different implementations and potential future optimizations, btw. |
these will also differ from |
This is PACK without threshold and factor:
with threshold of 16 and factor of 0.7
|
As you said different platforms can have different performance, but since i dont really have that many machines to test, and even if we can, we still need to set a target for the bench... Anyway, i am open to all options here, if you think it is OK, i would happily adopt your suggestion directly. As to comment from @cschuchardt88, the same as above, we still need to have one final propsoal that works for all languages, differences between languages, yes, but i dont think i can take that into consideration. But i think anna or roman will provide the correspoing golang bench result and suggest for a proper update to the equation. |
Summary or problem description
As is explained in #3535 , neo vm excution time is not determined for the same amount of GAS, say one GAS, it can run at a range from a few minutes to few milliseconds. This issue follows #3535 and propose a potential solution to address that issue.
Do you have any solution you want to propose?
For OpCode operation that involves multiple subitems, we use the subitem count as a factor for the OpCode price.
The solution dependes on pr #3581 for light GC and pr #3528 for benchmark results.
Benchmark env:
For different opcodes, we construct corresponding benchmark scripts that contain infinite loops. During test execution, the bench will automatically stop when 1GAS system fee is exhausted. Since DOS attacks also need to construct loops, we believe it is reasonable to test OpCodes within loops.
The baseline of one GAS execution time is based on OPCODE.PUSHX, which costs around 400 ms.
Solution Overview
Based on a large amount of benchmark data, we designed the following formula to calculate the final price of an opcode during runtime:
If the number of elements exceeds the threshold: Final Price = Initial Price * Number of subitems* Price Coefficient
Otherwise: Final Price = Initial Price
We set this threshold because when the number of elements is below the threshold, its execution time remains basically stable. However, when the number of elements exceeds the threshold, its execution time increases dramatically. Different opcodes will have different thresholds and price coefficients, which need to be determined based on extensive benchmark data.
The key points are:
REVERSEN ( Initial Price: 1<<4)
Benchmark script:
Original benchmark:
Dynamic Price: ( Initial Price: 1<<2):
SubItem Threshold:64
Dynamic Factor: 0.02
Keep updating.
The text was updated successfully, but these errors were encountered: