cashscript icon indicating copy to clipboard operation
cashscript copied to clipboard

better support for hand-written/hand-optimized contract bytecode

Open mr-zwets opened this issue 1 year ago • 4 comments

Currently a contract's constructor-inputs are kept in the artifact as constructorInputs, and not repeated in the bytecode property on the artifact because they are assumed to be put in front of the bytecode (in reversed order).

For developers who want to hand-optimize their contracts, they will often not have these constructorInputs at the beginning.

To support constructorInputs at any place on the stack, we should allow for a templating syntax in the bytecode field.

For hand optimized contracts the debug info will be non existent, so they won't be able to leverage the debug tooling. This change would make it easy for developers to still continue using the CashScript SDK for transaction building even for hand optimized contracts.

These changes are a precursor to 'enable placing constructor params in any part of function body' (#156) but don't necessarily require any changes to the cashscript contract language itself.

mr-zwets avatar Oct 06 '24 08:10 mr-zwets

@mainnet-pat has already worked this out in further detail

bca's optimized xmr swaplock contract which has contract arguments pushed exactly at the place they are needed, not at the top of the locking bytecode

I've established the approach to put the placeholders there, then replacing them with values

{
  "bytecode": "OP_TXINPUTCOUNT OP_1 OP_NUMEQUALVERIFY OP_TXOUTPUTCOUNT OP_1 OP_NUMEQUALVERIFY <mining_fee> OP_0 OP_UTXOVALUE OP_0 OP_OUTPUTVALUE OP_SUB OP_NUMEQUALVERIFY OP_0 OP_UTXOTOKENCATEGORY OP_0 OP_OUTPUTTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_UTXOTOKENCOMMITMENT OP_0 OP_OUTPUTTOKENCOMMITMENT OP_EQUALVERIFY OP_0 OP_UTXOTOKENAMOUNT OP_0 OP_OUTPUTTOKENAMOUNT OP_NUMEQUALVERIFY OP_0 OP_INPUTSEQUENCENUMBER OP_NOTIF <out_1> OP_0 OP_OUTPUTBYTECODE OP_OVER OP_EQUALVERIFY <public_key> OP_CHECKDATASIG OP_ELSE <timelock> OP_CHECKSEQUENCEVERIFY OP_DROP <out_2> OP_0 OP_OUTPUTBYTECODE OP_EQUAL OP_ENDIF",
}

so notice the template variables <mining_fee>, <public_key>, <out_1>, <timelock> & <out_2>

these then should explicitly be marked in the artifact as TemplateVariable

mr-zwets avatar Oct 06 '24 09:10 mr-zwets

Because all variables are just inserted once in the contract above, right before their first usage, this could easily be done automatically by the compiler.

Then we don't need a marker for TemplateVariable as all constructor params would get inserted into the contract. Having multiple insertions of the same constructor variable would still be a manual optimization.

related discussion: 'enable placing constructor params in any part of function body' https://github.com/CashScript/cashscript/issues/156

mr-zwets avatar Oct 14 '24 08:10 mr-zwets

Another issue is that as soon as there are multiple abi functions, the SDK knows to use a functionIndex unlocking parameter automatically, however hand-optimized contracts will often not have this.

So for proper support of hand optimized/ hand crafted artifact bytecode, there shouldn't be any hidden functionIndex magic going on, everything should be made explicit and opt-out

mr-zwets avatar Oct 29 '24 06:10 mr-zwets

I used the CashScript SDK for the Cauldron contract, which is written in BCH script directly, and documented the issues I had with it in a Cauldron_Swap_Test repo.

Another way to look at this issue is that in CashScript this would only be one function with 'function overloading' (as described in #270), in this case just making functionIndex explicit and optional would just work, but for other hand-written functions which use overloaded function definitions this could still come up as an issue.

Fundamentally it is because CashScript requires fixed arguments for each function but bitcoin script doesn't have this requirement/abstraction.

mr-zwets avatar Feb 07 '25 07:02 mr-zwets