mirror of
https://github.com/corda/corda.git
synced 2025-01-21 03:55:00 +00:00
Regen the HTML
This commit is contained in:
parent
b4a3008302
commit
58ce060211
113
docs/build/html/_sources/tutorial.txt
vendored
113
docs/build/html/_sources/tutorial.txt
vendored
@ -7,8 +7,7 @@
|
||||
Tutorial
|
||||
========
|
||||
|
||||
This tutorial will take you through how the commercial paper contract works, and then teaches you how to define your own
|
||||
"hello world" contract for managing the ownership of an office building.
|
||||
This tutorial will take you through how the commercial paper contract works.
|
||||
|
||||
The code in this tutorial is available in both Kotlin and Java. You can quickly switch between them to get a feeling
|
||||
for how Kotlin syntax works.
|
||||
@ -18,7 +17,7 @@ Starting the commercial paper class
|
||||
|
||||
A smart contract is a class that implements the ``Contract`` interface. For now, they have to be a part of the main
|
||||
codebase, as dynamic loading of contract code is not yet implemented. Therefore, we start by creating a file named
|
||||
either `CommercialPaper.kt` or `CommercialPaper.java` in the src/contracts directory with the following contents:
|
||||
either ``CommercialPaper.kt`` or ``CommercialPaper.java`` in the src/contracts directory with the following contents:
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
@ -55,7 +54,7 @@ in which case the transaction is rejected.
|
||||
|
||||
We also need to define a constant hash that would, in a real system, be the hash of the program bytecode. For now
|
||||
we just set it to a dummy value as dynamic loading and sandboxing of bytecode is not implemented. This constant
|
||||
isn't shown in the code snippet but is called `CP_PROGRAM_ID`.
|
||||
isn't shown in the code snippet but is called ``CP_PROGRAM_ID``.
|
||||
|
||||
So far, so simple. Now we need to define the commercial paper *state*, which represents the fact of ownership of a
|
||||
piece of issued paper.
|
||||
@ -147,30 +146,30 @@ A state is a class that stores data that is checked by the contract.
|
||||
}
|
||||
}
|
||||
|
||||
We define a class that implements the `ContractState` and `SerializableWithKryo` interfaces. The
|
||||
We define a class that implements the ``ContractState`` and ``SerializableWithKryo`` interfaces. The
|
||||
latter is an artifact of how the prototype implements serialization and can be ignored for now: it wouldn't work
|
||||
like this in any final product.
|
||||
|
||||
The `ContractState` interface requires us to provide a `getProgramRef` method that is supposed to return a hash of
|
||||
The ``ContractState`` interface requires us to provide a ``getProgramRef`` method that is supposed to return a hash of
|
||||
the bytecode of the contract itself. For now this is a dummy value and isn't used: later on, this mechanism will change.
|
||||
Beyond that it's a freeform object into which we can put anything which can be serialized.
|
||||
|
||||
We have four fields in our state:
|
||||
|
||||
* `issuance`: a reference to a specific piece of commercial paper at an institution
|
||||
* `owner`: the public key of the current owner. This is the same concept as seen in Bitcoin: the public key has no
|
||||
* ``issuance``: a reference to a specific piece of commercial paper at an institution
|
||||
* ``owner``: the public key of the current owner. This is the same concept as seen in Bitcoin: the public key has no
|
||||
attached identity and is expected to be one-time-use for privacy reasons. However, unlike in Bitcoin, we model
|
||||
ownership at the level of individual contracts rather than as a platform-level concept as we envisage many
|
||||
(possibly most) contracts on the platform will not represent "owner/issuer" relationships, but "party/party"
|
||||
relationships such as a derivative contract.
|
||||
* `faceValue`: an `Amount`, which wraps an integer number of pennies and a currency.
|
||||
* `maturityDate`: an `Instant <https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html>`, which is a type
|
||||
* ``faceValue``: an ``Amount``, which wraps an integer number of pennies and a currency.
|
||||
* ``maturityDate``: an `Instant <https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html>`_, which is a type
|
||||
from the Java 8 standard time library. It defines a point on the timeline.
|
||||
|
||||
States are immutable, and thus the class is defined as immutable as well. The `data` modifier in the Kotlin version
|
||||
States are immutable, and thus the class is defined as immutable as well. The ``data`` modifier in the Kotlin version
|
||||
causes the compiler to generate the equals/hashCode/toString methods automatically, along with a copy method that can
|
||||
be used to create variants of the original object. Data classes are similar to case classes in Scala, if you are
|
||||
familiar with that language. The `withoutOwner` method uses the auto-generated copy method to return a version of
|
||||
familiar with that language. The ``withoutOwner```` method uses the auto-generated copy method to return a version of
|
||||
the state with the owner public key blanked out: this will prove useful later.
|
||||
|
||||
The Java code compiles to the same bytecode as the Kotlin version, but as you can see, is much more verbose.
|
||||
@ -186,7 +185,7 @@ is a piece of data associated with some *signatures*. By the time the contract r
|
||||
checked, so from the contract code's perspective, a command is simply a data structure with a list of attached
|
||||
public keys. Each key had a signature proving that the corresponding private key was used to sign.
|
||||
|
||||
Let's define a couple of commands now:
|
||||
Let's define a few commands now:
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
@ -224,7 +223,7 @@ Let's define a couple of commands now:
|
||||
}
|
||||
}
|
||||
|
||||
The `object` keyword in Kotlin just defines a singleton object. As the commands don't need any additional data in our
|
||||
The ``object`` keyword in Kotlin just defines a singleton object. As the commands don't need any additional data in our
|
||||
case, they can be empty and we just use their type as the important information. Java has no syntax for declaring
|
||||
singletons, so we just define a class that considers any other instance to be equal and that's good enough.
|
||||
|
||||
@ -247,26 +246,19 @@ 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() }
|
||||
|
||||
// There are two possible things that can be done with this CP. The first is trading it. The second is redeeming
|
||||
// it for cash on or after the maturity date.
|
||||
val command = tx.commands.requireSingleCommand<CommercialPaper.Commands>()
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
@Override
|
||||
public void verify(@NotNull TransactionForVerification tx) {
|
||||
// There are two possible things that can be done with CP. The first is trading it. The second is redeeming it
|
||||
// for cash on or after the maturity date.
|
||||
List<InOutGroup<State>> groups = tx.groupStates(State.class, State::withoutOwner);
|
||||
|
||||
// Find the command that instructs us what to do and check there's exactly one.
|
||||
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
|
||||
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
|
||||
a command object that inherits from the `CommercialPaper.Commands` supertype, and either returns it, or throws an
|
||||
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
|
||||
@ -287,7 +279,7 @@ multiple actors if they don't have a direct relationship with each other (as wou
|
||||
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.
|
||||
|
||||
To make this easier the contract API provides a notion of groups. A group is a set of input states and output states
|
||||
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
|
||||
@ -307,7 +299,7 @@ inputs e.g. because she received the dollars in two payments. The input and outp
|
||||
the cash smart contract must consider the pounds and the dollars separately because they are not fungible: they cannot
|
||||
be merged together. So we have two groups: A and B.
|
||||
|
||||
The `TransactionForVerification.groupStates` method handles this logic for us: firstly, it selects only states of the
|
||||
The ``TransactionForVerification.groupStates`` method handles this logic for us: firstly, it selects only states of the
|
||||
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.
|
||||
@ -329,21 +321,23 @@ logic.
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
for (group in groups) {
|
||||
when (command.value) {
|
||||
is Commands.Move -> {
|
||||
val input = group.inputs.single()
|
||||
requireThat {
|
||||
"the transaction is signed by the owner of the CP" by (command.signers.contains(input.owner))
|
||||
"the state is propagated" by (group.outputs.size == 1)
|
||||
}
|
||||
}
|
||||
|
||||
val output = group.outputs.singleOrNull()
|
||||
when (command.value) {
|
||||
is Commands.Move -> requireThat { "the output state is present" by (output != null) }
|
||||
|
||||
is Commands.Redeem -> {
|
||||
val received = tx.outStates.sumCashOrNull() ?: throw IllegalStateException("no cash being redeemed")
|
||||
val input = group.inputs.single()
|
||||
val received = tx.outStates.sumCashBy(input.owner)
|
||||
requireThat {
|
||||
"the paper must have matured" by (input.maturityDate < tx.time)
|
||||
"the received amount equals the face value" by (received == input.faceValue)
|
||||
"the paper must be destroyed" by (output == null)
|
||||
"the paper must be destroyed" by group.outputs.isEmpty()
|
||||
"the transaction is signed by the owner of the CP" by (command.signers.contains(input.owner))
|
||||
}
|
||||
}
|
||||
|
||||
@ -360,6 +354,7 @@ logic.
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Think about how to evolve contracts over time with new commands.
|
||||
else -> throw IllegalArgumentException("Unrecognised command")
|
||||
}
|
||||
}
|
||||
@ -403,7 +398,7 @@ This loop is the core logic of the contract.
|
||||
|
||||
The first line (first three lines in Java) impose a requirement that there be a single piece of commercial paper in
|
||||
this group. We do not allow multiple units of CP to be split or merged even if they are owned by the same owner. The
|
||||
`single()` method is a static *extension method* defined by the Kotlin standard library: given a list, it throws an
|
||||
``single()`` method is a static *extension method* defined by the Kotlin standard library: given a list, it throws an
|
||||
exception if the list size is not 1, otherwise it returns the single item in that list. In Java, this appears as a
|
||||
regular static method of the type familiar from many FooUtils type singleton classes. In Kotlin, it appears as a
|
||||
method that can be called on any JDK list. The syntax is slightly different but behind the scenes, the code compiles
|
||||
@ -416,17 +411,17 @@ is straightforward. The Kotlin version looks a little odd: we have a *requireTha
|
||||
built into the language. In fact *requireThat* is an ordinary function provided by the platform's contract API. Kotlin
|
||||
supports the creation of *domain specific languages* through the intersection of several features of the language, and
|
||||
we use it here to support the natural listing of requirements. To see what it compiles down to, look at the Java version.
|
||||
Each `"string" by (expression)` statement inside a `requireThat` turns into an assertion that the given expression is
|
||||
Each ``"string" by (expression)`` statement inside a ``requireThat`` turns into an assertion that the given expression is
|
||||
true, with an exception being thrown that contains the string if not. It's just another way to write out a regular
|
||||
assertion, but with the English-language requirement being put front and center.
|
||||
|
||||
Next, we take one of two paths, depending on what the type of the command object is.
|
||||
|
||||
If the command is a `Move` command, then we simply verify that the output state is actually present: a move is not
|
||||
If the command is a ``Move`` command, then we simply verify that the output state is actually present: a move is not
|
||||
allowed to delete the CP from the ledger. The grouping logic already ensured that the details are identical and haven't
|
||||
been changed, save for the public key of the owner.
|
||||
|
||||
If the command is a `Redeem` command, then the requirements are more complex:
|
||||
If the command is a ``Redeem`` command, then the requirements are more complex:
|
||||
|
||||
1. We want to see that the face value of the CP is being moved as a cash claim against some institution, that is, the
|
||||
issuer of the CP is really paying back the face value.
|
||||
@ -434,16 +429,16 @@ If the command is a `Redeem` command, then the requirements are more complex:
|
||||
3. The commercial paper must *not* be propagated by this transaction: it must be deleted, by the group having no
|
||||
output state. This prevents the same CP being considered redeemable multiple times.
|
||||
|
||||
To calculate how much cash is moving, we use the `sumCashOrNull` utility method. Again, this is an extension method,
|
||||
so in Kotlin code it appears as if it was a method on the `List<Cash.State>` type even though JDK provides no such
|
||||
method. In Java we see its true nature: it is actually a static method named `CashKt.sumCashOrNull`. This method simply
|
||||
returns an `Amount` object containing the sum of all the cash states in the transaction output, or null if there were
|
||||
To calculate how much cash is moving, we use the ``sumCashOrNull`` utility method. Again, this is an extension method,
|
||||
so in Kotlin code it appears as if it was a method on the ``List<Cash.State>`` type even though JDK provides no such
|
||||
method. In Java we see its true nature: it is actually a static method named ``CashKt.sumCashOrNull``. This method simply
|
||||
returns an ``Amount`` object containing the sum of all the cash states in the transaction output, or null if there were
|
||||
no such states *or* if there were different currencies represented in the outputs! So we can see that this contract
|
||||
imposes a limitation on the structure of a redemption transaction: you are not allowed to move currencies in the same
|
||||
transaction that the CP does not involve. This limitation could be addressed with better APIs, if it were to be a
|
||||
real limitation.
|
||||
|
||||
Finally, we support an `Issue` command, to create new instances of commercial paper on the ledger. It likewise
|
||||
Finally, we support an ``Issue`` command, to create new instances of commercial paper on the ledger. It likewise
|
||||
enforces various invariants upon the issuance.
|
||||
|
||||
This contract is extremely simple and does not implement all the business logic a real commercial paper lifecycle
|
||||
@ -492,7 +487,7 @@ We start by defining a new test class, with a basic CP state:
|
||||
}
|
||||
|
||||
We start by defining a commercial paper state. It will be owned by a pre-defined unit test institution, affectionately
|
||||
called `MEGA_CORP` (this constant, along with many others, is defined in `TestUtils.kt`). Due to Kotin's extensive
|
||||
called ``MEGA_CORP`` (this constant, along with many others, is defined in ``TestUtils.kt``). Due to Kotin's extensive
|
||||
type inference, many types are not written out explicitly in this code and it has the feel of a scripting language.
|
||||
But the types are there, and you can ask IntelliJ to reveal them by pressing Alt-Enter on a "val" or "var" and selecting
|
||||
"Specify type explicitly".
|
||||
@ -507,22 +502,22 @@ If you examine the code in the actual repository, you will also notice that it m
|
||||
in them by surrounding the name with backticks, rather than using underscores. We don't show this here as it breaks the
|
||||
doc website's syntax highlighting engine.
|
||||
|
||||
The `1000.DOLLARS` construct is quite simple: Kotlin allows you to define extension functions on primitive types like
|
||||
The ``1000.DOLLARS`` construct is quite simple: Kotlin allows you to define extension functions on primitive types like
|
||||
Int or Double. So by writing 7.days, for instance, the compiler will emit a call to a static method that takes an int
|
||||
and returns a `java.time.Duration`.
|
||||
and returns a ``java.time.Duration``.
|
||||
|
||||
As this is JUnit, we must remember to annotate each test method with @Test. Let's examine the contents of the first test.
|
||||
We are trying to check that it's not possible for just anyone to issue commercial paper in MegaCorp's name. That would
|
||||
be bad!
|
||||
|
||||
The `transactionGroup` function works the same way as the `requireThat` construct above. It is an example of what
|
||||
The ``transactionGroup`` function works the same way as the ``requireThat`` construct above. It is an example of what
|
||||
Kotlin calls a type safe builder, which you can read about in `the documentation for builders <https://kotlinlang.org/docs/reference/type-safe-builders.html>`_.
|
||||
The code block that follows it is run in the scope of a freshly created `TransactionGroupForTest` object, which assists
|
||||
The code block that follows it is run in the scope of a freshly created ``TransactionGroupForTest`` object, which assists
|
||||
you with building little transaction graphs and verifying them as a whole. Here, our "group" only actually has a
|
||||
single transaction in it, with a single output, no inputs, and an Issue command signed by `DUMMY_PUBKEY_1` which is just
|
||||
an arbitrary public key. As the paper claims to be issued by `MEGA_CORP`, this doesn't match and should cause a
|
||||
failure. The `expectFailureOfTx` method takes a 1-based index (in this case we expect the first transaction to fail)
|
||||
and a string that should appear in the exception message. Then it runs the `TransactionGroup.verify()` method to
|
||||
single transaction in it, with a single output, no inputs, and an Issue command signed by ``DUMMY_PUBKEY_1`` which is just
|
||||
an arbitrary public key. As the paper claims to be issued by ``MEGA_CORP``, this doesn't match and should cause a
|
||||
failure. The ``expectFailureOfTx`` method takes a 1-based index (in this case we expect the first transaction to fail)
|
||||
and a string that should appear in the exception message. Then it runs the ``TransactionGroup.verify()`` method to
|
||||
invoke all the involved contracts.
|
||||
|
||||
It's worth bearing in mind that even though this code may look like a totally different language to normal Kotlin or
|
||||
@ -581,22 +576,22 @@ Let's set up a full trade and ensure it works:
|
||||
|
||||
In this example we see some new features of the DSL:
|
||||
|
||||
* The `roots` construct. Sometimes you don't want to write transactions that laboriously issue everything you need
|
||||
in a formally correct way. Inside `roots` you can create a bunch of states without any contract checking what you're
|
||||
* The ``roots`` construct. Sometimes you don't want to write transactions that laboriously issue everything you need
|
||||
in a formally correct way. Inside ``roots`` you can create a bunch of states without any contract checking what you're
|
||||
doing. As states may not exist outside of transactions, each line inside defines a fake/invalid transaction with the
|
||||
given output states, which may be *labelled* with a short string. Those labels can be used later to join transactions
|
||||
together.
|
||||
* The `.CASH` suffix. This is a part of the unit test DSL specific to the cash contract. It takes a monetary amount
|
||||
* The ``.CASH`` suffix. This is a part of the unit test DSL specific to the cash contract. It takes a monetary amount
|
||||
like 1000.DOLLARS and then wraps it in a cash ledger state, with some fake data.
|
||||
* The owned_by `infix function <https://kotlinlang.org/docs/reference/functions.html#infix-notation>`_. This is just
|
||||
a normal function that we're allowed to write in a slightly different way, which returns a copy of the cash state
|
||||
with the owner field altered to be the given public key. `ALICE` is a constant defined by the test utilities that
|
||||
is, like `DUMMY_PUBKEY_1`, just an arbitrary keypair.
|
||||
with the owner field altered to be the given public key. ``ALICE`` is a constant defined by the test utilities that
|
||||
is, like ``DUMMY_PUBKEY_1``, just an arbitrary keypair.
|
||||
* We are now defining several transactions that chain together. We can optionally label any output we create. Obviously
|
||||
then, the `input` method requires us to give the label of some other output that it connects to.
|
||||
* The `transaction` function can also be given a time, to override the default timestamp on a transaction.
|
||||
then, the ``input`` method requires us to give the label of some other output that it connects to.
|
||||
* The ``transaction`` function can also be given a time, to override the default timestamp on a transaction.
|
||||
|
||||
The `trade` function is not itself a unit test. Instead it builds up a trade/transaction group, with some slight
|
||||
The ``trade`` function is not itself a unit test. Instead it builds up a trade/transaction group, with some slight
|
||||
differences depending on the parameters provided (Kotlin allows parameters to have default valus). Then it returns
|
||||
it, unexecuted.
|
||||
|
||||
@ -616,8 +611,8 @@ We use it like this:
|
||||
trade(redemptionTime = TEST_TX_TIME + 2.days).expectFailureOfTx(3, "must have matured")
|
||||
}
|
||||
|
||||
That's pretty simple: we just call `verify` in order to check all the transactions in the group. If any are invalid,
|
||||
an exception will be thrown indicating which transaction failed and why. In the second case, we call `expectFailureOfTx`
|
||||
That's pretty simple: we just call ``verify`` in order to check all the transactions in the group. If any are invalid,
|
||||
an exception will be thrown indicating which transaction failed and why. In the second case, we call ``expectFailureOfTx``
|
||||
again to ensure the third transaction fails with a message that contains "must have matured" (it doesn't have to be
|
||||
the exact message).
|
||||
|
||||
|
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
113
docs/build/html/tutorial.html
vendored
113
docs/build/html/tutorial.html
vendored
@ -145,15 +145,14 @@
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="_static/codesets.js"></script><div class="section" id="tutorial">
|
||||
<h1>Tutorial<a class="headerlink" href="#tutorial" title="Permalink to this headline">¶</a></h1>
|
||||
<p>This tutorial will take you through how the commercial paper contract works, and then teaches you how to define your own
|
||||
“hello world” contract for managing the ownership of an office building.</p>
|
||||
<p>This tutorial will take you through how the commercial paper contract works.</p>
|
||||
<p>The code in this tutorial is available in both Kotlin and Java. You can quickly switch between them to get a feeling
|
||||
for how Kotlin syntax works.</p>
|
||||
<div class="section" id="starting-the-commercial-paper-class">
|
||||
<h2>Starting the commercial paper class<a class="headerlink" href="#starting-the-commercial-paper-class" title="Permalink to this headline">¶</a></h2>
|
||||
<p>A smart contract is a class that implements the <code class="docutils literal"><span class="pre">Contract</span></code> interface. For now, they have to be a part of the main
|
||||
codebase, as dynamic loading of contract code is not yet implemented. Therefore, we start by creating a file named
|
||||
either <cite>CommercialPaper.kt</cite> or <cite>CommercialPaper.java</cite> in the src/contracts directory with the following contents:</p>
|
||||
either <code class="docutils literal"><span class="pre">CommercialPaper.kt</span></code> or <code class="docutils literal"><span class="pre">CommercialPaper.java</span></code> in the src/contracts directory with the following contents:</p>
|
||||
<div class="codeset container">
|
||||
<div class="highlight-kotlin"><div class="highlight"><pre><span class="k">class</span> <span class="nc">CommercialPaper</span> <span class="p">:</span> <span class="n">Contract</span> <span class="p">{</span>
|
||||
<span class="k">override</span> <span class="k">val</span> <span class="py">legalContractReference</span><span class="p">:</span> <span class="n">SecureHash</span> <span class="p">=</span> <span class="n">SecureHash</span><span class="p">.</span><span class="n">sha256</span><span class="p">(</span><span class="s">"https://en.wikipedia.org/wiki/Commercial_paper"</span><span class="p">);</span>
|
||||
@ -185,7 +184,7 @@ of a document that describes the legal contract and may take precedence over the
|
||||
in which case the transaction is rejected.</p>
|
||||
<p>We also need to define a constant hash that would, in a real system, be the hash of the program bytecode. For now
|
||||
we just set it to a dummy value as dynamic loading and sandboxing of bytecode is not implemented. This constant
|
||||
isn’t shown in the code snippet but is called <cite>CP_PROGRAM_ID</cite>.</p>
|
||||
isn’t shown in the code snippet but is called <code class="docutils literal"><span class="pre">CP_PROGRAM_ID</span></code>.</p>
|
||||
<p>So far, so simple. Now we need to define the commercial paper <em>state</em>, which represents the fact of ownership of a
|
||||
piece of issued paper.</p>
|
||||
</div>
|
||||
@ -272,28 +271,28 @@ piece of issued paper.</p>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>We define a class that implements the <cite>ContractState</cite> and <cite>SerializableWithKryo</cite> interfaces. The
|
||||
<p>We define a class that implements the <code class="docutils literal"><span class="pre">ContractState</span></code> and <code class="docutils literal"><span class="pre">SerializableWithKryo</span></code> interfaces. The
|
||||
latter is an artifact of how the prototype implements serialization and can be ignored for now: it wouldn’t work
|
||||
like this in any final product.</p>
|
||||
<p>The <cite>ContractState</cite> interface requires us to provide a <cite>getProgramRef</cite> method that is supposed to return a hash of
|
||||
<p>The <code class="docutils literal"><span class="pre">ContractState</span></code> interface requires us to provide a <code class="docutils literal"><span class="pre">getProgramRef</span></code> method that is supposed to return a hash of
|
||||
the bytecode of the contract itself. For now this is a dummy value and isn’t used: later on, this mechanism will change.
|
||||
Beyond that it’s a freeform object into which we can put anything which can be serialized.</p>
|
||||
<p>We have four fields in our state:</p>
|
||||
<ul class="simple">
|
||||
<li><cite>issuance</cite>: a reference to a specific piece of commercial paper at an institution</li>
|
||||
<li><cite>owner</cite>: the public key of the current owner. This is the same concept as seen in Bitcoin: the public key has no
|
||||
<li><code class="docutils literal"><span class="pre">issuance</span></code>: a reference to a specific piece of commercial paper at an institution</li>
|
||||
<li><code class="docutils literal"><span class="pre">owner</span></code>: the public key of the current owner. This is the same concept as seen in Bitcoin: the public key has no
|
||||
attached identity and is expected to be one-time-use for privacy reasons. However, unlike in Bitcoin, we model
|
||||
ownership at the level of individual contracts rather than as a platform-level concept as we envisage many
|
||||
(possibly most) contracts on the platform will not represent “owner/issuer” relationships, but “party/party”
|
||||
relationships such as a derivative contract.</li>
|
||||
<li><cite>faceValue</cite>: an <cite>Amount</cite>, which wraps an integer number of pennies and a currency.</li>
|
||||
<li><cite>maturityDate</cite>: an <cite>Instant <https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html></cite>, which is a type
|
||||
<li><code class="docutils literal"><span class="pre">faceValue</span></code>: an <code class="docutils literal"><span class="pre">Amount</span></code>, which wraps an integer number of pennies and a currency.</li>
|
||||
<li><code class="docutils literal"><span class="pre">maturityDate</span></code>: an <a class="reference external" href="https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html">Instant</a>, which is a type
|
||||
from the Java 8 standard time library. It defines a point on the timeline.</li>
|
||||
</ul>
|
||||
<p>States are immutable, and thus the class is defined as immutable as well. The <cite>data</cite> modifier in the Kotlin version
|
||||
<p>States are immutable, and thus the class is defined as immutable as well. The <code class="docutils literal"><span class="pre">data</span></code> modifier in the Kotlin version
|
||||
causes the compiler to generate the equals/hashCode/toString methods automatically, along with a copy method that can
|
||||
be used to create variants of the original object. Data classes are similar to case classes in Scala, if you are
|
||||
familiar with that language. The <cite>withoutOwner</cite> method uses the auto-generated copy method to return a version of
|
||||
familiar with that language. The <code class="docutils literal"><span class="pre">withoutOwner``</span></code> method uses the auto-generated copy method to return a version of
|
||||
the state with the owner public key blanked out: this will prove useful later.</p>
|
||||
<p>The Java code compiles to the same bytecode as the Kotlin version, but as you can see, is much more verbose.</p>
|
||||
</div>
|
||||
@ -305,7 +304,7 @@ pass additional data into the contract code that isn’t represented by the
|
||||
is a piece of data associated with some <em>signatures</em>. By the time the contract runs the signatures have already been
|
||||
checked, so from the contract code’s perspective, a command is simply a data structure with a list of attached
|
||||
public keys. Each key had a signature proving that the corresponding private key was used to sign.</p>
|
||||
<p>Let’s define a couple of commands now:</p>
|
||||
<p>Let’s define a few commands now:</p>
|
||||
<div class="codeset container">
|
||||
<div class="highlight-kotlin"><div class="highlight"><pre><span class="n">interface</span> <span class="n">Commands</span> <span class="p">:</span> <span class="n">Command</span> <span class="p">{</span>
|
||||
<span class="k">object</span> <span class="nc">Move</span> <span class="p">:</span> <span class="n">Commands</span>
|
||||
@ -339,7 +338,7 @@ public keys. Each key had a signature proving that the corresponding private key
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>The <cite>object</cite> keyword in Kotlin just defines a singleton object. As the commands don’t need any additional data in our
|
||||
<p>The <code class="docutils literal"><span class="pre">object</span></code> keyword in Kotlin just defines a singleton object. As the commands don’t need any additional data in our
|
||||
case, they can be empty and we just use their type as the important information. Java has no syntax for declaring
|
||||
singletons, so we just define a class that considers any other instance to be equal and that’s good enough.</p>
|
||||
</div>
|
||||
@ -356,27 +355,20 @@ run two contracts one time each: Cash and CommercialPaper.</p>
|
||||
<div class="highlight-kotlin"><div class="highlight"><pre><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="c1">// There are two possible things that can be done with this CP. The first is trading it. The second is redeeming</span>
|
||||
<span class="c1">// it for cash on or after the maturity date.</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 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="c1">// There are two possible things that can be done with CP. The first is trading it. The second is redeeming it</span>
|
||||
<span class="c1">// for cash on or after the maturity date.</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="c1">// Find the command that instructs us what to do and check there's exactly one.</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 <cite>groupStates</cite> method, which takes a type and a function (in functional programming a function
|
||||
<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
|
||||
a command object that inherits from the <cite>CommercialPaper.Commands</cite> supertype, and either returns it, or throws an
|
||||
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">
|
||||
@ -394,7 +386,7 @@ some other platforms work, this prototype favours a design that doesn’t ne
|
||||
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>
|
||||
<p>To make this easier the contract API provides a notion of groups. A group is a set of input states and output states
|
||||
<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
|
||||
@ -412,7 +404,7 @@ inputs of different currencies, and both parties get outputs of the opposite cur
|
||||
inputs e.g. because she received the dollars in two payments. The input and output amounts do balance correctly, but
|
||||
the cash smart contract must consider the pounds and the dollars separately because they are not fungible: they cannot
|
||||
be merged together. So we have two groups: A and B.</p>
|
||||
<p>The <cite>TransactionForVerification.groupStates</cite> method handles this logic for us: firstly, it selects only states of the
|
||||
<p>The <code class="docutils literal"><span class="pre">TransactionForVerification.groupStates</span></code> method handles this logic for us: firstly, it selects only states of the
|
||||
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>
|
||||
@ -427,21 +419,23 @@ trade many different pieces of commercial paper in a single atomic step.</p>
|
||||
logic.</p>
|
||||
<div class="codeset container">
|
||||
<div class="highlight-kotlin"><div class="highlight"><pre><span class="k">for</span> <span class="p">(</span><span class="n">group</span> <span class="k">in</span> <span class="n">groups</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="k">when</span> <span class="p">(</span><span class="n">command</span><span class="p">.</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="k">is</span> <span class="n">Commands</span><span class="p">.</span><span class="n">Move</span> <span class="p">-></span> <span class="p">{</span>
|
||||
<span class="k">val</span> <span class="py">input</span> <span class="p">=</span> <span class="n">group</span><span class="p">.</span><span class="n">inputs</span><span class="p">.</span><span class="n">single</span><span class="p">()</span>
|
||||
<span class="n">requireThat</span> <span class="p">{</span>
|
||||
<span class="s">"the transaction is signed by the owner of the CP"</span> <span class="k">by</span> <span class="p">(</span><span class="n">command</span><span class="p">.</span><span class="n">signers</span><span class="p">.</span><span class="n">contains</span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">owner</span><span class="p">))</span>
|
||||
<span class="s">"the state is propagated"</span> <span class="k">by</span> <span class="p">(</span><span class="n">group</span><span class="p">.</span><span class="n">outputs</span><span class="p">.</span><span class="n">size</span> <span class="p">==</span> <span class="m">1</span><span class="p">)</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="k">val</span> <span class="py">output</span> <span class="p">=</span> <span class="n">group</span><span class="p">.</span><span class="n">outputs</span><span class="p">.</span><span class="n">singleOrNull</span><span class="p">()</span>
|
||||
<span class="k">when</span> <span class="p">(</span><span class="n">command</span><span class="p">.</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span>
|
||||
<span class="k">is</span> <span class="n">Commands</span><span class="p">.</span><span class="n">Move</span> <span class="p">-></span> <span class="n">requireThat</span> <span class="p">{</span> <span class="s">"the output state is present"</span> <span class="k">by</span> <span class="p">(</span><span class="n">output</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">}</span>
|
||||
|
||||
<span class="k">is</span> <span class="n">Commands</span><span class="p">.</span><span class="n">Redeem</span> <span class="p">-></span> <span class="p">{</span>
|
||||
<span class="k">val</span> <span class="py">received</span> <span class="p">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">outStates</span><span class="p">.</span><span class="n">sumCashOrNull</span><span class="p">()</span> <span class="o">?:</span> <span class="k">throw</span> <span class="n">IllegalStateException</span><span class="p">(</span><span class="s">"no cash being redeemed"</span><span class="p">)</span>
|
||||
<span class="k">val</span> <span class="py">input</span> <span class="p">=</span> <span class="n">group</span><span class="p">.</span><span class="n">inputs</span><span class="p">.</span><span class="n">single</span><span class="p">()</span>
|
||||
<span class="k">val</span> <span class="py">received</span> <span class="p">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">outStates</span><span class="p">.</span><span class="n">sumCashBy</span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">owner</span><span class="p">)</span>
|
||||
<span class="n">requireThat</span> <span class="p">{</span>
|
||||
<span class="s">"the paper must have matured"</span> <span class="k">by</span> <span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">maturityDate</span> <span class="p"><</span> <span class="n">tx</span><span class="p">.</span><span class="n">time</span><span class="p">)</span>
|
||||
<span class="s">"the received amount equals the face value"</span> <span class="k">by</span> <span class="p">(</span><span class="n">received</span> <span class="p">==</span> <span class="n">input</span><span class="p">.</span><span class="n">faceValue</span><span class="p">)</span>
|
||||
<span class="s">"the paper must be destroyed"</span> <span class="k">by</span> <span class="p">(</span><span class="n">output</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
|
||||
<span class="s">"the paper must be destroyed"</span> <span class="k">by</span> <span class="n">group</span><span class="p">.</span><span class="n">outputs</span><span class="p">.</span><span class="n">isEmpty</span><span class="p">()</span>
|
||||
<span class="s">"the transaction is signed by the owner of the CP"</span> <span class="k">by</span> <span class="p">(</span><span class="n">command</span><span class="p">.</span><span class="n">signers</span><span class="p">.</span><span class="n">contains</span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">owner</span><span class="p">))</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
@ -458,6 +452,7 @@ logic.</p>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="c1">// TODO: Think about how to evolve contracts over time with new commands.</span>
|
||||
<span class="k">else</span> <span class="p">-></span> <span class="k">throw</span> <span class="n">IllegalArgumentException</span><span class="p">(</span><span class="s">"Unrecognised command"</span><span class="p">)</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
@ -501,7 +496,7 @@ logic.</p>
|
||||
<p>This loop is the core logic of the contract.</p>
|
||||
<p>The first line (first three lines in Java) impose a requirement that there be a single piece of commercial paper in
|
||||
this group. We do not allow multiple units of CP to be split or merged even if they are owned by the same owner. The
|
||||
<cite>single()</cite> method is a static <em>extension method</em> defined by the Kotlin standard library: given a list, it throws an
|
||||
<code class="docutils literal"><span class="pre">single()</span></code> method is a static <em>extension method</em> defined by the Kotlin standard library: given a list, it throws an
|
||||
exception if the list size is not 1, otherwise it returns the single item in that list. In Java, this appears as a
|
||||
regular static method of the type familiar from many FooUtils type singleton classes. In Kotlin, it appears as a
|
||||
method that can be called on any JDK list. The syntax is slightly different but behind the scenes, the code compiles
|
||||
@ -513,14 +508,14 @@ is straightforward. The Kotlin version looks a little odd: we have a <em>require
|
||||
built into the language. In fact <em>requireThat</em> is an ordinary function provided by the platform’s contract API. Kotlin
|
||||
supports the creation of <em>domain specific languages</em> through the intersection of several features of the language, and
|
||||
we use it here to support the natural listing of requirements. To see what it compiles down to, look at the Java version.
|
||||
Each <cite>“string” by (expression)</cite> statement inside a <cite>requireThat</cite> turns into an assertion that the given expression is
|
||||
Each <code class="docutils literal"><span class="pre">"string"</span> <span class="pre">by</span> <span class="pre">(expression)</span></code> statement inside a <code class="docutils literal"><span class="pre">requireThat</span></code> turns into an assertion that the given expression is
|
||||
true, with an exception being thrown that contains the string if not. It’s just another way to write out a regular
|
||||
assertion, but with the English-language requirement being put front and center.</p>
|
||||
<p>Next, we take one of two paths, depending on what the type of the command object is.</p>
|
||||
<p>If the command is a <cite>Move</cite> command, then we simply verify that the output state is actually present: a move is not
|
||||
<p>If the command is a <code class="docutils literal"><span class="pre">Move</span></code> command, then we simply verify that the output state is actually present: a move is not
|
||||
allowed to delete the CP from the ledger. The grouping logic already ensured that the details are identical and haven’t
|
||||
been changed, save for the public key of the owner.</p>
|
||||
<p>If the command is a <cite>Redeem</cite> command, then the requirements are more complex:</p>
|
||||
<p>If the command is a <code class="docutils literal"><span class="pre">Redeem</span></code> command, then the requirements are more complex:</p>
|
||||
<ol class="arabic simple">
|
||||
<li>We want to see that the face value of the CP is being moved as a cash claim against some institution, that is, the
|
||||
issuer of the CP is really paying back the face value.</li>
|
||||
@ -528,15 +523,15 @@ issuer of the CP is really paying back the face value.</li>
|
||||
<li>The commercial paper must <em>not</em> be propagated by this transaction: it must be deleted, by the group having no
|
||||
output state. This prevents the same CP being considered redeemable multiple times.</li>
|
||||
</ol>
|
||||
<p>To calculate how much cash is moving, we use the <cite>sumCashOrNull</cite> utility method. Again, this is an extension method,
|
||||
so in Kotlin code it appears as if it was a method on the <cite>List<Cash.State></cite> type even though JDK provides no such
|
||||
method. In Java we see its true nature: it is actually a static method named <cite>CashKt.sumCashOrNull</cite>. This method simply
|
||||
returns an <cite>Amount</cite> object containing the sum of all the cash states in the transaction output, or null if there were
|
||||
<p>To calculate how much cash is moving, we use the <code class="docutils literal"><span class="pre">sumCashOrNull</span></code> utility method. Again, this is an extension method,
|
||||
so in Kotlin code it appears as if it was a method on the <code class="docutils literal"><span class="pre">List<Cash.State></span></code> type even though JDK provides no such
|
||||
method. In Java we see its true nature: it is actually a static method named <code class="docutils literal"><span class="pre">CashKt.sumCashOrNull</span></code>. This method simply
|
||||
returns an <code class="docutils literal"><span class="pre">Amount</span></code> object containing the sum of all the cash states in the transaction output, or null if there were
|
||||
no such states <em>or</em> if there were different currencies represented in the outputs! So we can see that this contract
|
||||
imposes a limitation on the structure of a redemption transaction: you are not allowed to move currencies in the same
|
||||
transaction that the CP does not involve. This limitation could be addressed with better APIs, if it were to be a
|
||||
real limitation.</p>
|
||||
<p>Finally, we support an <cite>Issue</cite> command, to create new instances of commercial paper on the ledger. It likewise
|
||||
<p>Finally, we support an <code class="docutils literal"><span class="pre">Issue</span></code> command, to create new instances of commercial paper on the ledger. It likewise
|
||||
enforces various invariants upon the issuance.</p>
|
||||
<p>This contract is extremely simple and does not implement all the business logic a real commercial paper lifecycle
|
||||
management program would. For instance, there is no logic requiring a signature from the issuer for redemption:
|
||||
@ -579,7 +574,7 @@ benefit from the DSL and would write them by hand).</p>
|
||||
</div>
|
||||
</div>
|
||||
<p>We start by defining a commercial paper state. It will be owned by a pre-defined unit test institution, affectionately
|
||||
called <cite>MEGA_CORP</cite> (this constant, along with many others, is defined in <cite>TestUtils.kt</cite>). Due to Kotin’s extensive
|
||||
called <code class="docutils literal"><span class="pre">MEGA_CORP</span></code> (this constant, along with many others, is defined in <code class="docutils literal"><span class="pre">TestUtils.kt</span></code>). Due to Kotin’s extensive
|
||||
type inference, many types are not written out explicitly in this code and it has the feel of a scripting language.
|
||||
But the types are there, and you can ask IntelliJ to reveal them by pressing Alt-Enter on a “val” or “var” and selecting
|
||||
“Specify type explicitly”.</p>
|
||||
@ -592,20 +587,20 @@ But the types are there, and you can ask IntelliJ to reveal them by pressing Alt
|
||||
<p>If you examine the code in the actual repository, you will also notice that it makes use of method names with spaces
|
||||
in them by surrounding the name with backticks, rather than using underscores. We don’t show this here as it breaks the
|
||||
doc website’s syntax highlighting engine.</p>
|
||||
<p>The <cite>1000.DOLLARS</cite> construct is quite simple: Kotlin allows you to define extension functions on primitive types like
|
||||
<p>The <code class="docutils literal"><span class="pre">1000.DOLLARS</span></code> construct is quite simple: Kotlin allows you to define extension functions on primitive types like
|
||||
Int or Double. So by writing 7.days, for instance, the compiler will emit a call to a static method that takes an int
|
||||
and returns a <cite>java.time.Duration</cite>.</p>
|
||||
and returns a <code class="docutils literal"><span class="pre">java.time.Duration</span></code>.</p>
|
||||
<p>As this is JUnit, we must remember to annotate each test method with @Test. Let’s examine the contents of the first test.
|
||||
We are trying to check that it’s not possible for just anyone to issue commercial paper in MegaCorp’s name. That would
|
||||
be bad!</p>
|
||||
<p>The <cite>transactionGroup</cite> function works the same way as the <cite>requireThat</cite> construct above. It is an example of what
|
||||
<p>The <code class="docutils literal"><span class="pre">transactionGroup</span></code> function works the same way as the <code class="docutils literal"><span class="pre">requireThat</span></code> construct above. It is an example of what
|
||||
Kotlin calls a type safe builder, which you can read about in <a class="reference external" href="https://kotlinlang.org/docs/reference/type-safe-builders.html">the documentation for builders</a>.
|
||||
The code block that follows it is run in the scope of a freshly created <cite>TransactionGroupForTest</cite> object, which assists
|
||||
The code block that follows it is run in the scope of a freshly created <code class="docutils literal"><span class="pre">TransactionGroupForTest</span></code> object, which assists
|
||||
you with building little transaction graphs and verifying them as a whole. Here, our “group” only actually has a
|
||||
single transaction in it, with a single output, no inputs, and an Issue command signed by <cite>DUMMY_PUBKEY_1</cite> which is just
|
||||
an arbitrary public key. As the paper claims to be issued by <cite>MEGA_CORP</cite>, this doesn’t match and should cause a
|
||||
failure. The <cite>expectFailureOfTx</cite> method takes a 1-based index (in this case we expect the first transaction to fail)
|
||||
and a string that should appear in the exception message. Then it runs the <cite>TransactionGroup.verify()</cite> method to
|
||||
single transaction in it, with a single output, no inputs, and an Issue command signed by <code class="docutils literal"><span class="pre">DUMMY_PUBKEY_1</span></code> which is just
|
||||
an arbitrary public key. As the paper claims to be issued by <code class="docutils literal"><span class="pre">MEGA_CORP</span></code>, this doesn’t match and should cause a
|
||||
failure. The <code class="docutils literal"><span class="pre">expectFailureOfTx</span></code> method takes a 1-based index (in this case we expect the first transaction to fail)
|
||||
and a string that should appear in the exception message. Then it runs the <code class="docutils literal"><span class="pre">TransactionGroup.verify()</span></code> method to
|
||||
invoke all the involved contracts.</p>
|
||||
<p>It’s worth bearing in mind that even though this code may look like a totally different language to normal Kotlin or
|
||||
Java, it’s actually not, and so you can embed arbitrary code anywhere inside any of these blocks.</p>
|
||||
@ -660,22 +655,22 @@ Java, it’s actually not, and so you can embed arbitrary code anywhere insi
|
||||
</div>
|
||||
<p>In this example we see some new features of the DSL:</p>
|
||||
<ul class="simple">
|
||||
<li>The <cite>roots</cite> construct. Sometimes you don’t want to write transactions that laboriously issue everything you need
|
||||
in a formally correct way. Inside <cite>roots</cite> you can create a bunch of states without any contract checking what you’re
|
||||
<li>The <code class="docutils literal"><span class="pre">roots</span></code> construct. Sometimes you don’t want to write transactions that laboriously issue everything you need
|
||||
in a formally correct way. Inside <code class="docutils literal"><span class="pre">roots</span></code> you can create a bunch of states without any contract checking what you’re
|
||||
doing. As states may not exist outside of transactions, each line inside defines a fake/invalid transaction with the
|
||||
given output states, which may be <em>labelled</em> with a short string. Those labels can be used later to join transactions
|
||||
together.</li>
|
||||
<li>The <cite>.CASH</cite> suffix. This is a part of the unit test DSL specific to the cash contract. It takes a monetary amount
|
||||
<li>The <code class="docutils literal"><span class="pre">.CASH</span></code> suffix. This is a part of the unit test DSL specific to the cash contract. It takes a monetary amount
|
||||
like 1000.DOLLARS and then wraps it in a cash ledger state, with some fake data.</li>
|
||||
<li>The owned_by <a class="reference external" href="https://kotlinlang.org/docs/reference/functions.html#infix-notation">infix function</a>. This is just
|
||||
a normal function that we’re allowed to write in a slightly different way, which returns a copy of the cash state
|
||||
with the owner field altered to be the given public key. <cite>ALICE</cite> is a constant defined by the test utilities that
|
||||
is, like <cite>DUMMY_PUBKEY_1</cite>, just an arbitrary keypair.</li>
|
||||
with the owner field altered to be the given public key. <code class="docutils literal"><span class="pre">ALICE</span></code> is a constant defined by the test utilities that
|
||||
is, like <code class="docutils literal"><span class="pre">DUMMY_PUBKEY_1</span></code>, just an arbitrary keypair.</li>
|
||||
<li>We are now defining several transactions that chain together. We can optionally label any output we create. Obviously
|
||||
then, the <cite>input</cite> method requires us to give the label of some other output that it connects to.</li>
|
||||
<li>The <cite>transaction</cite> function can also be given a time, to override the default timestamp on a transaction.</li>
|
||||
then, the <code class="docutils literal"><span class="pre">input</span></code> method requires us to give the label of some other output that it connects to.</li>
|
||||
<li>The <code class="docutils literal"><span class="pre">transaction</span></code> function can also be given a time, to override the default timestamp on a transaction.</li>
|
||||
</ul>
|
||||
<p>The <cite>trade</cite> function is not itself a unit test. Instead it builds up a trade/transaction group, with some slight
|
||||
<p>The <code class="docutils literal"><span class="pre">trade</span></code> function is not itself a unit test. Instead it builds up a trade/transaction group, with some slight
|
||||
differences depending on the parameters provided (Kotlin allows parameters to have default valus). Then it returns
|
||||
it, unexecuted.</p>
|
||||
<p>We use it like this:</p>
|
||||
@ -692,8 +687,8 @@ it, unexecuted.</p>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>That’s pretty simple: we just call <cite>verify</cite> in order to check all the transactions in the group. If any are invalid,
|
||||
an exception will be thrown indicating which transaction failed and why. In the second case, we call <cite>expectFailureOfTx</cite>
|
||||
<p>That’s pretty simple: we just call <code class="docutils literal"><span class="pre">verify</span></code> in order to check all the transactions in the group. If any are invalid,
|
||||
an exception will be thrown indicating which transaction failed and why. In the second case, we call <code class="docutils literal"><span class="pre">expectFailureOfTx</span></code>
|
||||
again to ensure the third transaction fails with a message that contains “must have matured” (it doesn’t have to be
|
||||
the exact message).</p>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user