hsd icon indicating copy to clipboard operation
hsd copied to clipboard

WIP primitives/covenant: add assembly method

Open tynes opened this issue 5 years ago • 8 comments

When looking at the Covenant field in JSON, it is not very helpful to understand what it means. This PR adds a Covenant.toASM method to return a human readable string.

The initial implementation takes advantage of a schema object that maps the index in Covenant.items to its type. Since different types of Covenants may have different types at the same index, an object is required to differentiate between the covenant item type that gets prefixed to the data in the covenant.items field.

A NONE type would look like this: TYPE:NONE

A BID type would look like this: TYPE:BID NAMEHASH:.... HEIGHT:24256 NAME:... HASH:....

I am open to suggestions on how to improve this method and make it more human friendly.

"covenant": {
  "type": 3,
  "action": "BID",
  "items": [
    "bbd9e905510ec6ca554591336a8ef507390c1fdb3200ea00a3af637535acfb63",
    "9d5e0000",
 "74687265652d68756e647265642d646f6d61696e732d74656e2d626964732d332d3634",
    "342714d9ea2c4eeb81209ebcedbc7d760cbff00a4edea5e67f297848b1f8051d"
  ],
  "asm": "TYPE:BID NAMEHASH:bbd9e905510ec6ca554591336a8ef507390c1fdb3200ea00a3af637535acfb63 HEIGHT:24221 NAME:74687265652d68756e647265642d646f6d61696e732d74656e2d626964732d332d3634 HASH:342714d9ea2c4eeb81209ebcedbc7d760cbff00a4edea5e67f297848b1f8051d"


"covenant": {
  "type": 0,
  "action": "NONE",
  "items": [],
  "asm": "TYPE:NONE"
}

TODO: make sure the schema is 100% accurate for each covenant type Edit: return a schema list instead where the indexes line up

tynes avatar Oct 09 '19 20:10 tynes

Tagging @kilpatty, this could be useful for hnscan.com

tynes avatar Oct 09 '19 22:10 tynes

Hmmmm... ASM stands for "assembly" and should refer exclusively to opcode UTXO script in my opinion. Don't really love the concatenated string look either... Almost none of the covenant items are really human-readable anyway. Could it be object-ified? Might be more on-style:

"items": [
    "bbd9e905510ec6ca554591336a8ef507390c1fdb3200ea00a3af637535acfb63",
    "9d5e0000",
 "74687265652d68756e647265642d646f6d61696e732d74656e2d626964732d332d3634",
    "342714d9ea2c4eeb81209ebcedbc7d760cbff00a4edea5e67f297848b1f8051d"
  ],
"decoded_items": {
  "namehash": "bbd9e905510ec6ca554591336a8ef507390c1fdb3200ea00a3af637535acfb63" 
  "start": 24221, 
  "rawName": "74687265652d68756e647265642d646f6d61696e732d74656e2d626964732d332d3634"
  "blind": "342714d9ea2c4eeb81209ebcedbc7d760cbff00a4edea5e67f297848b1f8051d"
}

pinheadmz avatar Oct 10 '19 18:10 pinheadmz

ASM stands for "assembly" and should refer exclusively to opcode UTXO script in my opinion.

I don't particularly agree with this, what about x86_64 assembly? There is no human readable covenant format, so I'm trying to define one to help make it easier to understand what the data means without having to always refer to a schema. Open to other names if you can propose a better one.

Could it be object-ified?

I think that this would be way easier on the eyes and would also prevent huge strings, but the problem is that objects are un-ordered while covenant data is ordered. I'm sure we could make it work though.

Note: the NAME in my example didn't decode correctly, it should be an ascii string. Will fix when updating this PR based on feedback

tynes avatar Oct 10 '19 19:10 tynes

I'm not super familiar with the ASM/Assembly semantics, but I would be in favor of an addition along these lines.

Perhaps we just update the "format" function: https://github.com/handshake-org/hsd/blob/master/lib/primitives/covenant.js#L620 to include this same logic?

If we stick with the toASM function, I think we should also add a fromASM function in order to parse those strings.

Additionally we could add the ASM change, but also add a boolean to getJSON. The bool defaults to false, but if it's true, then we return a object along the lines of @pinheadmz comment. Defaulting to false allows us to not have to change any of the existing getJSON calls.

getJSON(detail=false) {
  if (!detail) {
    //Return a more detailed object of the covenant with named property fields
  }
  //do the same as now
}

EDIT: This getJSON changes would be on top of the "minimal" addition.

kilpatty avatar Oct 10 '19 19:10 kilpatty

Ha, yeah I was just thinking a flag for getJSON as well - because what we really want is two versions of the same thing (items object returned as machine-readable stack of hex, and alternatively a human-readable dictionary)

We could also add a Covenant.decodeItems() that is just part of the library, easy to call by block explorer applications, but not necessarily part of the default console output of every tx. A similar example is how the witness stack looks in JSON - nothing is there to tell you which item is the pubKey or the script or the taproot control block!

pinheadmz avatar Oct 10 '19 19:10 pinheadmz

I think we should also add a fromASM

I actually know somebody that uses bitcoinjs and cannot switch to bcoin because they rely on fromASM and bcoin doesn't have that function.

tynes avatar Oct 10 '19 19:10 tynes

fromASM() would just be a wrapper around / prettier version of this?

    const redeem = new this.Script();

    redeem.pushSym('OP_IF');
    redeem.pushSym('OP_SHA256');
    redeem.pushData(hash);
    redeem.pushSym('OP_EQUALVERIFY');
    redeem.pushData(swapPubkey);
    redeem.pushSym('OP_CHECKSIG');
    redeem.pushSym('OP_ELSE');
    redeem.pushInt(locktime);
    redeem.pushSym('OP_CHECKSEQUENCEVERIFY');
    redeem.pushSym('OP_DROP');
    redeem.pushData(refundPubkey);
    redeem.pushSym('OP_CHECKSIG');
    redeem.pushSym('OP_ENDIF');
    redeem.compile();

pinheadmz avatar Oct 10 '19 19:10 pinheadmz

fromASM() would just be a wrapper around / prettier version of this?

Maybe we should continue this convo on a bcoin issue since this is offtopic, but look at the implementation here: https://github.com/bitcoinjs/bitcoinjs-lib/blob/94872f9bfedf0a441842f95586116582b94c004f/src/script.js#L136

It takes a string of asm like OP_DUP OP_HASH160 and builds the script object by splitting on whitespace and creating an opcode for each word.

tynes avatar Oct 10 '19 21:10 tynes