mirror of
https://github.com/corda/corda.git
synced 2025-01-01 18:56:44 +00:00
Merge pull request #1828 from corda/tlil/misc-tutorial-fixes-v1
Tutorial Fixes (#1823)
This commit is contained in:
commit
2806d3301a
@ -28,7 +28,7 @@ class CommercialPaperTest {
|
|||||||
transaction {
|
transaction {
|
||||||
attachments(CP_PROGRAM_ID)
|
attachments(CP_PROGRAM_ID)
|
||||||
input(CP_PROGRAM_ID) { inState }
|
input(CP_PROGRAM_ID) { inState }
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,7 +43,7 @@ class CommercialPaperTest {
|
|||||||
input(CP_PROGRAM_ID) { inState }
|
input(CP_PROGRAM_ID) { inState }
|
||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
||||||
attachments(CP_PROGRAM_ID)
|
attachments(CP_PROGRAM_ID)
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ class CommercialPaperTest {
|
|||||||
input(CP_PROGRAM_ID) { inState }
|
input(CP_PROGRAM_ID) { inState }
|
||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
||||||
attachments(CP_PROGRAM_ID)
|
attachments(CP_PROGRAM_ID)
|
||||||
this `fails with` "the state is propagated"
|
`fails with`("the state is propagated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,9 +73,9 @@ class CommercialPaperTest {
|
|||||||
input(CP_PROGRAM_ID) { inState }
|
input(CP_PROGRAM_ID) { inState }
|
||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
||||||
attachments(CP_PROGRAM_ID)
|
attachments(CP_PROGRAM_ID)
|
||||||
this `fails with` "the state is propagated"
|
`fails with`("the state is propagated")
|
||||||
output(CP_PROGRAM_ID, "alice's paper") { inState.withOwner(ALICE) }
|
output(CP_PROGRAM_ID, "alice's paper") { inState.withOwner(ALICE) }
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,11 +92,11 @@ class CommercialPaperTest {
|
|||||||
// The wrong pubkey.
|
// The wrong pubkey.
|
||||||
command(BIG_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
command(BIG_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
||||||
timeWindow(TEST_TX_TIME)
|
timeWindow(TEST_TX_TIME)
|
||||||
this `fails with` "output states are issued by a command signer"
|
`fails with`("output states are issued by a command signer")
|
||||||
}
|
}
|
||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
||||||
timeWindow(TEST_TX_TIME)
|
timeWindow(TEST_TX_TIME)
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,11 +112,11 @@ class CommercialPaperTest {
|
|||||||
// The wrong pubkey.
|
// The wrong pubkey.
|
||||||
command(BIG_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
command(BIG_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
||||||
timeWindow(TEST_TX_TIME)
|
timeWindow(TEST_TX_TIME)
|
||||||
this `fails with` "output states are issued by a command signer"
|
`fails with`("output states are issued by a command signer")
|
||||||
}
|
}
|
||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
||||||
timeWindow(TEST_TX_TIME)
|
timeWindow(TEST_TX_TIME)
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// DOCEND 7
|
// DOCEND 7
|
||||||
@ -138,7 +138,7 @@ class CommercialPaperTest {
|
|||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
||||||
attachments(CP_PROGRAM_ID)
|
attachments(CP_PROGRAM_ID)
|
||||||
timeWindow(TEST_TX_TIME)
|
timeWindow(TEST_TX_TIME)
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ class CommercialPaperTest {
|
|||||||
output(CP_PROGRAM_ID, "alice's paper") { "paper".output<ICommercialPaperState>().withOwner(ALICE) }
|
output(CP_PROGRAM_ID, "alice's paper") { "paper".output<ICommercialPaperState>().withOwner(ALICE) }
|
||||||
command(ALICE_PUBKEY) { Cash.Commands.Move() }
|
command(ALICE_PUBKEY) { Cash.Commands.Move() }
|
||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,7 +171,7 @@ class CommercialPaperTest {
|
|||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
||||||
attachments(CP_PROGRAM_ID)
|
attachments(CP_PROGRAM_ID)
|
||||||
timeWindow(TEST_TX_TIME)
|
timeWindow(TEST_TX_TIME)
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction("Trade") {
|
transaction("Trade") {
|
||||||
@ -181,7 +181,7 @@ class CommercialPaperTest {
|
|||||||
output(CP_PROGRAM_ID, "alice's paper") { "paper".output<ICommercialPaperState>().withOwner(ALICE) }
|
output(CP_PROGRAM_ID, "alice's paper") { "paper".output<ICommercialPaperState>().withOwner(ALICE) }
|
||||||
command(ALICE_PUBKEY) { Cash.Commands.Move() }
|
command(ALICE_PUBKEY) { Cash.Commands.Move() }
|
||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction {
|
transaction {
|
||||||
@ -189,10 +189,10 @@ class CommercialPaperTest {
|
|||||||
// We moved a paper to another pubkey.
|
// We moved a paper to another pubkey.
|
||||||
output(CP_PROGRAM_ID, "bob's paper") { "paper".output<ICommercialPaperState>().withOwner(BOB) }
|
output(CP_PROGRAM_ID, "bob's paper") { "paper".output<ICommercialPaperState>().withOwner(BOB) }
|
||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fails()
|
fails()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// DOCEND 9
|
// DOCEND 9
|
||||||
@ -213,7 +213,7 @@ class CommercialPaperTest {
|
|||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
||||||
attachments(CP_PROGRAM_ID)
|
attachments(CP_PROGRAM_ID)
|
||||||
timeWindow(TEST_TX_TIME)
|
timeWindow(TEST_TX_TIME)
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction("Trade") {
|
transaction("Trade") {
|
||||||
@ -223,7 +223,7 @@ class CommercialPaperTest {
|
|||||||
output(CP_PROGRAM_ID, "alice's paper") { "paper".output<ICommercialPaperState>().withOwner(ALICE) }
|
output(CP_PROGRAM_ID, "alice's paper") { "paper".output<ICommercialPaperState>().withOwner(ALICE) }
|
||||||
command(ALICE_PUBKEY) { Cash.Commands.Move() }
|
command(ALICE_PUBKEY) { Cash.Commands.Move() }
|
||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
@ -232,12 +232,12 @@ class CommercialPaperTest {
|
|||||||
// We moved a paper to another pubkey.
|
// We moved a paper to another pubkey.
|
||||||
output(CP_PROGRAM_ID, "bob's paper") { "paper".output<ICommercialPaperState>().withOwner(BOB) }
|
output(CP_PROGRAM_ID, "bob's paper") { "paper".output<ICommercialPaperState>().withOwner(BOB) }
|
||||||
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Move() }
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
this.fails()
|
fails()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.verifies()
|
verifies()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// DOCEND 10
|
// DOCEND 10
|
||||||
|
@ -327,7 +327,7 @@ little odd: we have a *requireThat* construct that looks like it's built into th
|
|||||||
ordinary function provided by the platform's contract API. Kotlin supports the creation of *domain specific languages*
|
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
|
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" using (expression)`` statement
|
requirements. To see what it compiles down to, look at the Java version. Each ``"string" using (expression)`` statement
|
||||||
inside a ``requireThat`` turns into an assertion that the given expression is true, with an ``IllegalStateException``
|
inside a ``requireThat`` turns into an assertion that the given expression is true, with an ``IllegalArgumentException``
|
||||||
being thrown that contains the string if not. It's just another way to write out a regular assertion, but with the
|
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.
|
English-language requirement being put front and center.
|
||||||
|
|
||||||
@ -340,8 +340,8 @@ the owner.
|
|||||||
1. We still check there is a CP input state.
|
1. We still check there is a CP input state.
|
||||||
2. We want to see that the face value of the CP is being moved as a cash claim against some party, that is, the
|
2. We want to see that the face value of the CP is being moved as a cash claim against some party, that is, the
|
||||||
issuer of the CP is really paying back the face value.
|
issuer of the CP is really paying back the face value.
|
||||||
2. The transaction must be happening after the maturity date.
|
3. The transaction must be happening after the maturity date.
|
||||||
3. The commercial paper must *not* be propagated by this transaction: it must be deleted, by the group having no
|
4. 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.
|
output state. This prevents the same CP being considered redeemable multiple times.
|
||||||
|
|
||||||
To calculate how much cash is moving, we use the ``sumCashBy`` utility function. Again, this is an extension function,
|
To calculate how much cash is moving, we use the ``sumCashBy`` utility function. Again, this is an extension function,
|
||||||
@ -476,7 +476,7 @@ generate methods should operate on the same transaction. You can see an example
|
|||||||
for the commercial paper contract.
|
for the commercial paper contract.
|
||||||
|
|
||||||
The paper is given to us as a ``StateAndRef<CommercialPaper.State>`` object. This is exactly what it sounds like:
|
The paper is given to us as a ``StateAndRef<CommercialPaper.State>`` object. This is exactly what it sounds like:
|
||||||
a small object that has a (copy of) a state object, and also the (txhash, index) that indicates the location of this
|
a small object that has a (copy of a) state object, and also the ``(txhash, index)`` that indicates the location of this
|
||||||
state on the ledger.
|
state on the ledger.
|
||||||
|
|
||||||
We add the existing paper state as an input, the same paper state with the owner field adjusted as an output,
|
We add the existing paper state as an input, the same paper state with the owner field adjusted as an output,
|
||||||
|
@ -114,7 +114,7 @@ The above code however doesn't compile:
|
|||||||
|
|
||||||
Error:(35, 27) java: incompatible types: bad return type in lambda expression missing return value
|
Error:(35, 27) java: incompatible types: bad return type in lambda expression missing return value
|
||||||
|
|
||||||
This is deliberate: The DSL forces us to specify either ``this.verifies()`` or ``this `fails with` "some text"`` on the
|
This is deliberate: The DSL forces us to specify either ``verifies()`` or ```fails with`("some text")`` on the
|
||||||
last line of ``transaction``:
|
last line of ``transaction``:
|
||||||
|
|
||||||
.. container:: codeset
|
.. container:: codeset
|
||||||
@ -160,7 +160,7 @@ When run, that code produces the following error:
|
|||||||
net.corda.core.contracts.TransactionVerificationException$ContractRejection: java.lang.IllegalStateException: the state is propagated
|
net.corda.core.contracts.TransactionVerificationException$ContractRejection: java.lang.IllegalStateException: the state is propagated
|
||||||
|
|
||||||
The transaction verification failed, because we wanted to move paper but didn't specify an output - but the state should be propagated.
|
The transaction verification failed, because we wanted to move paper but didn't specify an output - but the state should be propagated.
|
||||||
However we can specify that this is an intended behaviour by changing ``this.verifies()`` to ``this `fails with` "the state is propagated"``:
|
However we can specify that this is an intended behaviour by changing ``verifies()`` to ```fails with`("the state is propagated")``:
|
||||||
|
|
||||||
.. container:: codeset
|
.. container:: codeset
|
||||||
|
|
||||||
@ -256,7 +256,7 @@ Now that we know how to define a single transaction, let's look at how to define
|
|||||||
:dedent: 4
|
:dedent: 4
|
||||||
|
|
||||||
In this example we declare that ``ALICE`` has $900 but we don't care where from. For this we can use
|
In this example we declare that ``ALICE`` has $900 but we don't care where from. For this we can use
|
||||||
``unverifiedTransaction``. Note how we don't need to specify ``this.verifies()``.
|
``unverifiedTransaction``. Note how we don't need to specify ``verifies()``.
|
||||||
|
|
||||||
Notice that we labelled output with ``"alice's $900"``, also in transaction named ``"Issuance"``
|
Notice that we labelled output with ``"alice's $900"``, also in transaction named ``"Issuance"``
|
||||||
we labelled a commercial paper with ``"paper"``. Now we can subsequently refer to them in other transactions, e.g.
|
we labelled a commercial paper with ``"paper"``. Now we can subsequently refer to them in other transactions, e.g.
|
||||||
@ -265,7 +265,7 @@ by ``input("alice's $900")`` or ``"paper".output<ICommercialPaperState>()``.
|
|||||||
The last transaction named ``"Trade"`` exemplifies simple fact of selling the ``CommercialPaper`` to Alice for her $900,
|
The last transaction named ``"Trade"`` exemplifies simple fact of selling the ``CommercialPaper`` to Alice for her $900,
|
||||||
$100 less than the face value at 10% interest after only 7 days.
|
$100 less than the face value at 10% interest after only 7 days.
|
||||||
|
|
||||||
We can also test whole ledger calling ``this.verifies()`` and ``this.fails()`` on the ledger level.
|
We can also test whole ledger calling ``verifies()`` and ``fails()`` on the ledger level.
|
||||||
To do so let's create a simple example that uses the same input twice:
|
To do so let's create a simple example that uses the same input twice:
|
||||||
|
|
||||||
.. container:: codeset
|
.. container:: codeset
|
||||||
@ -283,7 +283,7 @@ To do so let's create a simple example that uses the same input twice:
|
|||||||
:dedent: 4
|
:dedent: 4
|
||||||
|
|
||||||
The transactions ``verifies()`` individually, however the state was spent twice! That's why we need the global ledger
|
The transactions ``verifies()`` individually, however the state was spent twice! That's why we need the global ledger
|
||||||
verification (``this.fails()`` at the end). As in previous examples we can use ``tweak`` to create a local copy of the whole ledger:
|
verification (``fails()`` at the end). As in previous examples we can use ``tweak`` to create a local copy of the whole ledger:
|
||||||
|
|
||||||
.. container:: codeset
|
.. container:: codeset
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user