mirror of
https://github.com/corda/corda.git
synced 2025-01-18 10:46:38 +00:00
611 lines
37 KiB
HTML
611 lines
37 KiB
HTML
|
|
|
|
<!DOCTYPE html>
|
|
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
|
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
|
<head>
|
|
<meta charset="utf-8">
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
<title>Protocol state machines — R3 Prototyping 0.1 documentation</title>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="top" title="R3 Prototyping 0.1 documentation" href="index.html"/>
|
|
<link rel="next" title="Using the visualiser" href="visualiser.html"/>
|
|
<link rel="prev" title="Writing a contract" href="tutorial.html"/>
|
|
|
|
|
|
<script src="_static/js/modernizr.min.js"></script>
|
|
|
|
</head>
|
|
|
|
<body class="wy-body-for-nav" role="document">
|
|
|
|
<div class="wy-grid-for-nav">
|
|
|
|
|
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
|
<div class="wy-side-scroll">
|
|
<div class="wy-side-nav-search">
|
|
|
|
|
|
|
|
<a href="index.html" class="icon icon-home"> R3 Prototyping
|
|
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
|
|
<div class="version">
|
|
0.1
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div role="search">
|
|
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
|
<input type="text" name="q" placeholder="Search docs" />
|
|
<input type="hidden" name="check_keywords" value="yes" />
|
|
<input type="hidden" name="area" value="default" />
|
|
</form>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
|
|
|
|
|
|
|
<p class="caption"><span class="caption-text">Overview</span></p>
|
|
<ul>
|
|
<li class="toctree-l1"><a class="reference internal" href="inthebox.html">What’s included?</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="messaging.html">Networking and messaging</a></li>
|
|
</ul>
|
|
<p class="caption"><span class="caption-text">Tutorials</span></p>
|
|
<ul class="current">
|
|
<li class="toctree-l1"><a class="reference internal" href="tutorial.html">Writing a contract</a></li>
|
|
<li class="toctree-l1 current"><a class="current reference internal" href="">Protocol state machines</a><ul>
|
|
<li class="toctree-l2"><a class="reference internal" href="#introduction">Introduction</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#theory">Theory</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#a-two-party-trading-protocol">A two party trading protocol</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-buyer">Implementing the buyer</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p class="caption"><span class="caption-text">Appendix</span></p>
|
|
<ul>
|
|
<li class="toctree-l1"><a class="reference internal" href="visualiser.html">Using the visualiser</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="roadmap.html">Roadmap</a></li>
|
|
</ul>
|
|
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
|
|
|
|
|
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
|
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
|
<a href="index.html">R3 Prototyping</a>
|
|
</nav>
|
|
|
|
|
|
|
|
<div class="wy-nav-content">
|
|
<div class="rst-content">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
|
<ul class="wy-breadcrumbs">
|
|
<li><a href="index.html">Docs</a> »</li>
|
|
|
|
<li>Protocol state machines</li>
|
|
<li class="wy-breadcrumbs-aside">
|
|
|
|
|
|
<a href="_sources/protocol-state-machines.txt" rel="nofollow"> View page source</a>
|
|
|
|
|
|
</li>
|
|
</ul>
|
|
<hr/>
|
|
</div>
|
|
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
|
<div itemprop="articleBody">
|
|
|
|
<script type="text/javascript" src="_static/jquery.js"></script>
|
|
<script type="text/javascript" src="_static/codesets.js"></script><div class="section" id="protocol-state-machines">
|
|
<h1>Protocol state machines<a class="headerlink" href="#protocol-state-machines" title="Permalink to this headline">¶</a></h1>
|
|
<p>This article explains our experimental approach to modelling financial protocols in code. It explains how the
|
|
platform’s state machine framework is used, and takes you through the code for a simple 2-party asset trading protocol
|
|
which is included in the source.</p>
|
|
<div class="section" id="introduction">
|
|
<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2>
|
|
<p>Shared distributed ledgers are interesting because they allow many different, mutually distrusting parties to
|
|
share a single source of truth about the ownership of assets. Digitally signed transactions are used to update that
|
|
shared ledger, and transactions may alter many states simultaneously and atomically.</p>
|
|
<p>Blockchain systems such as Bitcoin support the idea of building up a finished, signed transaction by passing around
|
|
partially signed invalid transactions outside of the main network, and by doing this you can implement
|
|
<em>delivery versus payment</em> such that there is no chance of settlement failure, because the movement of cash and the
|
|
traded asset are performed atomically by the same transaction. To perform such a trade involves a multi-step protocol
|
|
in which messages are passed back and forth privately between parties, checked, signed and so on.</p>
|
|
<p>Despite how useful these protocols are, platforms such as Bitcoin and Ethereum do not assist the developer with the rather
|
|
tricky task of actually building them. That is unfortunate. There are many awkward problems in their implementation
|
|
that a good platform would take care of for you, problems like:</p>
|
|
<ul class="simple">
|
|
<li>Avoiding “callback hell” in which code that should ideally be sequential is turned into an unreadable mess due to the
|
|
desire to avoid using up a thread for every protocol instantiation.</li>
|
|
<li>Surviving node shutdowns/restarts that may occur in the middle of the protocol without complicating things. This
|
|
implies that the state of the protocol must be persisted to disk.</li>
|
|
<li>Error handling.</li>
|
|
<li>Message routing.</li>
|
|
<li>Serialisation.</li>
|
|
<li>Catching type errors, in which the developer gets temporarily confused and expects to receive/send one type of message
|
|
when actually they need to receive/send another.</li>
|
|
<li>Unit testing of the finished protocol.</li>
|
|
</ul>
|
|
<p>Actor frameworks can solve some of the above but they are often tightly bound to a particular messaging layer, and
|
|
we would like to keep a clean separation. Additionally, they are typically not type safe, and don’t make persistence or
|
|
writing sequential code much easier.</p>
|
|
<p>To put these problems in perspective the <em>payment channel protocol</em> in the bitcoinj library, which allows bitcoins to
|
|
be temporarily moved off-chain and traded at high speed between two parties in private, consists of about 7000 lines of
|
|
Java and took over a month of full time work to develop. Most of that code is concerned with the details of persistence,
|
|
message passing, lifecycle management, error handling and callback management. Because the business logic is quite
|
|
spread out the code can be difficult to read and debug.</p>
|
|
<p>As small contract-specific trading protocols are a common occurence in finance, we provide a framework for the
|
|
construction of them that automatically handles many of the concerns outlined above.</p>
|
|
</div>
|
|
<div class="section" id="theory">
|
|
<h2>Theory<a class="headerlink" href="#theory" title="Permalink to this headline">¶</a></h2>
|
|
<p>A <em>continuation</em> is a suspended stack frame stored in a regular object that can be passed around, serialised,
|
|
unserialised and resumed from where it was suspended. This may sound abstract but don’t worry, the examples below
|
|
will make it clearer. The JVM does not natively support continuations, so we implement them using a library called
|
|
JavaFlow which works through behind-the-scenes bytecode rewriting. You don’t have to know how this works to benefit
|
|
from it, however.</p>
|
|
<p>We use continuations for the following reasons:</p>
|
|
<ul class="simple">
|
|
<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.
|
|
In contrast a suspended Java stack can easily be 1mb in size.</li>
|
|
<li>It frees the developer from thinking (much) about persistence and serialisation.</li>
|
|
</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
|
|
model (that represent facts about the world on the ledger), but rather indicate different stages in the progression
|
|
of a multi-stage protocol. Typically writing a state machine would require the use of a big switch statement and some
|
|
explicit variables to keep track of where you’re up to. The use of continuations avoids this hassle.</p>
|
|
</div>
|
|
<div class="section" id="a-two-party-trading-protocol">
|
|
<h2>A two party trading protocol<a class="headerlink" href="#a-two-party-trading-protocol" title="Permalink to this headline">¶</a></h2>
|
|
<p>We would like to implement the “hello world” of shared transaction building protocols: a seller wishes to sell some
|
|
<em>asset</em> (e.g. some commercial paper) in return for <em>cash</em>. The buyer wishes to purchase the asset using his cash. They
|
|
want the trade to be atomic so neither side is exposed to the risk of settlement failure. We assume that the buyer
|
|
and seller have found each other and arranged the details on some exchange, or over the counter. The details of how
|
|
the trade is arranged isn’t covered in this article.</p>
|
|
<p>Our protocol has two parties (B and S for buyer and seller) and will proceed as follows:</p>
|
|
<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
|
|
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’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
|
|
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>
|
|
</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>Assuming no malicious termination, they both end the protocol being in posession of a valid, signed transaction that
|
|
represents an atomic asset swap.</p>
|
|
<p>Note that it’s the <em>seller</em> who initiates contact with the buyer, not vice-versa as you might imagine.</p>
|
|
<p>We start by defining an abstract base class to encapsulate the protocol. This is what code that invokes the protocol
|
|
will see:</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre>abstract class TwoPartyTradeProtocol {
|
|
class SellerInitialArgs(
|
|
val assetToSell: StateAndRef<OwnableState>,
|
|
val price: Amount,
|
|
val myKeyPair: KeyPair,
|
|
val buyerSessionID: Long
|
|
)
|
|
|
|
abstract fun runSeller(otherSide: SingleMessageRecipient, args: SellerInitialArgs): Seller
|
|
|
|
class BuyerInitialArgs(
|
|
val acceptablePrice: Amount,
|
|
val typeToBuy: Class<out OwnableState>,
|
|
val sessionID: Long
|
|
)
|
|
|
|
abstract fun runBuyer(otherSide: SingleMessageRecipient, args: BuyerInitialArgs): Buyer
|
|
|
|
abstract class Buyer : ProtocolStateMachine<BuyerInitialArgs, Pair<TimestampedWireTransaction, LedgerTransaction>>()
|
|
abstract class Seller : ProtocolStateMachine<SellerInitialArgs, Pair<TimestampedWireTransaction, LedgerTransaction>>()
|
|
|
|
companion object {
|
|
@JvmStatic fun create(smm: StateMachineManager): TwoPartyTradeProtocol {
|
|
return TwoPartyTradeProtocolImpl(smm)
|
|
}
|
|
}
|
|
}
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>Let’s unpack what this code does:</p>
|
|
<ul class="simple">
|
|
<li>It defines a several classes nested inside the main <code class="docutils literal"><span class="pre">TwoPartyTradeProtocol</span></code> class, and a couple of methods, one to
|
|
run the buyer side of the protocol and one to run the seller side.</li>
|
|
<li>Two of the classes are simply wrappers for parameters to the trade; things like what is being sold, what the price
|
|
of the asset is, how much the buyer is willing to pay and so on. The <code class="docutils literal"><span class="pre">myKeyPair</span></code> field is simply the public key
|
|
that the seller wishes the buyer to send the cash to. The session ID field is sent from buyer to seller when the
|
|
trade is being set up and is used to keep messages separated on the network, and stop malicious entities trying to
|
|
interfere with the message stream.</li>
|
|
<li>The other two classes define empty abstract classes called <code class="docutils literal"><span class="pre">Buyer</span></code> and <code class="docutils literal"><span class="pre">Seller</span></code>. These inherit from a class
|
|
called <code class="docutils literal"><span class="pre">ProtocolStateMachine</span></code> and provide two type parameters: the arguments class we just defined for each side
|
|
and the type of the object that the protocol finally produces (this doesn’t have to be identical for each side, even
|
|
though in this case it is).</li>
|
|
<li>Finally it simply defines a static method that creates an instance of an object that inherits from this base class
|
|
and returns it, with a <code class="docutils literal"><span class="pre">StateMachineManager</span></code> as an instance. The Impl class will be defined below.</li>
|
|
</ul>
|
|
<div class="admonition note">
|
|
<p class="first admonition-title">Note</p>
|
|
<p class="last">Session IDs keep different traffic streams separated, so for security they must be large and random enough
|
|
to be unguessable. 63 bits is good enough.</p>
|
|
</div>
|
|
<p>Alright, so using this protocol shouldn’t be too hard: in the simplest case we can just pass in the details of the trade
|
|
to either runBuyer or runSeller, depending on who we are, and then call <code class="docutils literal"><span class="pre">.resultFuture.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
|
|
will be invoked when it’s done, where we could e.g. update a user interface.</p>
|
|
<p>The only tricky part is how to get one of these things. We need a <code class="docutils literal"><span class="pre">StateMachineManager</span></code>. Where does that come from
|
|
and why do we need one?</p>
|
|
</div>
|
|
<div class="section" id="the-state-machine-manager">
|
|
<h2>The state machine manager<a class="headerlink" href="#the-state-machine-manager" title="Permalink to this headline">¶</a></h2>
|
|
<p>The SMM is a class responsible for taking care of all running protocols in a node. It knows how to register handlers
|
|
with a <code class="docutils literal"><span class="pre">MessagingService</span></code> and iterate the right state machine when the time comes. It provides the
|
|
send/receive/sendAndReceive calls that let the code request network interaction and it will store a serialised copy of
|
|
each state machine before it’s suspended to wait for the network.</p>
|
|
<p>To get a <code class="docutils literal"><span class="pre">StateMachineManager</span></code>, you currently have to build one by passing in a <code class="docutils literal"><span class="pre">ServiceHub</span></code> and a thread or thread
|
|
pool which it can use. This will change in future so don’t worry about the details of this too much: just check the
|
|
unit tests to see how it’s done.</p>
|
|
</div>
|
|
<div class="section" id="implementing-the-seller">
|
|
<h2>Implementing the seller<a class="headerlink" href="#implementing-the-seller" title="Permalink to this headline">¶</a></h2>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre>private class TwoPartyTradeProtocolImpl(private val smm: StateMachineManager) : TwoPartyTradeProtocol() {
|
|
companion object {
|
|
val TRADE_TOPIC = "com.r3cev.protocols.trade"
|
|
}
|
|
|
|
class SellerImpl : Seller() {
|
|
override fun call(args: SellerInitialArgs): Pair<TimestampedWireTransaction, LedgerTransaction> {
|
|
TODO()
|
|
}
|
|
}
|
|
|
|
|
|
class BuyerImpl : Buyer() {
|
|
override fun call(args: BuyerInitialArgs): Pair<TimestampedWireTransaction, LedgerTransaction> {
|
|
TODO()
|
|
}
|
|
}
|
|
|
|
override fun runSeller(otherSide: SingleMessageRecipient, args: SellerInitialArgs): Seller {
|
|
return smm.add(otherSide, args, "$TRADE_TOPIC.seller", SellerImpl::class.java)
|
|
}
|
|
|
|
override fun runBuyer(otherSide: SingleMessageRecipient, args: BuyerInitialArgs): Buyer {
|
|
return smm.add(otherSide, args, "$TRADE_TOPIC.buyer", BuyerImpl::class.java)
|
|
}
|
|
}
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>We start with a skeleton on which we will build the protocol. Putting things in a <em>companion object</em> in Kotlin is like
|
|
declaring them as static members in Java. Here, we define a “topic” that will identify trade related messages that
|
|
arrive at a node (see <a class="reference internal" href="messaging.html"><em>Networking and messaging</em></a> for details).</p>
|
|
<p>The runSeller and runBuyer methods simply start the state machines, passing in a reference to the classes and the topics
|
|
each side will use.</p>
|
|
<p>Now let’s try implementing the seller side. Firstly, we’re going to need a message to send to the buyer describing what
|
|
we want to trade. Remember: this data comes from whatever system was used to find the trading partner to begin with.
|
|
It could be as simple as a chat room or as complex as a 24/7 exchange.</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span class="c1">// This object is serialised to the network and is the first protocol message</span>
|
|
<span class="c1">// the seller sends to the buyer.</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"><</span><span class="n">OwnableState</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">buyerSessionID</span><span class="p">:</span> <span class="n">Long</span>
|
|
<span class="p">)</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>That’s simple enough: our opening protocol message will be serialised before being sent over the wire, and it contains
|
|
the details that were agreed so we can double check them. It also contains a session ID so we can identify this
|
|
trade’s messages, and a pointer to where the asset that is being sold can be found on the ledger.</p>
|
|
<p>Next we add some code to the <code class="docutils literal"><span class="pre">SellerImpl.call</span></code> method:</p>
|
|
<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>
|
|
|
|
<span class="c1">// Make the first message we'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">args</span><span class="p">.</span><span class="n">assetToSell</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="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="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">SignedWireTransaction</span><span class="p">>(</span><span class="n">TRADE_TOPIC</span><span class="p">,</span> <span class="n">args</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">"Received partially signed transaction"</span> <span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>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 <code class="docutils literal"><span class="pre">sendAndReceive</span></code>. This function takes a few arguments:</p>
|
|
<ul class="simple">
|
|
<li>A type argument, which is the object we’re expecting to receive from the other side.</li>
|
|
<li>The topic string that ensures the message is routed to the right bit of code in the other side’s node.</li>
|
|
<li>The session IDs that ensure the messages don’t get mixed up with other simultaneous trades.</li>
|
|
<li>And finally, the thing to send. It’ll be serialised and sent automatically.</li>
|
|
</ul>
|
|
<p>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
|
|
cash put into the transaction and their signature on it authorising the movement of the cash.</p>
|
|
<div class="admonition note">
|
|
<p class="first admonition-title">Note</p>
|
|
<p>There are a few rules you need to bear in mind when writing a class that will be used as a continuation.
|
|
The first is that anything on the stack when the function is suspended will be stored into the heap and kept alive by
|
|
the garbage collector. So try to avoid keeping enormous data structures alive unless you really have to.</p>
|
|
<p>The second is that as well as being kept on the heap, objects reachable from the stack will be serialised. The state
|
|
of the function call may be resurrected much later! Kryo doesn’t require objects be marked as serialisable, but even so,
|
|
doing things like creating threads from inside these calls would be a bad idea. They should only contain business
|
|
logic.</p>
|
|
<p class="last">The third rule to bear in mind is that you can’t declare variables or methods in these classes and access
|
|
them from outside of the class, due to the bytecode rewriting and classloader tricks that are used to make this all
|
|
work. If you want access to something inside the BuyerImpl or SellerImpl classes, you must define a super-interface
|
|
or super-class (like <code class="docutils literal"><span class="pre">Buyer</span></code>/<code class="docutils literal"><span class="pre">Seller</span></code>) and put what you want to access there.</p>
|
|
</div>
|
|
<p>OK, let’s keep going:</p>
|
|
<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>
|
|
<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"><</span><span class="n">WireTransaction</span><span class="p">>()</span>
|
|
|
|
<span class="n">requireThat</span> <span class="p">{</span>
|
|
<span class="s">"transaction sends us the right amount of cash"</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="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't intending to sell to the secondary, if</span>
|
|
<span class="c1">// we're reusing keys! So don'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="c1">//</span>
|
|
<span class="c1">// but the goal of this code is not to be fully secure, 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="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="c1">// We should run it through our full TransactionGroup of all transactions here.</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">"Built finished transaction, sending back to secondary!"</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>
|
|
</div>
|
|
</div>
|
|
<p>Here, we see some assertions and signature checking to satisfy ourselves that we’re not about to sign something
|
|
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
|
|
transaction, and send the now finalised and validated transaction back to the buyer.</p>
|
|
<div class="admonition warning">
|
|
<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
|
|
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
|
|
future version of the code.</p>
|
|
</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 class="section" id="implementing-the-buyer">
|
|
<h2>Implementing the buyer<a class="headerlink" href="#implementing-the-buyer" title="Permalink to this headline">¶</a></h2>
|
|
<p>OK, let’s do the same for the buyer side:</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre>class BuyerImpl : Buyer() {
|
|
override fun call(args: BuyerInitialArgs): Pair<TimestampedWireTransaction, LedgerTransaction> {
|
|
// Wait for a trade request to come in on our pre-provided session ID.
|
|
val tradeRequest = receive<SellerTradeInfo>(TRADE_TOPIC, args.sessionID)
|
|
|
|
// What is the seller trying to sell us?
|
|
val assetTypeName = tradeRequest.assetForSale.state.javaClass.name
|
|
logger().trace { "Got trade request for a $assetTypeName" }
|
|
|
|
// Check the start message for acceptability.
|
|
check(tradeRequest.sessionID > 0)
|
|
if (tradeRequest.price > args.acceptablePrice)
|
|
throw UnacceptablePriceException(tradeRequest.price)
|
|
if (!args.typeToBuy.isInstance(tradeRequest.assetForSale.state))
|
|
throw AssetMismatchException(args.typeToBuy.name, assetTypeName)
|
|
|
|
// TODO: Either look up the stateref here in our local db, or accept a long chain
|
|
// of states and validate them to audit the other side and ensure it actually owns
|
|
// the state we are being offered! For now, just assume validity!
|
|
|
|
// Generate the shared transaction that both sides will sign, using the data we have.
|
|
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))
|
|
|
|
// Now sign the transaction with whatever keys we need to move the cash.
|
|
for (k in cashSigningPubKeys) {
|
|
val priv = serviceHub.keyManagementService.toPrivate(k)
|
|
ptx.signWith(KeyPair(k, priv))
|
|
}
|
|
|
|
val stx = 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.
|
|
|
|
logger().trace { "Sending partially signed transaction to seller" }
|
|
|
|
// TODO: Protect against the buyer terminating here and leaving us in the lurch without
|
|
// the final tx.
|
|
// TODO: Protect against a malicious buyer sending us back a different transaction to
|
|
// the one we built.
|
|
val fullySigned = sendAndReceive<TimestampedWireTransaction>(TRADE_TOPIC,
|
|
tradeRequest.sessionID, args.sessionID, stx)
|
|
|
|
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)
|
|
}
|
|
}
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>This code is fairly straightforward. Here are some things to pay attention to:</p>
|
|
<ol class="arabic simple">
|
|
<li>We do some sanity checking on the received message to ensure we’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’t
|
|
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
|
|
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
|
|
or data which may frequently change should be accessed ‘just in time’.</li>
|
|
<li>Finally, we send the unfinsished, 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>
|
|
</ol>
|
|
<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>
|
|
<div class="admonition warning">
|
|
<p class="first admonition-title">Warning</p>
|
|
<p class="last">When accessing things via the <code class="docutils literal"><span class="pre">serviceHub</span></code> field, avoid the temptation to stuff a reference into a local variable.
|
|
If you do this then next time your protocol waits to receive an object, the system will try and serialise all your
|
|
local variables and end up trying to serialise, e.g. the timestamping service, which doesn’t make any conceptual
|
|
sense. The <code class="docutils literal"><span class="pre">serviceHub</span></code> field is defined by the <code class="docutils literal"><span class="pre">ProtocolStateMachine</span></code> superclass and is marked transient so
|
|
this problem doesn’t occur. It’s also restored for you when a protocol state machine is restored after a node
|
|
restart.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
<footer>
|
|
|
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
|
|
|
<a href="visualiser.html" class="btn btn-neutral float-right" title="Using the visualiser" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
|
|
|
|
|
|
<a href="tutorial.html" class="btn btn-neutral" title="Writing a contract" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
|
|
|
|
</div>
|
|
|
|
|
|
<hr/>
|
|
|
|
<div role="contentinfo">
|
|
<p>
|
|
© Copyright 2015, R3 CEV.
|
|
|
|
</p>
|
|
</div>
|
|
Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
|
|
|
</footer>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</section>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
var DOCUMENTATION_OPTIONS = {
|
|
URL_ROOT:'./',
|
|
VERSION:'0.1',
|
|
COLLAPSE_INDEX:false,
|
|
FILE_SUFFIX:'.html',
|
|
HAS_SOURCE: true
|
|
};
|
|
</script>
|
|
<script type="text/javascript" src="_static/jquery.js"></script>
|
|
<script type="text/javascript" src="_static/underscore.js"></script>
|
|
<script type="text/javascript" src="_static/doctools.js"></script>
|
|
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript" src="_static/js/theme.js"></script>
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
jQuery(function () {
|
|
SphinxRtdTheme.StickyNav.enable();
|
|
});
|
|
</script>
|
|
|
|
|
|
</body>
|
|
</html> |