btcsuite/btcscript

Feature request: Export parseScript and opcode fields

Closed this issue · 11 comments

Thank you for creating and maintaining btcscript.
As far as I can see, there is currently no possibility for external packages to parse the bytes from btcwire.MsgTx.TxOut[i].PkScript to an array of opcodes. The function parseScript achieves that, but is not exported.
In order to further process the script it is necessary that the fields of opcode and parsedOpcode are accessible.
Example of what could be possible:

func printScriptPubkey(txOut *btcwire.TxOut) {
    scriptPubkey, _ := btcscript.ParseScript(txOut.PkScript)

    for _, op := range scriptPubkey {
        log.Println(op.Opcode.Name)
    }
}

Did you have something specific in mind you're trying to do?

There is already a function, DisasmString, to do the script disassembly. There are also functions to get all pertinent details from a script such as ExtractPkScriptAddrs (example) and GetScriptClass.

Accessing the opcodes themselves seems like something that callers should not be concerning themselves with as that seems to be the domain of the script engine. I'm not 100% opposed to the idea, just simply trying to understand what use case you're after.

I agree that this is more about diagnosis and testing.
For that you do not really want to parse the output of DisasmString yourself given that the required function and datastructures are already available. Consider for example you want to record a potential malleability attack by checking if the scriptSig contains additional pushes.
Also, DisasmString does not include the actual OP_DATA_* that is being used.

Fair enough. I suppose it could be useful to access the parsed opcodes for diagnosis/testing purposes. That said, you can get all the pushed data with the PushedData function for your particular example.

I suspect the vast majority of things you'd want to do are already available, but I can see it might be a bit more flexible with raw access to the parsed opcodes.

+1, exporting the opcodes, or possibly just opcodemap, would make it more feasible to use btcscript to build arbitrary transaction Scripts. I was going to build my own lookup derived from opcodemap but then realized it was not exported. :(

Er, to clarify on how this is different from #5 (which I just noticed), this would also allow reusing this code for building our own assembler/scripting language without having to copypasta all the opcodes and keep them in sync.

@shazow: As you noted, you can build arbitrary scripts with the Script Builder. The opcodes themselves are exported already too, so you shouldn't have to copypasta them (e.g btcscript.OP_CHECKSIG).

@davecgh I mean rather to get a mapping from their semantic name to their logical value (string{"OP_CHECKSIG"} -> byte{172})

Instead of exporting the map, how about giving the opcodes their own exported type and making them a fmt.Stringer?

edit: actually if you wanted to go the reverse direction (from string to byte), opcodemap is not quite what you want, unless you created the reverse mapping in your own package.

@jrick: I think that is the opposite of what @shazow was talking about from what he posted. It appears he wants to be able to look up OP_CHECKSIG by name and get the associated opcode value. The only reason I see why you'd even want to do that is parsing a disassembly back into opcodes. Otherwise you know what opcode(s) you want, so you can just do btcscript.OP_XYZ.

The only reason I see why you'd even want to do that is parsing a disassembly back into opcodes.

Correct, one idea we were playing around with is building scripts by reading in human-readable semantic opcodes from a JSON payload or somesuch.

This has been moved to btcsuite/btcd#267.