summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Jannotti <john.jannotti@algorand.com>2022-01-28 07:55:45 -0500
committerGitHub <noreply@github.com>2022-01-28 07:55:45 -0500
commit26321eccc46f224cd3dd50f12b9dca8592b41c38 (patch)
tree2519548e84109d9191c029f14ca517519ba23fde
parentca0676419868a915257a46b779c62ccabf384c92 (diff)
txn LastLog (#3525)
* txn LastLog * Insulate test from the type of field
-rw-r--r--data/transactions/logic/README.md1
-rw-r--r--data/transactions/logic/TEAL_opcodes.md1
-rw-r--r--data/transactions/logic/assembler_test.go1
-rw-r--r--data/transactions/logic/doc.go1
-rw-r--r--data/transactions/logic/eval.go6
-rw-r--r--data/transactions/logic/evalStateful_test.go38
-rw-r--r--data/transactions/logic/eval_test.go5
-rw-r--r--data/transactions/logic/fields.go13
-rw-r--r--data/transactions/logic/fields_string.go7
-rw-r--r--data/transactions/logic/fields_test.go8
10 files changed, 70 insertions, 11 deletions
diff --git a/data/transactions/logic/README.md b/data/transactions/logic/README.md
index 104a0d661..79cf215f9 100644
--- a/data/transactions/logic/README.md
+++ b/data/transactions/logic/README.md
@@ -454,6 +454,7 @@ Some of these have immediate data in the byte or bytes after the opcode.
| 59 | NumLogs | uint64 | v5 | Number of Logs (only with `itxn` in v5). Application mode only |
| 60 | CreatedAssetID | uint64 | v5 | Asset ID allocated by the creation of an ASA (only with `itxn` in v5). Application mode only |
| 61 | CreatedApplicationID | uint64 | v5 | ApplicationID allocated by the creation of an application (only with `itxn` in v5). Application mode only |
+| 62 | LastLog | []byte | v6 | The last message emitted. Empty bytes if none were emitted. Application mode only |
Additional details in the [opcodes document](TEAL_opcodes.md#txn) on the `txn` op.
diff --git a/data/transactions/logic/TEAL_opcodes.md b/data/transactions/logic/TEAL_opcodes.md
index 94ecee800..b68d7e3f7 100644
--- a/data/transactions/logic/TEAL_opcodes.md
+++ b/data/transactions/logic/TEAL_opcodes.md
@@ -436,6 +436,7 @@ The notation J,K indicates that two uint64 values J and K are interpreted as a u
| 59 | NumLogs | uint64 | v5 | Number of Logs (only with `itxn` in v5). Application mode only |
| 60 | CreatedAssetID | uint64 | v5 | Asset ID allocated by the creation of an ASA (only with `itxn` in v5). Application mode only |
| 61 | CreatedApplicationID | uint64 | v5 | ApplicationID allocated by the creation of an application (only with `itxn` in v5). Application mode only |
+| 62 | LastLog | []byte | v6 | The last message emitted. Empty bytes if none were emitted. Application mode only |
TypeEnum mapping:
diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go
index 0758e5b2e..f310d7f21 100644
--- a/data/transactions/logic/assembler_test.go
+++ b/data/transactions/logic/assembler_test.go
@@ -1396,6 +1396,7 @@ itxna Logs 1
itxn NumLogs
itxn CreatedAssetID
itxn CreatedApplicationID
+itxn LastLog
`, AssemblerMaxVersion)
for _, globalField := range GlobalFieldNames {
if !strings.Contains(text, globalField) {
diff --git a/data/transactions/logic/doc.go b/data/transactions/logic/doc.go
index c7ac55212..185d212e2 100644
--- a/data/transactions/logic/doc.go
+++ b/data/transactions/logic/doc.go
@@ -471,6 +471,7 @@ var txnFieldDocs = map[string]string{
"Logs": "Log messages emitted by an application call (only with `itxn` in v5)",
"NumLogs": "Number of Logs (only with `itxn` in v5)",
+ "LastLog": "The last message emitted. Empty bytes if none were emitted",
"CreatedAssetID": "Asset ID allocated by the creation of an ASA (only with `itxn` in v5)",
"CreatedApplicationID": "ApplicationID allocated by the creation of an application (only with `itxn` in v5)",
}
diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go
index 4cacc6396..c4dabbcf2 100644
--- a/data/transactions/logic/eval.go
+++ b/data/transactions/logic/eval.go
@@ -2231,6 +2231,12 @@ func (cx *EvalContext) txnFieldToStack(stxn *transactions.SignedTxnWithAD, fs *t
sv.Bytes = nilToEmpty([]byte(stxn.EvalDelta.Logs[arrayFieldIdx]))
case NumLogs:
sv.Uint = uint64(len(stxn.EvalDelta.Logs))
+ case LastLog:
+ if logs := len(stxn.EvalDelta.Logs); logs > 0 {
+ sv.Bytes = nilToEmpty([]byte(stxn.EvalDelta.Logs[logs-1]))
+ } else {
+ sv.Bytes = nilToEmpty(nil)
+ }
case CreatedAssetID:
sv.Uint = uint64(stxn.ApplyData.ConfigAsset)
case CreatedApplicationID:
diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go
index cafc496fd..729d5a606 100644
--- a/data/transactions/logic/evalStateful_test.go
+++ b/data/transactions/logic/evalStateful_test.go
@@ -336,7 +336,19 @@ func testApps(t *testing.T, programs []string, txgroup []transactions.SignedTxn,
codes[i] = testProg(t, program, version).Program
}
}
+ if txgroup == nil {
+ for _, program := range programs {
+ sample := makeSampleTxn()
+ if program != "" {
+ sample.Txn.Type = protocol.ApplicationCallTx
+ }
+ txgroup = append(txgroup, sample)
+ }
+ }
ep := NewEvalParams(transactions.WrapSignedTxnsWithAD(txgroup), makeTestProtoV(version), &transactions.SpecialAddresses{})
+ if ledger == nil {
+ ledger = MakeLedger(nil)
+ }
ep.Ledger = ledger
testAppsBytes(t, codes, ep, expected...)
}
@@ -2386,6 +2398,32 @@ func TestReturnTypes(t *testing.T) {
}
}
+func TestTxnEffects(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+ ep, _, _ := makeSampleEnv()
+ // We don't allow the effects fields to see the current or future transactions
+ testApp(t, "byte 0x32; log; txn NumLogs; int 1; ==", ep)
+ testApp(t, "byte 0x32; log; txn Logs 0; byte 0x32; ==", ep)
+ testApp(t, "byte 0x32; log; txn LastLog; byte 0x32; ==", ep)
+ testApp(t, "byte 0x32; log; gtxn 0 NumLogs; int 1; ==", ep)
+ testApp(t, "byte 0x32; log; gtxn 0 Logs 0; byte 0x32; ==", ep)
+ testApp(t, "byte 0x32; log; gtxn 0 LastLog; byte 0x32; ==", ep)
+
+ // Look at the logs of tx 0
+ testApps(t, []string{"", "byte 0x32; log; gtxn 0 LastLog; byte 0x; =="}, nil, AssemblerMaxVersion, nil)
+ testApps(t, []string{"byte 0x33; log; int 1", "gtxn 0 LastLog; byte 0x33; =="}, nil, AssemblerMaxVersion, nil)
+ testApps(t, []string{"byte 0x33; dup; log; log; int 1", "gtxn 0 NumLogs; int 2; =="}, nil, AssemblerMaxVersion, nil)
+ testApps(t, []string{"byte 0x37; log; int 1", "gtxn 0 Logs 0; byte 0x37; =="}, nil, AssemblerMaxVersion, nil)
+ testApps(t, []string{"byte 0x37; log; int 1", "int 0; gtxnas 0 Logs; byte 0x37; =="}, nil, AssemblerMaxVersion, nil)
+
+ // Look past the logs of tx 0
+ testApps(t, []string{"byte 0x37; log; int 1", "gtxna 0 Logs 1; byte 0x37; =="}, nil, AssemblerMaxVersion, nil,
+ Expect{1, "invalid Logs index 1"})
+ testApps(t, []string{"byte 0x37; log; int 1", "int 6; gtxnas 0 Logs; byte 0x37; =="}, nil, AssemblerMaxVersion, nil,
+ Expect{1, "invalid Logs index 6"})
+}
+
func TestRound(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()
diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go
index c7f703b9f..841f180af 100644
--- a/data/transactions/logic/eval_test.go
+++ b/data/transactions/logic/eval_test.go
@@ -1390,6 +1390,11 @@ byte "prefilled"
==
assert
+txn LastLog
+byte "prefilled"
+==
+assert
+
int 1
`
diff --git a/data/transactions/logic/fields.go b/data/transactions/logic/fields.go
index a1c944ffb..7dbbc91f5 100644
--- a/data/transactions/logic/fields.go
+++ b/data/transactions/logic/fields.go
@@ -159,6 +159,9 @@ const (
// CreatedApplicationID Transaction.ApplyData.EvalDelta.ApplicationID
CreatedApplicationID
+ // LastLog Logs[len(Logs)-1]
+ LastLog
+
invalidTxnField // fence for some setup that loops from Sender..invalidTxnField
)
@@ -275,10 +278,12 @@ var txnFieldSpecs = []txnFieldSpec{
{ExtraProgramPages, StackUint64, false, 4, 6, false},
{Nonparticipation, StackUint64, false, 5, 6, false},
- {Logs, StackBytes, true, 5, 5, true},
- {NumLogs, StackUint64, false, 5, 5, true},
- {CreatedAssetID, StackUint64, false, 5, 5, true},
- {CreatedApplicationID, StackUint64, false, 5, 5, true},
+ // "Effects" Last two things are always going to: 0, true
+ {Logs, StackBytes, true, 5, 0, true},
+ {NumLogs, StackUint64, false, 5, 0, true},
+ {CreatedAssetID, StackUint64, false, 5, 0, true},
+ {CreatedApplicationID, StackUint64, false, 5, 0, true},
+ {LastLog, StackBytes, false, 6, 0, true},
}
// TxnaFieldNames are arguments to the 'txna' opcode
diff --git a/data/transactions/logic/fields_string.go b/data/transactions/logic/fields_string.go
index 34515d78d..91e77a115 100644
--- a/data/transactions/logic/fields_string.go
+++ b/data/transactions/logic/fields_string.go
@@ -70,12 +70,13 @@ func _() {
_ = x[NumLogs-59]
_ = x[CreatedAssetID-60]
_ = x[CreatedApplicationID-61]
- _ = x[invalidTxnField-62]
+ _ = x[LastLog-62]
+ _ = x[invalidTxnField-63]
}
-const _TxnField_name = "SenderFeeFirstValidFirstValidTimeLastValidNoteLeaseReceiverAmountCloseRemainderToVotePKSelectionPKVoteFirstVoteLastVoteKeyDilutionTypeTypeEnumXferAssetAssetAmountAssetSenderAssetReceiverAssetCloseToGroupIndexTxIDApplicationIDOnCompletionApplicationArgsNumAppArgsAccountsNumAccountsApprovalProgramClearStateProgramRekeyToConfigAssetConfigAssetTotalConfigAssetDecimalsConfigAssetDefaultFrozenConfigAssetUnitNameConfigAssetNameConfigAssetURLConfigAssetMetadataHashConfigAssetManagerConfigAssetReserveConfigAssetFreezeConfigAssetClawbackFreezeAssetFreezeAssetAccountFreezeAssetFrozenAssetsNumAssetsApplicationsNumApplicationsGlobalNumUintGlobalNumByteSliceLocalNumUintLocalNumByteSliceExtraProgramPagesNonparticipationLogsNumLogsCreatedAssetIDCreatedApplicationIDinvalidTxnField"
+const _TxnField_name = "SenderFeeFirstValidFirstValidTimeLastValidNoteLeaseReceiverAmountCloseRemainderToVotePKSelectionPKVoteFirstVoteLastVoteKeyDilutionTypeTypeEnumXferAssetAssetAmountAssetSenderAssetReceiverAssetCloseToGroupIndexTxIDApplicationIDOnCompletionApplicationArgsNumAppArgsAccountsNumAccountsApprovalProgramClearStateProgramRekeyToConfigAssetConfigAssetTotalConfigAssetDecimalsConfigAssetDefaultFrozenConfigAssetUnitNameConfigAssetNameConfigAssetURLConfigAssetMetadataHashConfigAssetManagerConfigAssetReserveConfigAssetFreezeConfigAssetClawbackFreezeAssetFreezeAssetAccountFreezeAssetFrozenAssetsNumAssetsApplicationsNumApplicationsGlobalNumUintGlobalNumByteSliceLocalNumUintLocalNumByteSliceExtraProgramPagesNonparticipationLogsNumLogsCreatedAssetIDCreatedApplicationIDLastLoginvalidTxnField"
-var _TxnField_index = [...]uint16{0, 6, 9, 19, 33, 42, 46, 51, 59, 65, 81, 87, 98, 107, 115, 130, 134, 142, 151, 162, 173, 186, 198, 208, 212, 225, 237, 252, 262, 270, 281, 296, 313, 320, 331, 347, 366, 390, 409, 424, 438, 461, 479, 497, 514, 533, 544, 562, 579, 585, 594, 606, 621, 634, 652, 664, 681, 698, 714, 718, 725, 739, 759, 774}
+var _TxnField_index = [...]uint16{0, 6, 9, 19, 33, 42, 46, 51, 59, 65, 81, 87, 98, 107, 115, 130, 134, 142, 151, 162, 173, 186, 198, 208, 212, 225, 237, 252, 262, 270, 281, 296, 313, 320, 331, 347, 366, 390, 409, 424, 438, 461, 479, 497, 514, 533, 544, 562, 579, 585, 594, 606, 621, 634, 652, 664, 681, 698, 714, 718, 725, 739, 759, 766, 781}
func (i TxnField) String() string {
if i < 0 || i >= TxnField(len(_TxnField_index)-1) {
diff --git a/data/transactions/logic/fields_test.go b/data/transactions/logic/fields_test.go
index d40ddc263..78cac3569 100644
--- a/data/transactions/logic/fields_test.go
+++ b/data/transactions/logic/fields_test.go
@@ -180,9 +180,9 @@ func TestTxnEffectsAvailable(t *testing.T) {
if !fs.effects {
continue
}
- source := fmt.Sprintf("txn %s", fs.field.String())
+ source := fmt.Sprintf("txn %s; pop; int 1", fs.field)
if fs.array {
- source = fmt.Sprintf("txna %s 0", fs.field.String())
+ source = fmt.Sprintf("txn %s 0; pop; int 1", fs.field)
}
for v := fs.version; v <= AssemblerMaxVersion; v++ {
ops := testProg(t, source, v)
@@ -193,12 +193,12 @@ func TestTxnEffectsAvailable(t *testing.T) {
ep.Ledger = MakeLedger(nil)
_, err = EvalApp(ops.Program, 0, 0, ep)
if v < txnEffectsVersion {
- require.Error(t, err)
+ require.Error(t, err, source)
} else {
if fs.array {
continue // Array (Logs) will be 0 length, so will fail anyway
}
- require.NoError(t, err)
+ require.NoError(t, err, source)
}
}
}