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
3 changes: 3 additions & 0 deletions data/transactions/logic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ Global fields are fields that are common to all the transactions in the group. I
| 9 | CreatorAddress | []byte | Address of the creator of the current application. Fails if no such application is executing. LogicSigVersion >= 3. |
| 10 | CurrentApplicationAddress | []byte | Address that the current application controls. Fails in LogicSigs. LogicSigVersion >= 5. |
| 11 | GroupID | []byte | ID of the transaction group. 32 zero bytes if the transaction is not part of a group. LogicSigVersion >= 5. |
| 12 | OpcodeBudget | uint64 | The remaining cost that can be spent by opcodes in this program. LogicSigVersion >= 6. |
| 13 | CallerApplicationID | uint64 | The application ID of the application that called this application. 0 if this application is at the top-level. LogicSigVersion >= 6. |
| 14 | CallerApplicationAddress | []byte | The application address of the application that called this application. ZeroAddress if this application is at the top-level. LogicSigVersion >= 6. |


**Asset Fields**
Expand Down
3 changes: 3 additions & 0 deletions data/transactions/logic/TEAL_opcodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,9 @@ FirstValidTime causes the program to fail. The field is reserved for future use.
| 9 | CreatorAddress | []byte | Address of the creator of the current application. Fails if no such application is executing. LogicSigVersion >= 3. |
| 10 | CurrentApplicationAddress | []byte | Address that the current application controls. Fails in LogicSigs. LogicSigVersion >= 5. |
| 11 | GroupID | []byte | ID of the transaction group. 32 zero bytes if the transaction is not part of a group. LogicSigVersion >= 5. |
| 12 | OpcodeBudget | uint64 | The remaining cost that can be spent by opcodes in this program. LogicSigVersion >= 6. |
| 13 | CallerApplicationID | uint64 | The application ID of the application that called this application. 0 if this application is at the top-level. LogicSigVersion >= 6. |
| 14 | CallerApplicationAddress | []byte | The application address of the application that called this application. ZeroAddress if this application is at the top-level. LogicSigVersion >= 6. |


## gtxn t f
Expand Down
3 changes: 3 additions & 0 deletions data/transactions/logic/assembler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,9 @@ global LatestTimestamp
global CurrentApplicationID
global CreatorAddress
global GroupID
global OpcodeBudget
global CallerApplicationID
global CallerApplicationAddress
txn Sender
txn Fee
bnz label1
Expand Down
3 changes: 3 additions & 0 deletions data/transactions/logic/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,9 @@ var globalFieldDocs = map[string]string{
"CreatorAddress": "Address of the creator of the current application. Fails if no such application is executing",
"CurrentApplicationAddress": "Address that the current application controls. Fails in LogicSigs",
"GroupID": "ID of the transaction group. 32 zero bytes if the transaction is not part of a group.",
"OpcodeBudget": "The remaining cost that can be spent by opcodes in this program.",
"CallerApplicationID": "The application ID of the application that called this application. 0 if this application is at the top-level.",
"CallerApplicationAddress": "The application address of the application that called this application. ZeroAddress if this application is at the top-level.",
}

// GlobalFieldDocs are notes on fields available in `global` with extra versioning info if any
Expand Down
16 changes: 16 additions & 0 deletions data/transactions/logic/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -2636,6 +2636,22 @@ func (cx *EvalContext) globalFieldToValue(fs globalFieldSpec) (sv stackValue, er
sv.Bytes, err = cx.getCreatorAddress()
case GroupID:
sv.Bytes = cx.Txn.Txn.Group[:]
case OpcodeBudget:
sv.Uint = uint64(cx.budget() - cx.cost)
case CallerApplicationID:
if cx.caller != nil {
sv.Uint, err = cx.caller.getApplicationID()
} else {
sv.Uint = 0
}
case CallerApplicationAddress:
if cx.caller != nil {
var addr basics.Address
addr, err = cx.caller.getApplicationAddress()
sv.Bytes = addr[:]
} else {
sv.Bytes = zeroAddress[:]
}
default:
err = fmt.Errorf("invalid global field %d", fs.field)
}
Expand Down
61 changes: 59 additions & 2 deletions data/transactions/logic/evalAppTxn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -845,8 +845,8 @@ int 1

// TestInnerBudgetIncrement ensures that an app can make a (nearly) empty inner
// app call in order to get 700 extra opcode budget. Unfortunately, it costs a
// bit to create the call, and the app itself consumes a little, so it's more
// like 690 or so.
// bit to create the call, and the app itself consumes 1, so it ends up being
// about 690 (see next test).
func TestInnerBudgetIncrement(t *testing.T) {
ep, tx, ledger := makeSampleEnv()
gasup := testProg(t, "pushint 1", AssemblerMaxVersion)
Expand Down Expand Up @@ -874,6 +874,36 @@ itxn_submit;
testApp(t, buy+buy+strings.Repeat(waste, 12)+"int 1", ep)
}

func TestIncrementCheck(t *testing.T) {
ep, tx, ledger := makeSampleEnv()
gasup := testProg(t, "pushint 1", AssemblerMaxVersion)
ledger.NewApp(tx.Receiver, 222, basics.AppParams{
ApprovalProgram: gasup.Program,
})

source := `
// 698, not 699, because intcblock happens first
global OpcodeBudget; int 698; ==; assert
// "buy" more
itxn_begin
int appl; itxn_field TypeEnum
int 222; itxn_field ApplicationID
itxn_submit;
global OpcodeBudget; int 1387; ==; assert
itxn_begin
int appl; itxn_field TypeEnum
int 222; itxn_field ApplicationID
itxn_submit;
global OpcodeBudget; int 2076; ==; assert
int 1
`

ledger.NewApp(tx.Receiver, 888, basics.AppParams{})
ledger.NewAccount(ledger.ApplicationID().Address(), 50_000)
tx.ForeignApps = []basics.AppIndex{basics.AppIndex(222)}
testApp(t, source, ep)
}

// TestInnerTxIDs confirms that TxIDs are available and different
func TestInnerTxIDs(t *testing.T) {
ep, tx, ledger := makeSampleEnv()
Expand Down Expand Up @@ -1140,3 +1170,30 @@ int 890
==
`, ep)
}

// TestCallerGlobals checks that a called app can see its caller.
func TestCallerGlobals(t *testing.T) {
ep, tx, ledger := makeSampleEnv()
globals := testProg(t, fmt.Sprintf(`
global CallerApplicationID
int 888
==
global CallerApplicationAddress
addr %s
==
&&
`, basics.AppIndex(888).Address()), AssemblerMaxVersion)
ledger.NewApp(tx.Receiver, 222, basics.AppParams{
ApprovalProgram: globals.Program,
})

ledger.NewApp(tx.Receiver, 888, basics.AppParams{})
ledger.NewAccount(ledger.ApplicationID().Address(), 50_000)
tx.ForeignApps = []basics.AppIndex{basics.AppIndex(222)}
testApp(t, `itxn_begin
int appl; itxn_field TypeEnum
int 222; itxn_field ApplicationID
itxn_submit
int 1
`, ep)
}
15 changes: 15 additions & 0 deletions data/transactions/logic/evalStateful_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2419,3 +2419,18 @@ func TestAppAddress(t *testing.T) {
source = fmt.Sprintf("int 0; app_params_get AppAddress; assert; addr %s; ==;", a)
testApp(t, source, ep)
}

func TestBudget(t *testing.T) {
ep, tx, ledger := makeSampleEnv()
ledger.NewApp(tx.Receiver, 888, basics.AppParams{})
source := `
global OpcodeBudget
int 699
==
assert
global OpcodeBudget
int 695
==
`
testApp(t, source, ep)
}
24 changes: 17 additions & 7 deletions data/transactions/logic/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,17 @@ byte 0x0706000000000000000000000000000000000000000000000000000000000000
`

const globalV6TestProgram = globalV5TestProgram + `
// No new globals in v6
global OpcodeBudget
int 0
>
&&
global CallerApplicationAddress
global ZeroAddress
==
&&
global CallerApplicationID
!
&&
`

func TestGlobal(t *testing.T) {
Expand All @@ -941,17 +951,19 @@ func TestGlobal(t *testing.T) {
lastField GlobalField
program string
}
// Associate the highest allowed global constant with each version's test program
tests := map[uint64]desc{
0: {GroupSize, globalV1TestProgram},
1: {GroupSize, globalV1TestProgram},
2: {CurrentApplicationID, globalV2TestProgram},
3: {CreatorAddress, globalV3TestProgram},
4: {CreatorAddress, globalV4TestProgram},
5: {GroupID, globalV5TestProgram},
6: {GroupID, globalV6TestProgram},
6: {CallerApplicationAddress, globalV6TestProgram},
}
// tests keys are versions so they must be in a range 1..AssemblerMaxVersion plus zero version
require.LessOrEqual(t, len(tests), AssemblerMaxVersion+1)
require.Len(t, globalFieldSpecs, int(invalidGlobalField))

ledger := MakeLedger(nil)
addr, err := basics.UnmarshalChecksumAddress(testAddr)
Expand All @@ -963,13 +975,13 @@ func TestGlobal(t *testing.T) {
t.Run(fmt.Sprintf("v=%d", v), func(t *testing.T) {
last := tests[v].lastField
testProgram := tests[v].program
for _, globalField := range GlobalFieldNames[:last] {
for _, globalField := range GlobalFieldNames[:last+1] {
if !strings.Contains(testProgram, globalField) {
t.Errorf("TestGlobal missing field %v", globalField)
}
}

var txn transactions.SignedTxn
txn := transactions.SignedTxn{}
txn.Txn.Group = crypto.Digest{0x07, 0x06}

proto := config.ConsensusParams{
Expand Down Expand Up @@ -1024,9 +1036,7 @@ int %s
==
&&`, symbol, string(tt))
ops := testProg(t, text, v)
if v < appsEnabledVersion && tt == protocol.ApplicationCallTx {
}
var txn transactions.SignedTxn
txn := transactions.SignedTxn{}
txn.Txn.Type = tt
if v < appsEnabledVersion && tt == protocol.ApplicationCallTx {
testLogicBytes(t, ops.Program, defaultEvalParams(&txn),
Expand Down
14 changes: 14 additions & 0 deletions data/transactions/logic/fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,17 @@ const (
// GroupID [32]byte
GroupID

// v6

// OpcodeBudget The remaining budget available for execution
OpcodeBudget

// CallerApplicationID The ID of the caller app, else 0
CallerApplicationID

// CallerApplicationAddress The Address of the caller app, else ZeroAddress
CallerApplicationAddress

invalidGlobalField
)

Expand Down Expand Up @@ -400,6 +411,9 @@ var globalFieldSpecs = []globalFieldSpec{
{CreatorAddress, StackBytes, runModeApplication, 3},
{CurrentApplicationAddress, StackBytes, runModeApplication, 5},
{GroupID, StackBytes, modeAny, 5},
{OpcodeBudget, StackUint64, runModeApplication, 6},
{CallerApplicationID, StackUint64, runModeApplication, 6},
{CallerApplicationAddress, StackBytes, runModeApplication, 6},
}

// GlobalFieldSpecByField maps GlobalField to spec
Expand Down
9 changes: 6 additions & 3 deletions data/transactions/logic/fields_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion ledger/internal/apptxn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,8 @@ func TestClawbackAction(t *testing.T) {
Accounts: []basics.Address{addrs[0], addrs[1]},
}
eval = nextBlock(t, l, true, nil)
txgroup(t, l, eval, &overpay, &clawmove)
err := txgroup(t, l, eval, &overpay, &clawmove)
require.NoError(t, err)
endBlock(t, l, eval)

amount, _ := holding(t, l, addrs[1], asaIndex)
Expand Down