Skip to content

Commit

Permalink
update stateful
Browse files Browse the repository at this point in the history
  • Loading branch information
xhliu committed Nov 3, 2022
1 parent 9080e16 commit 6de72e2
Showing 1 changed file with 27 additions and 24 deletions.
51 changes: 27 additions & 24 deletions docs/state.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ The state property can be used the same way as a regular property.
}
Propagate the State
===================
Update the State
================
A contract can keep state across chained transactions by storing it in the locking script.
In the following example, a contract goes from ``state0`` to ``state1``, and then to ``state2``.
Input in transaction 1 ``tx1`` is spending UTXO in ``tx0``, and ``tx2`` spending ``tx1``.
Expand All @@ -34,11 +34,13 @@ Input in transaction 1 ``tx1`` is spending UTXO in ``tx0``, and ``tx2`` spending
:alt: keep state
:align: center

When you are ready to pass the new state into the output[s] in the current spending transaction,
simply call a built-in function ``this.getStateScript()`` to get the locking script containing the latest stateful properties.
It is automatically generated for every stateful contract, i.e., a contract that has at least one property decorated with ``@state``.
When you are ready to pass the new state into the next UTXO, simply call built-in function ``this.updateState()`` with two arguments:
- `txPreimage`: it is the :ref:`preimage<pushtx-label>` of the current spending transaction. It must only have one output and have the new state in it.
- `amount`: the number of satoshis in that single output.

The function is automatically generated for every stateful contract, i.e., a contract that has at least one property decorated with ``@state``.
Use ``updateStateSigHashType`` if you need a customed sighash type, different from the default of ``SigHash.ALL | SigHash.FORKID``.

Finally, use :ref:`OP_PUSH_TX<pushtx-label>` to ensure the output[s] containing the state go into the current spending transaction.
The following is an example contract that records the number of times ``increment()`` have been called.

.. code-block:: solidity
Expand All @@ -48,44 +50,45 @@ The following is an example contract that records the number of times ``incremen
int counter;
public function increment(SigHashPreimage txPreimage, int amount) {
require(Tx.checkPreimage(txPreimage));
// mutate state
this.counter++;
// get the locking script containing the latest stateful properties
bytes outputScript = this.getStateScript();
require(this.updateState(txPreimage, amount));
// construct an output from its locking script and satoshi amount
bytes output = Utils.buildOutput(outputScript, amount);
// only 1 input here
require(hash256(output) == SigHash.hashOutputs(txPreimage));
// customed sighash type
// require(this.updateStateSigHashType(txPreimage, amount, SigHash.SINGLE | SigHash.FORKID));
}
}
You can also use ``this.updateState()`` or ``this.updateStateSigHashType()`` to ensure that the output containing the state goes into the current spend transaction.
This functions implement the following steps:
Advanced
========

If you ever need to have more fine-grained control of the state, e.g., having multiple outputs in the spending transaction,
you call another built-in function ``this.getStateScript()`` to get the locking script containing the latest stateful properties.

* Check the transaction preimage
* Get the locking script containing the latest stateful properties
* Construct an output from its locking script and satoshi amount
* Ensure the current transaction contains the output above by checking the hash of the output
Next, you use :ref:`OP_PUSH_TX<pushtx-label>` to ensure the output[s] containing the state go into the current spending transaction.
It is equivalent to the contract above using ``this.updateState()``.

.. code-block:: solidity
contract Counter {
@state
int counter;
public function increment(SigHashPreimage txPreimage, int amount) {
public function increment(SigHashPreimage txPreimage, int amount) {
// mutate state
this.counter++;
require(this.updateState(txPreimage, amount));
require(Tx.checkPreimage(txPreimage));
// using updateStateSigHashType if you want to custom signature type, default is SigHash.ALL | SigHash.FORKID
// require(this.updateStateSigHashType(txPreimage, amount, SigHash.SINGLE | SigHash.FORKID));
// get the locking script containing the latest stateful properties
bytes outputScript = this.getStateScript();
// construct an output from its locking script and satoshi amount
bytes output = Utils.buildOutput(outputScript, amount);
// only 1 input here
require(hash256(output) == SigHash.hashOutputs(txPreimage));
}
}
Expand Down

0 comments on commit 6de72e2

Please sign in to comment.