-
Notifications
You must be signed in to change notification settings - Fork 493
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
Pool App call budget in group transactions #2711
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's discuss the shared budget pointer idea. I think it fits more closely with how we have done some other recent features. (In fact, see my PR for how I'm handling the excess fee credit in app txn creation: Look for "FeeCredit" in https://github.com/algorand/go-algorand/pull/2661/files)
ledger/eval_test.go
Outdated
{approvalProgram2, "dynamic cost budget exceeded, executing keccak256: remaining budget is 700 but program cost was 783"}, | ||
} | ||
|
||
for _, testCase := range cases { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think at one point we wanted to do the protocol checks in data/transactions/logic/evalStateful_test.go
, but there is some ledger code that also needs to be tested (prepareEvalParams
) for correct protocol, so I put this test in the ledger tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these tests look good but I think we should not test everything here because in ledger package we only set pooled budget for multiple app calls in one group. And the decisions are made in logic.
Let's do the following:
- a unit test for
prepareEvalParams
call on a group with 2 txns with app calls on old and new protos. No ledger construction/blocks needed. - Preserve a high-level test with block evaluator: no pooling on old proto and pooling on new proto. Programs should be simple but valid, something like
"byte "a"\n" + strings.Repeat("keccak256\n", 50)
. - Make more precise testing on
ed25519verify
in logic package - it is needed anyway, and theEvalParams
with proto and budget can be easily set there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the prepareEvalParams
tests above like you have suggested. Just to be clear, we should probably only check for correct pooling here, and check for cost/budget in the data/transactions/logic/evalStateful_test.go
file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is always a good idea to check both happy case and error case. The idea is to have 1) minimal sufficient coverage 2) without knowing to much details about stuff from other packeges.
I I suggest to use the following code to generate test programs of difference cost by varying N:
prog := "byte "a\n" + strings.Repeat("keccak256\n", N) + "pop\nint 1\n";
So here in ledger
the following four cases would be enough:
- cost ~701 + cost ~100 => FAIL on v29.
- same combo OK on vFuture
- ~701 + ~701 => FAIL on both v29 and vFuture
data/transactions/logic/eval.go
Outdated
if pass && cx.EvalParams.Proto.EnableAppCostPooling { | ||
// if eval passes, then budget is always greater than cost, so should not have underflow | ||
*cx.EvalParams.PooledApplicationBudget -= cx.cost | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If an app doesn't pass, everything's probably going to get aborted. Nonetheless, I don't see a good reason not to decrease the pooled budget.
This also needs to be super careful about underflow. Going negative here almost certainly leads to the possibility of a the budget being interpreted as a high number elsewhere.
Codecov Report
@@ Coverage Diff @@
## master #2711 +/- ##
=======================================
Coverage 47.09% 47.10%
=======================================
Files 350 350
Lines 56309 56321 +12
=======================================
+ Hits 26520 26528 +8
- Misses 26817 26821 +4
Partials 2972 2972
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, some work needed: 1) ed25519verify
must be only allowed in stateful TEAL v5+ 2) restructure your TEAL tests in legder: it only should check evaluation on old/new proto with as trivial programs as possible. All TEAL heavy-lifting should go into logic
package. Especially this change does not depends on ledger interface for TEAL, only EvalParams
preparation, so this preparation in isolation, and a big picture needed to be tested there.
ledger/eval_test.go
Outdated
{approvalProgram2, "dynamic cost budget exceeded, executing keccak256: remaining budget is 700 but program cost was 783"}, | ||
} | ||
|
||
for _, testCase := range cases { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these tests look good but I think we should not test everything here because in ledger package we only set pooled budget for multiple app calls in one group. And the decisions are made in logic.
Let's do the following:
- a unit test for
prepareEvalParams
call on a group with 2 txns with app calls on old and new protos. No ledger construction/blocks needed. - Preserve a high-level test with block evaluator: no pooling on old proto and pooling on new proto. Programs should be simple but valid, something like
"byte "a"\n" + strings.Repeat("keccak256\n", 50)
. - Make more precise testing on
ed25519verify
in logic package - it is needed anyway, and theEvalParams
with proto and budget can be easily set there.
ledger/eval_test.go
Outdated
for i, testCase := range cases { | ||
t.Run(fmt.Sprintf("i=%d", i), func(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not must but something you might to consider: there are two almost identical loops.
If fact, it can be done as a single loop over cases
.
- Remove fake proto from
eval
construction above - Make
params
array consisting on 3 elements: fake params withApplication: true, MaxAppProgramCost: 700
, vFuture, v29. - Modify
evalTestCase
struct and add number of app calls in tx group (numAppCalls
) - Run loops over cases, params, and calculate pooled cost as
proto.MaxAppProgramCost * numAppCalls
, and compare against a value EvalParams
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good suggestion, will refactor this part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, one question about pushint
in tests.
… algochoi/pool-tx-costs
Summary
ed25519verify
to be called in Application calls, given that there is enough budget in the poolvFuture
consensus parameterCloses #2636
Test Plan
ledger/
to check that group transactions pool the App call budget (700 * number of app calls)ed25519verify
is allowed in App calls, given enough budget in the pool