Skip to content
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
82 changes: 0 additions & 82 deletions data/transactions/blackbox_test.go

This file was deleted.

28 changes: 25 additions & 3 deletions data/transactions/logic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,31 @@ must rerun their code to determine if the ApplicationCall transactions
in their pool would still succeed each time a block is added to the
blockchain.

Smart contracts have limits on their execution cost (700, consensus
parameter MaxAppProgramCost). Before v4, this was a static limit on
the cost of all the instructions in the program. Since then, the cost
is tracked dynamically during execution and must not exceed
MaxAppProgramCost. Beginning with v5, programs costs are pooled and
tracked dynamically across app executions in a group. If `n`
application invocations appear in a group, then the total execution
cost of such calls must not exceed `n`*MaxAppProgramCost. In v6, inner
application calls become possible, and each such call increases the
pooled budget by MaxAppProgramCost.

Executions of the ClearStateProgram are more stringent, in order to
ensure that applications may be closed out, but that applications also
are assured a chance to clean up their internal state. At the
beginning of the execution of a ClearStateProgram, the pooled budget
available must be MaxAppProgramCost or higher. If it is not, the
containing transaction group fails without clearing the app's
state. During the execution of the ClearStateProgram, no more than
MaxAppProgramCost may be drawn. If further execution is attempted, the
ClearStateProgram fails, and the app's state _is cleared_.


### Resource availability

Smart contracts have limits on their execution budget (700, consensus
parameter MaxAppProgramCost), and the amount of blockchain state they
Smart contracts have limits on the amount of blockchain state they
may examine. Opcodes may only access blockchain resources such as
Accounts, Assets, and contract state if the given resource is
_available_.
Expand Down Expand Up @@ -596,7 +617,8 @@ In v5, inner transactions may perform `pay`, `axfer`, `acfg`, and
`itxn_submit`, the effects of the transaction are visible begining
with the next instruction with, for example, `balance` and
`min_balance` checks. In v6, inner transactions may also perform
`keyreg` and `appl` effects.
`keyreg` and `appl` effects. Inner `appl` calls fail if they attempt
to invoke a program with version less than v6.

In v5, only a subset of the transaction's header fields may be set: `Type`/`TypeEnum`,
`Sender`, and `Fee`. In v6, header fields `Note` and `RekeyTo` may
Expand Down
28 changes: 25 additions & 3 deletions data/transactions/logic/README_in.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,31 @@ must rerun their code to determine if the ApplicationCall transactions
in their pool would still succeed each time a block is added to the
blockchain.

Smart contracts have limits on their execution cost (700, consensus
parameter MaxAppProgramCost). Before v4, this was a static limit on
the cost of all the instructions in the program. Since then, the cost
is tracked dynamically during execution and must not exceed
MaxAppProgramCost. Beginning with v5, programs costs are pooled and
tracked dynamically across app executions in a group. If `n`
application invocations appear in a group, then the total execution
cost of such calls must not exceed `n`*MaxAppProgramCost. In v6, inner
application calls become possible, and each such call increases the
pooled budget by MaxAppProgramCost.

Executions of the ClearStateProgram are more stringent, in order to
ensure that applications may be closed out, but that applications also
are assured a chance to clean up their internal state. At the
beginning of the execution of a ClearStateProgram, the pooled budget
available must be MaxAppProgramCost or higher. If it is not, the
containing transaction group fails without clearing the app's
state. During the execution of the ClearStateProgram, no more than
MaxAppProgramCost may be drawn. If further execution is attempted, the
ClearStateProgram fails, and the app's state _is cleared_.


### Resource availability

Smart contracts have limits on their execution budget (700, consensus
parameter MaxAppProgramCost), and the amount of blockchain state they
Smart contracts have limits on the amount of blockchain state they
may examine. Opcodes may only access blockchain resources such as
Accounts, Assets, and contract state if the given resource is
_available_.
Expand Down Expand Up @@ -311,7 +332,8 @@ In v5, inner transactions may perform `pay`, `axfer`, `acfg`, and
`itxn_submit`, the effects of the transaction are visible begining
with the next instruction with, for example, `balance` and
`min_balance` checks. In v6, inner transactions may also perform
`keyreg` and `appl` effects.
`keyreg` and `appl` effects. Inner `appl` calls fail if they attempt
to invoke a program with version less than v6.

In v5, only a subset of the transaction's header fields may be set: `Type`/`TypeEnum`,
`Sender`, and `Fee`. In v6, header fields `Note` and `RekeyTo` may
Expand Down
48 changes: 32 additions & 16 deletions data/transactions/logic/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ func NewEvalParams(txgroup []transactions.SignedTxnWithAD, proto *config.Consens
var pooledApplicationBudget *int
var pooledAllowedInners *int

credit, _ := transactions.FeeCredit(txgroup, proto.MinTxnFee)
credit := feeCredit(txgroup, proto.MinTxnFee)

if proto.EnableAppCostPooling && apps > 0 {
pooledApplicationBudget = new(int)
Expand All @@ -337,6 +337,25 @@ func NewEvalParams(txgroup []transactions.SignedTxnWithAD, proto *config.Consens
}
}

// feeCredit returns the extra fee supplied in this top-level txgroup compared
// to required minfee. It can make assumptions about overflow because the group
// is known OK according to TxnGroupBatchVerify. (In essence the group is
// "WellFormed")
func feeCredit(txgroup []transactions.SignedTxnWithAD, minFee uint64) uint64 {
minFeeCount := uint64(0)
feesPaid := uint64(0)
for _, stxn := range txgroup {
if stxn.Txn.Type != protocol.CompactCertTx {
minFeeCount++
}
feesPaid = basics.AddSaturate(feesPaid, stxn.Txn.Fee.Raw)
}
// Overflow is impossible, because TxnGroupBatchVerify checked.
feeNeeded := minFee * minFeeCount

return feesPaid - feeNeeded
}

// NewInnerEvalParams creates an EvalParams to be used while evaluating an inner group txgroup
func NewInnerEvalParams(txg []transactions.SignedTxnWithAD, caller *EvalContext) *EvalParams {
minTealVersion := ComputeMinTealVersion(txg, true)
Expand Down Expand Up @@ -3733,12 +3752,9 @@ func opAppGlobalDel(cx *EvalContext) {

func appReference(cx *EvalContext, ref uint64, foreign bool) (basics.AppIndex, error) {
if cx.version >= directRefEnabledVersion {
if ref == 0 {
if ref == 0 || ref == uint64(cx.appID) {
return cx.appID, nil
}
if ref <= uint64(len(cx.Txn.Txn.ForeignApps)) {
return basics.AppIndex(cx.Txn.Txn.ForeignApps[ref-1]), nil
}
for _, appID := range cx.Txn.Txn.ForeignApps {
if appID == basics.AppIndex(ref) {
return appID, nil
Expand All @@ -3752,13 +3768,11 @@ func appReference(cx *EvalContext, ref uint64, foreign bool) (basics.AppIndex, e
}
}
}
// It should be legal to use your own app id, which can't be in
// ForeignApps during creation, because it is unknown then. But it can
// be discovered in the app code. It's tempting to combine this with
// the == 0 test, above, but it must come after the check for being
// below len(ForeignApps)
if ref == uint64(cx.appID) {
return cx.appID, nil
// Allow use of indexes, but this comes last so that clear advice can be
// given to anyone who cares about semantics in the first few rounds of
// a new network - don't use indexes for references, use the App ID
if ref <= uint64(len(cx.Txn.Txn.ForeignApps)) {
return basics.AppIndex(cx.Txn.Txn.ForeignApps[ref-1]), nil
}
} else {
// Old rules
Expand All @@ -3780,10 +3794,6 @@ func appReference(cx *EvalContext, ref uint64, foreign bool) (basics.AppIndex, e

func asaReference(cx *EvalContext, ref uint64, foreign bool) (basics.AssetIndex, error) {
if cx.version >= directRefEnabledVersion {
// In recent versions, accept either kind of ASA reference
if ref < uint64(len(cx.Txn.Txn.ForeignAssets)) {
return basics.AssetIndex(cx.Txn.Txn.ForeignAssets[ref]), nil
}
for _, assetID := range cx.Txn.Txn.ForeignAssets {
if assetID == basics.AssetIndex(ref) {
return assetID, nil
Expand All @@ -3797,6 +3807,12 @@ func asaReference(cx *EvalContext, ref uint64, foreign bool) (basics.AssetIndex,
}
}
}
// Allow use of indexes, but this comes last so that clear advice can be
// given to anyone who cares about semantics in the first few rounds of
// a new network - don't use indexes for references, use the asa ID.
if ref < uint64(len(cx.Txn.Txn.ForeignAssets)) {
return basics.AssetIndex(cx.Txn.Txn.ForeignAssets[ref]), nil
}
} else {
// Old rules
if foreign {
Expand Down
30 changes: 0 additions & 30 deletions data/transactions/signedtxn.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package transactions

import (
"errors"
"fmt"

"github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/basics"
Expand Down Expand Up @@ -130,32 +129,3 @@ func WrapSignedTxnsWithAD(txgroup []SignedTxn) []SignedTxnWithAD {
}
return txgroupad
}

// FeeCredit computes the amount of fee credit that can be spent on
// inner txns because it was more than required.
func FeeCredit(txgroup []SignedTxnWithAD, minFee uint64) (uint64, error) {
minFeeCount := uint64(0)
feesPaid := uint64(0)
for _, stxn := range txgroup {
if stxn.Txn.Type != protocol.CompactCertTx {
minFeeCount++
}
feesPaid = basics.AddSaturate(feesPaid, stxn.Txn.Fee.Raw)
}
feeNeeded, overflow := basics.OMul(minFee, minFeeCount)
if overflow {
return 0, fmt.Errorf("txgroup fee requirement overflow")
}
// feesPaid may have saturated. That's ok. Since we know
// feeNeeded did not overflow, simple comparison tells us
// feesPaid was enough.
if feesPaid < feeNeeded {
return 0, fmt.Errorf("txgroup had %d in fees, which is less than the minimum %d * %d",
feesPaid, minFeeCount, minFee)
}
// Now, if feesPaid *did* saturate, you will not get "credit" for
// all those fees while executing AVM code that might create
// transactions. But you'll get the max uint64 - good luck
// spending it.
return feesPaid - feeNeeded, nil
}
Loading