corda/docs/build/html/tutorial-building-transactions.html
2017-02-07 17:18:21 +00:00

706 lines
56 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- If you edit this, then please make the same changes to layout_for_doc_website.html, as that is used for the web
doc site generation which we put analytics tracking on to identify any potential problem pages -->
<!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>Building transactions &mdash; R3 Corda latest documentation</title>
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
<link rel="top" title="R3 Corda latest documentation" href="index.html"/>
<link rel="next" title="Writing flows" href="flow-state-machines.html"/>
<link rel="prev" title="Client RPC API tutorial" href="tutorial-clientrpc-api.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 Corda
</a>
<div class="version">
latest
</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>
<br>
API reference: <a href="api/kotlin/corda/index.html">Kotlin</a>/ <a href="api/javadoc/index.html">JavaDoc</a>
<br>
<a href="https://discourse.corda.net">Discourse Forums</a>
<br>
<a href="http://slack.corda.net">Slack</a>
<br>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
<p class="caption"><span class="caption-text">Getting started</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="inthebox.html">What&#8217;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="getting-set-up-fault-finding.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="running-the-demos.html">Running the demos</a></li>
<li class="toctree-l1"><a class="reference internal" href="CLI-vs-IDE.html">CLI vs IDE</a></li>
</ul>
<p class="caption"><span class="caption-text">Key concepts</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="key-concepts.html">Overview</a></li>
<li class="toctree-l1"><a class="reference internal" href="key-concepts-ecosystem.html">Corda ecosystem</a></li>
<li class="toctree-l1"><a class="reference internal" href="key-concepts-data-model.html">Data model</a></li>
<li class="toctree-l1"><a class="reference internal" href="key-concepts-core-types.html">Core types</a></li>
<li class="toctree-l1"><a class="reference internal" href="key-concepts-financial-model.html">Financial model</a></li>
<li class="toctree-l1"><a class="reference internal" href="key-concepts-flow-framework.html">Flow framework</a></li>
<li class="toctree-l1"><a class="reference internal" href="key-concepts-consensus-notaries.html">Consensus and notaries</a></li>
<li class="toctree-l1"><a class="reference internal" href="key-concepts-vault.html">Vault</a></li>
<li class="toctree-l1"><a class="reference internal" href="key-concepts-security-model.html">Security model</a></li>
</ul>
<p class="caption"><span class="caption-text">CorDapps</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="creating-a-cordapp.html">CorDapp basics</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-cordapp.html">The CorDapp template</a></li>
</ul>
<p class="caption"><span class="caption-text">The Corda node</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="clientrpc.html">Client RPC</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="persistence.html">Persistence</a></li>
<li class="toctree-l1"><a class="reference internal" href="node-administration.html">Node administration</a></li>
<li class="toctree-l1"><a class="reference internal" href="corda-configuration-file.html">Node configuration</a></li>
<li class="toctree-l1"><a class="reference internal" href="corda-plugins.html">The Corda plugin framework</a></li>
<li class="toctree-l1"><a class="reference internal" href="node-services.html">Brief introduction to the node services</a></li>
<li class="toctree-l1"><a class="reference internal" href="node-explorer.html">Node Explorer</a></li>
<li class="toctree-l1"><a class="reference internal" href="permissioning.html">Network permissioning</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-contract.html">Writing a contract</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-contract-clauses.html">Writing a contract using clauses</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-test-dsl.html">Writing a contract test</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-integration-testing.html">Integration testing</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-clientrpc-api.html">Client RPC API tutorial</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Building transactions</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#introduction">Introduction</a></li>
<li class="toctree-l2"><a class="reference internal" href="#the-basic-lifecycle-of-transactions">The Basic Lifecycle Of Transactions</a></li>
<li class="toctree-l2"><a class="reference internal" href="#gathering-inputs">Gathering Inputs</a></li>
<li class="toctree-l2"><a class="reference internal" href="#generating-commands">Generating Commands</a></li>
<li class="toctree-l2"><a class="reference internal" href="#generating-outputs">Generating Outputs</a></li>
<li class="toctree-l2"><a class="reference internal" href="#building-the-wiretransaction">Building the WireTransaction</a></li>
<li class="toctree-l2"><a class="reference internal" href="#completing-the-signedtransaction">Completing the SignedTransaction</a></li>
<li class="toctree-l2"><a class="reference internal" href="#committing-the-transaction">Committing the Transaction</a></li>
<li class="toctree-l2"><a class="reference internal" href="#partially-visible-transactions">Partially Visible Transactions</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="flow-state-machines.html">Writing flows</a></li>
<li class="toctree-l1"><a class="reference internal" href="flow-testing.html">Writing flow tests</a></li>
<li class="toctree-l1"><a class="reference internal" href="running-a-notary.html">Running a notary service</a></li>
<li class="toctree-l1"><a class="reference internal" href="using-a-notary.html">Using a notary service</a></li>
<li class="toctree-l1"><a class="reference internal" href="oracles.html">Writing oracle services</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-attachments.html">Using attachments</a></li>
<li class="toctree-l1"><a class="reference internal" href="event-scheduling.html">Event scheduling</a></li>
</ul>
<p class="caption"><span class="caption-text">Other</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="network-simulator.html">Network Simulator</a></li>
<li class="toctree-l1"><a class="reference internal" href="clauses.html">Clauses</a></li>
<li class="toctree-l1"><a class="reference internal" href="merkle-trees.html">Transaction tear-offs</a></li>
</ul>
<p class="caption"><span class="caption-text">Component library</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="contract-catalogue.html">Contract catalogue</a></li>
<li class="toctree-l1"><a class="reference internal" href="contract-irs.html">Interest rate swaps</a></li>
</ul>
<p class="caption"><span class="caption-text">Appendix</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="loadtesting.html">Load testing</a></li>
<li class="toctree-l1"><a class="reference internal" href="setting-up-a-corda-network.html">What is a corda network?</a></li>
<li class="toctree-l1"><a class="reference internal" href="secure-coding-guidelines.html">Secure coding guidelines</a></li>
<li class="toctree-l1"><a class="reference internal" href="release-process.html">Release process</a></li>
<li class="toctree-l1"><a class="reference internal" href="release-notes.html">Release notes</a></li>
<li class="toctree-l1"><a class="reference internal" href="codestyle.html">Code style guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="building-the-docs.html">Building the documentation</a></li>
<li class="toctree-l1"><a class="reference internal" href="further-notes-on-kotlin.html">Further notes on Kotlin</a></li>
<li class="toctree-l1"><a class="reference internal" href="publishing-corda.html">Publishing Corda</a></li>
<li class="toctree-l1"><a class="reference internal" href="azure-vm.html">Working with the Corda Demo on Azure Marketplace</a></li>
</ul>
<p class="caption"><span class="caption-text">Glossary</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="glossary.html">Glossary</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 Corda</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> &raquo;</li>
<li>Building transactions</li>
<li class="wy-breadcrumbs-aside">
<a href="_sources/tutorial-building-transactions.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">
<div class="section" id="building-transactions">
<h1>Building transactions<a class="headerlink" href="#building-transactions" title="Permalink to this headline"></a></h1>
<div class="section" id="introduction">
<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline"></a></h2>
<p>Understanding and implementing transactions in Corda is key to building
and implementing real world smart contracts. It is only through
construction of valid Corda transactions containing appropriate data
that nodes on the ledger can map real world business objects into a
shared digital view of the data in the Corda ledger. More importantly as
the developer of new smart contracts it is the code which determines
what data is well formed and what data should be rejected as mistakes,
or to prevent malicious activity. This document details some of the
considerations and APIs used to when constructing transactions as part
of a flow.</p>
</div>
<div class="section" id="the-basic-lifecycle-of-transactions">
<h2>The Basic Lifecycle Of Transactions<a class="headerlink" href="#the-basic-lifecycle-of-transactions" title="Permalink to this headline"></a></h2>
<p>Transactions in Corda are constructed in stages and contain a number of
elements. In particular a transactions core data structure is the
<code class="docutils literal"><span class="pre">net.corda.core.transactions.WireTransaction</span></code>, which is usually
manipulated via a
<code class="docutils literal"><span class="pre">net.corda.core.contracts.General.TransactionBuilder</span></code> and contains:</p>
<p>1. A set of Input state references that will be consumed by the final
accepted transaction.</p>
<p>2. A set of Output states to create/replace the consumed states and thus
become the new latest versions of data on the ledger.</p>
<p>3. A set of <code class="docutils literal"><span class="pre">Attachment</span></code> items which can contain legal documents, contract
code, or private encrypted sections as an extension beyond the native
contract states.</p>
<p>4. A set of <code class="docutils literal"><span class="pre">Command</span></code> items which give a context to the type of ledger
transition that is encoded in the transaction. Also each command has an
associated set of signer keys, which will be required to sign the
transaction.</p>
<p>5. A signers list, which is populated by the <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> to
be the union of the signers on the individual Command objects.</p>
<p>6. A notary identity to specify the Notary node which is tracking the
state consumption. (If the input states are registered with different
notary nodes the flow will have to insert additional <code class="docutils literal"><span class="pre">NotaryChange</span></code>
transactions to migrate the states across to a consistent notary node,
before being allowed to mutate any states.)</p>
<p>7. Optionally a timestamp that can used in the Notary to time bound the
period in which the proposed transaction stays valid.</p>
<p>Typically, the <code class="docutils literal"><span class="pre">WireTransaction</span></code> should be regarded as a proposal and
may need to be exchanged back and forth between parties before it can be
fully populated. This is an immediate consequence of the Corda privacy
model, which means that the input states are likely to be unknown to the
other node.</p>
<p>Once the proposed data is fully populated the flow code should freeze
the <code class="docutils literal"><span class="pre">WireTransaction</span></code> and form a <code class="docutils literal"><span class="pre">SignedTransaction</span></code>. This is key to
the ledger agreement process, as once a flow has attached a nodes
signature it has stated that all details of the transaction are
acceptable to it. A flow should take care not to attach signatures to
intermediate data, which might be maliciously used to construct a
different <code class="docutils literal"><span class="pre">SignedTransaction</span></code>. For instance in a foreign exchange
scenario we shouldn&#8217;t send a <code class="docutils literal"><span class="pre">SignedTransaction</span></code> with only our sell
side populated as that could be used to take the money without the
expected return of the other currency. Also, it is best practice for
flows to receive back the <code class="docutils literal"><span class="pre">DigitalSignature.WithKey</span></code> of other parties
rather than a full <code class="docutils literal"><span class="pre">SignedTransaction</span></code> objects, because otherwise we
have to separately check that this is still the same
<code class="docutils literal"><span class="pre">SignedTransaction</span></code> and not a malicious substitute.</p>
<p>The final stage of committing the transaction to the ledger is to
notarise the <code class="docutils literal"><span class="pre">SignedTransaction</span></code>, distribute this to all appropriate
parties and record the data into the ledger. These actions are best
delegated to the <code class="docutils literal"><span class="pre">FinalityFlow</span></code>, rather than calling the individual
steps manually. However, do note that the final broadcast to the other
nodes is asynchronous, so care must be used in unit testing to
correctly await the Vault updates.</p>
</div>
<div class="section" id="gathering-inputs">
<h2>Gathering Inputs<a class="headerlink" href="#gathering-inputs" title="Permalink to this headline"></a></h2>
<p>One of the first steps to forming a transaction is gathering the set of
input references. This process will clearly vary according to the nature
of the business process being captured by the smart contract and the
parameterised details of the request. However, it will generally involve
searching the Vault via the <code class="docutils literal"><span class="pre">VaultService</span></code> interface on the
<code class="docutils literal"><span class="pre">ServiceHub</span></code> to locate the input states.</p>
<p>To give a few more specific details consider two simplified real world
scenarios. First, a basic foreign exchange Cash transaction. This
transaction needs to locate a set of funds to exchange. A flow
modelling this is implemented in <code class="docutils literal"><span class="pre">FxTransactionBuildTutorial.kt</span></code>.
Second, a simple business model in which parties manually accept, or
reject each other&#8217;s trade proposals which is implemented in
<code class="docutils literal"><span class="pre">WorkflowTransactionBuildTutorial.kt</span></code>. To run and explore these
examples using the IntelliJ IDE one can run/step the respective unit
tests in <code class="docutils literal"><span class="pre">FxTransactionBuildTutorialTest.kt</span></code> and
<code class="docutils literal"><span class="pre">WorkflowTransactionBuildTutorialTest.kt</span></code>, which drive the flows as
part of a simulated in-memory network of nodes. When creating the
IntelliJ run configuration for these unit test set the workspace
points to the root <code class="docutils literal"><span class="pre">r3prototyping</span></code> folder and add
<code class="docutils literal"><span class="pre">-javaagent:lib/quasar.jar</span></code> to the VM options, so that the <code class="docutils literal"><span class="pre">Quasar</span></code>
instrumentation is correctly configured.</p>
<p>For the Cash transaction lets assume the cash resources are using the
standard <code class="docutils literal"><span class="pre">CashState</span></code> in the <code class="docutils literal"><span class="pre">:financial</span></code> Gradle module. The Cash
contract uses <code class="docutils literal"><span class="pre">FungibleAsset</span></code> states to model holdings of
interchangeable assets and allow the split/merge and summing of
states to meet a contractual obligation. We would normally use the
<code class="docutils literal"><span class="pre">generateSpend</span></code> method on the <code class="docutils literal"><span class="pre">VaultService</span></code> to gather the required
amount of cash into a <code class="docutils literal"><span class="pre">TransactionBuilder</span></code>, set the outputs and move
command. However, to elucidate more clearly example flow code is shown
here that will manually carry out the inputs queries using the lower
level <code class="docutils literal"><span class="pre">VaultService</span></code>.</p>
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="c1">// This is equivalent to the VaultService.generateSpend</span>
<span class="c1">// Which is brought here to make the filtering logic more visible in the example</span>
<span class="k">private</span> <span class="k">fun</span> <span class="nf">gatherOurInputs</span><span class="p">(</span><span class="n">serviceHub</span><span class="p">:</span> <span class="n">ServiceHub</span><span class="p">,</span>
<span class="n">amountRequired</span><span class="p">:</span> <span class="n">Amount</span><span class="p">&lt;</span><span class="n">Issued</span><span class="p">&lt;</span><span class="n">Currency</span><span class="p">&gt;&gt;,</span>
<span class="n">notary</span><span class="p">:</span> <span class="n">Party</span><span class="p">?):</span> <span class="n">Pair</span><span class="p">&lt;</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="n">Long</span><span class="p">&gt;</span> <span class="p">{</span>
<span class="c1">// Collect cash type inputs</span>
<span class="k">val</span> <span class="py">cashStates</span> <span class="p">=</span> <span class="n">serviceHub</span><span class="p">.</span><span class="n">vaultService</span><span class="p">.</span><span class="n">currentVault</span><span class="p">.</span><span class="n">statesOfType</span><span class="p">&lt;</span><span class="n">Cash</span><span class="p">.</span><span class="n">State</span><span class="p">&gt;()</span>
<span class="c1">// extract our key identity for convenience</span>
<span class="k">val</span> <span class="py">ourKey</span> <span class="p">=</span> <span class="n">serviceHub</span><span class="p">.</span><span class="n">myInfo</span><span class="p">.</span><span class="n">legalIdentity</span><span class="p">.</span><span class="n">owningKey</span>
<span class="c1">// Filter down to our own cash states with right currency and issuer</span>
<span class="k">val</span> <span class="py">suitableCashStates</span> <span class="p">=</span> <span class="n">cashStates</span><span class="p">.</span><span class="n">filter</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">state</span> <span class="p">=</span> <span class="n">it</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="k">data</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">ourKey</span><span class="p">)</span>
<span class="p">&amp;&amp;</span> <span class="p">(</span><span class="n">state</span><span class="p">.</span><span class="n">amount</span><span class="p">.</span><span class="n">token</span> <span class="p">==</span> <span class="n">amountRequired</span><span class="p">.</span><span class="n">token</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">require</span><span class="p">(!</span><span class="n">suitableCashStates</span><span class="p">.</span><span class="n">isEmpty</span><span class="p">())</span> <span class="p">{</span> <span class="s">&quot;Insufficient funds&quot;</span> <span class="p">}</span>
<span class="k">var</span> <span class="py">remaining</span> <span class="p">=</span> <span class="n">amountRequired</span><span class="p">.</span><span class="n">quantity</span>
<span class="c1">// We will need all of the inputs to be on the same notary.</span>
<span class="c1">// For simplicity we just filter on the first notary encountered</span>
<span class="c1">// A production quality flow would need to migrate notary if the</span>
<span class="c1">// the amounts were not sufficient in any one notary</span>
<span class="k">val</span> <span class="py">sourceNotary</span><span class="p">:</span> <span class="n">Party</span> <span class="p">=</span> <span class="n">notary</span> <span class="o">?:</span> <span class="n">suitableCashStates</span><span class="p">.</span><span class="n">first</span><span class="p">().</span><span class="n">state</span><span class="p">.</span><span class="n">notary</span>
<span class="k">val</span> <span class="py">inputsList</span> <span class="p">=</span> <span class="n">mutableListOf</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="c1">// Iterate over filtered cash states to gather enough to pay</span>
<span class="k">for</span> <span class="p">(</span><span class="n">cash</span> <span class="k">in</span> <span class="n">suitableCashStates</span><span class="p">.</span><span class="n">filter</span> <span class="p">{</span> <span class="n">it</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">notary</span> <span class="p">==</span> <span class="n">sourceNotary</span> <span class="p">})</span> <span class="p">{</span>
<span class="n">inputsList</span> <span class="p">+=</span> <span class="n">cash</span>
<span class="k">if</span> <span class="p">(</span><span class="n">remaining</span> <span class="p">&lt;=</span> <span class="n">cash</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="k">data</span><span class="p">.</span><span class="n">amount</span><span class="p">.</span><span class="n">quantity</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">Pair</span><span class="p">(</span><span class="n">inputsList</span><span class="p">,</span> <span class="n">cash</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="k">data</span><span class="p">.</span><span class="n">amount</span><span class="p">.</span><span class="n">quantity</span> <span class="p">-</span> <span class="n">remaining</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">remaining</span> <span class="p">-=</span> <span class="n">cash</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="k">data</span><span class="p">.</span><span class="n">amount</span><span class="p">.</span><span class="n">quantity</span>
<span class="p">}</span>
<span class="k">throw</span> <span class="n">IllegalStateException</span><span class="p">(</span><span class="s">&quot;Insufficient funds&quot;</span><span class="p">)</span>
<span class="p">}</span>
</pre></div>
</div>
<p>As a foreign exchange transaction we expect an exchange of two
currencies, so we will also require a set of input states from the other
counterparty. However, the Corda privacy model means we do not know the
other nodes states. Our flow must therefore negotiate with the other
node for them to carry out a similar query and populate the inputs (See
the <code class="docutils literal"><span class="pre">ForeignExchangeFlow</span></code> for more details of the exchange). Having
identified a set of Input <code class="docutils literal"><span class="pre">StateRef</span></code> items we can then create the
output as discussed below.</p>
<p>For the trade approval flow we need to implement a simple workflow
pattern. We start by recording the unconfirmed trade details in a state
object implementing the <code class="docutils literal"><span class="pre">LinearState</span></code> interface. One field of this
record is used to map the business workflow to an enumerated state.
Initially the initiator creates a new state object which receives a new
<code class="docutils literal"><span class="pre">UniqueIdentifier</span></code> in its <code class="docutils literal"><span class="pre">linearId</span></code> property and a starting
workflow state of <code class="docutils literal"><span class="pre">NEW</span></code>. The <code class="docutils literal"><span class="pre">Contract.verify</span></code> method is written to
allow the initiator to sign this initial transaction and send it to the
other party. This pattern ensures that a permanent copy is recorded on
both ledgers for audit purposes, but the state is prevented from being
maliciously put in an approved state. The subsequent workflow steps then
follow with transactions that consume the state as inputs on one side
and output a new version with whatever state updates, or amendments
match to the business process, the <code class="docutils literal"><span class="pre">linearId</span></code> being preserved across
the changes. Attached <code class="docutils literal"><span class="pre">Command</span></code> objects help the verify method
restrict changes to appropriate fields and signers at each step in the
workflow. In this it is typical to have both parties sign the change
transactions, but it can be valid to allow unilateral signing, if for instance
one side could block a rejection. Commonly the manual initiator of these
workflows will query the Vault for states of the right contract type and
in the right workflow state over the RPC interface. The RPC will then
initiate the relevant flow using <code class="docutils literal"><span class="pre">StateRef</span></code>, or <code class="docutils literal"><span class="pre">linearId</span></code> values as
parameters to the flow to identify the states being operated upon. Thus
code to gather the latest input state would be:</p>
<div class="highlight-kotlin"><div class="highlight"><pre><span></span>
// Helper method to locate the latest Vault version of a LinearState from a possibly out of date StateRef
inline fun &lt;reified T : LinearState&gt; ServiceHub.latest(ref: StateRef): StateAndRef&lt;T&gt; {
val linearHeads = vaultService.linearHeadsOfType&lt;T&gt;()
val original = toStateAndRef&lt;T&gt;(ref)
return linearHeads.get(original.state.data.linearId)!!
}
</pre></div>
</div>
<div class="codeset container">
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="c1">// Pull in the latest Vault version of the StateRef as a full StateAndRef</span>
<span class="k">val</span> <span class="py">latestRecord</span> <span class="p">=</span> <span class="n">serviceHub</span><span class="p">.</span><span class="n">latest</span><span class="p">&lt;</span><span class="n">TradeApprovalContract</span><span class="p">.</span><span class="n">State</span><span class="p">&gt;(</span><span class="n">ref</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="generating-commands">
<h2>Generating Commands<a class="headerlink" href="#generating-commands" title="Permalink to this headline"></a></h2>
<p>For the commands that will be added to the transaction, these will need
to correctly reflect the task at hand. These must match because inside
the <code class="docutils literal"><span class="pre">Contract.verify</span></code> method the command will be used to select the
validation code path. The <code class="docutils literal"><span class="pre">Contract.verify</span></code> method will then restrict
the allowed contents of the transaction to reflect this context. Typical
restrictions might include that the input cash amount must equal the
output cash amount, or that a workflow step is only allowed to change
the status field. Sometimes, the command may capture some data too e.g.
the foreign exchange rate, or the identity of one party, or the StateRef
of the specific input that originates the command in a bulk operation.
This data will be used to further aid the <code class="docutils literal"><span class="pre">Contract.verify</span></code>, because
to ensure consistent, secure and reproducible behaviour in a distributed
environment the <code class="docutils literal"><span class="pre">Contract.verify</span></code>, transaction is the only allowed to
use the content of the transaction to decide validity.</p>
<p>Another essential requirement for commands is that the correct set of
<code class="docutils literal"><span class="pre">CompositeKeys</span></code> are added to the Command on the builder, which will be
used to form the set of required signers on the final validated
transaction. These must correctly align with the expectations of the
<code class="docutils literal"><span class="pre">Contract.verify</span></code> method, which should be written to defensively check
this. In particular, it is expected that at minimum the owner of an
asset would have to be signing to permission transfer of that asset. In
addition, other signatories will often be required e.g. an Oracle
identity for an Oracle command, or both parties when there is an
exchange of assets.</p>
</div>
<div class="section" id="generating-outputs">
<h2>Generating Outputs<a class="headerlink" href="#generating-outputs" title="Permalink to this headline"></a></h2>
<p>Having located a set of <code class="docutils literal"><span class="pre">StateAndRefs</span></code> as the transaction inputs, the
flow has to generate the output states. Typically, this is a simple call
to the Kotlin <code class="docutils literal"><span class="pre">copy</span></code> method to modify the few fields that will
transitioned in the transaction. The contract code may provide a
<code class="docutils literal"><span class="pre">generateXXX</span></code> method to help with this process if the task is more
complicated. With a workflow state a slightly modified copy state is
usually sufficient, especially as it is expected that we wish to preserve
the <code class="docutils literal"><span class="pre">linearId</span></code> between state revisions, so that Vault queries can find
the latest revision.</p>
<p>For fungible contract states such as <code class="docutils literal"><span class="pre">Cash</span></code> it is common to distribute
and split the total amount e.g. to produce a remaining balance output
state for the original owner when breaking up a large amount input
state. Remember that the result of a successful transaction is always to
fully consume/spend the input states, so this is required to conserve
the total cash. For example from the demo code:</p>
<div class="highlight-kotlin"><div class="highlight"><pre><span></span> // Gather our inputs. We would normally use VaultService.generateSpend
// to carry out the build in a single step. To be more explicit
// we will use query manually in the helper function below.
// Putting this into a non-suspendable function also prevents issues when
// the flow is suspended.
val (inputs, residual) = gatherOurInputs(serviceHub, sellAmount, request.notary)
// Build and an output state for the counterparty
val transferedFundsOutput = Cash.State(sellAmount, request.counterparty.owningKey)
if (residual &gt; 0L) {
// Build an output state for the residual change back to us
val residualAmount = Amount(residual, sellAmount.token)
val residualOutput = Cash.State(residualAmount, serviceHub.myInfo.legalIdentity.owningKey)
return FxResponse(inputs, listOf(transferedFundsOutput, residualOutput))
} else {
return FxResponse(inputs, listOf(transferedFundsOutput))
}
</pre></div>
</div>
</div>
<div class="section" id="building-the-wiretransaction">
<h2>Building the WireTransaction<a class="headerlink" href="#building-the-wiretransaction" title="Permalink to this headline"></a></h2>
<p>Having gathered all the ingredients for the transaction we now need to
use a <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> to construct the full <code class="docutils literal"><span class="pre">WireTransaction</span></code>.
The initial <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> should be created by calling the
<code class="docutils literal"><span class="pre">TransactionType.General.Builder</span></code> method. (The other
<code class="docutils literal"><span class="pre">TransactionBuilder</span></code> implementation is only used for the <code class="docutils literal"><span class="pre">NotaryChange</span></code> flow where
<code class="docutils literal"><span class="pre">ContractStates</span></code> need moving to a different Notary.) At this point the
Notary to associate with the states should be recorded. Then we keep
adding inputs, outputs, commands and attachments to fill the
transaction. Examples of this process are:</p>
<div class="highlight-kotlin"><div class="highlight"><pre><span></span> <span class="c1">// Modify the state field for new output. We use copy, to ensure no other modifications.</span>
<span class="c1">// It is especially important for a LinearState that the linearId is copied across,</span>
<span class="c1">// not accidentally assigned a new random id.</span>
<span class="k">val</span> <span class="py">newState</span> <span class="p">=</span> <span class="n">latestRecord</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="k">data</span><span class="p">.</span><span class="n">copy</span><span class="p">(</span><span class="n">state</span> <span class="p">=</span> <span class="n">verdict</span><span class="p">)</span>
<span class="c1">// We have to use the original notary for the new transaction</span>
<span class="k">val</span> <span class="py">notary</span> <span class="p">=</span> <span class="n">latestRecord</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">notary</span>
<span class="c1">// Get and populate the new TransactionBuilder</span>
<span class="c1">// To destroy the old proposal state and replace with the new completion state.</span>
<span class="c1">// Also add the Completed command with keys of all parties to signal the Tx purpose</span>
<span class="c1">// to the Contract verify method.</span>
<span class="k">val</span> <span class="py">tx</span> <span class="p">=</span> <span class="n">TransactionType</span><span class="p">.</span>
<span class="n">General</span><span class="p">.</span>
<span class="n">Builder</span><span class="p">(</span><span class="n">notary</span><span class="p">).</span>
<span class="n">withItems</span><span class="p">(</span>
<span class="n">latestRecord</span><span class="p">,</span>
<span class="n">newState</span><span class="p">,</span>
<span class="n">Command</span><span class="p">(</span><span class="n">TradeApprovalContract</span><span class="p">.</span><span class="n">Commands</span><span class="p">.</span><span class="n">Completed</span><span class="p">(),</span>
<span class="n">listOf</span><span class="p">(</span><span class="n">serviceHub</span><span class="p">.</span><span class="n">myInfo</span><span class="p">.</span><span class="n">legalIdentity</span><span class="p">.</span><span class="n">owningKey</span><span class="p">,</span> <span class="n">latestRecord</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="k">data</span><span class="p">.</span><span class="n">source</span><span class="p">.</span><span class="n">owningKey</span><span class="p">)))</span>
<span class="n">tx</span><span class="p">.</span><span class="n">setTime</span><span class="p">(</span><span class="n">serviceHub</span><span class="p">.</span><span class="n">clock</span><span class="p">.</span><span class="n">instant</span><span class="p">(),</span> <span class="n">Duration</span><span class="p">.</span><span class="n">ofSeconds</span><span class="p">(</span><span class="m">60</span><span class="p">))</span>
<span class="c1">// We can sign this transaction immediately as we have already checked all the fields and the decision</span>
<span class="c1">// is ultimately a manual one from the caller.</span>
<span class="n">tx</span><span class="p">.</span><span class="n">signWith</span><span class="p">(</span><span class="n">serviceHub</span><span class="p">.</span><span class="n">legalIdentityKey</span><span class="p">)</span>
<span class="c1">// Convert to SignedTransaction we can pass around certain that it cannot be modified.</span>
<span class="k">val</span> <span class="py">selfSignedTx</span> <span class="p">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">toSignedTransaction</span><span class="p">(</span><span class="k">false</span><span class="p">)</span>
</pre></div>
</div>
<div class="highlight-kotlin"><div class="highlight"><pre><span></span> <span class="k">private</span> <span class="k">fun</span> <span class="nf">buildTradeProposal</span><span class="p">(</span><span class="n">ourStates</span><span class="p">:</span> <span class="n">FxResponse</span><span class="p">,</span> <span class="n">theirStates</span><span class="p">:</span> <span class="n">FxResponse</span><span class="p">):</span> <span class="n">SignedTransaction</span> <span class="p">{</span>
<span class="c1">// This is the correct way to create a TransactionBuilder,</span>
<span class="c1">// do not construct directly.</span>
<span class="c1">// We also set the notary to match the input notary</span>
<span class="k">val</span> <span class="py">builder</span> <span class="p">=</span> <span class="n">TransactionType</span><span class="p">.</span><span class="n">General</span><span class="p">.</span><span class="n">Builder</span><span class="p">(</span><span class="n">ourStates</span><span class="p">.</span><span class="n">inputs</span><span class="p">.</span><span class="n">first</span><span class="p">().</span><span class="n">state</span><span class="p">.</span><span class="n">notary</span><span class="p">)</span>
<span class="c1">// Add the move commands and key to indicate all the respective owners and need to sign</span>
<span class="k">val</span> <span class="py">ourSigners</span> <span class="p">=</span> <span class="n">ourStates</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">state</span><span class="p">.</span><span class="k">data</span><span class="p">.</span><span class="n">owner</span> <span class="p">}.</span><span class="n">toSet</span><span class="p">()</span>
<span class="k">val</span> <span class="py">theirSigners</span> <span class="p">=</span> <span class="n">theirStates</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">state</span><span class="p">.</span><span class="k">data</span><span class="p">.</span><span class="n">owner</span> <span class="p">}.</span><span class="n">toSet</span><span class="p">()</span>
<span class="n">builder</span><span class="p">.</span><span class="n">addCommand</span><span class="p">(</span><span class="n">Cash</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="p">(</span><span class="n">ourSigners</span> <span class="p">+</span> <span class="n">theirSigners</span><span class="p">).</span><span class="n">toList</span><span class="p">())</span>
<span class="c1">// Build and add the inputs and outputs</span>
<span class="n">builder</span><span class="p">.</span><span class="n">withItems</span><span class="p">(*</span><span class="n">ourStates</span><span class="p">.</span><span class="n">inputs</span><span class="p">.</span><span class="n">toTypedArray</span><span class="p">())</span>
<span class="n">builder</span><span class="p">.</span><span class="n">withItems</span><span class="p">(*</span><span class="n">theirStates</span><span class="p">.</span><span class="n">inputs</span><span class="p">.</span><span class="n">toTypedArray</span><span class="p">())</span>
<span class="n">builder</span><span class="p">.</span><span class="n">withItems</span><span class="p">(*</span><span class="n">ourStates</span><span class="p">.</span><span class="n">outputs</span><span class="p">.</span><span class="n">toTypedArray</span><span class="p">())</span>
<span class="n">builder</span><span class="p">.</span><span class="n">withItems</span><span class="p">(*</span><span class="n">theirStates</span><span class="p">.</span><span class="n">outputs</span><span class="p">.</span><span class="n">toTypedArray</span><span class="p">())</span>
<span class="c1">// We have already validated their response and trust our own data</span>
<span class="c1">// so we can sign</span>
<span class="n">builder</span><span class="p">.</span><span class="n">signWith</span><span class="p">(</span><span class="n">serviceHub</span><span class="p">.</span><span class="n">legalIdentityKey</span><span class="p">)</span>
<span class="c1">// create a signed transaction, but pass false as parameter, because we know it is not fully signed</span>
<span class="k">val</span> <span class="py">signedTransaction</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="n">toSignedTransaction</span><span class="p">(</span><span class="n">checkSufficientSignatures</span> <span class="p">=</span> <span class="k">false</span><span class="p">)</span>
<span class="k">return</span> <span class="n">signedTransaction</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<div class="section" id="completing-the-signedtransaction">
<h2>Completing the SignedTransaction<a class="headerlink" href="#completing-the-signedtransaction" title="Permalink to this headline"></a></h2>
<p>Having created an initial <code class="docutils literal"><span class="pre">WireTransaction</span></code> and converted this to an
initial <code class="docutils literal"><span class="pre">SignedTransaction</span></code> the process of verifying and forming a
full <code class="docutils literal"><span class="pre">SignedTransaction</span></code> begins and then completes with the
notarisation. In practice this is a relatively stereotypical process,
because assuming the <code class="docutils literal"><span class="pre">WireTransaction</span></code> is correctly constructed the
verification should be immediate. However, it is also important to
recheck the business details of any data received back from an external
node, because a malicious party could always modify the contents before
returning the transaction. Each remote flow should therefore check as
much as possible of the initial <code class="docutils literal"><span class="pre">SignedTransaction</span></code> inside the <code class="docutils literal"><span class="pre">unwrap</span></code> of
the receive before agreeing to sign. Any issues should immediately throw
an exception to abort the flow. Similarly the originator, should always
apply any new signatures to its original proposal to ensure the contents
of the transaction has not been altered by the remote parties.</p>
<p>The typical code therefore checks the received <code class="docutils literal"><span class="pre">SignedTransaction</span></code>
using the <code class="docutils literal"><span class="pre">verifySignatures</span></code> method, but excluding itself, the notary
and any other parties yet to apply their signature. The contents of the
<code class="docutils literal"><span class="pre">WireTransaction</span></code> inside the <code class="docutils literal"><span class="pre">SignedTransaction</span></code> should be fully
verified further by expanding with <code class="docutils literal"><span class="pre">toLedgerTransaction</span></code> and calling
<code class="docutils literal"><span class="pre">verify</span></code>. Further context specific and business checks should then be
made, because the <code class="docutils literal"><span class="pre">Contract.verify</span></code> is not allowed to access external
context. For example the flow may need to check that the parties are the
right ones, or that the <code class="docutils literal"><span class="pre">Command</span></code> present on the transaction is as
expected for this specific flow. An example of this from the demo code is:</p>
<div class="highlight-kotlin"><div class="highlight"><pre><span></span> <span class="c1">// First we receive the verdict transaction signed by their single key</span>
<span class="k">val</span> <span class="py">completeTx</span> <span class="p">=</span> <span class="n">receive</span><span class="p">&lt;</span><span class="n">SignedTransaction</span><span class="p">&gt;(</span><span class="n">source</span><span class="p">).</span><span class="n">unwrap</span> <span class="p">{</span>
<span class="c1">// Check the transaction is signed apart from our own key and the notary</span>
<span class="k">val</span> <span class="py">wtx</span> <span class="p">=</span> <span class="n">it</span><span class="p">.</span><span class="n">verifySignatures</span><span class="p">(</span><span class="n">serviceHub</span><span class="p">.</span><span class="n">myInfo</span><span class="p">.</span><span class="n">legalIdentity</span><span class="p">.</span><span class="n">owningKey</span><span class="p">,</span> <span class="n">it</span><span class="p">.</span><span class="n">tx</span><span class="p">.</span><span class="n">notary</span><span class="o">!!</span><span class="p">.</span><span class="n">owningKey</span><span class="p">)</span>
<span class="c1">// Check the transaction data is correctly formed</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">verify</span><span class="p">()</span>
<span class="c1">// Confirm that this is the expected type of transaction</span>
<span class="n">require</span><span class="p">(</span><span class="n">wtx</span><span class="p">.</span><span class="n">commands</span><span class="p">.</span><span class="n">single</span><span class="p">().</span><span class="n">value</span> <span class="k">is</span> <span class="n">TradeApprovalContract</span><span class="p">.</span><span class="n">Commands</span><span class="p">.</span><span class="n">Completed</span><span class="p">)</span> <span class="p">{</span>
<span class="s">&quot;Transaction must represent a workflow completion&quot;</span>
<span class="p">}</span>
<span class="c1">// Check the context dependent parts of the transaction as the</span>
<span class="c1">// Contract verify method must not use serviceHub queries.</span>
<span class="k">val</span> <span class="py">state</span> <span class="p">=</span> <span class="n">wtx</span><span class="p">.</span><span class="n">outRef</span><span class="p">&lt;</span><span class="n">TradeApprovalContract</span><span class="p">.</span><span class="n">State</span><span class="p">&gt;(</span><span class="m">0</span><span class="p">)</span>
<span class="n">require</span><span class="p">(</span><span class="n">state</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="k">data</span><span class="p">.</span><span class="n">source</span> <span class="p">==</span> <span class="n">serviceHub</span><span class="p">.</span><span class="n">myInfo</span><span class="p">.</span><span class="n">legalIdentity</span><span class="p">)</span> <span class="p">{</span>
<span class="s">&quot;Proposal not one of our original proposals&quot;</span>
<span class="p">}</span>
<span class="n">require</span><span class="p">(</span><span class="n">state</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="k">data</span><span class="p">.</span><span class="n">counterparty</span> <span class="p">==</span> <span class="n">source</span><span class="p">)</span> <span class="p">{</span>
<span class="s">&quot;Proposal not for sent from correct source&quot;</span>
<span class="p">}</span>
<span class="n">it</span>
<span class="p">}</span>
</pre></div>
</div>
<p>After verification the remote flow will return its signature to the
originator. The originator should apply that signature to the starting
<code class="docutils literal"><span class="pre">SignedTransaction</span></code> and recheck the signatures match.</p>
</div>
<div class="section" id="committing-the-transaction">
<h2>Committing the Transaction<a class="headerlink" href="#committing-the-transaction" title="Permalink to this headline"></a></h2>
<p>Once all the party signatures are applied to the SignedTransaction the
final step is notarisation. This involves calling <code class="docutils literal"><span class="pre">NotaryFlow.Client</span></code>
to confirm the transaction, consume the inputs and return its confirming
signature. Then the flow should ensure that all nodes end with all
signatures and that they call <code class="docutils literal"><span class="pre">ServiceHub.recordTransactions</span></code>. The
code for this is standardised in the <code class="docutils literal"><span class="pre">FinalityFlow</span></code>, or more explicitly
an example is:</p>
<div class="highlight-kotlin"><div class="highlight"><pre><span></span> <span class="c1">// Run the FinalityFlow to notarise and distribute the completed transaction.</span>
<span class="n">subFlow</span><span class="p">(</span><span class="n">FinalityFlow</span><span class="p">(</span><span class="n">allPartySignedTx</span><span class="p">,</span>
<span class="n">setOf</span><span class="p">(</span><span class="n">latestRecord</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="k">data</span><span class="p">.</span><span class="n">source</span><span class="p">,</span> <span class="n">latestRecord</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="k">data</span><span class="p">.</span><span class="n">counterparty</span><span class="p">)))</span>
</pre></div>
</div>
</div>
<div class="section" id="partially-visible-transactions">
<h2>Partially Visible Transactions<a class="headerlink" href="#partially-visible-transactions" title="Permalink to this headline"></a></h2>
<p>The discussion so far has assumed that the parties need full visibility
of the transaction to sign. However, there may be situations where each
party needs to store private data for audit purposes, or for evidence to
a regulator, but does not wish to share that with the other trading
partner. The tear-off/Merkle tree support in Corda allows flows to send
portions of the full transaction to restrict visibility to remote
parties. To do this one can use the
<code class="docutils literal"><span class="pre">WireTransaction.buildFilteredTransaction</span></code> extension method to produce
a <code class="docutils literal"><span class="pre">FilteredTransaction</span></code>. The elements of the <code class="docutils literal"><span class="pre">SignedTransaction</span></code>
which we wish to be hide will be replaced with their secure hash. The
overall transaction txid is still provable from the
<code class="docutils literal"><span class="pre">FilteredTransaction</span></code> preventing change of the private data, but we do
not expose that data to the other node directly. A full example of this
can be found in the <code class="docutils literal"><span class="pre">NodeInterestRates</span></code> Oracle code from the
<code class="docutils literal"><span class="pre">irs-demo</span></code> project which interacts with the <code class="docutils literal"><span class="pre">RatesFixFlow</span></code> flow.
Also, refer to the <a class="reference internal" href="merkle-trees.html"><span class="doc">Transaction tear-offs</span></a> documentation.</p>
</div>
</div>
</div>
</div>
<footer>
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="flow-state-machines.html" class="btn btn-neutral float-right" title="Writing flows" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
<a href="tutorial-clientrpc-api.html" class="btn btn-neutral" title="Client RPC API tutorial" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
</div>
<hr/>
<div role="contentinfo">
<p>
&copy; Copyright 2016, R3 Limited.
</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:'latest',
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>