Regen docsite

This commit is contained in:
Mike Hearn 2016-02-25 13:29:28 +01:00
parent f32c83b8b3
commit dfc15a6bab
20 changed files with 614 additions and 328 deletions

View File

@ -1,4 +1,4 @@
# Sphinx build info version 1 # Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: b79bc8e267991c90208eba2e06b900db config: ad139b05c69c728d506a9770157eaa25
tags: 645f666f9bcd5a90fca523b33c5a78b7 tags: 645f666f9bcd5a90fca523b33c5a78b7

View File

@ -65,7 +65,7 @@ We use continuations for the following reasons:
* It allows us to write code that is free of callbacks, that looks like ordinary sequential code. * It allows us to write code that is free of callbacks, that looks like ordinary sequential code.
* A suspended continuation takes far less memory than a suspended thread. It can be as low as a few hundred bytes. * A suspended continuation takes far less memory than a suspended thread. It can be as low as a few hundred bytes.
In contrast a suspended Java stack can easily be 1mb in size. In contrast a suspended Java thread stack can easily be 1mb in size.
* It frees the developer from thinking (much) about persistence and serialisation. * It frees the developer from thinking (much) about persistence and serialisation.
A *state machine* is a piece of code that moves through various *states*. These are not the same as states in the data A *state machine* is a piece of code that moves through various *states*. These are not the same as states in the data
@ -86,10 +86,10 @@ Our protocol has two parties (B and S for buyer and seller) and will proceed as
1. S sends a ``StateAndRef`` pointing to the state they want to sell to B, along with info about the price they require 1. S sends a ``StateAndRef`` pointing to the state they want to sell to B, along with info about the price they require
B to pay. B to pay.
2. B sends to S a ``SignedWireTransaction`` that includes the state as input, B's cash as input, the state with the new 2. B sends to S a ``SignedTransaction`` that includes the state as input, B's cash as input, the state with the new
owner key as output, and any change cash as output. It contains a single signature from B but isn't valid because owner key as output, and any change cash as output. It contains a single signature from B but isn't valid because
it lacks a signature from S authorising movement of the asset. it lacks a signature from S authorising movement of the asset.
3. S signs it and hands the now finalised ``SignedWireTransaction`` back to B. 3. S signs it and hands the now finalised ``SignedTransaction`` back to B.
You can find the implementation of this protocol in the file ``contracts/protocols/TwoPartyTradeProtocol.kt``. You can find the implementation of this protocol in the file ``contracts/protocols/TwoPartyTradeProtocol.kt``.
@ -111,7 +111,7 @@ each side.
fun runSeller(smm: StateMachineManager, timestampingAuthority: LegallyIdentifiableNode, fun runSeller(smm: StateMachineManager, timestampingAuthority: LegallyIdentifiableNode,
otherSide: SingleMessageRecipient, assetToSell: StateAndRef<OwnableState>, price: Amount, otherSide: SingleMessageRecipient, assetToSell: StateAndRef<OwnableState>, price: Amount,
myKeyPair: KeyPair, buyerSessionID: Long): ListenableFuture<Pair<WireTransaction, LedgerTransaction>> { myKeyPair: KeyPair, buyerSessionID: Long): ListenableFuture<SignedTransaction> {
val seller = Seller(otherSide, timestampingAuthority, assetToSell, price, myKeyPair, buyerSessionID) val seller = Seller(otherSide, timestampingAuthority, assetToSell, price, myKeyPair, buyerSessionID)
smm.add("$TRADE_TOPIC.seller", seller) smm.add("$TRADE_TOPIC.seller", seller)
return seller.resultFuture return seller.resultFuture
@ -119,46 +119,46 @@ each side.
fun runBuyer(smm: StateMachineManager, timestampingAuthority: LegallyIdentifiableNode, fun runBuyer(smm: StateMachineManager, timestampingAuthority: LegallyIdentifiableNode,
otherSide: SingleMessageRecipient, acceptablePrice: Amount, typeToBuy: Class<out OwnableState>, otherSide: SingleMessageRecipient, acceptablePrice: Amount, typeToBuy: Class<out OwnableState>,
sessionID: Long): ListenableFuture<Pair<WireTransaction, LedgerTransaction>> { sessionID: Long): ListenableFuture<SignedTransaction> {
val buyer = Buyer(otherSide, timestampingAuthority.identity, acceptablePrice, typeToBuy, sessionID) val buyer = Buyer(otherSide, timestampingAuthority.identity, acceptablePrice, typeToBuy, sessionID)
smm.add("$TRADE_TOPIC.buyer", buyer) smm.add("$TRADE_TOPIC.buyer", buyer)
return buyer.resultFuture return buyer.resultFuture
} }
class Seller(val otherSide: SingleMessageRecipient,
val timestampingAuthority: LegallyIdentifiableNode,
val assetToSell: StateAndRef<OwnableState>,
val price: Amount,
val myKeyPair: KeyPair,
val buyerSessionID: Long) : ProtocolStateMachine<Pair<WireTransaction, LedgerTransaction>>() {
@Suspendable
override fun call(): Pair<WireTransaction, LedgerTransaction> {
TODO()
}
}
// This object is serialised to the network and is the first protocol message the seller sends to the buyer. // This object is serialised to the network and is the first protocol message the seller sends to the buyer.
private class SellerTradeInfo( class SellerTradeInfo(
val assetForSale: StateAndRef<OwnableState>, val assetForSale: StateAndRef<OwnableState>,
val price: Amount, val price: Amount,
val sellerOwnerKey: PublicKey, val sellerOwnerKey: PublicKey,
val sessionID: Long val sessionID: Long
) )
class SignaturesFromSeller(val timestampAuthoritySig: DigitalSignature.WithKey, val sellerSig: DigitalSignature.WithKey)
class Seller(val otherSide: SingleMessageRecipient,
val timestampingAuthority: LegallyIdentifiableNode,
val assetToSell: StateAndRef<OwnableState>,
val price: Amount,
val myKeyPair: KeyPair,
val buyerSessionID: Long) : ProtocolLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
TODO()
}
}
class UnacceptablePriceException(val givenPrice: Amount) : Exception() class UnacceptablePriceException(val givenPrice: Amount) : Exception()
class AssetMismatchException(val expectedTypeName: String, val typeName: String) : Exception() { class AssetMismatchException(val expectedTypeName: String, val typeName: String) : Exception() {
override fun toString() = "The submitted asset didn't match the expected type: $expectedTypeName vs $typeName" override fun toString() = "The submitted asset didn't match the expected type: $expectedTypeName vs $typeName"
} }
// The buyer's side of the protocol. See note above Seller to learn about the caveats here.
class Buyer(val otherSide: SingleMessageRecipient, class Buyer(val otherSide: SingleMessageRecipient,
val timestampingAuthority: Party, val timestampingAuthority: Party,
val acceptablePrice: Amount, val acceptablePrice: Amount,
val typeToBuy: Class<out OwnableState>, val typeToBuy: Class<out OwnableState>,
val sessionID: Long) : ProtocolStateMachine<Pair<WireTransaction, LedgerTransaction>>() { val sessionID: Long) : ProtocolLogic<SignedTransaction>() {
@Suspendable @Suspendable
override fun call(): Pair<WireTransaction, LedgerTransaction> { override fun call(): SignedTransaction {
TODO() TODO()
} }
} }
@ -167,7 +167,7 @@ each side.
Let's unpack what this code does: Let's unpack what this code does:
- It defines a several classes nested inside the main ``TwoPartyTradeProtocol`` singleton, and a couple of methods, one - It defines a several classes nested inside the main ``TwoPartyTradeProtocol`` singleton, and a couple of methods, one
to run the buyer side of the protocol and one to run the seller side. to run the buyer side of the protocol and one to run the seller side. Some of the classes are simply protocol messages.
- It defines the "trade topic", which is just a string that namespaces this protocol. The prefix "platform." is reserved - It defines the "trade topic", which is just a string that namespaces this protocol. The prefix "platform." is reserved
by the DLG, but you can define your own protocols using standard Java-style reverse DNS notation. by the DLG, but you can define your own protocols using standard Java-style reverse DNS notation.
- The ``runBuyer`` and ``runSeller`` methods take a number of parameters that specialise the protocol for this run, - The ``runBuyer`` and ``runSeller`` methods take a number of parameters that specialise the protocol for this run,
@ -205,7 +205,8 @@ to either runBuyer or runSeller, depending on who we are, and then call ``.get()
block the calling thread until the protocol has finished. Or we could register a callback on the returned future that block the calling thread until the protocol has finished. Or we could register a callback on the returned future that
will be invoked when it's done, where we could e.g. update a user interface. will be invoked when it's done, where we could e.g. update a user interface.
Finally, we define a couple of exceptions, and a class that will be used as a protocol message called ``SellerTradeInfo``. Finally, we define a couple of exceptions, and two classes that will be used as a protocol message called
``SellerTradeInfo`` and ``SignaturesFromSeller``.
Suspendable methods Suspendable methods
------------------- -------------------
@ -244,13 +245,72 @@ Let's implement the ``Seller.call`` method. This will be invoked by the platform
.. sourcecode:: kotlin .. sourcecode:: kotlin
val partialTX: SignedTransaction = receiveAndCheckProposedTransaction()
// These two steps could be done in parallel, in theory. Our framework doesn't support that yet though.
val ourSignature = signWithOurKey(partialTX)
val tsaSig = subProtocol(TimestampingProtocol(timestampingAuthority, partialTX.txBits))
val stx: SignedTransaction = sendSignatures(partialTX, ourSignature, tsaSig)
return stx
Here we see the outline of the procedure. We receive a proposed trade transaction from the buyer and check that it's
valid. Then we sign with our own key, request a timestamping authority to assert with another signature that the
timestamp in the transaction (if any) is valid, and finally we send back both our signature and the TSA's signature.
Finally, we hand back to the code that invoked the protocol the finished transaction in a couple of different forms.
.. note:: ``ProtocolLogic`` classes can be composed together. Here, we see the use of the ``subProtocol`` method, which
is given an instance of ``TimestampingProtocol``. This protocol will run to completion and yield a result, almost
as if it's a regular method call. In fact, under the hood, all the ``subProtocol`` method does is pass the current
fiber object into the newly created object and then run ``call()`` on it ... so it basically _is_ just a method call.
This is where we can see the benefits of using continuations/fibers as a programming model.
Let's fill out the ``receiveAndCheckProposedTransaction()`` method.
.. container:: codeset
.. sourcecode:: kotlin
@Suspendable
open fun receiveAndCheckProposedTransaction(): SignedTransaction {
val sessionID = random63BitValue() val sessionID = random63BitValue()
// Make the first message we'll send to kick off the protocol. // Make the first message we'll send to kick off the protocol.
val hello = SellerTradeInfo(assetToSell, price, myKeyPair.public, sessionID) val hello = SellerTradeInfo(assetToSell, price, myKeyPair.public, sessionID)
val partialTX = sendAndReceive(TRADE_TOPIC, buyerSessionID, sessionID, hello, SignedWireTransaction::class.java) val maybeSTX = sendAndReceive<SignedTransaction>(TRADE_TOPIC, otherSide, buyerSessionID, sessionID, hello)
logger().trace { "Received partially signed transaction" }
maybeSTX.validate {
// Check that the tx proposed by the buyer is valid.
val missingSigs = it.verify(throwIfSignaturesAreMissing = false)
if (missingSigs != setOf(myKeyPair.public, timestampingAuthority.identity.owningKey))
throw SignatureException("The set of missing signatures is not as expected: $missingSigs")
val wtx: WireTransaction = it.tx
logger.trace { "Received partially signed transaction: ${it.id}" }
checkDependencies(it)
// This verifies that the transaction is contract-valid, even though it is missing signatures.
serviceHub.verifyTransaction(wtx.toLedgerTransaction(serviceHub.identityService))
if (wtx.outputs.sumCashBy(myKeyPair.public) != price)
throw IllegalArgumentException("Transaction is not sending us the right amounnt of cash")
// There are all sorts of funny games a malicious secondary might play here, we should fix them:
//
// - This tx may attempt to send some assets we aren't intending to sell to the secondary, if
// we're reusing keys! So don't reuse keys!
// - This tx may include output states that impose odd conditions on the movement of the cash,
// once we implement state pairing.
//
// but the goal of this code is not to be fully secure (yet), but rather, just to find good ways to
// express protocol state machines on top of the messaging layer.
return it
}
}
That's pretty straightforward. We generate a session ID to identify what's happening on the seller side, fill out That's pretty straightforward. We generate a session ID to identify what's happening on the seller side, fill out
the initial protocol message, and then call ``sendAndReceive``. This function takes a few arguments: the initial protocol message, and then call ``sendAndReceive``. This function takes a few arguments:
@ -260,7 +320,7 @@ the initial protocol message, and then call ``sendAndReceive``. This function ta
- The thing to send. It'll be serialised and sent automatically. - The thing to send. It'll be serialised and sent automatically.
- Finally a type argument, which is the kind of object we're expecting to receive from the other side. - Finally a type argument, which is the kind of object we're expecting to receive from the other side.
Once sendAndReceive is called, the call method will be suspended into a continuation. When it gets back we'll do a log Once ``sendAndReceive`` is called, the call method will be suspended into a continuation. When it gets back we'll do a log
message. The buyer is supposed to send us a transaction with all the right inputs/outputs/commands in return, with their message. The buyer is supposed to send us a transaction with all the right inputs/outputs/commands in return, with their
cash put into the transaction and their signature on it authorising the movement of the cash. cash put into the transaction and their signature on it authorising the movement of the cash.
@ -273,51 +333,70 @@ cash put into the transaction and their signature on it authorising the movement
doing things like creating threads from inside these calls would be a bad idea. They should only contain business doing things like creating threads from inside these calls would be a bad idea. They should only contain business
logic. logic.
OK, let's keep going: You get back a simple wrapper class, ``UntrustworthyData<SignedTransaction>``, which is just a marker class that reminds
us that the data came from a potentially malicious external source and may have been tampered with or be unexpected in
other ways. It doesn't add any functionality, but acts as a reminder to "scrub" the data before use. Here, our scrubbing
simply involves checking the signatures on it. Then we go ahead and check all the dependencies of this partial
transaction for validity. Here's the code to do that:
.. container:: codeset .. container:: codeset
.. sourcecode:: kotlin .. sourcecode:: kotlin
partialTX.verifySignatures() @Suspendable
val wtx = partialTX.txBits.deserialize<WireTransaction>() private fun checkDependencies(stx: SignedTransaction) {
// Download and check all the transactions that this transaction depends on, but do not check this
requireThat { // transaction itself.
"transaction sends us the right amount of cash" by (wtx.outputStates.sumCashBy(args.myKeyPair.public) == args.price) val dependencyTxIDs = stx.tx.inputs.map { it.txhash }.toSet()
// There are all sorts of funny games a malicious secondary might play here, we should fix them: subProtocol(ResolveTransactionsProtocol(dependencyTxIDs, otherSide))
//
// - This tx may attempt to send some assets we aren't intending to sell to the secondary, if
// we're reusing keys! So don't reuse keys!
// - This tx may not be valid according to the contracts of the input states, so we must resolve
// and fully audit the transaction chains to convince ourselves that it is actually valid.
// - This tx may include output states that impose odd conditions on the movement of the cash,
// once we implement state pairing.
} }
val ourSignature = args.myKeyPair.signWithECDSA(partialTX.txBits.bits) This is simple enough: we mark the method as ``@Suspendable`` because we're going to invoke a sub-protocol, extract the
val fullySigned: SignedWireTransaction = partialTX.copy(sigs = partialTX.sigs + ourSignature) IDs of the transactions the proposed transaction depends on, and then uses a protocol provided by the system to download
fullySigned.verify() and check them all. This protocol does a breadth-first search over the dependency graph, bottoming out at issuance
val timestamped: TimestampedWireTransaction = fullySigned.toTimestampedTransaction(serviceHub.timestampingService) transactions that don't have any inputs themselves. Once the node has audited the transaction history, all the dependencies
logger().trace { "Built finished transaction, sending back to secondary!" } are committed to the node's local database so they won't be checked again next time.
send(TRADE_TOPIC, sessionID, timestamped) .. note:: Transaction dependency resolution assumes that the peer you got the transaction from has all of the
dependencies itself. It must do, otherwise it could not have convinced itself that the dependencies were themselves
valid. It's important to realise that requesting only the transactions we require is a privacy leak, because if
we don't download a transaction from the peer, they know we must have already seen it before. Fixing this privacy
leak will come later.
return Pair(timestamped, timestamped.verifyToLedgerTransaction(serviceHub.timestampingService, serviceHub.identityService)) After the dependencies, we check the proposed trading transaction for validity by running the contracts for that as
well (but having handled the fact that some signatures are missing ourselves).
Here, we see some assertions and signature checking to satisfy ourselves that we're not about to sign something Here's the rest of the code:
incorrect. Once we're happy, we calculate a signature over the transaction to authorise the movement of the asset
we are selling, and then we verify things to make sure it's all OK. Finally, we request timestamping of the .. container:: codeset
transaction, in case the contracts governing the asset we're selling require it, and send the now finalised and
validated transaction back to the buyer. .. sourcecode:: kotlin
open fun signWithOurKey(partialTX: SignedTransaction) = myKeyPair.signWithECDSA(partialTX.txBits)
@Suspendable
open fun sendSignatures(partialTX: SignedTransaction, ourSignature: DigitalSignature.WithKey,
tsaSig: DigitalSignature.LegallyIdentifiable): SignedTransaction {
val fullySigned = partialTX + tsaSig + ourSignature
logger.trace { "Built finished transaction, sending back to secondary!" }
send(TRADE_TOPIC, otherSide, buyerSessionID, SignaturesFromSeller(tsaSig, ourSignature))
return fullySigned
}
It's should be all pretty straightforward: here, ``txBits`` is the raw byte array representing the transaction.
In ``sendSignatures``, we take the two signatures we calculated, then add them to the partial transaction we were sent.
We provide an overload for the + operator so signatures can be added to a SignedTransaction easily. Finally, we wrap the
two signatures in a simple wrapper message class and send it back. The send won't block waiting for an acknowledgement,
but the underlying message queue software will retry delivery if the other side has gone away temporarily.
.. warning:: This code is **not secure**. Other than not checking for all possible invalid constructions, if the .. warning:: This code is **not secure**. Other than not checking for all possible invalid constructions, if the
seller stops before sending the finalised transaction to the buyer, the seller is left with a valid transaction seller stops before sending the finalised transaction to the buyer, the seller is left with a valid transaction
but the buyer isn't, so they can't spend the asset they just purchased! This sort of thing will be fixed in a but the buyer isn't, so they can't spend the asset they just purchased! This sort of thing will be fixed in a
future version of the code. future version of the code.
Finally, the call function returns with the result of the protocol: in our case, the final transaction in two different
forms.
Implementing the buyer Implementing the buyer
---------------------- ----------------------
@ -328,82 +407,99 @@ OK, let's do the same for the buyer side:
.. sourcecode:: kotlin .. sourcecode:: kotlin
@Suspendable @Suspendable
override fun call(): Pair<TimestampedWireTransaction, LedgerTransaction> { override fun call(): SignedTransaction {
// Wait for a trade request to come in on our pre-provided session ID. val tradeRequest = receiveAndValidateTradeRequest()
val tradeRequest = receive(TRADE_TOPIC, args.sessionID, SellerTradeInfo::class.java) val (ptx, cashSigningPubKeys) = assembleSharedTX(tradeRequest)
val stx = signWithOurKeys(cashSigningPubKeys, ptx)
val signatures = swapSignaturesWithSeller(stx, tradeRequest.sessionID)
logger.trace { "Got signatures from seller, verifying ... "}
val fullySigned = stx + signatures.timestampAuthoritySig + signatures.sellerSig
fullySigned.verify()
logger.trace { "Fully signed transaction was valid. Trade complete! :-)" }
return fullySigned
}
@Suspendable
open fun receiveAndValidateTradeRequest(): SellerTradeInfo {
// Wait for a trade request to come in on our pre-provided session ID.
val maybeTradeRequest = receive<SellerTradeInfo>(TRADE_TOPIC, sessionID)
maybeTradeRequest.validate {
// What is the seller trying to sell us? // What is the seller trying to sell us?
val assetTypeName = tradeRequest.assetForSale.state.javaClass.name val asset = it.assetForSale.state
logger().trace { "Got trade request for a $assetTypeName" } val assetTypeName = asset.javaClass.name
logger.trace { "Got trade request for a $assetTypeName: ${it.assetForSale}" }
// Check the start message for acceptability. // Check the start message for acceptability.
check(tradeRequest.sessionID > 0) check(it.sessionID > 0)
if (tradeRequest.price > acceptablePrice) if (it.price > acceptablePrice)
throw UnacceptablePriceException(tradeRequest.price) throw UnacceptablePriceException(it.price)
if (!typeToBuy.isInstance(tradeRequest.assetForSale.state)) if (!typeToBuy.isInstance(asset))
throw AssetMismatchException(typeToBuy.name, assetTypeName) throw AssetMismatchException(typeToBuy.name, assetTypeName)
// TODO: Either look up the stateref here in our local db, or accept a long chain // Check the transaction that contains the state which is being resolved.
// of states and validate them to audit the other side and ensure it actually owns // We only have a hash here, so if we don't know it already, we have to ask for it.
// the state we are being offered! For now, just assume validity! subProtocol(ResolveTransactionsProtocol(setOf(it.assetForSale.ref.txhash), otherSide))
// Generate the shared transaction that both sides will sign, using the data we have. return it
val ptx = TransactionBuilder() }
// Add input and output states for the movement of cash, by using the Cash contract }
// to generate the states.
val wallet = serviceHub.walletService.currentWallet
val cashStates = wallet.statesOfType<Cash.State>()
val cashSigningPubKeys = Cash().craftSpend(ptx, tradeRequest.price,
tradeRequest.sellerOwnerKey, cashStates)
// Add inputs/outputs/a command for the movement of the asset.
ptx.addInputState(tradeRequest.assetForSale.ref)
// Just pick some new public key for now.
val freshKey = serviceHub.keyManagementService.freshKey()
val (command, state) = tradeRequest.assetForSale.state.withNewOwner(freshKey.public)
ptx.addOutputState(state)
ptx.addArg(WireCommand(command, tradeRequest.assetForSale.state.owner))
@Suspendable
open fun swapSignaturesWithSeller(stx: SignedTransaction, theirSessionID: Long): SignaturesFromSeller {
logger.trace { "Sending partially signed transaction to seller" }
// TODO: Protect against the seller terminating here and leaving us in the lurch without the final tx.
return sendAndReceive(TRADE_TOPIC, otherSide, theirSessionID, sessionID, stx, SignaturesFromSeller::class.java).validate { it }
}
open fun signWithOurKeys(cashSigningPubKeys: List<PublicKey>, ptx: TransactionBuilder): SignedTransaction {
// Now sign the transaction with whatever keys we need to move the cash. // Now sign the transaction with whatever keys we need to move the cash.
for (k in cashSigningPubKeys) { for (k in cashSigningPubKeys) {
val priv = serviceHub.keyManagementService.toPrivate(k) val priv = serviceHub.keyManagementService.toPrivate(k)
ptx.signWith(KeyPair(k, priv)) ptx.signWith(KeyPair(k, priv))
} }
val stx = ptx.toSignedTransaction(checkSufficientSignatures = false) return ptx.toSignedTransaction(checkSufficientSignatures = false)
stx.verifySignatures() // Verifies that we generated a signed transaction correctly. }
// TODO: Could run verify() here to make sure the only signature missing is the sellers. open fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair<TransactionBuilder, List<PublicKey>> {
val ptx = TransactionBuilder()
// Add input and output states for the movement of cash, by using the Cash contract to generate the states.
val wallet = serviceHub.walletService.currentWallet
val cashStates = wallet.statesOfType<Cash.State>()
val cashSigningPubKeys = Cash().generateSpend(ptx, tradeRequest.price, tradeRequest.sellerOwnerKey, cashStates)
// Add inputs/outputs/a command for the movement of the asset.
ptx.addInputState(tradeRequest.assetForSale.ref)
// Just pick some new public key for now. This won't be linked with our identity in any way, which is what
// we want for privacy reasons: the key is here ONLY to manage and control ownership, it is not intended to
// reveal who the owner actually is. The key management service is expected to derive a unique key from some
// initial seed in order to provide privacy protection.
val freshKey = serviceHub.keyManagementService.freshKey()
val (command, state) = tradeRequest.assetForSale.state.withNewOwner(freshKey.public)
ptx.addOutputState(state)
ptx.addCommand(command, tradeRequest.assetForSale.state.owner)
logger().trace { "Sending partially signed transaction to seller" } // And add a request for timestamping: it may be that none of the contracts need this! But it can't hurt
// to have one.
// TODO: Protect against the buyer terminating here and leaving us in the lurch without ptx.setTime(Instant.now(), timestampingAuthority, 30.seconds)
// the final tx. return Pair(ptx, cashSigningPubKeys)
// TODO: Protect against a malicious buyer sending us back a different transaction to
// the one we built.
val fullySigned = sendAndReceive(TRADE_TOPIC, tradeRequest.sessionID, sessionID, stx,
TimestampedWireTransaction::class.java)
logger().trace { "Got fully signed transaction, verifying ... "}
val ltx = fullySigned.verifyToLedgerTransaction(serviceHub.timestampingService,
serviceHub.identityService)
logger().trace { "Fully signed transaction was valid. Trade complete! :-)" }
return Pair(fullySigned, ltx)
} }
This code is longer but still fairly straightforward. Here are some things to pay attention to: This code is longer but still fairly straightforward. Here are some things to pay attention to:
1. We do some sanity checking on the received message to ensure we're being offered what we expected to be offered. 1. We do some sanity checking on the received message to ensure we're being offered what we expected to be offered.
2. We create a cash spend in the normal way, by using ``Cash().craftSpend``. See the contracts tutorial if this isn't 2. We create a cash spend in the normal way, by using ``Cash().generateSpend``. See the contracts tutorial if this isn't
clear. clear.
3. We access the *service hub* when we need it to access things that are transient and may change or be recreated 3. We access the *service hub* when we need it to access things that are transient and may change or be recreated
whilst a protocol is suspended, things like the wallet or the timestamping service. Remember that a protocol may whilst a protocol is suspended, things like the wallet or the timestamping service. Remember that a protocol may
be suspended when it waits to receive a message across node or computer restarts, so objects representing a service be suspended when it waits to receive a message across node or computer restarts, so objects representing a service
or data which may frequently change should be accessed 'just in time'. or data which may frequently change should be accessed 'just in time'.
4. Finally, we send the unfinsished, invalid transaction to the seller so they can sign it. They are expected to send 4. Finally, we send the unfinished, invalid transaction to the seller so they can sign it. They are expected to send
back to us a ``TimestampedWireTransaction``, which once we verify it, should be the final outcome of the trade. back to us a ``SignaturesFromSeller``, which once we verify it, should be the final outcome of the trade.
As you can see, the protocol logic is straightforward and does not contain any callbacks or network glue code, despite As you can see, the protocol logic is straightforward and does not contain any callbacks or network glue code, despite
the fact that it takes minimal resources and can survive node restarts. the fact that it takes minimal resources and can survive node restarts.
@ -415,3 +511,52 @@ the fact that it takes minimal resources and can survive node restarts.
this problem doesn't occur. It's also restored for you when a protocol state machine is restored after a node this problem doesn't occur. It's also restored for you when a protocol state machine is restored after a node
restart. restart.
Progress tracking
-----------------
Not shown in the code snippets above is the usage of the ``ProgressTracker`` API. Progress tracking exports information
from a protocol about where it's got up to in such a way that observers can render it in a useful manner to humans who
may need to be informed. It may be rendered via an API, in a GUI, onto a terminal window, etc.
A ``ProgressTracker`` is constructed with a series of ``Step`` objects, where each step is an object representing a
stage in a piece of work. It is therefore typical to use singletons that subclass ``Step``, which may be defined easily
in one line when using Kotlin. Typical steps might be "Waiting for response from peer", "Waiting for signature to be
approved", "Downloading and verifying data" etc.
Each step exposes a label. By default labels are fixed, but by subclassing ``RelabelableStep``
you can make a step that can update its label on the fly. That's useful for steps that want to expose non-structured
progress information like the current file being downloaded. By defining your own step types, you can export progress
in a way that's both human readable and machine readable.
Progress trackers are hierarchical. Each step can be the parent for another tracker. By altering the
``ProgressTracker.childrenFor[step] = tracker`` map, a tree of steps can be created. It's allowed to alter the hierarchy
at runtime, on the fly, and the progress renderers will adapt to that properly. This can be helpful when you don't
fully know ahead of time what steps will be required. If you _do_ know what is required, configuring as much of the
hierarchy ahead of time is a good idea, as that will help the users see what is coming up.
Every tracker has not only the steps given to it at construction time, but also the singleton
``ProgressTracker.UNSTARTED`` step and the ``ProgressTracker.DONE`` step. Once a tracker has become ``DONE`` its
position may not be modified again (because e.g. the UI may have been removed/cleaned up), but until that point, the
position can be set to any arbitrary set both forwards and backwards. Steps may be skipped, repeated, etc. Note that
rolling the current step backwards will delete any progress trackers that are children of the steps being reversed, on
the assumption that those subtasks will have to be repeated.
Trackers provide an `Rx observable <http://reactivex.io/>`_ which streams changes to the hierarchy. The top level
observable exposes all the events generated by its children as well. The changes are represented by objects indicating
whether the change is one of position (i.e. progress), structure (i.e. new subtasks being added/removed) or some other
aspect of rendering (i.e. a step has changed in some way and is requesting a re-render).
The protocol framework is somewhat integrated with this API. Each ``ProtocolLogic`` may optionally provide a tracker by
overriding the ``protocolTracker`` property (``getProtocolTracker`` method in Java). If the
``ProtocolLogic.subProtocol`` method is used, then the tracker of the sub-protocol will be made a child of the current
step in the parent protocol automatically, if the parent is using tracking in the first place. The framework will also
automatically set the current step to ``DONE`` for you, when the protocol is finished.
Because a protocol may sometimes wish to configure the children in its progress hierarchy _before_ the sub-protocol
is constructed, for sub-protocols that always follow the same outline regardless of their parameters it's conventional
to define a companion object/static method (for Kotlin/Java respectively) that constructs a tracker, and then allow
the sub-protocol to have the tracker it will use be passed in as a parameter. This allows all trackers to be built
and linked ahead of time.
In future, the progress tracking framework will become a vital part of how exceptions, errors, and other faults are
surfaced to human operators for investigation and resolution.

View File

@ -9,20 +9,20 @@ let us know.
Now, open two terminals, and in the first run::: Now, open two terminals, and in the first run:::
./gradlew runDemoBuyer ./scripts/trader-demo.sh buyer
It will create a directory named "buyer" and ask you to edit the configuration file inside. Open up ``buyer/config`` It will compile things, if necessary, then create a directory named "buyer" with a bunch of files inside and start
in your favourite text editor and give the node a legal identity of "Big Buyer Corp, Inc" or whatever else you feel like. the node. You should see it waiting for a trade to begin.
The actual text string is not important. Now run the gradle command again, and it should start up and wait for
a seller to connect.
In the second terminal, run:: In the second terminal, run::
./gradlew runDemoSeller ./scripts/trader-demo.sh seller
and repeat the process, this time calling the node ... something else.
You should see some log lines scroll past, and within a few seconds the messages "Purchase complete - we are a You should see some log lines scroll past, and within a few seconds the messages "Purchase complete - we are a
happy customer!" and "Sale completed - we have a happy customer!" should be printed. happy customer!" and "Sale completed - we have a happy customer!" should be printed.
If it doesn't work, jump on the mailing list and let us know. If it doesn't work, jump on the mailing list and let us know.
For Windows users, the contents of the shell script are very trivial and can easily be done by hand from a command
window. Essentially, it just runs Gradle to create the startup scripts, and then starts the node with one set of
flags or another.

View File

@ -636,22 +636,22 @@ again to ensure the third transaction fails with a message that contains "must h
the exact message). the exact message).
Adding a crafting API to your contract Adding a generation API to your contract
-------------------------------------- ----------------------------------------
Contract classes **must** provide a verify function, but they may optionally also provide helper functions to simplify Contract classes **must** provide a verify function, but they may optionally also provide helper functions to simplify
their usage. A simple class of functions most contracts provide are *crafting functions*, which either generate or their usage. A simple class of functions most contracts provide are *generation functions*, which either create or
modify a transaction to perform certain actions (an action is normally mappable 1:1 to a command, but doesn't have to modify a transaction to perform certain actions (an action is normally mappable 1:1 to a command, but doesn't have to
be so). be so).
Crafting may involve complex logic. For example, the cash contract has a ``craftSpend`` method that is given a set of Generation may involve complex logic. For example, the cash contract has a ``generateSpend`` method that is given a set of
cash states and chooses a way to combine them together to satisfy the amount of money that is being sent. In the cash states and chooses a way to combine them together to satisfy the amount of money that is being sent. In the
immutable-state model that we are using ledger entries (states) can only be created and deleted, but never modified. immutable-state model that we are using ledger entries (states) can only be created and deleted, but never modified.
Therefore to send $1200 when we have only $900 and $500 requires combining both states together, and then creating Therefore to send $1200 when we have only $900 and $500 requires combining both states together, and then creating
two new output states of $1200 and $200 back to ourselves. This latter state is called the *change* and is a concept two new output states of $1200 and $200 back to ourselves. This latter state is called the *change* and is a concept
that should be familiar to anyone who has worked with Bitcoin. that should be familiar to anyone who has worked with Bitcoin.
As another example, we can imagine code that implements a netting algorithm may craft complex transactions that must As another example, we can imagine code that implements a netting algorithm may generate complex transactions that must
be signed by many people. Whilst such code might be too big for a single utility method (it'd probably be sized more be signed by many people. Whilst such code might be too big for a single utility method (it'd probably be sized more
like a module), the basic concept is the same: preparation of a transaction using complex logic. like a module), the basic concept is the same: preparation of a transaction using complex logic.
@ -662,7 +662,7 @@ a method to wrap up the issuance process:
.. sourcecode:: kotlin .. sourcecode:: kotlin
fun craftIssue(issuance: InstitutionReference, faceValue: Amount, maturityDate: Instant): TransactionBuilder { fun generateIssue(issuance: InstitutionReference, faceValue: Amount, maturityDate: Instant): TransactionBuilder {
val state = State(issuance, issuance.party.owningKey, faceValue, maturityDate) val state = State(issuance, issuance.party.owningKey, faceValue, maturityDate)
return TransactionBuilder(state, WireCommand(Commands.Issue, issuance.party.owningKey)) return TransactionBuilder(state, WireCommand(Commands.Issue, issuance.party.owningKey))
} }
@ -673,7 +673,7 @@ returns a ``TransactionBuilder``. A ``TransactionBuilder`` is one of the few mut
It allows you to add inputs, outputs and commands to it and is designed to be passed around, potentially between It allows you to add inputs, outputs and commands to it and is designed to be passed around, potentially between
multiple contracts. multiple contracts.
.. note:: Crafting methods should ideally be written to compose with each other, that is, they should take a .. note:: Generation methods should ideally be written to compose with each other, that is, they should take a
``TransactionBuilder`` as an argument instead of returning one, unless you are sure it doesn't make sense to ``TransactionBuilder`` as an argument instead of returning one, unless you are sure it doesn't make sense to
combine this type of transaction with others. In this case, issuing CP at the same time as doing other things combine this type of transaction with others. In this case, issuing CP at the same time as doing other things
would just introduce complexity that isn't likely to be worth it, so we return a fresh object each time: instead, would just introduce complexity that isn't likely to be worth it, so we return a fresh object each time: instead,
@ -697,7 +697,7 @@ What about moving the paper, i.e. reassigning ownership to someone else?
.. sourcecode:: kotlin .. sourcecode:: kotlin
fun craftMove(tx: TransactionBuilder, paper: StateAndRef<State>, newOwner: PublicKey) { fun generateMove(tx: TransactionBuilder, paper: StateAndRef<State>, newOwner: PublicKey) {
tx.addInputState(paper.ref) tx.addInputState(paper.ref)
tx.addOutputState(paper.state.copy(owner = newOwner)) tx.addOutputState(paper.state.copy(owner = newOwner))
tx.addArg(WireCommand(Commands.Move, paper.state.owner)) tx.addArg(WireCommand(Commands.Move, paper.state.owner))
@ -705,7 +705,7 @@ What about moving the paper, i.e. reassigning ownership to someone else?
Here, the method takes a pre-existing ``TransactionBuilder`` and adds to it. This is correct because typically Here, the method takes a pre-existing ``TransactionBuilder`` and adds to it. This is correct because typically
you will want to combine a sale of CP atomically with the movement of some other asset, such as cash. So both you will want to combine a sale of CP atomically with the movement of some other asset, such as cash. So both
craft methods should operate on the same transaction. You can see an example of this being done in the unit tests generate methods should operate on the same transaction. You can see an example of this being done in the unit tests
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:
@ -719,9 +719,9 @@ Finally, we can do redemption.
.. sourcecode:: kotlin .. sourcecode:: kotlin
@Throws(InsufficientBalanceException::class) @Throws(InsufficientBalanceException::class)
fun craftRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<Cash.State>>) { fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<Cash.State>>) {
// Add the cash movement using the states in our wallet. // Add the cash movement using the states in our wallet.
Cash().craftSpend(tx, paper.state.faceValue, paper.state.owner, wallet) Cash().generateSpend(tx, paper.state.faceValue, paper.state.owner, wallet)
tx.addInputState(paper.ref) tx.addInputState(paper.ref)
tx.addArg(WireCommand(CommercialPaper.Commands.Redeem, paper.state.owner)) tx.addArg(WireCommand(CommercialPaper.Commands.Redeem, paper.state.owner))
} }
@ -744,10 +744,9 @@ A ``TransactionBuilder`` is not by itself ready to be used anywhere, so first, w
is recognised by the network. The most important next step is for the participating entities to sign it using the is recognised by the network. The most important next step is for the participating entities to sign it using the
``signWith()`` method. This takes a keypair, serialises the transaction, signs the serialised form and then stores the ``signWith()`` method. This takes a keypair, serialises the transaction, signs the serialised form and then stores the
signature inside the ``TransactionBuilder``. Once all parties have signed, you can call ``TransactionBuilder.toSignedTransaction()`` signature inside the ``TransactionBuilder``. Once all parties have signed, you can call ``TransactionBuilder.toSignedTransaction()``
to get a ``SignedWireTransaction`` object. This is an immutable form of the transaction that's ready for *timestamping*. to get a ``SignedTransaction`` object. This is an immutable form of the transaction that's ready for *timestamping*,
which can be done using a ``TimestamperClient``. To learn more about that, please refer to the
.. note:: Timestamping and passing around of partial transactions for group signing is not yet fully implemented. :doc:`protocol-state-machines` document.
This tutorial will be updated once it is.
You can see how transactions flow through the different stages of construction by examining the commercial paper You can see how transactions flow through the different stages of construction by examining the commercial paper
unit tests. unit tests.

View File

@ -25,3 +25,7 @@
.codeset > .highlight-java { .codeset > .highlight-java {
display: none; display: none;
} }
.wy-nav-content {
max-width: 1000px;
}

View File

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Code style guide &mdash; R3 Prototyping 0.1 documentation</title> <title>Code style guide &mdash; R3 Prototyping latest documentation</title>
@ -30,7 +30,7 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/> <link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
<link rel="prev" title="Roadmap" href="roadmap.html"/> <link rel="prev" title="Roadmap" href="roadmap.html"/>
@ -59,7 +59,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -326,7 +326,7 @@ really necessary. In other words, don&#8217;t do this:</p>
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true

View File

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Data model &mdash; R3 Prototyping 0.1 documentation</title> <title>Data model &mdash; R3 Prototyping latest documentation</title>
@ -30,7 +30,7 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/> <link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
<link rel="next" title="Networking and messaging" href="messaging.html"/> <link rel="next" title="Networking and messaging" href="messaging.html"/>
<link rel="prev" title="Getting set up" href="getting-set-up.html"/> <link rel="prev" title="Getting set up" href="getting-set-up.html"/>
@ -60,7 +60,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -92,6 +92,7 @@
</ul> </ul>
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="messaging.html">Networking and messaging</a></li> <li class="toctree-l1"><a class="reference internal" href="messaging.html">Networking and messaging</a></li>
<li class="toctree-l1"><a class="reference internal" href="running-the-trading-demo.html">Running the trading demo</a></li>
</ul> </ul>
<p class="caption"><span class="caption-text">Tutorials</span></p> <p class="caption"><span class="caption-text">Tutorials</span></p>
<ul> <ul>
@ -292,7 +293,7 @@ platform considers non-financial applications to be out of scope.</li>
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true

View File

@ -9,7 +9,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Index &mdash; R3 Prototyping 0.1 documentation</title> <title>Index &mdash; R3 Prototyping latest documentation</title>
@ -31,7 +31,7 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/> <link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
<script src="_static/js/modernizr.min.js"></script> <script src="_static/js/modernizr.min.js"></script>
@ -59,7 +59,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -179,7 +179,7 @@
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true

View File

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Getting set up &mdash; R3 Prototyping 0.1 documentation</title> <title>Getting set up &mdash; R3 Prototyping latest documentation</title>
@ -30,7 +30,7 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/> <link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
<link rel="next" title="Data model" href="data-model.html"/> <link rel="next" title="Data model" href="data-model.html"/>
<link rel="prev" title="Whats included?" href="inthebox.html"/> <link rel="prev" title="Whats included?" href="inthebox.html"/>
@ -60,7 +60,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -91,6 +91,7 @@
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="data-model.html">Data model</a></li> <li class="toctree-l1"><a class="reference internal" href="data-model.html">Data model</a></li>
<li class="toctree-l1"><a class="reference internal" href="messaging.html">Networking and messaging</a></li> <li class="toctree-l1"><a class="reference internal" href="messaging.html">Networking and messaging</a></li>
<li class="toctree-l1"><a class="reference internal" href="running-the-trading-demo.html">Running the trading demo</a></li>
</ul> </ul>
<p class="caption"><span class="caption-text">Tutorials</span></p> <p class="caption"><span class="caption-text">Tutorials</span></p>
<ul> <ul>
@ -227,7 +228,7 @@ found at something like</p>
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true

View File

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to the R3 prototyping repository! &mdash; R3 Prototyping 0.1 documentation</title> <title>Welcome to the R3 prototyping repository! &mdash; R3 Prototyping latest documentation</title>
@ -30,7 +30,7 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="#"/> <link rel="top" title="R3 Prototyping latest documentation" href="#"/>
<link rel="next" title="Whats included?" href="inthebox.html"/> <link rel="next" title="Whats included?" href="inthebox.html"/>
@ -59,7 +59,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -196,7 +196,7 @@ prove or disprove the following hypothesis:</p>
<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#understanding-fungibility">Understanding fungibility</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#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#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-crafting-api-to-your-contract">Adding a crafting API to 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>
<li class="toctree-l2"><a class="reference internal" href="tutorial.html#non-asset-oriented-based-smart-contracts">Non-asset-oriented based smart contracts</a></li> <li class="toctree-l2"><a class="reference internal" href="tutorial.html#non-asset-oriented-based-smart-contracts">Non-asset-oriented based smart contracts</a></li>
</ul> </ul>
</li> </li>
@ -208,6 +208,7 @@ prove or disprove the following hypothesis:</p>
<li class="toctree-l2"><a class="reference internal" href="protocol-state-machines.html#the-state-machine-manager">The state machine manager</a></li> <li class="toctree-l2"><a class="reference internal" href="protocol-state-machines.html#the-state-machine-manager">The state machine manager</a></li>
<li class="toctree-l2"><a class="reference internal" href="protocol-state-machines.html#implementing-the-seller">Implementing the seller</a></li> <li class="toctree-l2"><a class="reference internal" href="protocol-state-machines.html#implementing-the-seller">Implementing the seller</a></li>
<li class="toctree-l2"><a class="reference internal" href="protocol-state-machines.html#implementing-the-buyer">Implementing the buyer</a></li> <li class="toctree-l2"><a class="reference internal" href="protocol-state-machines.html#implementing-the-buyer">Implementing the buyer</a></li>
<li class="toctree-l2"><a class="reference internal" href="protocol-state-machines.html#progress-tracking">Progress tracking</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -267,7 +268,7 @@ prove or disprove the following hypothesis:</p>
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true

View File

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Whats included? &mdash; R3 Prototyping 0.1 documentation</title> <title>Whats included? &mdash; R3 Prototyping latest documentation</title>
@ -30,7 +30,7 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/> <link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
<link rel="next" title="Getting set up" href="getting-set-up.html"/> <link rel="next" title="Getting set up" href="getting-set-up.html"/>
<link rel="prev" title="Welcome to the R3 prototyping repository!" href="index.html"/> <link rel="prev" title="Welcome to the R3 prototyping repository!" href="index.html"/>
@ -60,7 +60,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -258,7 +258,7 @@ to write contracts in both Kotlin and Java. You can <a class="reference external
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true

View File

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Networking and messaging &mdash; R3 Prototyping 0.1 documentation</title> <title>Networking and messaging &mdash; R3 Prototyping latest documentation</title>
@ -30,8 +30,8 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/> <link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
<link rel="next" title="Writing a contract" href="tutorial.html"/> <link rel="next" title="Running the trading demo" href="running-the-trading-demo.html"/>
<link rel="prev" title="Data model" href="data-model.html"/> <link rel="prev" title="Data model" href="data-model.html"/>
@ -60,7 +60,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -92,6 +92,7 @@
<li class="toctree-l2"><a class="reference internal" href="#in-memory-implementation">In memory implementation</a></li> <li class="toctree-l2"><a class="reference internal" href="#in-memory-implementation">In memory implementation</a></li>
</ul> </ul>
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="running-the-trading-demo.html">Running the trading demo</a></li>
</ul> </ul>
<p class="caption"><span class="caption-text">Tutorials</span></p> <p class="caption"><span class="caption-text">Tutorials</span></p>
<ul> <ul>
@ -239,7 +240,7 @@ nodes run in parallel, just as they would on a real network spread over multiple
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation"> <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="tutorial.html" class="btn btn-neutral float-right" title="Writing a contract" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a> <a href="running-the-trading-demo.html" class="btn btn-neutral float-right" title="Running the trading demo" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
<a href="data-model.html" class="btn btn-neutral" title="Data model" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a> <a href="data-model.html" class="btn btn-neutral" title="Data model" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
@ -273,7 +274,7 @@ nodes run in parallel, just as they would on a real network spread over multiple
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true

Binary file not shown.

View File

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Protocol state machines &mdash; R3 Prototyping 0.1 documentation</title> <title>Protocol state machines &mdash; R3 Prototyping latest documentation</title>
@ -30,7 +30,7 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/> <link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
<link rel="next" title="Using the visualiser" href="visualiser.html"/> <link rel="next" title="Using the visualiser" href="visualiser.html"/>
<link rel="prev" title="Writing a contract" href="tutorial.html"/> <link rel="prev" title="Writing a contract" href="tutorial.html"/>
@ -60,7 +60,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -100,6 +100,7 @@
<li class="toctree-l2"><a class="reference internal" href="#the-state-machine-manager">The state machine manager</a></li> <li class="toctree-l2"><a class="reference internal" href="#the-state-machine-manager">The state machine manager</a></li>
<li class="toctree-l2"><a class="reference internal" href="#implementing-the-seller">Implementing the seller</a></li> <li class="toctree-l2"><a class="reference internal" href="#implementing-the-seller">Implementing the seller</a></li>
<li class="toctree-l2"><a class="reference internal" href="#implementing-the-buyer">Implementing the buyer</a></li> <li class="toctree-l2"><a class="reference internal" href="#implementing-the-buyer">Implementing the buyer</a></li>
<li class="toctree-l2"><a class="reference internal" href="#progress-tracking">Progress tracking</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -205,7 +206,7 @@ bytecode rewriting. You don&#8217;t have to know how this works to benefit from
<ul class="simple"> <ul class="simple">
<li>It allows us to write code that is free of callbacks, that looks like ordinary sequential code.</li> <li>It allows us to write code that is free of callbacks, that looks like ordinary sequential code.</li>
<li>A suspended continuation takes far less memory than a suspended thread. It can be as low as a few hundred bytes. <li>A suspended continuation takes far less memory than a suspended thread. It can be as low as a few hundred bytes.
In contrast a suspended Java stack can easily be 1mb in size.</li> In contrast a suspended Java thread stack can easily be 1mb in size.</li>
<li>It frees the developer from thinking (much) about persistence and serialisation.</li> <li>It frees the developer from thinking (much) about persistence and serialisation.</li>
</ul> </ul>
<p>A <em>state machine</em> is a piece of code that moves through various <em>states</em>. These are not the same as states in the data <p>A <em>state machine</em> is a piece of code that moves through various <em>states</em>. These are not the same as states in the data
@ -224,10 +225,10 @@ the trade is arranged isn&#8217;t covered in this article.</p>
<ol class="arabic simple"> <ol class="arabic simple">
<li>S sends a <code class="docutils literal"><span class="pre">StateAndRef</span></code> pointing to the state they want to sell to B, along with info about the price they require <li>S sends a <code class="docutils literal"><span class="pre">StateAndRef</span></code> pointing to the state they want to sell to B, along with info about the price they require
B to pay.</li> B to pay.</li>
<li>B sends to S a <code class="docutils literal"><span class="pre">SignedWireTransaction</span></code> that includes the state as input, B&#8217;s cash as input, the state with the new <li>B sends to S a <code class="docutils literal"><span class="pre">SignedTransaction</span></code> that includes the state as input, B&#8217;s cash as input, the state with the new
owner key as output, and any change cash as output. It contains a single signature from B but isn&#8217;t valid because owner key as output, and any change cash as output. It contains a single signature from B but isn&#8217;t valid because
it lacks a signature from S authorising movement of the asset.</li> it lacks a signature from S authorising movement of the asset.</li>
<li>S signs it and hands the now finalised <code class="docutils literal"><span class="pre">SignedWireTransaction</span></code> back to B.</li> <li>S signs it and hands the now finalised <code class="docutils literal"><span class="pre">SignedTransaction</span></code> back to B.</li>
</ol> </ol>
<p>You can find the implementation of this protocol in the file <code class="docutils literal"><span class="pre">contracts/protocols/TwoPartyTradeProtocol.kt</span></code>.</p> <p>You can find the implementation of this protocol in the file <code class="docutils literal"><span class="pre">contracts/protocols/TwoPartyTradeProtocol.kt</span></code>.</p>
<p>Assuming no malicious termination, they both end the protocol being in posession of a valid, signed transaction that <p>Assuming no malicious termination, they both end the protocol being in posession of a valid, signed transaction that
@ -242,7 +243,7 @@ each side.</p>
<span class="k">fun</span> <span class="nf">runSeller</span><span class="p">(</span><span class="n">smm</span><span class="p">:</span> <span class="n">StateMachineManager</span><span class="p">,</span> <span class="n">timestampingAuthority</span><span class="p">:</span> <span class="n">LegallyIdentifiableNode</span><span class="p">,</span> <span class="k">fun</span> <span class="nf">runSeller</span><span class="p">(</span><span class="n">smm</span><span class="p">:</span> <span class="n">StateMachineManager</span><span class="p">,</span> <span class="n">timestampingAuthority</span><span class="p">:</span> <span class="n">LegallyIdentifiableNode</span><span class="p">,</span>
<span class="n">otherSide</span><span class="p">:</span> <span class="n">SingleMessageRecipient</span><span class="p">,</span> <span class="n">assetToSell</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">OwnableState</span><span class="p">&gt;,</span> <span class="n">price</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span> <span class="n">otherSide</span><span class="p">:</span> <span class="n">SingleMessageRecipient</span><span class="p">,</span> <span class="n">assetToSell</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">OwnableState</span><span class="p">&gt;,</span> <span class="n">price</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span>
<span class="n">myKeyPair</span><span class="p">:</span> <span class="n">KeyPair</span><span class="p">,</span> <span class="n">buyerSessionID</span><span class="p">:</span> <span class="n">Long</span><span class="p">):</span> <span class="n">ListenableFuture</span><span class="p">&lt;</span><span class="n">Pair</span><span class="p">&lt;</span><span class="n">WireTransaction</span><span class="p">,</span> <span class="n">LedgerTransaction</span><span class="p">&gt;&gt;</span> <span class="p">{</span> <span class="n">myKeyPair</span><span class="p">:</span> <span class="n">KeyPair</span><span class="p">,</span> <span class="n">buyerSessionID</span><span class="p">:</span> <span class="n">Long</span><span class="p">):</span> <span class="n">ListenableFuture</span><span class="p">&lt;</span><span class="n">SignedTransaction</span><span class="p">&gt;</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">seller</span> <span class="p">=</span> <span class="n">Seller</span><span class="p">(</span><span class="n">otherSide</span><span class="p">,</span> <span class="n">timestampingAuthority</span><span class="p">,</span> <span class="n">assetToSell</span><span class="p">,</span> <span class="n">price</span><span class="p">,</span> <span class="n">myKeyPair</span><span class="p">,</span> <span class="n">buyerSessionID</span><span class="p">)</span> <span class="k">val</span> <span class="py">seller</span> <span class="p">=</span> <span class="n">Seller</span><span class="p">(</span><span class="n">otherSide</span><span class="p">,</span> <span class="n">timestampingAuthority</span><span class="p">,</span> <span class="n">assetToSell</span><span class="p">,</span> <span class="n">price</span><span class="p">,</span> <span class="n">myKeyPair</span><span class="p">,</span> <span class="n">buyerSessionID</span><span class="p">)</span>
<span class="n">smm</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">&quot;$TRADE_TOPIC.seller&quot;</span><span class="p">,</span> <span class="n">seller</span><span class="p">)</span> <span class="n">smm</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">&quot;$TRADE_TOPIC.seller&quot;</span><span class="p">,</span> <span class="n">seller</span><span class="p">)</span>
<span class="k">return</span> <span class="n">seller</span><span class="p">.</span><span class="n">resultFuture</span> <span class="k">return</span> <span class="n">seller</span><span class="p">.</span><span class="n">resultFuture</span>
@ -250,46 +251,46 @@ each side.</p>
<span class="k">fun</span> <span class="nf">runBuyer</span><span class="p">(</span><span class="n">smm</span><span class="p">:</span> <span class="n">StateMachineManager</span><span class="p">,</span> <span class="n">timestampingAuthority</span><span class="p">:</span> <span class="n">LegallyIdentifiableNode</span><span class="p">,</span> <span class="k">fun</span> <span class="nf">runBuyer</span><span class="p">(</span><span class="n">smm</span><span class="p">:</span> <span class="n">StateMachineManager</span><span class="p">,</span> <span class="n">timestampingAuthority</span><span class="p">:</span> <span class="n">LegallyIdentifiableNode</span><span class="p">,</span>
<span class="n">otherSide</span><span class="p">:</span> <span class="n">SingleMessageRecipient</span><span class="p">,</span> <span class="n">acceptablePrice</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span> <span class="n">typeToBuy</span><span class="p">:</span> <span class="n">Class</span><span class="p">&lt;</span><span class="k">out</span> <span class="n">OwnableState</span><span class="p">&gt;,</span> <span class="n">otherSide</span><span class="p">:</span> <span class="n">SingleMessageRecipient</span><span class="p">,</span> <span class="n">acceptablePrice</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span> <span class="n">typeToBuy</span><span class="p">:</span> <span class="n">Class</span><span class="p">&lt;</span><span class="k">out</span> <span class="n">OwnableState</span><span class="p">&gt;,</span>
<span class="n">sessionID</span><span class="p">:</span> <span class="n">Long</span><span class="p">):</span> <span class="n">ListenableFuture</span><span class="p">&lt;</span><span class="n">Pair</span><span class="p">&lt;</span><span class="n">WireTransaction</span><span class="p">,</span> <span class="n">LedgerTransaction</span><span class="p">&gt;&gt;</span> <span class="p">{</span> <span class="n">sessionID</span><span class="p">:</span> <span class="n">Long</span><span class="p">):</span> <span class="n">ListenableFuture</span><span class="p">&lt;</span><span class="n">SignedTransaction</span><span class="p">&gt;</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">buyer</span> <span class="p">=</span> <span class="n">Buyer</span><span class="p">(</span><span class="n">otherSide</span><span class="p">,</span> <span class="n">timestampingAuthority</span><span class="p">.</span><span class="n">identity</span><span class="p">,</span> <span class="n">acceptablePrice</span><span class="p">,</span> <span class="n">typeToBuy</span><span class="p">,</span> <span class="n">sessionID</span><span class="p">)</span> <span class="k">val</span> <span class="py">buyer</span> <span class="p">=</span> <span class="n">Buyer</span><span class="p">(</span><span class="n">otherSide</span><span class="p">,</span> <span class="n">timestampingAuthority</span><span class="p">.</span><span class="n">identity</span><span class="p">,</span> <span class="n">acceptablePrice</span><span class="p">,</span> <span class="n">typeToBuy</span><span class="p">,</span> <span class="n">sessionID</span><span class="p">)</span>
<span class="n">smm</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">&quot;$TRADE_TOPIC.buyer&quot;</span><span class="p">,</span> <span class="n">buyer</span><span class="p">)</span> <span class="n">smm</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">&quot;$TRADE_TOPIC.buyer&quot;</span><span class="p">,</span> <span class="n">buyer</span><span class="p">)</span>
<span class="k">return</span> <span class="n">buyer</span><span class="p">.</span><span class="n">resultFuture</span> <span class="k">return</span> <span class="n">buyer</span><span class="p">.</span><span class="n">resultFuture</span>
<span class="p">}</span> <span class="p">}</span>
<span class="k">class</span> <span class="nc">Seller</span><span class="p">(</span><span class="k">val</span> <span class="py">otherSide</span><span class="p">:</span> <span class="n">SingleMessageRecipient</span><span class="p">,</span>
<span class="k">val</span> <span class="py">timestampingAuthority</span><span class="p">:</span> <span class="n">LegallyIdentifiableNode</span><span class="p">,</span>
<span class="k">val</span> <span class="py">assetToSell</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">OwnableState</span><span class="p">&gt;,</span>
<span class="k">val</span> <span class="py">price</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span>
<span class="k">val</span> <span class="py">myKeyPair</span><span class="p">:</span> <span class="n">KeyPair</span><span class="p">,</span>
<span class="k">val</span> <span class="py">buyerSessionID</span><span class="p">:</span> <span class="n">Long</span><span class="p">)</span> <span class="p">:</span> <span class="n">ProtocolStateMachine</span><span class="p">&lt;</span><span class="n">Pair</span><span class="p">&lt;</span><span class="n">WireTransaction</span><span class="p">,</span> <span class="n">LedgerTransaction</span><span class="p">&gt;&gt;()</span> <span class="p">{</span>
<span class="n">@Suspendable</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">call</span><span class="p">():</span> <span class="n">Pair</span><span class="p">&lt;</span><span class="n">WireTransaction</span><span class="p">,</span> <span class="n">LedgerTransaction</span><span class="p">&gt;</span> <span class="p">{</span>
<span class="n">TODO</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// This object is serialised to the network and is the first protocol message the seller sends to the buyer.</span> <span class="c1">// This object is serialised to the network and is the first protocol message the seller sends to the buyer.</span>
<span class="k">private</span> <span class="k">class</span> <span class="nc">SellerTradeInfo</span><span class="p">(</span> <span class="k">class</span> <span class="nc">SellerTradeInfo</span><span class="p">(</span>
<span class="k">val</span> <span class="py">assetForSale</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">OwnableState</span><span class="p">&gt;,</span> <span class="k">val</span> <span class="py">assetForSale</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">OwnableState</span><span class="p">&gt;,</span>
<span class="k">val</span> <span class="py">price</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span> <span class="k">val</span> <span class="py">price</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span>
<span class="k">val</span> <span class="py">sellerOwnerKey</span><span class="p">:</span> <span class="n">PublicKey</span><span class="p">,</span> <span class="k">val</span> <span class="py">sellerOwnerKey</span><span class="p">:</span> <span class="n">PublicKey</span><span class="p">,</span>
<span class="k">val</span> <span class="py">sessionID</span><span class="p">:</span> <span class="n">Long</span> <span class="k">val</span> <span class="py">sessionID</span><span class="p">:</span> <span class="n">Long</span>
<span class="p">)</span> <span class="p">)</span>
<span class="k">class</span> <span class="nc">SignaturesFromSeller</span><span class="p">(</span><span class="k">val</span> <span class="py">timestampAuthoritySig</span><span class="p">:</span> <span class="n">DigitalSignature</span><span class="p">.</span><span class="n">WithKey</span><span class="p">,</span> <span class="k">val</span> <span class="py">sellerSig</span><span class="p">:</span> <span class="n">DigitalSignature</span><span class="p">.</span><span class="n">WithKey</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Seller</span><span class="p">(</span><span class="k">val</span> <span class="py">otherSide</span><span class="p">:</span> <span class="n">SingleMessageRecipient</span><span class="p">,</span>
<span class="k">val</span> <span class="py">timestampingAuthority</span><span class="p">:</span> <span class="n">LegallyIdentifiableNode</span><span class="p">,</span>
<span class="k">val</span> <span class="py">assetToSell</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">OwnableState</span><span class="p">&gt;,</span>
<span class="k">val</span> <span class="py">price</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span>
<span class="k">val</span> <span class="py">myKeyPair</span><span class="p">:</span> <span class="n">KeyPair</span><span class="p">,</span>
<span class="k">val</span> <span class="py">buyerSessionID</span><span class="p">:</span> <span class="n">Long</span><span class="p">)</span> <span class="p">:</span> <span class="n">ProtocolLogic</span><span class="p">&lt;</span><span class="n">SignedTransaction</span><span class="p">&gt;()</span> <span class="p">{</span>
<span class="n">@Suspendable</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">call</span><span class="p">():</span> <span class="n">SignedTransaction</span> <span class="p">{</span>
<span class="n">TODO</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">class</span> <span class="nc">UnacceptablePriceException</span><span class="p">(</span><span class="k">val</span> <span class="py">givenPrice</span><span class="p">:</span> <span class="n">Amount</span><span class="p">)</span> <span class="p">:</span> <span class="n">Exception</span><span class="p">()</span> <span class="k">class</span> <span class="nc">UnacceptablePriceException</span><span class="p">(</span><span class="k">val</span> <span class="py">givenPrice</span><span class="p">:</span> <span class="n">Amount</span><span class="p">)</span> <span class="p">:</span> <span class="n">Exception</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">AssetMismatchException</span><span class="p">(</span><span class="k">val</span> <span class="py">expectedTypeName</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span> <span class="k">val</span> <span class="py">typeName</span><span class="p">:</span> <span class="n">String</span><span class="p">)</span> <span class="p">:</span> <span class="n">Exception</span><span class="p">()</span> <span class="p">{</span> <span class="k">class</span> <span class="nc">AssetMismatchException</span><span class="p">(</span><span class="k">val</span> <span class="py">expectedTypeName</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span> <span class="k">val</span> <span class="py">typeName</span><span class="p">:</span> <span class="n">String</span><span class="p">)</span> <span class="p">:</span> <span class="n">Exception</span><span class="p">()</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">toString</span><span class="p">()</span> <span class="p">=</span> <span class="s">&quot;The submitted asset didn&#39;t match the expected type: $expectedTypeName vs $typeName&quot;</span> <span class="k">override</span> <span class="k">fun</span> <span class="nf">toString</span><span class="p">()</span> <span class="p">=</span> <span class="s">&quot;The submitted asset didn&#39;t match the expected type: $expectedTypeName vs $typeName&quot;</span>
<span class="p">}</span> <span class="p">}</span>
<span class="c1">// The buyer&#39;s side of the protocol. See note above Seller to learn about the caveats here.</span>
<span class="k">class</span> <span class="nc">Buyer</span><span class="p">(</span><span class="k">val</span> <span class="py">otherSide</span><span class="p">:</span> <span class="n">SingleMessageRecipient</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Buyer</span><span class="p">(</span><span class="k">val</span> <span class="py">otherSide</span><span class="p">:</span> <span class="n">SingleMessageRecipient</span><span class="p">,</span>
<span class="k">val</span> <span class="py">timestampingAuthority</span><span class="p">:</span> <span class="n">Party</span><span class="p">,</span> <span class="k">val</span> <span class="py">timestampingAuthority</span><span class="p">:</span> <span class="n">Party</span><span class="p">,</span>
<span class="k">val</span> <span class="py">acceptablePrice</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span> <span class="k">val</span> <span class="py">acceptablePrice</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span>
<span class="k">val</span> <span class="py">typeToBuy</span><span class="p">:</span> <span class="n">Class</span><span class="p">&lt;</span><span class="k">out</span> <span class="n">OwnableState</span><span class="p">&gt;,</span> <span class="k">val</span> <span class="py">typeToBuy</span><span class="p">:</span> <span class="n">Class</span><span class="p">&lt;</span><span class="k">out</span> <span class="n">OwnableState</span><span class="p">&gt;,</span>
<span class="k">val</span> <span class="py">sessionID</span><span class="p">:</span> <span class="n">Long</span><span class="p">)</span> <span class="p">:</span> <span class="n">ProtocolStateMachine</span><span class="p">&lt;</span><span class="n">Pair</span><span class="p">&lt;</span><span class="n">WireTransaction</span><span class="p">,</span> <span class="n">LedgerTransaction</span><span class="p">&gt;&gt;()</span> <span class="p">{</span> <span class="k">val</span> <span class="py">sessionID</span><span class="p">:</span> <span class="n">Long</span><span class="p">)</span> <span class="p">:</span> <span class="n">ProtocolLogic</span><span class="p">&lt;</span><span class="n">SignedTransaction</span><span class="p">&gt;()</span> <span class="p">{</span>
<span class="n">@Suspendable</span> <span class="n">@Suspendable</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">call</span><span class="p">():</span> <span class="n">Pair</span><span class="p">&lt;</span><span class="n">WireTransaction</span><span class="p">,</span> <span class="n">LedgerTransaction</span><span class="p">&gt;</span> <span class="p">{</span> <span class="k">override</span> <span class="k">fun</span> <span class="nf">call</span><span class="p">():</span> <span class="n">SignedTransaction</span> <span class="p">{</span>
<span class="n">TODO</span><span class="p">()</span> <span class="n">TODO</span><span class="p">()</span>
<span class="p">}</span> <span class="p">}</span>
<span class="p">}</span> <span class="p">}</span>
@ -300,7 +301,7 @@ each side.</p>
<p>Let&#8217;s unpack what this code does:</p> <p>Let&#8217;s unpack what this code does:</p>
<ul class="simple"> <ul class="simple">
<li>It defines a several classes nested inside the main <code class="docutils literal"><span class="pre">TwoPartyTradeProtocol</span></code> singleton, and a couple of methods, one <li>It defines a several classes nested inside the main <code class="docutils literal"><span class="pre">TwoPartyTradeProtocol</span></code> singleton, and a couple of methods, one
to run the buyer side of the protocol and one to run the seller side.</li> to run the buyer side of the protocol and one to run the seller side. Some of the classes are simply protocol messages.</li>
<li>It defines the &#8220;trade topic&#8221;, which is just a string that namespaces this protocol. The prefix &#8220;platform.&#8221; is reserved <li>It defines the &#8220;trade topic&#8221;, which is just a string that namespaces this protocol. The prefix &#8220;platform.&#8221; is reserved
by the DLG, but you can define your own protocols using standard Java-style reverse DNS notation.</li> by the DLG, but you can define your own protocols using standard Java-style reverse DNS notation.</li>
<li>The <code class="docutils literal"><span class="pre">runBuyer</span></code> and <code class="docutils literal"><span class="pre">runSeller</span></code> methods take a number of parameters that specialise the protocol for this run, <li>The <code class="docutils literal"><span class="pre">runBuyer</span></code> and <code class="docutils literal"><span class="pre">runSeller</span></code> methods take a number of parameters that specialise the protocol for this run,
@ -338,7 +339,8 @@ sell side of the protocol isn&#8217;t trying to sell us the wrong thing, whether
to either runBuyer or runSeller, depending on who we are, and then call <code class="docutils literal"><span class="pre">.get()</span></code> on resulting object to to either runBuyer or runSeller, depending on who we are, and then call <code class="docutils literal"><span class="pre">.get()</span></code> on resulting object to
block the calling thread until the protocol has finished. Or we could register a callback on the returned future that block the calling thread until the protocol has finished. Or we could register a callback on the returned future that
will be invoked when it&#8217;s done, where we could e.g. update a user interface.</p> will be invoked when it&#8217;s done, where we could e.g. update a user interface.</p>
<p>Finally, we define a couple of exceptions, and a class that will be used as a protocol message called <code class="docutils literal"><span class="pre">SellerTradeInfo</span></code>.</p> <p>Finally, we define a couple of exceptions, and two classes that will be used as a protocol message called
<code class="docutils literal"><span class="pre">SellerTradeInfo</span></code> and <code class="docutils literal"><span class="pre">SignaturesFromSeller</span></code>.</p>
</div> </div>
<div class="section" id="suspendable-methods"> <div class="section" id="suspendable-methods">
<h2>Suspendable methods<a class="headerlink" href="#suspendable-methods" title="Permalink to this headline"></a></h2> <h2>Suspendable methods<a class="headerlink" href="#suspendable-methods" title="Permalink to this headline"></a></h2>
@ -370,13 +372,71 @@ unit tests to see how it&#8217;s done.</p>
<p>Let&#8217;s implement the <code class="docutils literal"><span class="pre">Seller.call</span></code> method. This will be invoked by the platform when the protocol is started by the <p>Let&#8217;s implement the <code class="docutils literal"><span class="pre">Seller.call</span></code> method. This will be invoked by the platform when the protocol is started by the
<code class="docutils literal"><span class="pre">StateMachineManager</span></code>.</p> <code class="docutils literal"><span class="pre">StateMachineManager</span></code>.</p>
<div class="codeset container"> <div class="codeset container">
<div class="highlight-kotlin"><div class="highlight"><pre><span class="k">val</span> <span class="py">sessionID</span> <span class="p">=</span> <span class="n">random63BitValue</span><span class="p">()</span> <div class="highlight-kotlin"><div class="highlight"><pre><span class="k">val</span> <span class="py">partialTX</span><span class="p">:</span> <span class="n">SignedTransaction</span> <span class="p">=</span> <span class="n">receiveAndCheckProposedTransaction</span><span class="p">()</span>
<span class="c1">// These two steps could be done in parallel, in theory. Our framework doesn&#39;t support that yet though.</span>
<span class="k">val</span> <span class="py">ourSignature</span> <span class="p">=</span> <span class="n">signWithOurKey</span><span class="p">(</span><span class="n">partialTX</span><span class="p">)</span>
<span class="k">val</span> <span class="py">tsaSig</span> <span class="p">=</span> <span class="n">subProtocol</span><span class="p">(</span><span class="n">TimestampingProtocol</span><span class="p">(</span><span class="n">timestampingAuthority</span><span class="p">,</span> <span class="n">partialTX</span><span class="p">.</span><span class="n">txBits</span><span class="p">))</span>
<span class="k">val</span> <span class="py">stx</span><span class="p">:</span> <span class="n">SignedTransaction</span> <span class="p">=</span> <span class="n">sendSignatures</span><span class="p">(</span><span class="n">partialTX</span><span class="p">,</span> <span class="n">ourSignature</span><span class="p">,</span> <span class="n">tsaSig</span><span class="p">)</span>
<span class="k">return</span> <span class="n">stx</span>
</pre></div>
</div>
</div>
<p>Here we see the outline of the procedure. We receive a proposed trade transaction from the buyer and check that it&#8217;s
valid. Then we sign with our own key, request a timestamping authority to assert with another signature that the
timestamp in the transaction (if any) is valid, and finally we send back both our signature and the TSA&#8217;s signature.
Finally, we hand back to the code that invoked the protocol the finished transaction in a couple of different forms.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last"><code class="docutils literal"><span class="pre">ProtocolLogic</span></code> classes can be composed together. Here, we see the use of the <code class="docutils literal"><span class="pre">subProtocol</span></code> method, which
is given an instance of <code class="docutils literal"><span class="pre">TimestampingProtocol</span></code>. This protocol will run to completion and yield a result, almost
as if it&#8217;s a regular method call. In fact, under the hood, all the <code class="docutils literal"><span class="pre">subProtocol</span></code> method does is pass the current
fiber object into the newly created object and then run <code class="docutils literal"><span class="pre">call()</span></code> on it ... so it basically _is_ just a method call.
This is where we can see the benefits of using continuations/fibers as a programming model.</p>
</div>
<p>Let&#8217;s fill out the <code class="docutils literal"><span class="pre">receiveAndCheckProposedTransaction()</span></code> method.</p>
<div class="codeset container">
<div class="highlight-kotlin"><div class="highlight"><pre><span class="n">@Suspendable</span>
<span class="k">open</span> <span class="k">fun</span> <span class="nf">receiveAndCheckProposedTransaction</span><span class="p">():</span> <span class="n">SignedTransaction</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">sessionID</span> <span class="p">=</span> <span class="n">random63BitValue</span><span class="p">()</span>
<span class="c1">// Make the first message we&#39;ll send to kick off the protocol.</span> <span class="c1">// Make the first message we&#39;ll send to kick off the protocol.</span>
<span class="k">val</span> <span class="py">hello</span> <span class="p">=</span> <span class="n">SellerTradeInfo</span><span class="p">(</span><span class="n">assetToSell</span><span class="p">,</span> <span class="n">price</span><span class="p">,</span> <span class="n">myKeyPair</span><span class="p">.</span><span class="k">public</span><span class="p">,</span> <span class="n">sessionID</span><span class="p">)</span> <span class="k">val</span> <span class="py">hello</span> <span class="p">=</span> <span class="n">SellerTradeInfo</span><span class="p">(</span><span class="n">assetToSell</span><span class="p">,</span> <span class="n">price</span><span class="p">,</span> <span class="n">myKeyPair</span><span class="p">.</span><span class="k">public</span><span class="p">,</span> <span class="n">sessionID</span><span class="p">)</span>
<span class="k">val</span> <span class="py">partialTX</span> <span class="p">=</span> <span class="n">sendAndReceive</span><span class="p">(</span><span class="n">TRADE_TOPIC</span><span class="p">,</span> <span class="n">buyerSessionID</span><span class="p">,</span> <span class="n">sessionID</span><span class="p">,</span> <span class="n">hello</span><span class="p">,</span> <span class="n">SignedWireTransaction</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span> <span class="k">val</span> <span class="py">maybeSTX</span> <span class="p">=</span> <span class="n">sendAndReceive</span><span class="p">&lt;</span><span class="n">SignedTransaction</span><span class="p">&gt;(</span><span class="n">TRADE_TOPIC</span><span class="p">,</span> <span class="n">otherSide</span><span class="p">,</span> <span class="n">buyerSessionID</span><span class="p">,</span> <span class="n">sessionID</span><span class="p">,</span> <span class="n">hello</span><span class="p">)</span>
<span class="n">logger</span><span class="p">().</span><span class="n">trace</span> <span class="p">{</span> <span class="s">&quot;Received partially signed transaction&quot;</span> <span class="p">}</span>
<span class="n">maybeSTX</span><span class="p">.</span><span class="n">validate</span> <span class="p">{</span>
<span class="c1">// Check that the tx proposed by the buyer is valid.</span>
<span class="k">val</span> <span class="py">missingSigs</span> <span class="p">=</span> <span class="n">it</span><span class="p">.</span><span class="n">verify</span><span class="p">(</span><span class="n">throwIfSignaturesAreMissing</span> <span class="p">=</span> <span class="k">false</span><span class="p">)</span>
<span class="k">if</span> <span class="p">(</span><span class="n">missingSigs</span> <span class="p">!=</span> <span class="n">setOf</span><span class="p">(</span><span class="n">myKeyPair</span><span class="p">.</span><span class="k">public</span><span class="p">,</span> <span class="n">timestampingAuthority</span><span class="p">.</span><span class="n">identity</span><span class="p">.</span><span class="n">owningKey</span><span class="p">))</span>
<span class="k">throw</span> <span class="n">SignatureException</span><span class="p">(</span><span class="s">&quot;The set of missing signatures is not as expected: $missingSigs&quot;</span><span class="p">)</span>
<span class="k">val</span> <span class="py">wtx</span><span class="p">:</span> <span class="n">WireTransaction</span> <span class="p">=</span> <span class="n">it</span><span class="p">.</span><span class="n">tx</span>
<span class="n">logger</span><span class="p">.</span><span class="n">trace</span> <span class="p">{</span> <span class="s">&quot;Received partially signed transaction: ${it.id}&quot;</span> <span class="p">}</span>
<span class="n">checkDependencies</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
<span class="c1">// This verifies that the transaction is contract-valid, even though it is missing signatures.</span>
<span class="n">serviceHub</span><span class="p">.</span><span class="n">verifyTransaction</span><span class="p">(</span><span class="n">wtx</span><span class="p">.</span><span class="n">toLedgerTransaction</span><span class="p">(</span><span class="n">serviceHub</span><span class="p">.</span><span class="n">identityService</span><span class="p">))</span>
<span class="k">if</span> <span class="p">(</span><span class="n">wtx</span><span class="p">.</span><span class="n">outputs</span><span class="p">.</span><span class="n">sumCashBy</span><span class="p">(</span><span class="n">myKeyPair</span><span class="p">.</span><span class="k">public</span><span class="p">)</span> <span class="p">!=</span> <span class="n">price</span><span class="p">)</span>
<span class="k">throw</span> <span class="n">IllegalArgumentException</span><span class="p">(</span><span class="s">&quot;Transaction is not sending us the right amounnt of cash&quot;</span><span class="p">)</span>
<span class="c1">// There are all sorts of funny games a malicious secondary might play here, we should fix them:</span>
<span class="c1">//</span>
<span class="c1">// - This tx may attempt to send some assets we aren&#39;t intending to sell to the secondary, if</span>
<span class="c1">// we&#39;re reusing keys! So don&#39;t reuse keys!</span>
<span class="c1">// - This tx may include output states that impose odd conditions on the movement of the cash,</span>
<span class="c1">// once we implement state pairing.</span>
<span class="c1">//</span>
<span class="c1">// but the goal of this code is not to be fully secure (yet), but rather, just to find good ways to</span>
<span class="c1">// express protocol state machines on top of the messaging layer.</span>
<span class="k">return</span> <span class="n">it</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div> </pre></div>
</div> </div>
</div> </div>
@ -388,7 +448,7 @@ the initial protocol message, and then call <code class="docutils literal"><span
<li>The thing to send. It&#8217;ll be serialised and sent automatically.</li> <li>The thing to send. It&#8217;ll be serialised and sent automatically.</li>
<li>Finally a type argument, which is the kind of object we&#8217;re expecting to receive from the other side.</li> <li>Finally a type argument, which is the kind of object we&#8217;re expecting to receive from the other side.</li>
</ul> </ul>
<p>Once sendAndReceive is called, the call method will be suspended into a continuation. When it gets back we&#8217;ll do a log <p>Once <code class="docutils literal"><span class="pre">sendAndReceive</span></code> is called, the call method will be suspended into a continuation. When it gets back we&#8217;ll do a log
message. The buyer is supposed to send us a transaction with all the right inputs/outputs/commands in return, with their message. The buyer is supposed to send us a transaction with all the right inputs/outputs/commands in return, with their
cash put into the transaction and their signature on it authorising the movement of the cash.</p> cash put into the transaction and their signature on it authorising the movement of the cash.</p>
<div class="admonition note"> <div class="admonition note">
@ -401,40 +461,59 @@ of the function call may be resurrected much later! Kryo doesn&#8217;t require o
doing things like creating threads from inside these calls would be a bad idea. They should only contain business doing things like creating threads from inside these calls would be a bad idea. They should only contain business
logic.</p> logic.</p>
</div> </div>
<p>OK, let&#8217;s keep going:</p> <p>You get back a simple wrapper class, <code class="docutils literal"><span class="pre">UntrustworthyData&lt;SignedTransaction&gt;</span></code>, which is just a marker class that reminds
us that the data came from a potentially malicious external source and may have been tampered with or be unexpected in
other ways. It doesn&#8217;t add any functionality, but acts as a reminder to &#8220;scrub&#8221; the data before use. Here, our scrubbing
simply involves checking the signatures on it. Then we go ahead and check all the dependencies of this partial
transaction for validity. Here&#8217;s the code to do that:</p>
<div class="codeset container"> <div class="codeset container">
<div class="highlight-kotlin"><div class="highlight"><pre><span class="n">partialTX</span><span class="p">.</span><span class="n">verifySignatures</span><span class="p">()</span> <div class="highlight-kotlin"><div class="highlight"><pre><span class="n">@Suspendable</span>
<span class="k">val</span> <span class="py">wtx</span> <span class="p">=</span> <span class="n">partialTX</span><span class="p">.</span><span class="n">txBits</span><span class="p">.</span><span class="n">deserialize</span><span class="p">&lt;</span><span class="n">WireTransaction</span><span class="p">&gt;()</span> <span class="k">private</span> <span class="k">fun</span> <span class="nf">checkDependencies</span><span class="p">(</span><span class="n">stx</span><span class="p">:</span> <span class="n">SignedTransaction</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Download and check all the transactions that this transaction depends on, but do not check this</span>
<span class="n">requireThat</span> <span class="p">{</span> <span class="c1">// transaction itself.</span>
<span class="s">&quot;transaction sends us the right amount of cash&quot;</span> <span class="k">by</span> <span class="p">(</span><span class="n">wtx</span><span class="p">.</span><span class="n">outputStates</span><span class="p">.</span><span class="n">sumCashBy</span><span class="p">(</span><span class="n">args</span><span class="p">.</span><span class="n">myKeyPair</span><span class="p">.</span><span class="k">public</span><span class="p">)</span> <span class="p">==</span> <span class="n">args</span><span class="p">.</span><span class="n">price</span><span class="p">)</span> <span class="k">val</span> <span class="py">dependencyTxIDs</span> <span class="p">=</span> <span class="n">stx</span><span class="p">.</span><span class="n">tx</span><span class="p">.</span><span class="n">inputs</span><span class="p">.</span><span class="n">map</span> <span class="p">{</span> <span class="n">it</span><span class="p">.</span><span class="n">txhash</span> <span class="p">}.</span><span class="n">toSet</span><span class="p">()</span>
<span class="c1">// There are all sorts of funny games a malicious secondary might play here, we should fix them:</span> <span class="n">subProtocol</span><span class="p">(</span><span class="n">ResolveTransactionsProtocol</span><span class="p">(</span><span class="n">dependencyTxIDs</span><span class="p">,</span> <span class="n">otherSide</span><span class="p">))</span>
<span class="c1">//</span>
<span class="c1">// - This tx may attempt to send some assets we aren&#39;t intending to sell to the secondary, if</span>
<span class="c1">// we&#39;re reusing keys! So don&#39;t reuse keys!</span>
<span class="c1">// - This tx may not be valid according to the contracts of the input states, so we must resolve</span>
<span class="c1">// and fully audit the transaction chains to convince ourselves that it is actually valid.</span>
<span class="c1">// - This tx may include output states that impose odd conditions on the movement of the cash,</span>
<span class="c1">// once we implement state pairing.</span>
<span class="p">}</span> <span class="p">}</span>
<span class="k">val</span> <span class="py">ourSignature</span> <span class="p">=</span> <span class="n">args</span><span class="p">.</span><span class="n">myKeyPair</span><span class="p">.</span><span class="n">signWithECDSA</span><span class="p">(</span><span class="n">partialTX</span><span class="p">.</span><span class="n">txBits</span><span class="p">.</span><span class="n">bits</span><span class="p">)</span>
<span class="k">val</span> <span class="py">fullySigned</span><span class="p">:</span> <span class="n">SignedWireTransaction</span> <span class="p">=</span> <span class="n">partialTX</span><span class="p">.</span><span class="n">copy</span><span class="p">(</span><span class="n">sigs</span> <span class="p">=</span> <span class="n">partialTX</span><span class="p">.</span><span class="n">sigs</span> <span class="p">+</span> <span class="n">ourSignature</span><span class="p">)</span>
<span class="n">fullySigned</span><span class="p">.</span><span class="n">verify</span><span class="p">()</span>
<span class="k">val</span> <span class="py">timestamped</span><span class="p">:</span> <span class="n">TimestampedWireTransaction</span> <span class="p">=</span> <span class="n">fullySigned</span><span class="p">.</span><span class="n">toTimestampedTransaction</span><span class="p">(</span><span class="n">serviceHub</span><span class="p">.</span><span class="n">timestampingService</span><span class="p">)</span>
<span class="n">logger</span><span class="p">().</span><span class="n">trace</span> <span class="p">{</span> <span class="s">&quot;Built finished transaction, sending back to secondary!&quot;</span> <span class="p">}</span>
<span class="n">send</span><span class="p">(</span><span class="n">TRADE_TOPIC</span><span class="p">,</span> <span class="n">sessionID</span><span class="p">,</span> <span class="n">timestamped</span><span class="p">)</span>
<span class="k">return</span> <span class="n">Pair</span><span class="p">(</span><span class="n">timestamped</span><span class="p">,</span> <span class="n">timestamped</span><span class="p">.</span><span class="n">verifyToLedgerTransaction</span><span class="p">(</span><span class="n">serviceHub</span><span class="p">.</span><span class="n">timestampingService</span><span class="p">,</span> <span class="n">serviceHub</span><span class="p">.</span><span class="n">identityService</span><span class="p">))</span>
</pre></div> </pre></div>
</div> </div>
</div> </div>
<p>Here, we see some assertions and signature checking to satisfy ourselves that we&#8217;re not about to sign something <p>This is simple enough: we mark the method as <code class="docutils literal"><span class="pre">&#64;Suspendable</span></code> because we&#8217;re going to invoke a sub-protocol, extract the
incorrect. Once we&#8217;re happy, we calculate a signature over the transaction to authorise the movement of the asset IDs of the transactions the proposed transaction depends on, and then uses a protocol provided by the system to download
we are selling, and then we verify things to make sure it&#8217;s all OK. Finally, we request timestamping of the and check them all. This protocol does a breadth-first search over the dependency graph, bottoming out at issuance
transaction, in case the contracts governing the asset we&#8217;re selling require it, and send the now finalised and transactions that don&#8217;t have any inputs themselves. Once the node has audited the transaction history, all the dependencies
validated transaction back to the buyer.</p> are committed to the node&#8217;s local database so they won&#8217;t be checked again next time.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Transaction dependency resolution assumes that the peer you got the transaction from has all of the
dependencies itself. It must do, otherwise it could not have convinced itself that the dependencies were themselves
valid. It&#8217;s important to realise that requesting only the transactions we require is a privacy leak, because if
we don&#8217;t download a transaction from the peer, they know we must have already seen it before. Fixing this privacy
leak will come later.</p>
</div>
<p>After the dependencies, we check the proposed trading transaction for validity by running the contracts for that as
well (but having handled the fact that some signatures are missing ourselves).</p>
<p>Here&#8217;s the rest of the code:</p>
<div class="codeset container">
<div class="highlight-kotlin"><div class="highlight"><pre><span class="k">open</span> <span class="k">fun</span> <span class="nf">signWithOurKey</span><span class="p">(</span><span class="n">partialTX</span><span class="p">:</span> <span class="n">SignedTransaction</span><span class="p">)</span> <span class="p">=</span> <span class="n">myKeyPair</span><span class="p">.</span><span class="n">signWithECDSA</span><span class="p">(</span><span class="n">partialTX</span><span class="p">.</span><span class="n">txBits</span><span class="p">)</span>
<span class="n">@Suspendable</span>
<span class="k">open</span> <span class="k">fun</span> <span class="nf">sendSignatures</span><span class="p">(</span><span class="n">partialTX</span><span class="p">:</span> <span class="n">SignedTransaction</span><span class="p">,</span> <span class="n">ourSignature</span><span class="p">:</span> <span class="n">DigitalSignature</span><span class="p">.</span><span class="n">WithKey</span><span class="p">,</span>
<span class="n">tsaSig</span><span class="p">:</span> <span class="n">DigitalSignature</span><span class="p">.</span><span class="n">LegallyIdentifiable</span><span class="p">):</span> <span class="n">SignedTransaction</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">fullySigned</span> <span class="p">=</span> <span class="n">partialTX</span> <span class="p">+</span> <span class="n">tsaSig</span> <span class="p">+</span> <span class="n">ourSignature</span>
<span class="n">logger</span><span class="p">.</span><span class="n">trace</span> <span class="p">{</span> <span class="s">&quot;Built finished transaction, sending back to secondary!&quot;</span> <span class="p">}</span>
<span class="n">send</span><span class="p">(</span><span class="n">TRADE_TOPIC</span><span class="p">,</span> <span class="n">otherSide</span><span class="p">,</span> <span class="n">buyerSessionID</span><span class="p">,</span> <span class="n">SignaturesFromSeller</span><span class="p">(</span><span class="n">tsaSig</span><span class="p">,</span> <span class="n">ourSignature</span><span class="p">))</span>
<span class="k">return</span> <span class="n">fullySigned</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<p>It&#8217;s should be all pretty straightforward: here, <code class="docutils literal"><span class="pre">txBits</span></code> is the raw byte array representing the transaction.</p>
<p>In <code class="docutils literal"><span class="pre">sendSignatures</span></code>, we take the two signatures we calculated, then add them to the partial transaction we were sent.
We provide an overload for the + operator so signatures can be added to a SignedTransaction easily. Finally, we wrap the
two signatures in a simple wrapper message class and send it back. The send won&#8217;t block waiting for an acknowledgement,
but the underlying message queue software will retry delivery if the other side has gone away temporarily.</p>
<div class="admonition warning"> <div class="admonition warning">
<p class="first admonition-title">Warning</p> <p class="first admonition-title">Warning</p>
<p class="last">This code is <strong>not secure</strong>. Other than not checking for all possible invalid constructions, if the <p class="last">This code is <strong>not secure</strong>. Other than not checking for all possible invalid constructions, if the
@ -442,77 +521,92 @@ seller stops before sending the finalised transaction to the buyer, the seller i
but the buyer isn&#8217;t, so they can&#8217;t spend the asset they just purchased! This sort of thing will be fixed in a but the buyer isn&#8217;t, so they can&#8217;t spend the asset they just purchased! This sort of thing will be fixed in a
future version of the code.</p> future version of the code.</p>
</div> </div>
<p>Finally, the call function returns with the result of the protocol: in our case, the final transaction in two different
forms.</p>
</div> </div>
<div class="section" id="implementing-the-buyer"> <div class="section" id="implementing-the-buyer">
<h2>Implementing the buyer<a class="headerlink" href="#implementing-the-buyer" title="Permalink to this headline"></a></h2> <h2>Implementing the buyer<a class="headerlink" href="#implementing-the-buyer" title="Permalink to this headline"></a></h2>
<p>OK, let&#8217;s do the same for the buyer side:</p> <p>OK, let&#8217;s do the same for the buyer side:</p>
<div class="codeset container"> <div class="codeset container">
<div class="highlight-kotlin"><div class="highlight"><pre>@Suspendable <div class="highlight-kotlin"><div class="highlight"><pre>@Suspendable
override fun call(): Pair&lt;TimestampedWireTransaction, LedgerTransaction&gt; { override fun call(): SignedTransaction {
// Wait for a trade request to come in on our pre-provided session ID. val tradeRequest = receiveAndValidateTradeRequest()
val tradeRequest = receive(TRADE_TOPIC, args.sessionID, SellerTradeInfo::class.java) val (ptx, cashSigningPubKeys) = assembleSharedTX(tradeRequest)
val stx = signWithOurKeys(cashSigningPubKeys, ptx)
val signatures = swapSignaturesWithSeller(stx, tradeRequest.sessionID)
logger.trace { &quot;Got signatures from seller, verifying ... &quot;}
val fullySigned = stx + signatures.timestampAuthoritySig + signatures.sellerSig
fullySigned.verify()
logger.trace { &quot;Fully signed transaction was valid. Trade complete! :-)&quot; }
return fullySigned
}
@Suspendable
open fun receiveAndValidateTradeRequest(): SellerTradeInfo {
// Wait for a trade request to come in on our pre-provided session ID.
val maybeTradeRequest = receive&lt;SellerTradeInfo&gt;(TRADE_TOPIC, sessionID)
maybeTradeRequest.validate {
// What is the seller trying to sell us? // What is the seller trying to sell us?
val assetTypeName = tradeRequest.assetForSale.state.javaClass.name val asset = it.assetForSale.state
logger().trace { &quot;Got trade request for a $assetTypeName&quot; } val assetTypeName = asset.javaClass.name
logger.trace { &quot;Got trade request for a $assetTypeName: ${it.assetForSale}&quot; }
// Check the start message for acceptability. // Check the start message for acceptability.
check(tradeRequest.sessionID &gt; 0) check(it.sessionID &gt; 0)
if (tradeRequest.price &gt; acceptablePrice) if (it.price &gt; acceptablePrice)
throw UnacceptablePriceException(tradeRequest.price) throw UnacceptablePriceException(it.price)
if (!typeToBuy.isInstance(tradeRequest.assetForSale.state)) if (!typeToBuy.isInstance(asset))
throw AssetMismatchException(typeToBuy.name, assetTypeName) throw AssetMismatchException(typeToBuy.name, assetTypeName)
// TODO: Either look up the stateref here in our local db, or accept a long chain // Check the transaction that contains the state which is being resolved.
// of states and validate them to audit the other side and ensure it actually owns // We only have a hash here, so if we don&#39;t know it already, we have to ask for it.
// the state we are being offered! For now, just assume validity! subProtocol(ResolveTransactionsProtocol(setOf(it.assetForSale.ref.txhash), otherSide))
// Generate the shared transaction that both sides will sign, using the data we have. return it
val ptx = TransactionBuilder() }
// Add input and output states for the movement of cash, by using the Cash contract }
// to generate the states.
val wallet = serviceHub.walletService.currentWallet
val cashStates = wallet.statesOfType&lt;Cash.State&gt;()
val cashSigningPubKeys = Cash().craftSpend(ptx, tradeRequest.price,
tradeRequest.sellerOwnerKey, cashStates)
// Add inputs/outputs/a command for the movement of the asset.
ptx.addInputState(tradeRequest.assetForSale.ref)
// Just pick some new public key for now.
val freshKey = serviceHub.keyManagementService.freshKey()
val (command, state) = tradeRequest.assetForSale.state.withNewOwner(freshKey.public)
ptx.addOutputState(state)
ptx.addArg(WireCommand(command, tradeRequest.assetForSale.state.owner))
@Suspendable
open fun swapSignaturesWithSeller(stx: SignedTransaction, theirSessionID: Long): SignaturesFromSeller {
logger.trace { &quot;Sending partially signed transaction to seller&quot; }
// TODO: Protect against the seller terminating here and leaving us in the lurch without the final tx.
return sendAndReceive(TRADE_TOPIC, otherSide, theirSessionID, sessionID, stx, SignaturesFromSeller::class.java).validate { it }
}
open fun signWithOurKeys(cashSigningPubKeys: List&lt;PublicKey&gt;, ptx: TransactionBuilder): SignedTransaction {
// Now sign the transaction with whatever keys we need to move the cash. // Now sign the transaction with whatever keys we need to move the cash.
for (k in cashSigningPubKeys) { for (k in cashSigningPubKeys) {
val priv = serviceHub.keyManagementService.toPrivate(k) val priv = serviceHub.keyManagementService.toPrivate(k)
ptx.signWith(KeyPair(k, priv)) ptx.signWith(KeyPair(k, priv))
} }
val stx = ptx.toSignedTransaction(checkSufficientSignatures = false) return ptx.toSignedTransaction(checkSufficientSignatures = false)
stx.verifySignatures() // Verifies that we generated a signed transaction correctly. }
// TODO: Could run verify() here to make sure the only signature missing is the sellers. open fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair&lt;TransactionBuilder, List&lt;PublicKey&gt;&gt; {
val ptx = TransactionBuilder()
// Add input and output states for the movement of cash, by using the Cash contract to generate the states.
val wallet = serviceHub.walletService.currentWallet
val cashStates = wallet.statesOfType&lt;Cash.State&gt;()
val cashSigningPubKeys = Cash().generateSpend(ptx, tradeRequest.price, tradeRequest.sellerOwnerKey, cashStates)
// Add inputs/outputs/a command for the movement of the asset.
ptx.addInputState(tradeRequest.assetForSale.ref)
// Just pick some new public key for now. This won&#39;t be linked with our identity in any way, which is what
// we want for privacy reasons: the key is here ONLY to manage and control ownership, it is not intended to
// reveal who the owner actually is. The key management service is expected to derive a unique key from some
// initial seed in order to provide privacy protection.
val freshKey = serviceHub.keyManagementService.freshKey()
val (command, state) = tradeRequest.assetForSale.state.withNewOwner(freshKey.public)
ptx.addOutputState(state)
ptx.addCommand(command, tradeRequest.assetForSale.state.owner)
logger().trace { &quot;Sending partially signed transaction to seller&quot; } // And add a request for timestamping: it may be that none of the contracts need this! But it can&#39;t hurt
// to have one.
// TODO: Protect against the buyer terminating here and leaving us in the lurch without ptx.setTime(Instant.now(), timestampingAuthority, 30.seconds)
// the final tx. return Pair(ptx, cashSigningPubKeys)
// TODO: Protect against a malicious buyer sending us back a different transaction to
// the one we built.
val fullySigned = sendAndReceive(TRADE_TOPIC, tradeRequest.sessionID, sessionID, stx,
TimestampedWireTransaction::class.java)
logger().trace { &quot;Got fully signed transaction, verifying ... &quot;}
val ltx = fullySigned.verifyToLedgerTransaction(serviceHub.timestampingService,
serviceHub.identityService)
logger().trace { &quot;Fully signed transaction was valid. Trade complete! :-)&quot; }
return Pair(fullySigned, ltx)
} }
</pre></div> </pre></div>
</div> </div>
@ -520,14 +614,14 @@ override fun call(): Pair&lt;TimestampedWireTransaction, LedgerTransaction&gt; {
<p>This code is longer but still fairly straightforward. Here are some things to pay attention to:</p> <p>This code is longer but still fairly straightforward. Here are some things to pay attention to:</p>
<ol class="arabic simple"> <ol class="arabic simple">
<li>We do some sanity checking on the received message to ensure we&#8217;re being offered what we expected to be offered.</li> <li>We do some sanity checking on the received message to ensure we&#8217;re being offered what we expected to be offered.</li>
<li>We create a cash spend in the normal way, by using <code class="docutils literal"><span class="pre">Cash().craftSpend</span></code>. See the contracts tutorial if this isn&#8217;t <li>We create a cash spend in the normal way, by using <code class="docutils literal"><span class="pre">Cash().generateSpend</span></code>. See the contracts tutorial if this isn&#8217;t
clear.</li> clear.</li>
<li>We access the <em>service hub</em> when we need it to access things that are transient and may change or be recreated <li>We access the <em>service hub</em> when we need it to access things that are transient and may change or be recreated
whilst a protocol is suspended, things like the wallet or the timestamping service. Remember that a protocol may whilst a protocol is suspended, things like the wallet or the timestamping service. Remember that a protocol may
be suspended when it waits to receive a message across node or computer restarts, so objects representing a service be suspended when it waits to receive a message across node or computer restarts, so objects representing a service
or data which may frequently change should be accessed &#8216;just in time&#8217;.</li> or data which may frequently change should be accessed &#8216;just in time&#8217;.</li>
<li>Finally, we send the unfinsished, invalid transaction to the seller so they can sign it. They are expected to send <li>Finally, we send the unfinished, invalid transaction to the seller so they can sign it. They are expected to send
back to us a <code class="docutils literal"><span class="pre">TimestampedWireTransaction</span></code>, which once we verify it, should be the final outcome of the trade.</li> back to us a <code class="docutils literal"><span class="pre">SignaturesFromSeller</span></code>, which once we verify it, should be the final outcome of the trade.</li>
</ol> </ol>
<p>As you can see, the protocol logic is straightforward and does not contain any callbacks or network glue code, despite <p>As you can see, the protocol logic is straightforward and does not contain any callbacks or network glue code, despite
the fact that it takes minimal resources and can survive node restarts.</p> the fact that it takes minimal resources and can survive node restarts.</p>
@ -541,6 +635,47 @@ this problem doesn&#8217;t occur. It&#8217;s also restored for you when a protoc
restart.</p> restart.</p>
</div> </div>
</div> </div>
<div class="section" id="progress-tracking">
<h2>Progress tracking<a class="headerlink" href="#progress-tracking" title="Permalink to this headline"></a></h2>
<p>Not shown in the code snippets above is the usage of the <code class="docutils literal"><span class="pre">ProgressTracker</span></code> API. Progress tracking exports information
from a protocol about where it&#8217;s got up to in such a way that observers can render it in a useful manner to humans who
may need to be informed. It may be rendered via an API, in a GUI, onto a terminal window, etc.</p>
<p>A <code class="docutils literal"><span class="pre">ProgressTracker</span></code> is constructed with a series of <code class="docutils literal"><span class="pre">Step</span></code> objects, where each step is an object representing a
stage in a piece of work. It is therefore typical to use singletons that subclass <code class="docutils literal"><span class="pre">Step</span></code>, which may be defined easily
in one line when using Kotlin. Typical steps might be &#8220;Waiting for response from peer&#8221;, &#8220;Waiting for signature to be
approved&#8221;, &#8220;Downloading and verifying data&#8221; etc.</p>
<p>Each step exposes a label. By default labels are fixed, but by subclassing <code class="docutils literal"><span class="pre">RelabelableStep</span></code>
you can make a step that can update its label on the fly. That&#8217;s useful for steps that want to expose non-structured
progress information like the current file being downloaded. By defining your own step types, you can export progress
in a way that&#8217;s both human readable and machine readable.</p>
<p>Progress trackers are hierarchical. Each step can be the parent for another tracker. By altering the
<code class="docutils literal"><span class="pre">ProgressTracker.childrenFor[step]</span> <span class="pre">=</span> <span class="pre">tracker</span></code> map, a tree of steps can be created. It&#8217;s allowed to alter the hierarchy
at runtime, on the fly, and the progress renderers will adapt to that properly. This can be helpful when you don&#8217;t
fully know ahead of time what steps will be required. If you _do_ know what is required, configuring as much of the
hierarchy ahead of time is a good idea, as that will help the users see what is coming up.</p>
<p>Every tracker has not only the steps given to it at construction time, but also the singleton
<code class="docutils literal"><span class="pre">ProgressTracker.UNSTARTED</span></code> step and the <code class="docutils literal"><span class="pre">ProgressTracker.DONE</span></code> step. Once a tracker has become <code class="docutils literal"><span class="pre">DONE</span></code> its
position may not be modified again (because e.g. the UI may have been removed/cleaned up), but until that point, the
position can be set to any arbitrary set both forwards and backwards. Steps may be skipped, repeated, etc. Note that
rolling the current step backwards will delete any progress trackers that are children of the steps being reversed, on
the assumption that those subtasks will have to be repeated.</p>
<p>Trackers provide an <a class="reference external" href="http://reactivex.io/">Rx observable</a> which streams changes to the hierarchy. The top level
observable exposes all the events generated by its children as well. The changes are represented by objects indicating
whether the change is one of position (i.e. progress), structure (i.e. new subtasks being added/removed) or some other
aspect of rendering (i.e. a step has changed in some way and is requesting a re-render).</p>
<p>The protocol framework is somewhat integrated with this API. Each <code class="docutils literal"><span class="pre">ProtocolLogic</span></code> may optionally provide a tracker by
overriding the <code class="docutils literal"><span class="pre">protocolTracker</span></code> property (<code class="docutils literal"><span class="pre">getProtocolTracker</span></code> method in Java). If the
<code class="docutils literal"><span class="pre">ProtocolLogic.subProtocol</span></code> method is used, then the tracker of the sub-protocol will be made a child of the current
step in the parent protocol automatically, if the parent is using tracking in the first place. The framework will also
automatically set the current step to <code class="docutils literal"><span class="pre">DONE</span></code> for you, when the protocol is finished.</p>
<p>Because a protocol may sometimes wish to configure the children in its progress hierarchy _before_ the sub-protocol
is constructed, for sub-protocols that always follow the same outline regardless of their parameters it&#8217;s conventional
to define a companion object/static method (for Kotlin/Java respectively) that constructs a tracker, and then allow
the sub-protocol to have the tracker it will use be passed in as a parameter. This allows all trackers to be built
and linked ahead of time.</p>
<p>In future, the progress tracking framework will become a vital part of how exceptions, errors, and other faults are
surfaced to human operators for investigation and resolution.</p>
</div>
</div> </div>
@ -584,7 +719,7 @@ restart.</p>
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true

View File

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Roadmap &mdash; R3 Prototyping 0.1 documentation</title> <title>Roadmap &mdash; R3 Prototyping latest documentation</title>
@ -30,7 +30,7 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/> <link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
<link rel="next" title="Code style guide" href="codestyle.html"/> <link rel="next" title="Code style guide" href="codestyle.html"/>
<link rel="prev" title="Using the visualiser" href="visualiser.html"/> <link rel="prev" title="Using the visualiser" href="visualiser.html"/>
@ -60,7 +60,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -87,6 +87,7 @@
<li class="toctree-l1"><a class="reference internal" href="getting-set-up.html">Getting set up</a></li> <li class="toctree-l1"><a class="reference internal" href="getting-set-up.html">Getting set up</a></li>
<li class="toctree-l1"><a class="reference internal" href="data-model.html">Data model</a></li> <li class="toctree-l1"><a class="reference internal" href="data-model.html">Data model</a></li>
<li class="toctree-l1"><a class="reference internal" href="messaging.html">Networking and messaging</a></li> <li class="toctree-l1"><a class="reference internal" href="messaging.html">Networking and messaging</a></li>
<li class="toctree-l1"><a class="reference internal" href="running-the-trading-demo.html">Running the trading demo</a></li>
</ul> </ul>
<p class="caption"><span class="caption-text">Tutorials</span></p> <p class="caption"><span class="caption-text">Tutorials</span></p>
<ul> <ul>
@ -220,7 +221,7 @@ Thread.stop() unsafe to use), and to measure and enforce runtime limits to handl
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true

View File

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Running the trading demo &mdash; R3 Prototyping 0.1 documentation</title> <title>Running the trading demo &mdash; R3 Prototyping latest documentation</title>
@ -30,7 +30,7 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/> <link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
<link rel="next" title="Writing a contract" href="tutorial.html"/> <link rel="next" title="Writing a contract" href="tutorial.html"/>
<link rel="prev" title="Networking and messaging" href="messaging.html"/> <link rel="prev" title="Networking and messaging" href="messaging.html"/>
@ -60,7 +60,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -150,21 +150,21 @@ can learn about in <a class="reference internal" href="protocol-state-machines.h
<p>The node has only currently been tested on MacOS X and Ubuntu Linux. If you have success on other platforms, please <p>The node has only currently been tested on MacOS X and Ubuntu Linux. If you have success on other platforms, please
let us know.</p> let us know.</p>
<p>Now, open two terminals, and in the first run::</p> <p>Now, open two terminals, and in the first run::</p>
<div class="highlight-kotlin"><div class="highlight"><pre><span class="p">./</span><span class="n">gradlew</span> <span class="n">runDemoBuyer</span> <div class="highlight-kotlin"><div class="highlight"><pre><span class="p">./</span><span class="n">scripts</span><span class="p">/</span><span class="n">trader</span><span class="p">-</span><span class="n">demo</span><span class="p">.</span><span class="n">sh</span> <span class="n">buyer</span>
</pre></div> </pre></div>
</div> </div>
<p>It will create a directory named &#8220;buyer&#8221; and ask you to edit the configuration file inside. Open up <code class="docutils literal"><span class="pre">buyer/config</span></code> <p>It will compile things, if necessary, then create a directory named &#8220;buyer&#8221; with a bunch of files inside and start
in your favourite text editor and give the node a legal identity of &#8220;Big Buyer Corp, Inc&#8221; or whatever else you feel like. the node. You should see it waiting for a trade to begin.</p>
The actual text string is not important. Now run the gradle command again, and it should start up and wait for
a seller to connect.</p>
<p>In the second terminal, run:</p> <p>In the second terminal, run:</p>
<div class="highlight-kotlin"><div class="highlight"><pre><span class="p">./</span><span class="n">gradlew</span> <span class="n">runDemoSeller</span> <div class="highlight-kotlin"><div class="highlight"><pre><span class="p">./</span><span class="n">scripts</span><span class="p">/</span><span class="n">trader</span><span class="p">-</span><span class="n">demo</span><span class="p">.</span><span class="n">sh</span> <span class="n">seller</span>
</pre></div> </pre></div>
</div> </div>
<p>and repeat the process, this time calling the node ... something else.</p>
<p>You should see some log lines scroll past, and within a few seconds the messages &#8220;Purchase complete - we are a <p>You should see some log lines scroll past, and within a few seconds the messages &#8220;Purchase complete - we are a
happy customer!&#8221; and &#8220;Sale completed - we have a happy customer!&#8221; should be printed.</p> happy customer!&#8221; and &#8220;Sale completed - we have a happy customer!&#8221; should be printed.</p>
<p>If it doesn&#8217;t work, jump on the mailing list and let us know.</p> <p>If it doesn&#8217;t work, jump on the mailing list and let us know.</p>
<p>For Windows users, the contents of the shell script are very trivial and can easily be done by hand from a command
window. Essentially, it just runs Gradle to create the startup scripts, and then starts the node with one set of
flags or another.</p>
</div> </div>
@ -208,7 +208,7 @@ happy customer!&#8221; and &#8220;Sale completed - we have a happy customer!&#82
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true

View File

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Search &mdash; R3 Prototyping 0.1 documentation</title> <title>Search &mdash; R3 Prototyping latest documentation</title>
@ -30,7 +30,7 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/> <link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
<script src="_static/js/modernizr.min.js"></script> <script src="_static/js/modernizr.min.js"></script>
@ -58,7 +58,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -182,7 +182,7 @@
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Writing a contract &mdash; R3 Prototyping 0.1 documentation</title> <title>Writing a contract &mdash; R3 Prototyping latest documentation</title>
@ -30,7 +30,7 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/> <link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
<link rel="next" title="Protocol state machines" href="protocol-state-machines.html"/> <link rel="next" title="Protocol state machines" href="protocol-state-machines.html"/>
<link rel="prev" title="Running the trading demo" href="running-the-trading-demo.html"/> <link rel="prev" title="Running the trading demo" href="running-the-trading-demo.html"/>
@ -60,7 +60,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -99,7 +99,7 @@
<li class="toctree-l2"><a class="reference internal" href="#understanding-fungibility">Understanding fungibility</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="#checking-the-requirements">Checking the requirements</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="#how-to-test-your-contract">How to test your contract</a></li>
<li class="toctree-l2"><a class="reference internal" href="#adding-a-crafting-api-to-your-contract">Adding a crafting API to 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>
<li class="toctree-l2"><a class="reference internal" href="#non-asset-oriented-based-smart-contracts">Non-asset-oriented based smart contracts</a></li> <li class="toctree-l2"><a class="reference internal" href="#non-asset-oriented-based-smart-contracts">Non-asset-oriented based smart contracts</a></li>
</ul> </ul>
</li> </li>
@ -725,25 +725,25 @@ an exception will be thrown indicating which transaction failed and why. In the
again to ensure the third transaction fails with a message that contains &#8220;must have matured&#8221; (it doesn&#8217;t have to be again to ensure the third transaction fails with a message that contains &#8220;must have matured&#8221; (it doesn&#8217;t have to be
the exact message).</p> the exact message).</p>
</div> </div>
<div class="section" id="adding-a-crafting-api-to-your-contract"> <div class="section" id="adding-a-generation-api-to-your-contract">
<h2>Adding a crafting API to your contract<a class="headerlink" href="#adding-a-crafting-api-to-your-contract" title="Permalink to this headline"></a></h2> <h2>Adding a generation API to your contract<a class="headerlink" href="#adding-a-generation-api-to-your-contract" title="Permalink to this headline"></a></h2>
<p>Contract classes <strong>must</strong> provide a verify function, but they may optionally also provide helper functions to simplify <p>Contract classes <strong>must</strong> provide a verify function, but they may optionally also provide helper functions to simplify
their usage. A simple class of functions most contracts provide are <em>crafting functions</em>, which either generate or their usage. A simple class of functions most contracts provide are <em>generation functions</em>, which either create or
modify a transaction to perform certain actions (an action is normally mappable 1:1 to a command, but doesn&#8217;t have to modify a transaction to perform certain actions (an action is normally mappable 1:1 to a command, but doesn&#8217;t have to
be so).</p> be so).</p>
<p>Crafting may involve complex logic. For example, the cash contract has a <code class="docutils literal"><span class="pre">craftSpend</span></code> method that is given a set of <p>Generation may involve complex logic. For example, the cash contract has a <code class="docutils literal"><span class="pre">generateSpend</span></code> method that is given a set of
cash states and chooses a way to combine them together to satisfy the amount of money that is being sent. In the cash states and chooses a way to combine them together to satisfy the amount of money that is being sent. In the
immutable-state model that we are using ledger entries (states) can only be created and deleted, but never modified. immutable-state model that we are using ledger entries (states) can only be created and deleted, but never modified.
Therefore to send $1200 when we have only $900 and $500 requires combining both states together, and then creating Therefore to send $1200 when we have only $900 and $500 requires combining both states together, and then creating
two new output states of $1200 and $200 back to ourselves. This latter state is called the <em>change</em> and is a concept two new output states of $1200 and $200 back to ourselves. This latter state is called the <em>change</em> and is a concept
that should be familiar to anyone who has worked with Bitcoin.</p> that should be familiar to anyone who has worked with Bitcoin.</p>
<p>As another example, we can imagine code that implements a netting algorithm may craft complex transactions that must <p>As another example, we can imagine code that implements a netting algorithm may generate complex transactions that must
be signed by many people. Whilst such code might be too big for a single utility method (it&#8217;d probably be sized more be signed by many people. Whilst such code might be too big for a single utility method (it&#8217;d probably be sized more
like a module), the basic concept is the same: preparation of a transaction using complex logic.</p> like a module), the basic concept is the same: preparation of a transaction using complex logic.</p>
<p>For our commercial paper contract however, the things that can be done with it are quite simple. Let&#8217;s start with <p>For our commercial paper contract however, the things that can be done with it are quite simple. Let&#8217;s start with
a method to wrap up the issuance process:</p> a method to wrap up the issuance process:</p>
<div class="codeset container"> <div class="codeset container">
<div class="highlight-kotlin"><div class="highlight"><pre><span class="k">fun</span> <span class="nf">craftIssue</span><span class="p">(</span><span class="n">issuance</span><span class="p">:</span> <span class="n">InstitutionReference</span><span class="p">,</span> <span class="n">faceValue</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span> <span class="n">maturityDate</span><span class="p">:</span> <span class="n">Instant</span><span class="p">):</span> <span class="n">TransactionBuilder</span> <span class="p">{</span> <div class="highlight-kotlin"><div class="highlight"><pre><span class="k">fun</span> <span class="nf">generateIssue</span><span class="p">(</span><span class="n">issuance</span><span class="p">:</span> <span class="n">InstitutionReference</span><span class="p">,</span> <span class="n">faceValue</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span> <span class="n">maturityDate</span><span class="p">:</span> <span class="n">Instant</span><span class="p">):</span> <span class="n">TransactionBuilder</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">state</span> <span class="p">=</span> <span class="n">State</span><span class="p">(</span><span class="n">issuance</span><span class="p">,</span> <span class="n">issuance</span><span class="p">.</span><span class="n">party</span><span class="p">.</span><span class="n">owningKey</span><span class="p">,</span> <span class="n">faceValue</span><span class="p">,</span> <span class="n">maturityDate</span><span class="p">)</span> <span class="k">val</span> <span class="py">state</span> <span class="p">=</span> <span class="n">State</span><span class="p">(</span><span class="n">issuance</span><span class="p">,</span> <span class="n">issuance</span><span class="p">.</span><span class="n">party</span><span class="p">.</span><span class="n">owningKey</span><span class="p">,</span> <span class="n">faceValue</span><span class="p">,</span> <span class="n">maturityDate</span><span class="p">)</span>
<span class="k">return</span> <span class="n">TransactionBuilder</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">WireCommand</span><span class="p">(</span><span class="n">Commands</span><span class="p">.</span><span class="n">Issue</span><span class="p">,</span> <span class="n">issuance</span><span class="p">.</span><span class="n">party</span><span class="p">.</span><span class="n">owningKey</span><span class="p">))</span> <span class="k">return</span> <span class="n">TransactionBuilder</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">WireCommand</span><span class="p">(</span><span class="n">Commands</span><span class="p">.</span><span class="n">Issue</span><span class="p">,</span> <span class="n">issuance</span><span class="p">.</span><span class="n">party</span><span class="p">.</span><span class="n">owningKey</span><span class="p">))</span>
<span class="p">}</span> <span class="p">}</span>
@ -757,7 +757,7 @@ It allows you to add inputs, outputs and commands to it and is designed to be pa
multiple contracts.</p> multiple contracts.</p>
<div class="admonition note"> <div class="admonition note">
<p class="first admonition-title">Note</p> <p class="first admonition-title">Note</p>
<p class="last">Crafting methods should ideally be written to compose with each other, that is, they should take a <p class="last">Generation methods should ideally be written to compose with each other, that is, they should take a
<code class="docutils literal"><span class="pre">TransactionBuilder</span></code> as an argument instead of returning one, unless you are sure it doesn&#8217;t make sense to <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> as an argument instead of returning one, unless you are sure it doesn&#8217;t make sense to
combine this type of transaction with others. In this case, issuing CP at the same time as doing other things combine this type of transaction with others. In this case, issuing CP at the same time as doing other things
would just introduce complexity that isn&#8217;t likely to be worth it, so we return a fresh object each time: instead, would just introduce complexity that isn&#8217;t likely to be worth it, so we return a fresh object each time: instead,
@ -774,7 +774,7 @@ any <code class="docutils literal"><span class="pre">ContractStateRef</span></co
for you.</p> for you.</p>
<p>What about moving the paper, i.e. reassigning ownership to someone else?</p> <p>What about moving the paper, i.e. reassigning ownership to someone else?</p>
<div class="codeset container"> <div class="codeset container">
<div class="highlight-kotlin"><div class="highlight"><pre><span class="k">fun</span> <span class="nf">craftMove</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">TransactionBuilder</span><span class="p">,</span> <span class="n">paper</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">State</span><span class="p">&gt;,</span> <span class="n">newOwner</span><span class="p">:</span> <span class="n">PublicKey</span><span class="p">)</span> <span class="p">{</span> <div class="highlight-kotlin"><div class="highlight"><pre><span class="k">fun</span> <span class="nf">generateMove</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">TransactionBuilder</span><span class="p">,</span> <span class="n">paper</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">State</span><span class="p">&gt;,</span> <span class="n">newOwner</span><span class="p">:</span> <span class="n">PublicKey</span><span class="p">)</span> <span class="p">{</span>
<span class="n">tx</span><span class="p">.</span><span class="n">addInputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">ref</span><span class="p">)</span> <span class="n">tx</span><span class="p">.</span><span class="n">addInputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">ref</span><span class="p">)</span>
<span class="n">tx</span><span class="p">.</span><span class="n">addOutputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">copy</span><span class="p">(</span><span class="n">owner</span> <span class="p">=</span> <span class="n">newOwner</span><span class="p">))</span> <span class="n">tx</span><span class="p">.</span><span class="n">addOutputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">copy</span><span class="p">(</span><span class="n">owner</span> <span class="p">=</span> <span class="n">newOwner</span><span class="p">))</span>
<span class="n">tx</span><span class="p">.</span><span class="n">addArg</span><span class="p">(</span><span class="n">WireCommand</span><span class="p">(</span><span class="n">Commands</span><span class="p">.</span><span class="n">Move</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">))</span> <span class="n">tx</span><span class="p">.</span><span class="n">addArg</span><span class="p">(</span><span class="n">WireCommand</span><span class="p">(</span><span class="n">Commands</span><span class="p">.</span><span class="n">Move</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">))</span>
@ -784,7 +784,7 @@ for you.</p>
</div> </div>
<p>Here, the method takes a pre-existing <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> and adds to it. This is correct because typically <p>Here, the method takes a pre-existing <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> and adds to it. This is correct because typically
you will want to combine a sale of CP atomically with the movement of some other asset, such as cash. So both you will want to combine a sale of CP atomically with the movement of some other asset, such as cash. So both
craft methods should operate on the same transaction. You can see an example of this being done in the unit tests generate methods should operate on the same transaction. You can see an example of this being done in the unit tests
for the commercial paper contract.</p> for the commercial paper contract.</p>
<p>The paper is given to us as a <code class="docutils literal"><span class="pre">StateAndRef&lt;CommercialPaper.State&gt;</span></code> object. This is exactly what it sounds like: <p>The paper is given to us as a <code class="docutils literal"><span class="pre">StateAndRef&lt;CommercialPaper.State&gt;</span></code> 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
@ -792,9 +792,9 @@ state on the ledger.</p>
<p>Finally, we can do redemption.</p> <p>Finally, we can do redemption.</p>
<div class="codeset container"> <div class="codeset container">
<div class="highlight-kotlin"><div class="highlight"><pre><span class="n">@Throws</span><span class="p">(</span><span class="n">InsufficientBalanceException</span><span class="o">::</span><span class="k">class</span><span class="p">)</span> <div class="highlight-kotlin"><div class="highlight"><pre><span class="n">@Throws</span><span class="p">(</span><span class="n">InsufficientBalanceException</span><span class="o">::</span><span class="k">class</span><span class="p">)</span>
<span class="k">fun</span> <span class="nf">craftRedeem</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">TransactionBuilder</span><span class="p">,</span> <span class="n">paper</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">State</span><span class="p">&gt;,</span> <span class="n">wallet</span><span class="p">:</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">Cash</span><span class="p">.</span><span class="n">State</span><span class="p">&gt;&gt;)</span> <span class="p">{</span> <span class="k">fun</span> <span class="nf">generateRedeem</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">TransactionBuilder</span><span class="p">,</span> <span class="n">paper</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">State</span><span class="p">&gt;,</span> <span class="n">wallet</span><span class="p">:</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">StateAndRef</span><span class="p">&lt;</span><span class="n">Cash</span><span class="p">.</span><span class="n">State</span><span class="p">&gt;&gt;)</span> <span class="p">{</span>
<span class="c1">// Add the cash movement using the states in our wallet.</span> <span class="c1">// Add the cash movement using the states in our wallet.</span>
<span class="n">Cash</span><span class="p">().</span><span class="n">craftSpend</span><span class="p">(</span><span class="n">tx</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">faceValue</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">,</span> <span class="n">wallet</span><span class="p">)</span> <span class="n">Cash</span><span class="p">().</span><span class="n">generateSpend</span><span class="p">(</span><span class="n">tx</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">faceValue</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">,</span> <span class="n">wallet</span><span class="p">)</span>
<span class="n">tx</span><span class="p">.</span><span class="n">addInputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">ref</span><span class="p">)</span> <span class="n">tx</span><span class="p">.</span><span class="n">addInputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">ref</span><span class="p">)</span>
<span class="n">tx</span><span class="p">.</span><span class="n">addArg</span><span class="p">(</span><span class="n">WireCommand</span><span class="p">(</span><span class="n">CommercialPaper</span><span class="p">.</span><span class="n">Commands</span><span class="p">.</span><span class="n">Redeem</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">))</span> <span class="n">tx</span><span class="p">.</span><span class="n">addArg</span><span class="p">(</span><span class="n">WireCommand</span><span class="p">(</span><span class="n">CommercialPaper</span><span class="p">.</span><span class="n">Commands</span><span class="p">.</span><span class="n">Redeem</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">))</span>
<span class="p">}</span> <span class="p">}</span>
@ -819,12 +819,9 @@ paper.</p>
is recognised by the network. The most important next step is for the participating entities to sign it using the is recognised by the network. The most important next step is for the participating entities to sign it using the
<code class="docutils literal"><span class="pre">signWith()</span></code> method. This takes a keypair, serialises the transaction, signs the serialised form and then stores the <code class="docutils literal"><span class="pre">signWith()</span></code> method. This takes a keypair, serialises the transaction, signs the serialised form and then stores the
signature inside the <code class="docutils literal"><span class="pre">TransactionBuilder</span></code>. Once all parties have signed, you can call <code class="docutils literal"><span class="pre">TransactionBuilder.toSignedTransaction()</span></code> signature inside the <code class="docutils literal"><span class="pre">TransactionBuilder</span></code>. Once all parties have signed, you can call <code class="docutils literal"><span class="pre">TransactionBuilder.toSignedTransaction()</span></code>
to get a <code class="docutils literal"><span class="pre">SignedWireTransaction</span></code> object. This is an immutable form of the transaction that&#8217;s ready for <em>timestamping</em>.</p> to get a <code class="docutils literal"><span class="pre">SignedTransaction</span></code> object. This is an immutable form of the transaction that&#8217;s ready for <em>timestamping</em>,
<div class="admonition note"> which can be done using a <code class="docutils literal"><span class="pre">TimestamperClient</span></code>. To learn more about that, please refer to the
<p class="first admonition-title">Note</p> <a class="reference internal" href="protocol-state-machines.html"><em>Protocol state machines</em></a> document.</p>
<p class="last">Timestamping and passing around of partial transactions for group signing is not yet fully implemented.
This tutorial will be updated once it is.</p>
</div>
<p>You can see how transactions flow through the different stages of construction by examining the commercial paper <p>You can see how transactions flow through the different stages of construction by examining the commercial paper
unit tests.</p> unit tests.</p>
</div> </div>
@ -902,7 +899,7 @@ be implemented once in a separate contract, with the controlling data being held
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true

View File

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Using the visualiser &mdash; R3 Prototyping 0.1 documentation</title> <title>Using the visualiser &mdash; R3 Prototyping latest documentation</title>
@ -30,7 +30,7 @@
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/> <link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
<link rel="next" title="Roadmap" href="roadmap.html"/> <link rel="next" title="Roadmap" href="roadmap.html"/>
<link rel="prev" title="Protocol state machines" href="protocol-state-machines.html"/> <link rel="prev" title="Protocol state machines" href="protocol-state-machines.html"/>
@ -60,7 +60,7 @@
<div class="version"> <div class="version">
0.1 latest
</div> </div>
@ -87,6 +87,7 @@
<li class="toctree-l1"><a class="reference internal" href="getting-set-up.html">Getting set up</a></li> <li class="toctree-l1"><a class="reference internal" href="getting-set-up.html">Getting set up</a></li>
<li class="toctree-l1"><a class="reference internal" href="data-model.html">Data model</a></li> <li class="toctree-l1"><a class="reference internal" href="data-model.html">Data model</a></li>
<li class="toctree-l1"><a class="reference internal" href="messaging.html">Networking and messaging</a></li> <li class="toctree-l1"><a class="reference internal" href="messaging.html">Networking and messaging</a></li>
<li class="toctree-l1"><a class="reference internal" href="running-the-trading-demo.html">Running the trading demo</a></li>
</ul> </ul>
<p class="caption"><span class="caption-text">Tutorials</span></p> <p class="caption"><span class="caption-text">Tutorials</span></p>
<ul> <ul>
@ -250,7 +251,7 @@ feature).</li>
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./', URL_ROOT:'./',
VERSION:'0.1', VERSION:'latest',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
HAS_SOURCE: true HAS_SOURCE: true