diff options
author | John Jannotti <john.jannotti@algorand.com> | 2022-01-28 07:55:45 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-28 07:55:45 -0500 |
commit | 26321eccc46f224cd3dd50f12b9dca8592b41c38 (patch) | |
tree | 2519548e84109d9191c029f14ca517519ba23fde | |
parent | ca0676419868a915257a46b779c62ccabf384c92 (diff) |
txn LastLog (#3525)
* txn LastLog
* Insulate test from the type of field
-rw-r--r-- | data/transactions/logic/README.md | 1 | ||||
-rw-r--r-- | data/transactions/logic/TEAL_opcodes.md | 1 | ||||
-rw-r--r-- | data/transactions/logic/assembler_test.go | 1 | ||||
-rw-r--r-- | data/transactions/logic/doc.go | 1 | ||||
-rw-r--r-- | data/transactions/logic/eval.go | 6 | ||||
-rw-r--r-- | data/transactions/logic/evalStateful_test.go | 38 | ||||
-rw-r--r-- | data/transactions/logic/eval_test.go | 5 | ||||
-rw-r--r-- | data/transactions/logic/fields.go | 13 | ||||
-rw-r--r-- | data/transactions/logic/fields_string.go | 7 | ||||
-rw-r--r-- | data/transactions/logic/fields_test.go | 8 |
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) } } } |