Skip to content

Commit

Permalink
add @State
Browse files Browse the repository at this point in the history
  • Loading branch information
xhliu committed Oct 7, 2021
1 parent 8b37eec commit 6d574fb
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 0 deletions.
Binary file added docs/_static/images/state.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/contracts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ The following example shows usage of the standard contract ``P2PKH`` that corres
}
}
.. _pushtx-label:

Contract ``OP_PUSH_TX``
-----------------------
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ sCrypt is designed to facilitate writing smart contract running on chain.
functions
contracts
ctc
state

.. toctree::
:maxdepth: 1
Expand Down
67 changes: 67 additions & 0 deletions docs/state.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
=================
Stateful Contract
=================

Bitcoin/sCrypt contract uses Unspent Transaction Output (UTXO) model: a contract is inside a UTXO, dictating how the bitcoins in the UTXO can be spent.
When a UTXO is spent (i.e., an sCrypt contract public function is called successfully), the contract is terminated.
For a contract to keep state and able to be called multiple times while carrying the mutable state, these steps have to be followed.

1. state decorator
==================
Declare any property that is part of the state with a decorator ``@state``.
The state property can be used the same way as a regular property.

.. code-block:: solidity
contract Counter {
@state
int counter;
constructor(int counter) {
this.counter = counter;
}
}
2. Propogate 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``.

.. image:: _static/images/state.png
:width: 400px
: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``.

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 ``mutate()`` have been called.

.. code-block:: solidity
contract Counter {
@state
int counter;
constructor() {
this.counter = 0;
}
public function mutate(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();
// construct an output from its locking script and satoshi amount
bytes output = Util.buildOutput(outputScript, amount);
// only 1 input here
require(hash256(output) == Util.hashOutputs(txPreimage));
}
}

0 comments on commit 6d574fb

Please sign in to comment.