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

eval: increase opcode budget with fee credit #5943

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
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
25 changes: 23 additions & 2 deletions data/transactions/logic/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -1542,8 +1542,29 @@ func (cx *EvalContext) step() error {
}

if opcost > cx.remainingBudget() {
return fmt.Errorf("pc=%3d dynamic cost budget exceeded, executing %s: local program cost was %d",
cx.pc, spec.Name, cx.cost)
if cx.runMode != ModeApp {
return fmt.Errorf("pc=%3d dynamic cost budget exceeded, executing %s: local program cost was %d",
cx.pc, spec.Name, cx.cost)
}

requiredExtraBudget := uint64(opcost - cx.remainingBudget())
budgetPerMinFee := uint64(cx.Proto.MaxAppProgramCost)
requiredMinFees := (requiredExtraBudget + budgetPerMinFee - 1) / budgetPerMinFee
requiredFee := cx.Proto.MinTxnFee * requiredMinFees

if cx.FeeCredit == nil || *cx.FeeCredit < requiredFee {
return fmt.Errorf("pc=%3d dynamic cost budget exceeded, executing %s: local program cost was %d",
cx.pc, spec.Name, cx.cost)
}
*cx.FeeCredit -= requiredFee

*cx.pooledAllowedInners -= int(requiredMinFees)
if *cx.pooledAllowedInners < 0 {
return fmt.Errorf("pc=%3d dynamic group cost budget exceeded, executing %s: local program cost was %d",
cx.pc, spec.Name, cx.cost)
}

*cx.PooledApplicationBudget += int(budgetPerMinFee * requiredMinFees)
}

cx.cost += opcost
Expand Down
46 changes: 46 additions & 0 deletions data/transactions/logic/evalAppTxn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,52 @@ itxn_submit;
TestApp(t, buy+buy+strings.Repeat(waste, 12)+"int 1", ep)
}

func TestInnerBudgetIncrementFromFee(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()

ep, tx, ledger := MakeSampleEnv()

waste := `global CurrentApplicationAddress; keccak256; pop;`

ledger.NewApp(tx.Receiver, 888, basics.AppParams{})
ledger.NewAccount(appAddr(888), 50_000)
tx.ForeignApps = []basics.AppIndex{basics.AppIndex(222)}

// For every variation ensure the following:
//
// 1. The opcode budget is increased, but not more than necessary
// 2. The fee credit is deducted

*ep.FeeCredit = 0
TestApp(t, strings.Repeat(waste, 5)+"int 1", ep)
require.IsIncreasing(t, []int{0, *ep.PooledApplicationBudget, ep.Proto.MaxAppProgramCost})
require.Equal(t, uint64(0), *ep.FeeCredit)
TestApp(t, strings.Repeat(waste, 6)+"int 1", ep, "dynamic cost budget exceeded")

*ep.FeeCredit = ep.Proto.MinTxnFee
TestApp(t, strings.Repeat(waste, 6)+"int 1", ep)
require.IsIncreasing(t, []int{0, *ep.PooledApplicationBudget, ep.Proto.MaxAppProgramCost})
require.Equal(t, uint64(0), *ep.FeeCredit)
TestApp(t, strings.Repeat(waste, 11)+"int 1", ep, "dynamic cost budget exceeded")

*ep.FeeCredit = ep.Proto.MinTxnFee * 2
TestApp(t, strings.Repeat(waste, 11)+"int 1", ep)
require.IsIncreasing(t, []int{0, *ep.PooledApplicationBudget, ep.Proto.MaxAppProgramCost})
require.Equal(t, uint64(0), *ep.FeeCredit)
TestApp(t, strings.Repeat(waste, 16)+"int 1", ep, "dynamic cost budget exceeded")

// Ensure that the fee credit isn't deducted more than necessary
*ep.FeeCredit = ep.Proto.MinTxnFee * 3
TestApp(t, strings.Repeat(waste, 11)+"int 1", ep)
require.IsIncreasing(t, []int{0, *ep.PooledApplicationBudget, ep.Proto.MaxAppProgramCost})
require.Equal(t, ep.Proto.MinTxnFee, *ep.FeeCredit)

// Ensure the group budget is still enforced
*ep.FeeCredit = ep.Proto.MinTxnFee * 257
TestApp(t, strings.Repeat(waste, 5*257)+"int 1", ep, "dynamic group cost budget exceeded")
}

func TestIncrementCheck(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()
Expand Down
Loading