You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
"source": "pragma cashscript ^0.8.0;\n\n/* This is a contract showcasing covenants outside of regular transactional use.\n * It enforces the contract to make an \"announcement\" on Memo.cash, and send the\n * remainder of contract funds back to the contract.\n */\ncontract Announcement() {\n function announce() {\n // Create the memo.cash announcement output\n bytes announcement = new LockingBytecodeNullData([\n 0x6d02,\n bytes('A contract may not injure a human being or, through inaction, allow a human being to come to harm.')\n ]);\n\n // Check that the first tx output matches the announcement\n require(tx.outputs[0].value == 0);\n require(tx.outputs[0].lockingBytecode == announcement);\n\n // Calculate leftover money after fee (1000 sats)\n // Check that the second tx output sends the change back if there's enough leftover for another announcement\n int minerFee = 1000;\n int changeAmount = tx.inputs[this.activeInputIndex].value - minerFee;\n if (changeAmount >= minerFee) {\n require(tx.outputs[1].lockingBytecode == tx.inputs[this.activeInputIndex].lockingBytecode);\n require(tx.outputs[1].value == changeAmount);\n }\n }\n}\n",
11
+
"source": "pragma cashscript ^0.9.0;\n\n/* This is a contract showcasing covenants outside of regular transactional use.\n * It enforces the contract to make an \"announcement\" on Memo.cash, and send the\n * remainder of contract funds back to the contract.\n */\ncontract Announcement() {\n function announce() {\n // Create the memo.cash announcement output\n bytes announcement = new LockingBytecodeNullData([\n 0x6d02,\n bytes('A contract may not injure a human being or, through inaction, allow a human being to come to harm.')\n ]);\n\n // Check that the first tx output matches the announcement\n require(tx.outputs[0].value == 0);\n require(tx.outputs[0].lockingBytecode == announcement);\n\n // Calculate leftover money after fee (1000 sats)\n // Check that the second tx output sends the change back if there's enough leftover for another announcement\n int minerFee = 1000;\n int changeAmount = tx.inputs[this.activeInputIndex].value - minerFee;\n if (changeAmount >= minerFee) {\n require(tx.outputs[1].lockingBytecode == tx.inputs[this.activeInputIndex].lockingBytecode);\n require(tx.outputs[1].value == changeAmount);\n }\n }\n}\n",
"source": "pragma cashscript ^0.8.0;\n\n/* This is an unofficial CashScript port of Licho's Mecenas contract. It is\n * not compatible with Licho's EC plugin, but rather meant as a demonstration\n * of covenants in CashScript.\n * The time checking has been removed so it can be tested without time requirements.\n */\ncontract Mecenas(bytes20 recipient, bytes20 funder, int pledge/*, int period */) {\n function receive() {\n // require(tx.age >= period);\n\n // Check that the first output sends to the recipient\n require(tx.outputs[0].lockingBytecode == new LockingBytecodeP2PKH(recipient));\n\n int minerFee = 1000;\n int currentValue = tx.inputs[this.activeInputIndex].value;\n int changeValue = currentValue - pledge - minerFee;\n\n // If there is not enough left for *another* pledge after this one, we send the remainder to the recipient\n // Otherwise we send the remainder to the recipient and the change back to the contract\n if (changeValue <= pledge + minerFee) {\n require(tx.outputs[0].value == currentValue - minerFee);\n } else {\n require(tx.outputs[0].value == pledge);\n require(tx.outputs[1].lockingBytecode == tx.inputs[this.activeInputIndex].lockingBytecode);\n require(tx.outputs[1].value == changeValue);\n }\n }\n\n function reclaim(pubkey pk, sig s) {\n require(hash160(pk) == funder);\n require(checkSig(s, pk));\n }\n}\n",
37
+
"source": "pragma cashscript ^0.9.0;\n\n/* This is an unofficial CashScript port of Licho's Mecenas contract. It is\n * not compatible with Licho's EC plugin, but rather meant as a demonstration\n * of covenants in CashScript.\n * The time checking has been removed so it can be tested without time requirements.\n */\ncontract Mecenas(bytes20 recipient, bytes20 funder, int pledge/*, int period */) {\n function receive() {\n // require(tx.age >= period);\n\n // Check that the first output sends to the recipient\n require(tx.outputs[0].lockingBytecode == new LockingBytecodeP2PKH(recipient));\n\n int minerFee = 1000;\n int currentValue = tx.inputs[this.activeInputIndex].value;\n int changeValue = currentValue - pledge - minerFee;\n\n // If there is not enough left for *another* pledge after this one, we send the remainder to the recipient\n // Otherwise we send the remainder to the recipient and the change back to the contract\n if (changeValue <= pledge + minerFee) {\n require(tx.outputs[0].value == currentValue - minerFee);\n } else {\n require(tx.outputs[0].value == pledge);\n require(tx.outputs[1].lockingBytecode == tx.inputs[this.activeInputIndex].lockingBytecode);\n require(tx.outputs[1].value == changeValue);\n }\n }\n\n function reclaim(pubkey pk, sig s) {\n require(hash160(pk) == funder);\n require(checkSig(s, pk));\n }\n}\n",
As you can see, in this case, the logic to spend time-locked funds and verify the spender takes up six (6) bytes of information.
68
68
69
-
The simplest workflow to optimize the redeem script of `hodl.cash`, or any contract, would be to compile it directly from the command line with `cashc` then look at the `bytecode` field on the generated artifact to see if there are any unnecessary or duplicative operations.
69
+
The simplest workflow to optimize the redeem script of `hodl.cash`, or any contract, would be to compile it directly from the command line with `cashc` then look at the `bytecode` field on the generated artifact to see if there are any unnecessary or duplicative operations.
70
70
71
71
In this toy example, the redeem script is so small there isn't a lot of need or use in making it smaller. The [anyhedge contracts](https://gitlab.com/GeneralProtocols/anyhedge/contracts/) are again a great example of a more complex progressive optimization over time.
72
72
@@ -77,13 +77,13 @@ There are two important alternative approaches to optimization to consider.
77
77
78
78
### OP_NOP
79
79
80
-
>We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.
80
+
>We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.
81
81
82
82
It's worth considering whether optimizing the redeem script is necessary at all. If the contract is accepted by the network, and there is no glaring inefficiency in the bytecode, perhaps the best optimization is to not to obsess prematurely about things like blocksize.
83
83
84
84
### Hyper Introspect-imization
85
85
86
86
Finally, there have been a number of novel approaches taken since 2009 to approximate higher level functionality with bitcoin's deliberately restricted instruction set. These techniques include using a cumbersome [old covenant style](https://fc16.ifca.ai/bitcoin/papers/MES16.pdf) of storing data, [`OP_CODESEPARATOR`](https://web.archive.org/web/20210507164307/https://mistcoin.org/#appendix-b) to split contracts around an old 520-byte limitation, and hiding redeem paths in "sidecars".
87
87
88
-
It's **very** important to be up-to-date on documentation covering introspection, as it greatly simplifies using state and writing more complex contracts. If a contract has been developed from an old example or a pre-introspection design pattern, the fastest way to achieve significant optimization is to utilize the [the latest introspection design patterns](./covenants).
88
+
It's **very** important to be up-to-date on documentation covering introspection, as it greatly simplifies using state and writing more complex contracts. If a contract has been developed from an old example or a pre-introspection design pattern, the fastest way to achieve significant optimization is to utilize the [the latest introspection design patterns](./covenants).
0 commit comments