mirror of
https://github.com/corda/corda.git
synced 2024-12-20 05:28:21 +00:00
Regen docsite
This commit is contained in:
parent
b120ce9fe1
commit
5a3c6e7fed
107
docs/build/html/_sources/tutorial.txt
vendored
107
docs/build/html/_sources/tutorial.txt
vendored
@ -245,46 +245,41 @@ run two contracts one time each: Cash and CommercialPaper.
|
||||
|
||||
override fun verify(tx: TransactionForVerification) {
|
||||
// Group by everything except owner: any modification to the CP at all is considered changing it fundamentally.
|
||||
val groups = tx.groupStates<State>() { it.withoutOwner() }
|
||||
val groups = tx.groupStates() { it: State -> it.withoutOwner() }
|
||||
val command = tx.commands.requireSingleCommand<CommercialPaper.Commands>()
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
@Override
|
||||
public void verify(@NotNull TransactionForVerification tx) {
|
||||
List<InOutGroup<State>> groups = tx.groupStates(State.class, State::withoutOwner);
|
||||
List<InOutGroup<State, State>> groups = tx.groupStates(State.class, State::withoutOwner);
|
||||
AuthenticatedObject<Command> cmd = requireSingleCommand(tx.getCommands(), Commands.class);
|
||||
|
||||
We start by using the ``groupStates`` method, which takes a type and a function (in functional programming a function
|
||||
that takes another function as an argument is called a *higher order function*). State grouping is a way of handling
|
||||
*fungibility* in a contract, which is explained next. The second line does what the code suggests: it searches for
|
||||
We start by using the ``groupStates`` method, which takes a type and a function. State grouping is a way of ensuring
|
||||
your contract can handle multiple unrelated states of the same type in the same transaction, which is needed for
|
||||
splitting/merging of assets, atomic swaps and so on. The second line does what the code suggests: it searches for
|
||||
a command object that inherits from the ``CommercialPaper.Commands`` supertype, and either returns it, or throws an
|
||||
exception if there's zero or more than one such command.
|
||||
|
||||
Understanding fungibility
|
||||
-------------------------
|
||||
Using state groups
|
||||
------------------
|
||||
|
||||
We say states are *fungible* if they are treated identically to each other by the recipient, despite the fact that they
|
||||
aren't quite identical. Dollar bills are fungible because even though one may be worn/a bit dirty and another may
|
||||
be crisp and new, they are still both worth exactly $1. Likewise, ten $1 bills are almost exactly equivalent to
|
||||
one $10 bill. On the other hand, $10 and £10 are not fungible: if you tried to pay for something that cost £20 with
|
||||
$10+£10 notes your trade would not be accepted.
|
||||
The simplest way to write a smart contract would be to say that each transaction can have a single input state and a
|
||||
single output state of the kind govered by that contract. This would be easy for the developer, but would prevent many
|
||||
important use cases.
|
||||
|
||||
So whilst our ledger could represent every monetary amount with a collection of states worth one penny, this would become
|
||||
extremely unwieldy. It's better to allow states to represent varying amounts and then define rules for merging them
|
||||
and splitting them. Similarly, we could also have considered modelling cash as a single contract that records the
|
||||
ownership of all holders of a given currency from a given issuer. Whilst this is possible, and is effectively how
|
||||
some other platforms work, this prototype favours a design that doesn't necessarily require state to be shared between
|
||||
multiple actors if they don't have a direct relationship with each other (as would implicitly be required if we had a
|
||||
single state representing multiple people's ownership). Keeping the states separated also has scalability benefits, as
|
||||
different parts of the global transaction graph can be updated in parallel.
|
||||
The next easiest way to write a contract would be to iterate over each input state and expect it to have an output
|
||||
state. Now you can build a single transaction that, for instance, moves two different cash states in different currencies
|
||||
simultaneously. But it gets complicated when you want to issue or exit one state at the same time as moving another.
|
||||
|
||||
Things get harder still once you want to split and merge states. We say states are *fungible* if they are
|
||||
treated identically to each other by the recipient, despite the fact that they aren't quite identical. Dollar bills are
|
||||
fungible because even though one may be worn/a bit dirty and another may be crisp and new, they are still both worth
|
||||
exactly $1. Likewise, ten $1 bills are almost exactly equivalent to one $10 bill. On the other hand, $10 and £10 are not
|
||||
fungible: if you tried to pay for something that cost £20 with $10+£10 notes your trade would not be accepted.
|
||||
|
||||
To make all this easier the contract API provides a notion of groups. A group is a set of input states and output states
|
||||
that should be checked for validity independently. It solves the following problem: because every contract sees every
|
||||
input and output state in a transaction, it would easy to accidentally write a contract that disallows useful
|
||||
combinations of states. For example, our cash contract might end up lazily assuming there's only one currency involved
|
||||
in a transaction, whereas in reality we would like the ability to model a currency trade in which two parties contribute
|
||||
inputs of different currencies, and both parties get outputs of the opposite currency.
|
||||
that should be checked for validity together.
|
||||
|
||||
Consider the following simplified currency trade transaction:
|
||||
|
||||
@ -304,11 +299,65 @@ given type (as the transaction may include other types of state, such as states
|
||||
multi-sig state) and then it takes a function that maps a state to a grouping key. All states that share the same key are
|
||||
grouped together. In the case of the cash example above, the grouping key would be the currency.
|
||||
|
||||
In our commercial paper contract, we don't want CP to be fungible: merging and splitting is (in our example) not allowed.
|
||||
So we just use a copy of the state minus the owner field as the grouping key. As a result, a single transaction can
|
||||
trade many different pieces of commercial paper in a single atomic step.
|
||||
In other kinds of contract, we don't want CP to be fungible: merging and splitting is (in our example) not allowed.
|
||||
So we just use a copy of the state minus the owner field as the grouping key.
|
||||
|
||||
Here are some code examples:
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
// Type of groups is List<InOutGroup<State, Pair<PartyReference, Currency>>>
|
||||
val groups = tx.groupStates() { it: Cash.State -> Pair(it.deposit, it.amount.currency) }
|
||||
for ((inputs, outputs, key) in groups) {
|
||||
// Either inputs or outputs could be empty.
|
||||
val (deposit, currency) = key
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
List<InOutGroup<State, Pair<PartyReference, Currency>>> groups = tx.groupStates(Cash.State.class, s -> Pair(s.deposit, s.amount.currency))
|
||||
for (InOutGroup<State, Pair<PartyReference, Currency>> group : groups) {
|
||||
List<State> inputs = group.getInputs();
|
||||
List<State> outputs = group.getOutputs();
|
||||
Pair<PartyReference, Currency> key = group.getKey();
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
The ``groupStates`` call uses the provided function to calculate a "grouping key". All states that have the same
|
||||
grouping key are placed in the same group. A grouping key can be anything that implements equals/hashCode, but it's
|
||||
always an aggregate of the fields that shouldn't change between input and output. In the above example we picked the
|
||||
fields we wanted and packed them into a ``Pair``. It returns a list of ``InOutGroup``s, which is just a holder for the
|
||||
inputs, outputs and the key that was used to define the group. In the Kotlin version we unpack these using destructuring
|
||||
to get convenient access to the inputs, the outputs, the deposit data and the currency. The Java version is more
|
||||
verbose, but equivalent.
|
||||
|
||||
The rules can then be applied to the inputs and outputs as if it were a single transaction. A group may have zero
|
||||
inputs or zero outputs: this can occur when issuing assets onto the ledger, or removing them.
|
||||
|
||||
In this example, we do it differently and use the state class itself as the aggregator. We just
|
||||
blank out fields that are allowed to change, making the grouping key be "everything that isn't that":
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
val groups = tx.groupStates() { it: State -> it.withoutOwner() }
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
List<InOutGroup<State, State>> groups = tx.groupStates(State.class, State::withoutOwner);
|
||||
|
||||
For large states with many fields that must remain constant and only one or two that are really mutable, it's often
|
||||
easier to do things this way than to specifically name each field that must stay the same. The ``withoutOwner`` function
|
||||
here simply returns a copy of the object but with the ``owner`` field set to ``NullPublicKey``, which is just a public key
|
||||
of all zeros. It's invalid and useless, but that's OK, because all we're doing is preventing the field from mattering
|
||||
in equals and hashCode.
|
||||
|
||||
A group may have zero inputs or zero outputs: this can occur when issuing assets onto the ledger, or removing them.
|
||||
|
||||
Checking the requirements
|
||||
-------------------------
|
||||
|
2
docs/build/html/index.html
vendored
2
docs/build/html/index.html
vendored
@ -216,7 +216,7 @@ prove or disprove the following hypothesis:</p>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorial.html#states">States</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorial.html#commands">Commands</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorial.html#the-verify-function">The verify function</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorial.html#understanding-fungibility">Understanding fungibility</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorial.html#using-state-groups">Using state groups</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorial.html#checking-the-requirements">Checking the requirements</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorial.html#how-to-test-your-contract">How to test your contract</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorial.html#adding-a-generation-api-to-your-contract">Adding a generation API to your contract</a></li>
|
||||
|
2
docs/build/html/robots.txt
vendored
Normal file
2
docs/build/html/robots.txt
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
2
docs/build/html/searchindex.js
vendored
2
docs/build/html/searchindex.js
vendored
File diff suppressed because one or more lines are too long
100
docs/build/html/tutorial.html
vendored
100
docs/build/html/tutorial.html
vendored
@ -102,7 +102,7 @@
|
||||
<li class="toctree-l2"><a class="reference internal" href="#states">States</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#commands">Commands</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#the-verify-function">The verify function</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#understanding-fungibility">Understanding fungibility</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#using-state-groups">Using state groups</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#checking-the-requirements">Checking the requirements</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#how-to-test-your-contract">How to test your contract</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="#adding-a-generation-api-to-your-contract">Adding a generation API to your contract</a></li>
|
||||
@ -116,6 +116,7 @@
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="visualiser.html">Using the visualiser</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="codestyle.html">Code style guide</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="building-the-docs.html">Building the documentation</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
@ -372,44 +373,38 @@ run two contracts one time each: Cash and CommercialPaper.</p>
|
||||
<div class="codeset container">
|
||||
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">override</span> <span class="k">fun</span> <span class="nf">verify</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">TransactionForVerification</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="c1">// Group by everything except owner: any modification to the CP at all is considered changing it fundamentally.</span>
|
||||
<span class="k">val</span> <span class="py">groups</span> <span class="p">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">groupStates</span><span class="p"><</span><span class="n">State</span><span class="p">>()</span> <span class="p">{</span> <span class="n">it</span><span class="p">.</span><span class="n">withoutOwner</span><span class="p">()</span> <span class="p">}</span>
|
||||
<span class="k">val</span> <span class="py">groups</span> <span class="p">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">groupStates</span><span class="p">()</span> <span class="p">{</span> <span class="n">it</span><span class="p">:</span> <span class="n">State</span> <span class="p">-></span> <span class="n">it</span><span class="p">.</span><span class="n">withoutOwner</span><span class="p">()</span> <span class="p">}</span>
|
||||
<span class="k">val</span> <span class="py">command</span> <span class="p">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">commands</span><span class="p">.</span><span class="n">requireSingleCommand</span><span class="p"><</span><span class="n">CommercialPaper</span><span class="p">.</span><span class="n">Commands</span><span class="p">>()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-java"><div class="highlight"><pre><span></span><span class="nd">@Override</span>
|
||||
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">verify</span><span class="o">(</span><span class="nd">@NotNull</span> <span class="n">TransactionForVerification</span> <span class="n">tx</span><span class="o">)</span> <span class="o">{</span>
|
||||
<span class="n">List</span><span class="o"><</span><span class="n">InOutGroup</span><span class="o"><</span><span class="n">State</span><span class="o">>></span> <span class="n">groups</span> <span class="o">=</span> <span class="n">tx</span><span class="o">.</span><span class="na">groupStates</span><span class="o">(</span><span class="n">State</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">State</span><span class="o">::</span><span class="n">withoutOwner</span><span class="o">);</span>
|
||||
<span class="n">List</span><span class="o"><</span><span class="n">InOutGroup</span><span class="o"><</span><span class="n">State</span><span class="o">,</span> <span class="n">State</span><span class="o">>></span> <span class="n">groups</span> <span class="o">=</span> <span class="n">tx</span><span class="o">.</span><span class="na">groupStates</span><span class="o">(</span><span class="n">State</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">State</span><span class="o">::</span><span class="n">withoutOwner</span><span class="o">);</span>
|
||||
<span class="n">AuthenticatedObject</span><span class="o"><</span><span class="n">Command</span><span class="o">></span> <span class="n">cmd</span> <span class="o">=</span> <span class="n">requireSingleCommand</span><span class="o">(</span><span class="n">tx</span><span class="o">.</span><span class="na">getCommands</span><span class="o">(),</span> <span class="n">Commands</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>We start by using the <code class="docutils literal"><span class="pre">groupStates</span></code> method, which takes a type and a function (in functional programming a function
|
||||
that takes another function as an argument is called a <em>higher order function</em>). State grouping is a way of handling
|
||||
<em>fungibility</em> in a contract, which is explained next. The second line does what the code suggests: it searches for
|
||||
<p>We start by using the <code class="docutils literal"><span class="pre">groupStates</span></code> method, which takes a type and a function. State grouping is a way of ensuring
|
||||
your contract can handle multiple unrelated states of the same type in the same transaction, which is needed for
|
||||
splitting/merging of assets, atomic swaps and so on. The second line does what the code suggests: it searches for
|
||||
a command object that inherits from the <code class="docutils literal"><span class="pre">CommercialPaper.Commands</span></code> supertype, and either returns it, or throws an
|
||||
exception if there’s zero or more than one such command.</p>
|
||||
</div>
|
||||
<div class="section" id="understanding-fungibility">
|
||||
<h2>Understanding fungibility<a class="headerlink" href="#understanding-fungibility" title="Permalink to this headline">¶</a></h2>
|
||||
<p>We say states are <em>fungible</em> if they are treated identically to each other by the recipient, despite the fact that they
|
||||
aren’t quite identical. Dollar bills are fungible because even though one may be worn/a bit dirty and another may
|
||||
be crisp and new, they are still both worth exactly $1. Likewise, ten $1 bills are almost exactly equivalent to
|
||||
one $10 bill. On the other hand, $10 and £10 are not fungible: if you tried to pay for something that cost £20 with
|
||||
$10+£10 notes your trade would not be accepted.</p>
|
||||
<p>So whilst our ledger could represent every monetary amount with a collection of states worth one penny, this would become
|
||||
extremely unwieldy. It’s better to allow states to represent varying amounts and then define rules for merging them
|
||||
and splitting them. Similarly, we could also have considered modelling cash as a single contract that records the
|
||||
ownership of all holders of a given currency from a given issuer. Whilst this is possible, and is effectively how
|
||||
some other platforms work, this prototype favours a design that doesn’t necessarily require state to be shared between
|
||||
multiple actors if they don’t have a direct relationship with each other (as would implicitly be required if we had a
|
||||
single state representing multiple people’s ownership). Keeping the states separated also has scalability benefits, as
|
||||
different parts of the global transaction graph can be updated in parallel.</p>
|
||||
<div class="section" id="using-state-groups">
|
||||
<h2>Using state groups<a class="headerlink" href="#using-state-groups" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The simplest way to write a smart contract would be to say that each transaction can have a single input state and a
|
||||
single output state of the kind govered by that contract. This would be easy for the developer, but would prevent many
|
||||
important use cases.</p>
|
||||
<p>The next easiest way to write a contract would be to iterate over each input state and expect it to have an output
|
||||
state. Now you can build a single transaction that, for instance, moves two different cash states in different currencies
|
||||
simultaneously. But it gets complicated when you want to issue or exit one state at the same time as moving another.</p>
|
||||
<p>Things get harder still once you want to split and merge states. We say states are <em>fungible</em> if they are
|
||||
treated identically to each other by the recipient, despite the fact that they aren’t quite identical. Dollar bills are
|
||||
fungible because even though one may be worn/a bit dirty and another may be crisp and new, they are still both worth
|
||||
exactly $1. Likewise, ten $1 bills are almost exactly equivalent to one $10 bill. On the other hand, $10 and £10 are not
|
||||
fungible: if you tried to pay for something that cost £20 with $10+£10 notes your trade would not be accepted.</p>
|
||||
<p>To make all this easier the contract API provides a notion of groups. A group is a set of input states and output states
|
||||
that should be checked for validity independently. It solves the following problem: because every contract sees every
|
||||
input and output state in a transaction, it would easy to accidentally write a contract that disallows useful
|
||||
combinations of states. For example, our cash contract might end up lazily assuming there’s only one currency involved
|
||||
in a transaction, whereas in reality we would like the ability to model a currency trade in which two parties contribute
|
||||
inputs of different currencies, and both parties get outputs of the opposite currency.</p>
|
||||
that should be checked for validity together.</p>
|
||||
<p>Consider the following simplified currency trade transaction:</p>
|
||||
<ul class="simple">
|
||||
<li><strong>Input</strong>: $12,000 owned by Alice (A)</li>
|
||||
@ -426,10 +421,55 @@ be merged together. So we have two groups: A and B.</p>
|
||||
given type (as the transaction may include other types of state, such as states representing bond ownership, or a
|
||||
multi-sig state) and then it takes a function that maps a state to a grouping key. All states that share the same key are
|
||||
grouped together. In the case of the cash example above, the grouping key would be the currency.</p>
|
||||
<p>In our commercial paper contract, we don’t want CP to be fungible: merging and splitting is (in our example) not allowed.
|
||||
So we just use a copy of the state minus the owner field as the grouping key. As a result, a single transaction can
|
||||
trade many different pieces of commercial paper in a single atomic step.</p>
|
||||
<p>A group may have zero inputs or zero outputs: this can occur when issuing assets onto the ledger, or removing them.</p>
|
||||
<p>In other kinds of contract, we don’t want CP to be fungible: merging and splitting is (in our example) not allowed.
|
||||
So we just use a copy of the state minus the owner field as the grouping key.</p>
|
||||
<p>Here are some code examples:</p>
|
||||
<div class="codeset container">
|
||||
<div class="highlight-kotlin"><div class="highlight"><pre><span></span>// Type of groups is List<InOutGroup<State, Pair<PartyReference, Currency>>>
|
||||
val groups = tx.groupStates() { it: Cash.State -> Pair(it.deposit, it.amount.currency) }
|
||||
for ((inputs, outputs, key) in groups) {
|
||||
// Either inputs or outputs could be empty.
|
||||
val (deposit, currency) = key
|
||||
|
||||
...
|
||||
}
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-java"><div class="highlight"><pre><span></span><span class="n">List</span><span class="o"><</span><span class="n">InOutGroup</span><span class="o"><</span><span class="n">State</span><span class="o">,</span> <span class="n">Pair</span><span class="o"><</span><span class="n">PartyReference</span><span class="o">,</span> <span class="n">Currency</span><span class="o">>>></span> <span class="n">groups</span> <span class="o">=</span> <span class="n">tx</span><span class="o">.</span><span class="na">groupStates</span><span class="o">(</span><span class="n">Cash</span><span class="o">.</span><span class="na">State</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">s</span> <span class="o">-></span> <span class="n">Pair</span><span class="o">(</span><span class="n">s</span><span class="o">.</span><span class="na">deposit</span><span class="o">,</span> <span class="n">s</span><span class="o">.</span><span class="na">amount</span><span class="o">.</span><span class="na">currency</span><span class="o">))</span>
|
||||
<span class="k">for</span> <span class="o">(</span><span class="n">InOutGroup</span><span class="o"><</span><span class="n">State</span><span class="o">,</span> <span class="n">Pair</span><span class="o"><</span><span class="n">PartyReference</span><span class="o">,</span> <span class="n">Currency</span><span class="o">>></span> <span class="n">group</span> <span class="o">:</span> <span class="n">groups</span><span class="o">)</span> <span class="o">{</span>
|
||||
<span class="n">List</span><span class="o"><</span><span class="n">State</span><span class="o">></span> <span class="n">inputs</span> <span class="o">=</span> <span class="n">group</span><span class="o">.</span><span class="na">getInputs</span><span class="o">();</span>
|
||||
<span class="n">List</span><span class="o"><</span><span class="n">State</span><span class="o">></span> <span class="n">outputs</span> <span class="o">=</span> <span class="n">group</span><span class="o">.</span><span class="na">getOutputs</span><span class="o">();</span>
|
||||
<span class="n">Pair</span><span class="o"><</span><span class="n">PartyReference</span><span class="o">,</span> <span class="n">Currency</span><span class="o">></span> <span class="n">key</span> <span class="o">=</span> <span class="n">group</span><span class="o">.</span><span class="na">getKey</span><span class="o">();</span>
|
||||
|
||||
<span class="o">...</span>
|
||||
<span class="o">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal"><span class="pre">groupStates</span></code> call uses the provided function to calculate a “grouping key”. All states that have the same
|
||||
grouping key are placed in the same group. A grouping key can be anything that implements equals/hashCode, but it’s
|
||||
always an aggregate of the fields that shouldn’t change between input and output. In the above example we picked the
|
||||
fields we wanted and packed them into a <code class="docutils literal"><span class="pre">Pair</span></code>. It returns a list of <a href="#id1"><span class="problematic" id="id2">``</span></a>InOutGroup``s, which is just a holder for the
|
||||
inputs, outputs and the key that was used to define the group. In the Kotlin version we unpack these using destructuring
|
||||
to get convenient access to the inputs, the outputs, the deposit data and the currency. The Java version is more
|
||||
verbose, but equivalent.</p>
|
||||
<p>The rules can then be applied to the inputs and outputs as if it were a single transaction. A group may have zero
|
||||
inputs or zero outputs: this can occur when issuing assets onto the ledger, or removing them.</p>
|
||||
<p>In this example, we do it differently and use the state class itself as the aggregator. We just
|
||||
blank out fields that are allowed to change, making the grouping key be “everything that isn’t that”:</p>
|
||||
<div class="codeset container">
|
||||
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">val</span> <span class="py">groups</span> <span class="p">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">groupStates</span><span class="p">()</span> <span class="p">{</span> <span class="n">it</span><span class="p">:</span> <span class="n">State</span> <span class="p">-></span> <span class="n">it</span><span class="p">.</span><span class="n">withoutOwner</span><span class="p">()</span> <span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-java"><div class="highlight"><pre><span></span><span class="n">List</span><span class="o"><</span><span class="n">InOutGroup</span><span class="o"><</span><span class="n">State</span><span class="o">,</span> <span class="n">State</span><span class="o">>></span> <span class="n">groups</span> <span class="o">=</span> <span class="n">tx</span><span class="o">.</span><span class="na">groupStates</span><span class="o">(</span><span class="n">State</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">State</span><span class="o">::</span><span class="n">withoutOwner</span><span class="o">);</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>For large states with many fields that must remain constant and only one or two that are really mutable, it’s often
|
||||
easier to do things this way than to specifically name each field that must stay the same. The <code class="docutils literal"><span class="pre">withoutOwner</span></code> function
|
||||
here simply returns a copy of the object but with the <code class="docutils literal"><span class="pre">owner</span></code> field set to <code class="docutils literal"><span class="pre">NullPublicKey</span></code>, which is just a public key
|
||||
of all zeros. It’s invalid and useless, but that’s OK, because all we’re doing is preventing the field from mattering
|
||||
in equals and hashCode.</p>
|
||||
</div>
|
||||
<div class="section" id="checking-the-requirements">
|
||||
<h2>Checking the requirements<a class="headerlink" href="#checking-the-requirements" title="Permalink to this headline">¶</a></h2>
|
||||
|
Loading…
Reference in New Issue
Block a user