Skip to content

Commit 21b4bc5

Browse files
authored
Fix langspec (and some assembly errors) for itxn_field (#3869)
1 parent e58901a commit 21b4bc5

File tree

7 files changed

+62
-20
lines changed

7 files changed

+62
-20
lines changed

cmd/opdoc/opdoc.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,12 @@ func fieldsAndTypes(group logic.FieldGroup) ([]string, string) {
285285

286286
func argEnums(name string) ([]string, string) {
287287
switch name {
288-
case "txn", "gtxn", "gtxns", "itxn", "gitxn", "itxn_field":
288+
case "txn", "gtxn", "gtxns", "itxn", "gitxn":
289289
return fieldsAndTypes(logic.TxnFields)
290+
case "itxn_field":
291+
// itxn_field does not *return* a type depending on its immediate. It *takes* it.
292+
// but until a consumer cares, ArgEnumTypes will be overloaded for that meaning.
293+
return fieldsAndTypes(logic.ItxnSettableFields)
290294
case "global":
291295
return fieldsAndTypes(logic.GlobalFields)
292296
case "txna", "gtxna", "gtxnsa", "txnas", "gtxnas", "gtxnsas", "itxna", "gitxna":

cmd/opdoc/tmLanguage.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,18 @@ func buildSyntaxHighlight() *tmLanguage {
136136
}
137137
}
138138

139+
var seen = make(map[string]bool, len(allNamedFields))
140+
var dedupe = make([]string, 0, len(allNamedFields))
141+
for _, name := range allNamedFields {
142+
if name != "" && !seen[name] {
143+
dedupe = append(dedupe, name)
144+
}
145+
seen[name] = true
146+
}
147+
139148
literals.Patterns = append(literals.Patterns, pattern{
140149
Name: "variable.parameter.teal",
141-
Match: fmt.Sprintf("\\b(%s)\\b", strings.Join(allNamedFields, "|")),
150+
Match: fmt.Sprintf("\\b(%s)\\b", strings.Join(dedupe, "|")),
142151
})
143152
tm.Repository["literals"] = literals
144153

data/transactions/logic/assembler.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1869,7 +1869,11 @@ func disDefault(dis *disassembleState, spec *OpSpec) (string, error) {
18691869
if int(b) >= len(imm.Group.Names) {
18701870
return "", fmt.Errorf("invalid immediate %s for %s: %d", imm.Name, spec.Name, b)
18711871
}
1872-
out += imm.Group.Names[b]
1872+
name := imm.Group.Names[b]
1873+
if name == "" {
1874+
return "", fmt.Errorf("invalid immediate %s for %s: %d", imm.Name, spec.Name, b)
1875+
}
1876+
out += name
18731877
} else {
18741878
out += fmt.Sprintf("%d", b)
18751879
}

data/transactions/logic/assembler_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2404,3 +2404,20 @@ func TestTxTypes(t *testing.T) {
24042404
testProg(t, "itxn_begin; byte 0x87123376; itxn_field Amount", 5, Expect{3, "...wanted type uint64 got []byte"})
24052405
testProg(t, "itxn_begin; int 1; itxn_field Amount", 5)
24062406
}
2407+
2408+
func TestBadInnerFields(t *testing.T) {
2409+
testProg(t, "itxn_begin; int 1000; itxn_field FirstValid", 5, Expect{3, "...is not allowed."})
2410+
testProg(t, "itxn_begin; int 1000; itxn_field FirstValidTime", 5, Expect{3, "...is not allowed."})
2411+
testProg(t, "itxn_begin; int 1000; itxn_field LastValid", 5, Expect{3, "...is not allowed."})
2412+
testProg(t, "itxn_begin; int 32; bzero; itxn_field Lease", 5, Expect{4, "...is not allowed."})
2413+
testProg(t, "itxn_begin; byte 0x7263; itxn_field Note", 5, Expect{3, "...Note field was introduced in TEAL v6..."})
2414+
testProg(t, "itxn_begin; byte 0x7263; itxn_field VotePK", 5, Expect{3, "...VotePK field was introduced in TEAL v6..."})
2415+
testProg(t, "itxn_begin; int 32; bzero; itxn_field TxID", 5, Expect{4, "...is not allowed."})
2416+
2417+
testProg(t, "itxn_begin; int 1000; itxn_field FirstValid", 6, Expect{3, "...is not allowed."})
2418+
testProg(t, "itxn_begin; int 1000; itxn_field LastValid", 6, Expect{3, "...is not allowed."})
2419+
testProg(t, "itxn_begin; int 32; bzero; itxn_field Lease", 6, Expect{4, "...is not allowed."})
2420+
testProg(t, "itxn_begin; byte 0x7263; itxn_field Note", 6)
2421+
testProg(t, "itxn_begin; byte 0x7263; itxn_field VotePK", 6)
2422+
testProg(t, "itxn_begin; int 32; bzero; itxn_field TxID", 6, Expect{4, "...is not allowed."})
2423+
}

data/transactions/logic/fields.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,29 @@ func txnaFieldNames() []string {
388388
return names
389389
}
390390

391+
// ItxnSettableFields collects info for itxn_field opcode
392+
var ItxnSettableFields = FieldGroup{
393+
"itxn_field", "",
394+
itxnSettableFieldNames(),
395+
txnFieldSpecByName,
396+
}
397+
398+
// itxnSettableFieldNames are txn field names that can be set by
399+
// itxn_field. Return value is a "sparse" slice, the names appear at their usual
400+
// index, unsettable slots are set to "". They are laid out this way so that it is
401+
// possible to get the name from the index value.
402+
func itxnSettableFieldNames() []string {
403+
names := make([]string, len(txnFieldSpecs))
404+
for i, fs := range txnFieldSpecs {
405+
if fs.itxVersion == 0 {
406+
names[i] = ""
407+
} else {
408+
names[i] = fs.field.String()
409+
}
410+
}
411+
return names
412+
}
413+
391414
var innerTxnTypes = map[string]uint64{
392415
string(protocol.PaymentTx): 5,
393416
string(protocol.KeyRegistrationTx): 6,

data/transactions/logic/langspec.json

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1842,11 +1842,7 @@
18421842
"ArgEnum": [
18431843
"Sender",
18441844
"Fee",
1845-
"FirstValid",
1846-
"FirstValidTime",
1847-
"LastValid",
18481845
"Note",
1849-
"Lease",
18501846
"Receiver",
18511847
"Amount",
18521848
"CloseRemainderTo",
@@ -1862,14 +1858,10 @@
18621858
"AssetSender",
18631859
"AssetReceiver",
18641860
"AssetCloseTo",
1865-
"GroupIndex",
1866-
"TxID",
18671861
"ApplicationID",
18681862
"OnCompletion",
18691863
"ApplicationArgs",
1870-
"NumAppArgs",
18711864
"Accounts",
1872-
"NumAccounts",
18731865
"ApprovalProgram",
18741866
"ClearStateProgram",
18751867
"RekeyTo",
@@ -1889,23 +1881,16 @@
18891881
"FreezeAssetAccount",
18901882
"FreezeAssetFrozen",
18911883
"Assets",
1892-
"NumAssets",
18931884
"Applications",
1894-
"NumApplications",
18951885
"GlobalNumUint",
18961886
"GlobalNumByteSlice",
18971887
"LocalNumUint",
18981888
"LocalNumByteSlice",
18991889
"ExtraProgramPages",
19001890
"Nonparticipation",
1901-
"Logs",
1902-
"NumLogs",
1903-
"CreatedAssetID",
1904-
"CreatedApplicationID",
1905-
"LastLog",
19061891
"StateProofPK"
19071892
],
1908-
"ArgEnumTypes": "BUUUUBBBUBBBUUUBUUUBBBUBUUBUBUBBBUUUUBBBBBBBBUBUUUUUUUUUUUBUUUBB",
1893+
"ArgEnumTypes": "BUBBUBBBUUUBUUUBBBUUBBBBBUUUUBBBBBBBBUBUUUUUUUUUB",
19091894
"Doc": "set field F of the current inner transaction to A",
19101895
"DocExtra": "`itxn_field` fails if A is of the wrong type for F, including a byte array of the wrong size for use as an address when F is an address field. `itxn_field` also fails if A is an account, asset, or app that is not _available_, or an attempt is made extend an array field beyond the limit imposed by consensus parameters. (Addresses set into asset params of acfg transactions need not be _available_.)",
19111896
"ImmediateNote": "{uint8 transaction field index}",

data/transactions/logic/teal.tmLanguage.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
},
113113
{
114114
"name": "variable.parameter.teal",
115-
"match": "\\b(unknown|pay|keyreg|acfg|axfer|afrz|appl|NoOp|OptIn|CloseOut|ClearState|UpdateApplication|DeleteApplication|Secp256k1|Secp256r1|Sender|Fee|FirstValid|FirstValidTime|LastValid|Note|Lease|Receiver|Amount|CloseRemainderTo|VotePK|SelectionPK|VoteFirst|VoteLast|VoteKeyDilution|Type|TypeEnum|XferAsset|AssetAmount|AssetSender|AssetReceiver|AssetCloseTo|GroupIndex|TxID|ApplicationID|OnCompletion|ApplicationArgs|NumAppArgs|Accounts|NumAccounts|ApprovalProgram|ClearStateProgram|RekeyTo|ConfigAsset|ConfigAssetTotal|ConfigAssetDecimals|ConfigAssetDefaultFrozen|ConfigAssetUnitName|ConfigAssetName|ConfigAssetURL|ConfigAssetMetadataHash|ConfigAssetManager|ConfigAssetReserve|ConfigAssetFreeze|ConfigAssetClawback|FreezeAsset|FreezeAssetAccount|FreezeAssetFrozen|Assets|NumAssets|Applications|NumApplications|GlobalNumUint|GlobalNumByteSlice|LocalNumUint|LocalNumByteSlice|ExtraProgramPages|Nonparticipation|Logs|NumLogs|CreatedAssetID|CreatedApplicationID|LastLog|StateProofPK|MinTxnFee|MinBalance|MaxTxnLife|ZeroAddress|GroupSize|LogicSigVersion|Round|LatestTimestamp|CurrentApplicationID|CreatorAddress|CurrentApplicationAddress|GroupID|OpcodeBudget|CallerApplicationID|CallerApplicationAddress|||||||||||||||||||||||||||ApplicationArgs||Accounts||||||||||||||||||||Assets||Applications||||||||Logs||||||URLEncoding|StdEncoding|JSONString|JSONUint64|JSONObject|AssetBalance|AssetFrozen|AssetTotal|AssetDecimals|AssetDefaultFrozen|AssetUnitName|AssetName|AssetURL|AssetMetadataHash|AssetManager|AssetReserve|AssetFreeze|AssetClawback|AssetCreator|AppApprovalProgram|AppClearStateProgram|AppGlobalNumUint|AppGlobalNumByteSlice|AppLocalNumUint|AppLocalNumByteSlice|AppExtraProgramPages|AppCreator|AppAddress|AcctBalance|AcctMinBalance|AcctAuthAddr)\\b"
115+
"match": "\\b(unknown|pay|keyreg|acfg|axfer|afrz|appl|NoOp|OptIn|CloseOut|ClearState|UpdateApplication|DeleteApplication|Secp256k1|Secp256r1|Sender|Fee|FirstValid|FirstValidTime|LastValid|Note|Lease|Receiver|Amount|CloseRemainderTo|VotePK|SelectionPK|VoteFirst|VoteLast|VoteKeyDilution|Type|TypeEnum|XferAsset|AssetAmount|AssetSender|AssetReceiver|AssetCloseTo|GroupIndex|TxID|ApplicationID|OnCompletion|ApplicationArgs|NumAppArgs|Accounts|NumAccounts|ApprovalProgram|ClearStateProgram|RekeyTo|ConfigAsset|ConfigAssetTotal|ConfigAssetDecimals|ConfigAssetDefaultFrozen|ConfigAssetUnitName|ConfigAssetName|ConfigAssetURL|ConfigAssetMetadataHash|ConfigAssetManager|ConfigAssetReserve|ConfigAssetFreeze|ConfigAssetClawback|FreezeAsset|FreezeAssetAccount|FreezeAssetFrozen|Assets|NumAssets|Applications|NumApplications|GlobalNumUint|GlobalNumByteSlice|LocalNumUint|LocalNumByteSlice|ExtraProgramPages|Nonparticipation|Logs|NumLogs|CreatedAssetID|CreatedApplicationID|LastLog|StateProofPK|MinTxnFee|MinBalance|MaxTxnLife|ZeroAddress|GroupSize|LogicSigVersion|Round|LatestTimestamp|CurrentApplicationID|CreatorAddress|CurrentApplicationAddress|GroupID|OpcodeBudget|CallerApplicationID|CallerApplicationAddress|URLEncoding|StdEncoding|JSONString|JSONUint64|JSONObject|AssetBalance|AssetFrozen|AssetTotal|AssetDecimals|AssetDefaultFrozen|AssetUnitName|AssetName|AssetURL|AssetMetadataHash|AssetManager|AssetReserve|AssetFreeze|AssetClawback|AssetCreator|AppApprovalProgram|AppClearStateProgram|AppGlobalNumUint|AppGlobalNumByteSlice|AppLocalNumUint|AppLocalNumByteSlice|AppExtraProgramPages|AppCreator|AppAddress|AcctBalance|AcctMinBalance|AcctAuthAddr)\\b"
116116
}
117117
]
118118
},

0 commit comments

Comments
 (0)