diff --git a/cmd/opdoc/opdoc.go b/cmd/opdoc/opdoc.go index 1a1e9941d1..409b1fa6c8 100644 --- a/cmd/opdoc/opdoc.go +++ b/cmd/opdoc/opdoc.go @@ -270,14 +270,20 @@ func typeString(types []logic.StackType) string { case logic.StackAny: out[i] = '.' case logic.StackNone: - if i == 0 && len(types) == 1 { - return "" - } - panic("unexpected StackNone in opdoc typeString") + out[i] = '_' default: panic("unexpected type in opdoc typeString") } } + + // Cant return None and !None from same op + if strings.Contains(string(out), "_") { + if strings.ContainsAny(string(out), "UB.") { + panic("unexpected StackNone in opdoc typeString") + } + return "" + } + return string(out) } @@ -295,6 +301,9 @@ func fieldsAndTypes(group logic.FieldGroup) ([]string, string) { } func argEnums(name string) ([]string, string) { + // reminder: this needs to be manually updated every time + // a new opcode is added with an associated FieldGroup + // it'd be nice to have this auto-update switch name { case "txn", "gtxn", "gtxns", "itxn", "gitxn": return fieldsAndTypes(logic.TxnFields) @@ -314,6 +323,16 @@ func argEnums(name string) ([]string, string) { return fieldsAndTypes(logic.AppParamsFields) case "acct_params_get": return fieldsAndTypes(logic.AcctParamsFields) + case "block": + return fieldsAndTypes(logic.BlockFields) + case "json_ref": + return fieldsAndTypes(logic.JSONRefTypes) + case "base64_decode": + return fieldsAndTypes(logic.Base64Encodings) + case "vrf_verify": + return fieldsAndTypes(logic.VrfStandards) + case "ecdsa_pk_recover", "ecdsa_verify", "ecdsa_pk_decompress": + return fieldsAndTypes(logic.EcdsaCurves) default: return nil, "" } diff --git a/data/transactions/logic/TEAL_opcodes.md b/data/transactions/logic/TEAL_opcodes.md index cd2bd5842d..54a80db8f9 100644 --- a/data/transactions/logic/TEAL_opcodes.md +++ b/data/transactions/logic/TEAL_opcodes.md @@ -280,7 +280,7 @@ The notation J,K indicates that two uint64 values J and K are interpreted as a u ## bytecblock bytes ... -- Opcode: 0x26 {varuint count} [({varuint value length} bytes), ...] +- Opcode: 0x26 {varuint count} [({varuint length} bytes), ...] - Stack: ... → ... - prepare block of byte-array constants for use by bytec @@ -318,7 +318,7 @@ The notation J,K indicates that two uint64 values J and K are interpreted as a u ## arg n -- Opcode: 0x2c {uint8 arg index N} +- Opcode: 0x2c {uint8 arg index} - Stack: ... → ..., []byte - Nth LogicSig argument - Mode: Signature @@ -811,7 +811,7 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on ## json_ref r -- Opcode: 0x5f {uint8 return type} +- Opcode: 0x5f {uint8 return type index} - Stack: ..., A: []byte, B: []byte → ..., any - key B's value, of type R, from a [valid](jsonspec.md) utf-8 encoded json object A - **Cost**: 25 + 2 per 7 bytes of A @@ -1059,7 +1059,7 @@ pushint args are not added to the intcblock during assembly processes ## pushbytess bytes ... -- Opcode: 0x82 {varuint count} [({varuint value length} bytes), ...] +- Opcode: 0x82 {varuint count} [({varuint length} bytes), ...] - Stack: ... → ..., [N items] - push sequences of immediate byte arrays to stack (first byte array being deepest) - Availability: v8 @@ -1548,7 +1548,7 @@ For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `bo ## block f -- Opcode: 0xd1 {uint8 block field} +- Opcode: 0xd1 {uint8 block field index} - Stack: ..., A: uint64 → ..., any - field F of block A. Fail unless A falls between txn.LastValid-1002 and txn.FirstValid (exclusive) - Availability: v7 diff --git a/data/transactions/logic/doc.go b/data/transactions/logic/doc.go index 243c22ec2c..8242ad1e2d 100644 --- a/data/transactions/logic/doc.go +++ b/data/transactions/logic/doc.go @@ -224,12 +224,12 @@ var opcodeImmediateNotes = map[string]string{ "intc": "{uint8 int constant index}", "pushint": "{varuint int}", "pushints": "{varuint count} [{varuint value}, ...]", - "bytecblock": "{varuint count} [({varuint value length} bytes), ...]", + "bytecblock": "{varuint count} [({varuint length} bytes), ...]", "bytec": "{uint8 byte constant index}", "pushbytes": "{varuint length} {bytes}", - "pushbytess": "{varuint count} [({varuint value length} bytes), ...]", + "pushbytess": "{varuint count} [({varuint length} bytes), ...]", - "arg": "{uint8 arg index N}", + "arg": "{uint8 arg index}", "global": "{uint8 global field index}", "txn": "{uint8 transaction field index}", @@ -279,10 +279,10 @@ var opcodeImmediateNotes = map[string]string{ "ecdsa_pk_recover": "{uint8 curve index}", "base64_decode": "{uint8 encoding index}", - "json_ref": "{uint8 return type}", + "json_ref": "{uint8 return type index}", "vrf_verify": "{uint8 parameters index}", - "block": "{uint8 block field}", + "block": "{uint8 block field index}", "switch": "{uint8 branch count} [{int16 branch offset, big-endian}, ...]", "match": "{uint8 branch count} [{int16 branch offset, big-endian}, ...]", diff --git a/data/transactions/logic/langspec.json b/data/transactions/logic/langspec.json index 148f83e073..cbfb4b0d95 100644 --- a/data/transactions/logic/langspec.json +++ b/data/transactions/logic/langspec.json @@ -67,6 +67,10 @@ "Args": "BBBBB", "Returns": "U", "Size": 2, + "ArgEnum": [ + "Secp256k1", + "Secp256r1" + ], "Doc": "for (data A, signature B, C and pubkey D, E) verify the signature of the data against the pubkey =\u003e {0 or 1}", "DocExtra": "The 32 byte Y-component of a public key is the last element on the stack, preceded by X-component of a pubkey, preceded by S and R components of a signature, preceded by the data that is fifth element on the stack. All values are big-endian encoded. The signed data must be 32 bytes long, and signatures in lower-S form are only accepted.", "ImmediateNote": "{uint8 curve index}", @@ -81,6 +85,10 @@ "Args": "B", "Returns": "BB", "Size": 2, + "ArgEnum": [ + "Secp256k1", + "Secp256r1" + ], "Doc": "decompress pubkey A into components X, Y", "DocExtra": "The 33 byte public key in a compressed form to be decompressed into X and Y (top) components. All values are big-endian encoded.", "ImmediateNote": "{uint8 curve index}", @@ -95,6 +103,10 @@ "Args": "BUBB", "Returns": "BB", "Size": 2, + "ArgEnum": [ + "Secp256k1", + "Secp256r1" + ], "Doc": "for (data A, recovery id B, signature C, D) recover a public key", "DocExtra": "S (top) and R elements of a signature, recovery id and data (bottom) are expected on the stack and used to deriver a public key. All values are big-endian encoded. The signed data must be 32 bytes long.", "ImmediateNote": "{uint8 curve index}", @@ -470,7 +482,7 @@ "Size": 0, "Doc": "prepare block of byte-array constants for use by bytec", "DocExtra": "`bytecblock` loads the following program bytes into an array of byte-array constants in the evaluator. These constants can be referred to by `bytec` and `bytec_*` which will push the value onto the stack. Subsequent calls to `bytecblock` reset and replace the bytes constants available to the script.", - "ImmediateNote": "{varuint count} [({varuint value length} bytes), ...]", + "ImmediateNote": "{varuint count} [({varuint length} bytes), ...]", "IntroducedVersion": 1, "Groups": [ "Loading Values" @@ -538,7 +550,7 @@ "Returns": "B", "Size": 2, "Doc": "Nth LogicSig argument", - "ImmediateNote": "{uint8 arg index N}", + "ImmediateNote": "{uint8 arg index}", "IntroducedVersion": 1, "Groups": [ "Loading Values" @@ -1410,6 +1422,11 @@ "Args": "B", "Returns": "B", "Size": 2, + "ArgEnum": [ + "URLEncoding", + "StdEncoding" + ], + "ArgEnumTypes": "..", "Doc": "decode A which was base64-encoded using _encoding_ E. Fail if A is not base64 encoded with encoding E", "DocExtra": "*Warning*: Usage should be restricted to very rare use cases. In almost all cases, smart contracts should directly handle non-encoded byte-strings.\tThis opcode should only be used in cases where base64 is the only available option, e.g. interoperability with a third-party that only signs base64 strings.\n\n Decodes A using the base64 encoding E. Specify the encoding with an immediate arg either as URL and Filename Safe (`URLEncoding`) or Standard (`StdEncoding`). See [RFC 4648 sections 4 and 5](https://rfc-editor.org/rfc/rfc4648.html#section-4). It is assumed that the encoding ends with the exact number of `=` padding characters as required by the RFC. When padding occurs, any unused pad bits in the encoding must be set to zero or the decoding will fail. The special cases of `\\n` and `\\r` are allowed but completely ignored. An error will result when attempting to decode a string with a character that is not in the encoding alphabet or not one of `=`, `\\r`, or `\\n`.", "ImmediateNote": "{uint8 encoding index}", @@ -1424,9 +1441,15 @@ "Args": "BB", "Returns": ".", "Size": 2, + "ArgEnum": [ + "JSONString", + "JSONUint64", + "JSONObject" + ], + "ArgEnumTypes": "BUB", "Doc": "key B's value, of type R, from a [valid](jsonspec.md) utf-8 encoded json object A", "DocExtra": "*Warning*: Usage should be restricted to very rare use cases, as JSON decoding is expensive and quite limited. In addition, JSON objects are large and not optimized for size.\n\nAlmost all smart contracts should use simpler and smaller methods (such as the [ABI](https://arc.algorand.foundation/ARCs/arc-0004). This opcode should only be used in cases where JSON is only available option, e.g. when a third-party only signs JSON.", - "ImmediateNote": "{uint8 return type}", + "ImmediateNote": "{uint8 return type index}", "IntroducedVersion": 7, "Groups": [ "Byte Array Manipulation" @@ -1704,7 +1727,7 @@ "Size": 0, "Doc": "push sequences of immediate byte arrays to stack (first byte array being deepest)", "DocExtra": "pushbytess args are not added to the bytecblock during assembly processes", - "ImmediateNote": "{varuint count} [({varuint value length} bytes), ...]", + "ImmediateNote": "{varuint count} [({varuint length} bytes), ...]", "IntroducedVersion": 8, "Groups": [ "Loading Values" @@ -2651,6 +2674,9 @@ "Args": "BBB", "Returns": "BU", "Size": 2, + "ArgEnum": [ + "VrfAlgorand" + ], "Doc": "Verify the proof B of message A against pubkey C. Returns vrf output and verification flag.", "DocExtra": "`VrfAlgorand` is the VRF used in Algorand. It is ECVRF-ED25519-SHA512-Elligator2, specified in the IETF internet draft [draft-irtf-cfrg-vrf-03](https://datatracker.ietf.org/doc/draft-irtf-cfrg-vrf/03/).", "ImmediateNote": "{uint8 parameters index}", @@ -2665,8 +2691,13 @@ "Args": "U", "Returns": ".", "Size": 2, + "ArgEnum": [ + "BlkSeed", + "BlkTimestamp" + ], + "ArgEnumTypes": "BU", "Doc": "field F of block A. Fail unless A falls between txn.LastValid-1002 and txn.FirstValid (exclusive)", - "ImmediateNote": "{uint8 block field}", + "ImmediateNote": "{uint8 block field index}", "IntroducedVersion": 7, "Groups": [ "State Access"