mirror of
https://github.com/corda/corda.git
synced 2024-12-21 22:07:55 +00:00
934 lines
94 KiB
HTML
934 lines
94 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>Writing a contract — R3 Prototyping latest documentation</title>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="top" title="R3 Prototyping latest documentation" href="index.html"/>
|
|
<link rel="next" title="Protocol state machines" href="protocol-state-machines.html"/>
|
|
<link rel="prev" title="Node administration" href="node-administration.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">
|
|
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>
|
|
<a href="api/index.html">API reference</a>
|
|
|
|
</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>
|
|
<li class="toctree-l1"><a class="reference internal" href="running-the-trading-demo.html">Running the trading demo</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="node-administration.html">Node administration</a></li>
|
|
</ul>
|
|
<p class="caption"><span class="caption-text">Tutorials</span></p>
|
|
<ul class="current">
|
|
<li class="toctree-l1 current"><a class="current reference internal" href="#">Writing a contract</a><ul>
|
|
<li class="toctree-l2"><a class="reference internal" href="#starting-the-commercial-paper-class">Starting the commercial paper class</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#states">States</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#commands">Commands</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#the-verify-function">The verify function</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#understanding-fungibility">Understanding fungibility</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#checking-the-requirements">Checking the requirements</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#how-to-test-your-contract">How to test your contract</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#adding-a-generation-api-to-your-contract">Adding a generation API to your contract</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="#non-asset-oriented-based-smart-contracts">Non-asset-oriented based smart contracts</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="toctree-l1"><a class="reference internal" href="protocol-state-machines.html">Protocol state machines</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="oracles.html">Writing oracle services</a></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="codestyle.html">Code style guide</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>Writing a contract</li>
|
|
<li class="wy-breadcrumbs-aside">
|
|
|
|
|
|
<a href="_sources/tutorial.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="writing-a-contract">
|
|
<h1>Writing a contract<a class="headerlink" href="#writing-a-contract" title="Permalink to this headline">¶</a></h1>
|
|
<p>This tutorial will take you through how the commercial paper contract works.</p>
|
|
<p>The code in this tutorial is available in both Kotlin and Java. You can quickly switch between them to get a feeling
|
|
for how Kotlin syntax works.</p>
|
|
<div class="section" id="starting-the-commercial-paper-class">
|
|
<h2>Starting the commercial paper class<a class="headerlink" href="#starting-the-commercial-paper-class" title="Permalink to this headline">¶</a></h2>
|
|
<p>A smart contract is a class that implements the <code class="docutils literal"><span class="pre">Contract</span></code> interface. For now, they have to be a part of the main
|
|
codebase, as dynamic loading of contract code is not yet implemented. Therefore, we start by creating a file named
|
|
either <code class="docutils literal"><span class="pre">CommercialPaper.kt</span></code> or <code class="docutils literal"><span class="pre">CommercialPaper.java</span></code> in the src/contracts directory with the following contents:</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">CommercialPaper</span> <span class="p">:</span> <span class="n">Contract</span> <span class="p">{</span>
|
|
<span class="k">override</span> <span class="k">val</span> <span class="py">legalContractReference</span><span class="p">:</span> <span class="n">SecureHash</span> <span class="p">=</span> <span class="n">SecureHash</span><span class="p">.</span><span class="n">sha256</span><span class="p">(</span><span class="s">"https://en.wikipedia.org/wiki/Commercial_paper"</span><span class="p">);</span>
|
|
|
|
<span class="k">override</span> <span class="k">fun</span> <span class="nf">verify</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">TransactionForVerification</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="n">TODO</span><span class="p">()</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<div class="highlight-java"><div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Cash</span> <span class="kd">implements</span> <span class="n">Contract</span> <span class="o">{</span>
|
|
<span class="nd">@Override</span>
|
|
<span class="kd">public</span> <span class="n">SecureHash</span> <span class="nf">getLegalContractReference</span><span class="o">()</span> <span class="o">{</span>
|
|
<span class="k">return</span> <span class="n">SecureHash</span><span class="o">.</span><span class="na">Companion</span><span class="o">.</span><span class="na">sha256</span><span class="o">(</span><span class="s">"https://en.wikipedia.org/wiki/Commercial_paper"</span><span class="o">);</span>
|
|
<span class="o">}</span>
|
|
|
|
<span class="nd">@Override</span>
|
|
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">verify</span><span class="o">(</span><span class="n">TransactionForVerification</span> <span class="n">tx</span><span class="o">)</span> <span class="o">{</span>
|
|
<span class="k">throw</span> <span class="k">new</span> <span class="n">UnsupportedOperationException</span><span class="o">();</span>
|
|
<span class="o">}</span>
|
|
<span class="o">}</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>Every contract must have at least a <code class="docutils literal"><span class="pre">getLegalContractReference()</span></code> and a <code class="docutils literal"><span class="pre">verify()</span></code> method. In Kotlin we express
|
|
a getter without a setter as an immutable property (val). The <em>legal contract reference</em> is supposed to be a hash
|
|
of a document that describes the legal contract and may take precedence over the code, in case of a dispute.</p>
|
|
<p>The verify method returns nothing. This is intentional: the function either completes correctly, or throws an exception,
|
|
in which case the transaction is rejected.</p>
|
|
<p>We also need to define a constant hash that would, in a real system, be the hash of the program bytecode. For now
|
|
we just set it to a dummy value as dynamic loading and sandboxing of bytecode is not implemented. This constant
|
|
isn’t shown in the code snippet but is called <code class="docutils literal"><span class="pre">CP_PROGRAM_ID</span></code>.</p>
|
|
<p>So far, so simple. Now we need to define the commercial paper <em>state</em>, which represents the fact of ownership of a
|
|
piece of issued paper.</p>
|
|
</div>
|
|
<div class="section" id="states">
|
|
<h2>States<a class="headerlink" href="#states" title="Permalink to this headline">¶</a></h2>
|
|
<p>A state is a class that stores data that is checked by the contract.</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">data</span> <span class="k">class</span> <span class="nc">State</span><span class="p">(</span>
|
|
<span class="k">val</span> <span class="py">issuance</span><span class="p">:</span> <span class="n">InstitutionReference</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">owner</span><span class="p">:</span> <span class="n">PublicKey</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">faceValue</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span>
|
|
<span class="k">val</span> <span class="py">maturityDate</span><span class="p">:</span> <span class="n">Instant</span>
|
|
<span class="p">)</span> <span class="p">:</span> <span class="n">ContractState</span> <span class="p">{</span>
|
|
<span class="k">override</span> <span class="k">val</span> <span class="py">programRef</span> <span class="p">=</span> <span class="n">CP_PROGRAM_ID</span>
|
|
|
|
<span class="k">fun</span> <span class="nf">withoutOwner</span><span class="p">()</span> <span class="p">=</span> <span class="n">copy</span><span class="p">(</span><span class="n">owner</span> <span class="p">=</span> <span class="n">NullPublicKey</span><span class="p">)</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<div class="highlight-java"><div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">State</span> <span class="kd">implements</span> <span class="n">ContractState</span><span class="o">,</span> <span class="n">SerializeableWithKryo</span> <span class="o">{</span>
|
|
<span class="kd">private</span> <span class="n">InstitutionReference</span> <span class="n">issuance</span><span class="o">;</span>
|
|
<span class="kd">private</span> <span class="n">PublicKey</span> <span class="n">owner</span><span class="o">;</span>
|
|
<span class="kd">private</span> <span class="n">Amount</span> <span class="n">faceValue</span><span class="o">;</span>
|
|
<span class="kd">private</span> <span class="n">Instant</span> <span class="n">maturityDate</span><span class="o">;</span>
|
|
|
|
<span class="kd">public</span> <span class="nf">State</span><span class="o">()</span> <span class="o">{}</span> <span class="c1">// For serialization</span>
|
|
|
|
<span class="kd">public</span> <span class="nf">State</span><span class="o">(</span><span class="n">InstitutionReference</span> <span class="n">issuance</span><span class="o">,</span> <span class="n">PublicKey</span> <span class="n">owner</span><span class="o">,</span> <span class="n">Amount</span> <span class="n">faceValue</span><span class="o">,</span> <span class="n">Instant</span> <span class="n">maturityDate</span><span class="o">)</span> <span class="o">{</span>
|
|
<span class="k">this</span><span class="o">.</span><span class="na">issuance</span> <span class="o">=</span> <span class="n">issuance</span><span class="o">;</span>
|
|
<span class="k">this</span><span class="o">.</span><span class="na">owner</span> <span class="o">=</span> <span class="n">owner</span><span class="o">;</span>
|
|
<span class="k">this</span><span class="o">.</span><span class="na">faceValue</span> <span class="o">=</span> <span class="n">faceValue</span><span class="o">;</span>
|
|
<span class="k">this</span><span class="o">.</span><span class="na">maturityDate</span> <span class="o">=</span> <span class="n">maturityDate</span><span class="o">;</span>
|
|
<span class="o">}</span>
|
|
|
|
<span class="kd">public</span> <span class="n">InstitutionReference</span> <span class="nf">getIssuance</span><span class="o">()</span> <span class="o">{</span>
|
|
<span class="k">return</span> <span class="n">issuance</span><span class="o">;</span>
|
|
<span class="o">}</span>
|
|
|
|
<span class="kd">public</span> <span class="n">PublicKey</span> <span class="nf">getOwner</span><span class="o">()</span> <span class="o">{</span>
|
|
<span class="k">return</span> <span class="n">owner</span><span class="o">;</span>
|
|
<span class="o">}</span>
|
|
|
|
<span class="kd">public</span> <span class="n">Amount</span> <span class="nf">getFaceValue</span><span class="o">()</span> <span class="o">{</span>
|
|
<span class="k">return</span> <span class="n">faceValue</span><span class="o">;</span>
|
|
<span class="o">}</span>
|
|
|
|
<span class="kd">public</span> <span class="n">Instant</span> <span class="nf">getMaturityDate</span><span class="o">()</span> <span class="o">{</span>
|
|
<span class="k">return</span> <span class="n">maturityDate</span><span class="o">;</span>
|
|
<span class="o">}</span>
|
|
|
|
<span class="nd">@NotNull</span>
|
|
<span class="nd">@Override</span>
|
|
<span class="kd">public</span> <span class="n">SecureHash</span> <span class="nf">getProgramRef</span><span class="o">()</span> <span class="o">{</span>
|
|
<span class="k">return</span> <span class="n">SecureHash</span><span class="o">.</span><span class="na">Companion</span><span class="o">.</span><span class="na">sha256</span><span class="o">(</span><span class="s">"java commercial paper (this should be a bytecode hash)"</span><span class="o">);</span>
|
|
<span class="o">}</span>
|
|
|
|
<span class="nd">@Override</span>
|
|
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">equals</span><span class="o">(</span><span class="n">Object</span> <span class="n">o</span><span class="o">)</span> <span class="o">{</span>
|
|
<span class="k">if</span> <span class="o">(</span><span class="k">this</span> <span class="o">==</span> <span class="n">o</span><span class="o">)</span> <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
|
|
<span class="k">if</span> <span class="o">(</span><span class="n">o</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">getClass</span><span class="o">()</span> <span class="o">!=</span> <span class="n">o</span><span class="o">.</span><span class="na">getClass</span><span class="o">())</span> <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
|
|
|
|
<span class="n">State</span> <span class="n">state</span> <span class="o">=</span> <span class="o">(</span><span class="n">State</span><span class="o">)</span> <span class="n">o</span><span class="o">;</span>
|
|
|
|
<span class="k">if</span> <span class="o">(</span><span class="n">issuance</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="o">!</span><span class="n">issuance</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">state</span><span class="o">.</span><span class="na">issuance</span><span class="o">)</span> <span class="o">:</span> <span class="n">state</span><span class="o">.</span><span class="na">issuance</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
|
|
<span class="k">if</span> <span class="o">(</span><span class="n">owner</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="o">!</span><span class="n">owner</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">state</span><span class="o">.</span><span class="na">owner</span><span class="o">)</span> <span class="o">:</span> <span class="n">state</span><span class="o">.</span><span class="na">owner</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
|
|
<span class="k">if</span> <span class="o">(</span><span class="n">faceValue</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="o">!</span><span class="n">faceValue</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">state</span><span class="o">.</span><span class="na">faceValue</span><span class="o">)</span> <span class="o">:</span> <span class="n">state</span><span class="o">.</span><span class="na">faceValue</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
|
|
<span class="k">return</span> <span class="o">!(</span><span class="n">maturityDate</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="o">!</span><span class="n">maturityDate</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">state</span><span class="o">.</span><span class="na">maturityDate</span><span class="o">)</span> <span class="o">:</span> <span class="n">state</span><span class="o">.</span><span class="na">maturityDate</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">);</span>
|
|
|
|
<span class="o">}</span>
|
|
|
|
<span class="nd">@Override</span>
|
|
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">hashCode</span><span class="o">()</span> <span class="o">{</span>
|
|
<span class="kt">int</span> <span class="n">result</span> <span class="o">=</span> <span class="n">issuance</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">issuance</span><span class="o">.</span><span class="na">hashCode</span><span class="o">()</span> <span class="o">:</span> <span class="mi">0</span><span class="o">;</span>
|
|
<span class="n">result</span> <span class="o">=</span> <span class="mi">31</span> <span class="o">*</span> <span class="n">result</span> <span class="o">+</span> <span class="o">(</span><span class="n">owner</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">owner</span><span class="o">.</span><span class="na">hashCode</span><span class="o">()</span> <span class="o">:</span> <span class="mi">0</span><span class="o">);</span>
|
|
<span class="n">result</span> <span class="o">=</span> <span class="mi">31</span> <span class="o">*</span> <span class="n">result</span> <span class="o">+</span> <span class="o">(</span><span class="n">faceValue</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">faceValue</span><span class="o">.</span><span class="na">hashCode</span><span class="o">()</span> <span class="o">:</span> <span class="mi">0</span><span class="o">);</span>
|
|
<span class="n">result</span> <span class="o">=</span> <span class="mi">31</span> <span class="o">*</span> <span class="n">result</span> <span class="o">+</span> <span class="o">(</span><span class="n">maturityDate</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">maturityDate</span><span class="o">.</span><span class="na">hashCode</span><span class="o">()</span> <span class="o">:</span> <span class="mi">0</span><span class="o">);</span>
|
|
<span class="k">return</span> <span class="n">result</span><span class="o">;</span>
|
|
<span class="o">}</span>
|
|
|
|
<span class="kd">public</span> <span class="n">State</span> <span class="nf">withoutOwner</span><span class="o">()</span> <span class="o">{</span>
|
|
<span class="k">return</span> <span class="k">new</span> <span class="n">State</span><span class="o">(</span><span class="n">issuance</span><span class="o">,</span> <span class="n">NullPublicKey</span><span class="o">.</span><span class="na">INSTANCE</span><span class="o">,</span> <span class="n">faceValue</span><span class="o">,</span> <span class="n">maturityDate</span><span class="o">);</span>
|
|
<span class="o">}</span>
|
|
<span class="o">}</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>We define a class that implements the <code class="docutils literal"><span class="pre">ContractState</span></code> and <code class="docutils literal"><span class="pre">SerializableWithKryo</span></code> interfaces. The
|
|
latter is an artifact of how the prototype implements serialization and can be ignored for now: it wouldn’t work
|
|
like this in any final product.</p>
|
|
<p>The <code class="docutils literal"><span class="pre">ContractState</span></code> interface requires us to provide a <code class="docutils literal"><span class="pre">getProgramRef</span></code> method that is supposed to return a hash of
|
|
the bytecode of the contract itself. For now this is a dummy value and isn’t used: later on, this mechanism will change.
|
|
Beyond that it’s a freeform object into which we can put anything which can be serialized.</p>
|
|
<p>We have four fields in our state:</p>
|
|
<ul class="simple">
|
|
<li><code class="docutils literal"><span class="pre">issuance</span></code>: a reference to a specific piece of commercial paper at a party</li>
|
|
<li><code class="docutils literal"><span class="pre">owner</span></code>: the public key of the current owner. This is the same concept as seen in Bitcoin: the public key has no
|
|
attached identity and is expected to be one-time-use for privacy reasons. However, unlike in Bitcoin, we model
|
|
ownership at the level of individual contracts rather than as a platform-level concept as we envisage many
|
|
(possibly most) contracts on the platform will not represent “owner/issuer” relationships, but “party/party”
|
|
relationships such as a derivative contract.</li>
|
|
<li><code class="docutils literal"><span class="pre">faceValue</span></code>: an <code class="docutils literal"><span class="pre">Amount</span></code>, which wraps an integer number of pennies and a currency.</li>
|
|
<li><code class="docutils literal"><span class="pre">maturityDate</span></code>: an <a class="reference external" href="https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html">Instant</a>, which is a type
|
|
from the Java 8 standard time library. It defines a point on the timeline.</li>
|
|
</ul>
|
|
<p>States are immutable, and thus the class is defined as immutable as well. The <code class="docutils literal"><span class="pre">data</span></code> modifier in the Kotlin version
|
|
causes the compiler to generate the equals/hashCode/toString methods automatically, along with a copy method that can
|
|
be used to create variants of the original object. Data classes are similar to case classes in Scala, if you are
|
|
familiar with that language. The <code class="docutils literal"><span class="pre">withoutOwner</span></code> method uses the auto-generated copy method to return a version of
|
|
the state with the owner public key blanked out: this will prove useful later.</p>
|
|
<p>The Java code compiles to the same bytecode as the Kotlin version, but as you can see, is much more verbose.</p>
|
|
</div>
|
|
<div class="section" id="commands">
|
|
<h2>Commands<a class="headerlink" href="#commands" title="Permalink to this headline">¶</a></h2>
|
|
<p>The logic for a contract may vary depending on what stage of a lifecycle it is automating. So it can be useful to
|
|
pass additional data into the contract code that isn’t represented by the states which exist permanently in the ledger.</p>
|
|
<p>For this purpose we have commands. Often, they don’t need to contain any data at all, they just need to exist. A command
|
|
is a piece of data associated with some <em>signatures</em>. By the time the contract runs the signatures have already been
|
|
checked, so from the contract code’s perspective, a command is simply a data structure with a list of attached
|
|
public keys. Each key had a signature proving that the corresponding private key was used to sign.</p>
|
|
<p>Let’s define a few commands now:</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">interface</span> <span class="nc">Commands</span> <span class="p">:</span> <span class="n">Command</span> <span class="p">{</span>
|
|
<span class="k">object</span> <span class="nc">Move</span> <span class="p">:</span> <span class="n">Commands</span>
|
|
<span class="k">object</span> <span class="nc">Redeem</span> <span class="p">:</span> <span class="n">Commands</span>
|
|
<span class="k">object</span> <span class="nc">Issue</span> <span class="p">:</span> <span class="n">Commands</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<div class="highlight-java"><div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">Commands</span> <span class="kd">implements</span> <span class="n">core</span><span class="o">.</span><span class="na">Command</span> <span class="o">{</span>
|
|
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">Move</span> <span class="kd">extends</span> <span class="n">Commands</span> <span class="o">{</span>
|
|
<span class="nd">@Override</span>
|
|
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">equals</span><span class="o">(</span><span class="n">Object</span> <span class="n">obj</span><span class="o">)</span> <span class="o">{</span>
|
|
<span class="k">return</span> <span class="n">obj</span> <span class="k">instanceof</span> <span class="n">Move</span><span class="o">;</span>
|
|
<span class="o">}</span>
|
|
<span class="o">}</span>
|
|
|
|
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">Redeem</span> <span class="kd">extends</span> <span class="n">Commands</span> <span class="o">{</span>
|
|
<span class="nd">@Override</span>
|
|
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">equals</span><span class="o">(</span><span class="n">Object</span> <span class="n">obj</span><span class="o">)</span> <span class="o">{</span>
|
|
<span class="k">return</span> <span class="n">obj</span> <span class="k">instanceof</span> <span class="n">Redeem</span><span class="o">;</span>
|
|
<span class="o">}</span>
|
|
<span class="o">}</span>
|
|
|
|
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">Issue</span> <span class="kd">extends</span> <span class="n">Commands</span> <span class="o">{</span>
|
|
<span class="nd">@Override</span>
|
|
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">equals</span><span class="o">(</span><span class="n">Object</span> <span class="n">obj</span><span class="o">)</span> <span class="o">{</span>
|
|
<span class="k">return</span> <span class="n">obj</span> <span class="k">instanceof</span> <span class="n">Issue</span><span class="o">;</span>
|
|
<span class="o">}</span>
|
|
<span class="o">}</span>
|
|
<span class="o">}</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>The <code class="docutils literal"><span class="pre">object</span></code> keyword in Kotlin just defines a singleton object. As the commands don’t need any additional data in our
|
|
case, they can be empty and we just use their type as the important information. Java has no syntax for declaring
|
|
singletons, so we just define a class that considers any other instance to be equal and that’s good enough.</p>
|
|
</div>
|
|
<div class="section" id="the-verify-function">
|
|
<h2>The verify function<a class="headerlink" href="#the-verify-function" title="Permalink to this headline">¶</a></h2>
|
|
<p>The heart of a smart contract is the code that verifies a set of state transitions (a <em>transaction</em>). The function is
|
|
simple: it’s given a class representing the transaction, and if the function returns then the transaction is considered
|
|
acceptable. If it throws an exception, the transaction is rejected.</p>
|
|
<p>Each transaction can have multiple input and output states of different types. The set of contracts to run is decided
|
|
by taking the code references inside each state. Each contract is run only once. As an example, a contract that includes
|
|
2 cash states and 1 commercial paper state as input, and has as output 1 cash state and 1 commercial paper state, will
|
|
run two contracts one time each: Cash and CommercialPaper.</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">override</span> <span class="k">fun</span> <span class="nf">verify</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">TransactionForVerification</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="c1">// Group by everything except owner: any modification to the CP at all is considered changing it fundamentally.</span>
|
|
<span class="k">val</span> <span class="py">groups</span> <span class="p">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">groupStates</span><span class="p"><</span><span class="n">State</span><span class="p">>()</span> <span class="p">{</span> <span class="n">it</span><span class="p">.</span><span class="n">withoutOwner</span><span class="p">()</span> <span class="p">}</span>
|
|
<span class="k">val</span> <span class="py">command</span> <span class="p">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">commands</span><span class="p">.</span><span class="n">requireSingleCommand</span><span class="p"><</span><span class="n">CommercialPaper</span><span class="p">.</span><span class="n">Commands</span><span class="p">>()</span>
|
|
</pre></div>
|
|
</div>
|
|
<div class="highlight-java"><div class="highlight"><pre><span></span><span class="nd">@Override</span>
|
|
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">verify</span><span class="o">(</span><span class="nd">@NotNull</span> <span class="n">TransactionForVerification</span> <span class="n">tx</span><span class="o">)</span> <span class="o">{</span>
|
|
<span class="n">List</span><span class="o"><</span><span class="n">InOutGroup</span><span class="o"><</span><span class="n">State</span><span class="o">>></span> <span class="n">groups</span> <span class="o">=</span> <span class="n">tx</span><span class="o">.</span><span class="na">groupStates</span><span class="o">(</span><span class="n">State</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">State</span><span class="o">::</span><span class="n">withoutOwner</span><span class="o">);</span>
|
|
<span class="n">AuthenticatedObject</span><span class="o"><</span><span class="n">Command</span><span class="o">></span> <span class="n">cmd</span> <span class="o">=</span> <span class="n">requireSingleCommand</span><span class="o">(</span><span class="n">tx</span><span class="o">.</span><span class="na">getCommands</span><span class="o">(),</span> <span class="n">Commands</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>We start by using the <code class="docutils literal"><span class="pre">groupStates</span></code> method, which takes a type and a function (in functional programming a function
|
|
that takes another function as an argument is called a <em>higher order function</em>). State grouping is a way of handling
|
|
<em>fungibility</em> in a contract, which is explained next. The second line does what the code suggests: it searches for
|
|
a command object that inherits from the <code class="docutils literal"><span class="pre">CommercialPaper.Commands</span></code> supertype, and either returns it, or throws an
|
|
exception if there’s zero or more than one such command.</p>
|
|
</div>
|
|
<div class="section" id="understanding-fungibility">
|
|
<h2>Understanding fungibility<a class="headerlink" href="#understanding-fungibility" title="Permalink to this headline">¶</a></h2>
|
|
<p>We say states are <em>fungible</em> if they are treated identically to each other by the recipient, despite the fact that they
|
|
aren’t quite identical. Dollar bills are fungible because even though one may be worn/a bit dirty and another may
|
|
be crisp and new, they are still both worth exactly $1. Likewise, ten $1 bills are almost exactly equivalent to
|
|
one $10 bill. On the other hand, $10 and £10 are not fungible: if you tried to pay for something that cost £20 with
|
|
$10+£10 notes your trade would not be accepted.</p>
|
|
<p>So whilst our ledger could represent every monetary amount with a collection of states worth one penny, this would become
|
|
extremely unwieldy. It’s better to allow states to represent varying amounts and then define rules for merging them
|
|
and splitting them. Similarly, we could also have considered modelling cash as a single contract that records the
|
|
ownership of all holders of a given currency from a given issuer. Whilst this is possible, and is effectively how
|
|
some other platforms work, this prototype favours a design that doesn’t necessarily require state to be shared between
|
|
multiple actors if they don’t have a direct relationship with each other (as would implicitly be required if we had a
|
|
single state representing multiple people’s ownership). Keeping the states separated also has scalability benefits, as
|
|
different parts of the global transaction graph can be updated in parallel.</p>
|
|
<p>To make all this easier the contract API provides a notion of groups. A group is a set of input states and output states
|
|
that should be checked for validity independently. It solves the following problem: because every contract sees every
|
|
input and output state in a transaction, it would easy to accidentally write a contract that disallows useful
|
|
combinations of states. For example, our cash contract might end up lazily assuming there’s only one currency involved
|
|
in a transaction, whereas in reality we would like the ability to model a currency trade in which two parties contribute
|
|
inputs of different currencies, and both parties get outputs of the opposite currency.</p>
|
|
<p>Consider the following simplified currency trade transaction:</p>
|
|
<ul class="simple">
|
|
<li><strong>Input</strong>: $12,000 owned by Alice (A)</li>
|
|
<li><strong>Input</strong>: $3,000 owned by Alice (A)</li>
|
|
<li><strong>Input</strong>: £10,000 owned by Bob (B)</li>
|
|
<li><strong>Output</strong>: £10,000 owned by Alice (B)</li>
|
|
<li><strong>Output</strong>: $15,000 owned by Bob (A)</li>
|
|
</ul>
|
|
<p>In this transaction Alice and Bob are trading $15,000 for £10,000. Alice has her money in the form of two different
|
|
inputs e.g. because she received the dollars in two payments. The input and output amounts do balance correctly, but
|
|
the cash smart contract must consider the pounds and the dollars separately because they are not fungible: they cannot
|
|
be merged together. So we have two groups: A and B.</p>
|
|
<p>The <code class="docutils literal"><span class="pre">TransactionForVerification.groupStates</span></code> method handles this logic for us: firstly, it selects only states of the
|
|
given type (as the transaction may include other types of state, such as states representing bond ownership, or a
|
|
multi-sig state) and then it takes a function that maps a state to a grouping key. All states that share the same key are
|
|
grouped together. In the case of the cash example above, the grouping key would be the currency.</p>
|
|
<p>In our commercial paper contract, we don’t want CP to be fungible: merging and splitting is (in our example) not allowed.
|
|
So we just use a copy of the state minus the owner field as the grouping key. As a result, a single transaction can
|
|
trade many different pieces of commercial paper in a single atomic step.</p>
|
|
<p>A group may have zero inputs or zero outputs: this can occur when issuing assets onto the ledger, or removing them.</p>
|
|
</div>
|
|
<div class="section" id="checking-the-requirements">
|
|
<h2>Checking the requirements<a class="headerlink" href="#checking-the-requirements" title="Permalink to this headline">¶</a></h2>
|
|
<p>After extracting the command and the groups, we then iterate over each group and verify it meets the required business
|
|
logic.</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">val</span> <span class="py">time</span> <span class="p">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">time</span>
|
|
<span class="k">for</span> <span class="p">(</span><span class="n">group</span> <span class="k">in</span> <span class="n">groups</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="k">when</span> <span class="p">(</span><span class="n">command</span><span class="p">.</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="k">is</span> <span class="n">Commands</span><span class="p">.</span><span class="n">Move</span> <span class="p">-></span> <span class="p">{</span>
|
|
<span class="k">val</span> <span class="py">input</span> <span class="p">=</span> <span class="n">group</span><span class="p">.</span><span class="n">inputs</span><span class="p">.</span><span class="n">single</span><span class="p">()</span>
|
|
<span class="n">requireThat</span> <span class="p">{</span>
|
|
<span class="s">"the transaction is signed by the owner of the CP"</span> <span class="k">by</span> <span class="p">(</span><span class="n">command</span><span class="p">.</span><span class="n">signers</span><span class="p">.</span><span class="n">contains</span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">owner</span><span class="p">))</span>
|
|
<span class="s">"the state is propagated"</span> <span class="k">by</span> <span class="p">(</span><span class="n">group</span><span class="p">.</span><span class="n">outputs</span><span class="p">.</span><span class="n">size</span> <span class="p">==</span> <span class="m">1</span><span class="p">)</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="k">is</span> <span class="n">Commands</span><span class="p">.</span><span class="n">Redeem</span> <span class="p">-></span> <span class="p">{</span>
|
|
<span class="k">val</span> <span class="py">input</span> <span class="p">=</span> <span class="n">group</span><span class="p">.</span><span class="n">inputs</span><span class="p">.</span><span class="n">single</span><span class="p">()</span>
|
|
<span class="k">val</span> <span class="py">received</span> <span class="p">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">outStates</span><span class="p">.</span><span class="n">sumCashBy</span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">owner</span><span class="p">)</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">time</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">throw</span> <span class="n">IllegalArgumentException</span><span class="p">(</span><span class="s">"Redemption transactions must be timestamped"</span><span class="p">)</span>
|
|
<span class="n">requireThat</span> <span class="p">{</span>
|
|
<span class="s">"the paper must have matured"</span> <span class="k">by</span> <span class="p">(</span><span class="n">time</span> <span class="p">></span> <span class="n">input</span><span class="p">.</span><span class="n">maturityDate</span><span class="p">)</span>
|
|
<span class="s">"the received amount equals the face value"</span> <span class="k">by</span> <span class="p">(</span><span class="n">received</span> <span class="p">==</span> <span class="n">input</span><span class="p">.</span><span class="n">faceValue</span><span class="p">)</span>
|
|
<span class="s">"the paper must be destroyed"</span> <span class="k">by</span> <span class="n">group</span><span class="p">.</span><span class="n">outputs</span><span class="p">.</span><span class="n">isEmpty</span><span class="p">()</span>
|
|
<span class="s">"the transaction is signed by the owner of the CP"</span> <span class="k">by</span> <span class="p">(</span><span class="n">command</span><span class="p">.</span><span class="n">signers</span><span class="p">.</span><span class="n">contains</span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">owner</span><span class="p">))</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="k">is</span> <span class="n">Commands</span><span class="p">.</span><span class="n">Issue</span> <span class="p">-></span> <span class="p">{</span>
|
|
<span class="k">val</span> <span class="py">output</span> <span class="p">=</span> <span class="n">group</span><span class="p">.</span><span class="n">outputs</span><span class="p">.</span><span class="n">single</span><span class="p">()</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">time</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">throw</span> <span class="n">IllegalArgumentException</span><span class="p">(</span><span class="s">"Issuance transactions must be timestamped"</span><span class="p">)</span>
|
|
<span class="n">requireThat</span> <span class="p">{</span>
|
|
<span class="c1">// Don't allow people to issue commercial paper under other entities identities.</span>
|
|
<span class="s">"the issuance is signed by the claimed issuer of the paper"</span> <span class="k">by</span>
|
|
<span class="p">(</span><span class="n">command</span><span class="p">.</span><span class="n">signers</span><span class="p">.</span><span class="n">contains</span><span class="p">(</span><span class="n">output</span><span class="p">.</span><span class="n">issuance</span><span class="p">.</span><span class="n">party</span><span class="p">.</span><span class="n">owningKey</span><span class="p">))</span>
|
|
<span class="s">"the face value is not zero"</span> <span class="k">by</span> <span class="p">(</span><span class="n">output</span><span class="p">.</span><span class="n">faceValue</span><span class="p">.</span><span class="n">pennies</span> <span class="p">></span> <span class="m">0</span><span class="p">)</span>
|
|
<span class="s">"the maturity date is not in the past"</span> <span class="k">by</span> <span class="p">(</span><span class="n">time</span> <span class="p"><</span> <span class="n">output</span><span class="p">.</span><span class="n">maturityDate</span> <span class="p">)</span>
|
|
<span class="c1">// Don't allow an existing CP state to be replaced by this issuance.</span>
|
|
<span class="s">"there is no input state"</span> <span class="k">by</span> <span class="n">group</span><span class="p">.</span><span class="n">inputs</span><span class="p">.</span><span class="n">isEmpty</span><span class="p">()</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="c1">// TODO: Think about how to evolve contracts over time with new commands.</span>
|
|
<span class="k">else</span> <span class="p">-></span> <span class="k">throw</span> <span class="n">IllegalArgumentException</span><span class="p">(</span><span class="s">"Unrecognised command"</span><span class="p">)</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<div class="highlight-java"><div class="highlight"><pre><span></span><span class="n">Instant</span> <span class="n">time</span> <span class="o">=</span> <span class="n">tx</span><span class="o">.</span><span class="na">getTime</span><span class="o">();</span> <span class="c1">// Can be null/missing.</span>
|
|
<span class="k">for</span> <span class="o">(</span><span class="n">InOutGroup</span><span class="o"><</span><span class="n">State</span><span class="o">></span> <span class="n">group</span> <span class="o">:</span> <span class="n">groups</span><span class="o">)</span> <span class="o">{</span>
|
|
<span class="n">List</span><span class="o"><</span><span class="n">State</span><span class="o">></span> <span class="n">inputs</span> <span class="o">=</span> <span class="n">group</span><span class="o">.</span><span class="na">getInputs</span><span class="o">();</span>
|
|
<span class="n">List</span><span class="o"><</span><span class="n">State</span><span class="o">></span> <span class="n">outputs</span> <span class="o">=</span> <span class="n">group</span><span class="o">.</span><span class="na">getOutputs</span><span class="o">();</span>
|
|
|
|
<span class="c1">// For now do not allow multiple pieces of CP to trade in a single transaction. Study this more!</span>
|
|
<span class="n">State</span> <span class="n">input</span> <span class="o">=</span> <span class="n">single</span><span class="o">(</span><span class="n">filterIsInstance</span><span class="o">(</span><span class="n">inputs</span><span class="o">,</span> <span class="n">State</span><span class="o">.</span><span class="na">class</span><span class="o">));</span>
|
|
|
|
<span class="k">if</span> <span class="o">(!</span><span class="n">cmd</span><span class="o">.</span><span class="na">getSigners</span><span class="o">().</span><span class="na">contains</span><span class="o">(</span><span class="n">input</span><span class="o">.</span><span class="na">getOwner</span><span class="o">()))</span>
|
|
<span class="k">throw</span> <span class="k">new</span> <span class="n">IllegalStateException</span><span class="o">(</span><span class="s">"Failed requirement: the transaction is signed by the owner of the CP"</span><span class="o">);</span>
|
|
|
|
<span class="k">if</span> <span class="o">(</span><span class="n">cmd</span><span class="o">.</span><span class="na">getValue</span><span class="o">()</span> <span class="k">instanceof</span> <span class="n">JavaCommercialPaper</span><span class="o">.</span><span class="na">Commands</span><span class="o">.</span><span class="na">Move</span><span class="o">)</span> <span class="o">{</span>
|
|
<span class="c1">// Check the output CP state is the same as the input state, ignoring the owner field.</span>
|
|
<span class="n">State</span> <span class="n">output</span> <span class="o">=</span> <span class="n">single</span><span class="o">(</span><span class="n">outputs</span><span class="o">);</span>
|
|
|
|
<span class="k">if</span> <span class="o">(!</span><span class="n">output</span><span class="o">.</span><span class="na">getFaceValue</span><span class="o">().</span><span class="na">equals</span><span class="o">(</span><span class="n">input</span><span class="o">.</span><span class="na">getFaceValue</span><span class="o">())</span> <span class="o">||</span>
|
|
<span class="o">!</span><span class="n">output</span><span class="o">.</span><span class="na">getIssuance</span><span class="o">().</span><span class="na">equals</span><span class="o">(</span><span class="n">input</span><span class="o">.</span><span class="na">getIssuance</span><span class="o">())</span> <span class="o">||</span>
|
|
<span class="o">!</span><span class="n">output</span><span class="o">.</span><span class="na">getMaturityDate</span><span class="o">().</span><span class="na">equals</span><span class="o">(</span><span class="n">input</span><span class="o">.</span><span class="na">getMaturityDate</span><span class="o">()))</span>
|
|
<span class="k">throw</span> <span class="k">new</span> <span class="n">IllegalStateException</span><span class="o">(</span><span class="s">"Failed requirement: the output state is the same as the input state except for owner"</span><span class="o">);</span>
|
|
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">cmd</span><span class="o">.</span><span class="na">getValue</span><span class="o">()</span> <span class="k">instanceof</span> <span class="n">JavaCommercialPaper</span><span class="o">.</span><span class="na">Commands</span><span class="o">.</span><span class="na">Redeem</span><span class="o">)</span> <span class="o">{</span>
|
|
<span class="n">Amount</span> <span class="n">received</span> <span class="o">=</span> <span class="n">CashKt</span><span class="o">.</span><span class="na">sumCashOrNull</span><span class="o">(</span><span class="n">inputs</span><span class="o">);</span>
|
|
<span class="k">if</span> <span class="o">(</span><span class="n">time</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
|
|
<span class="k">throw</span> <span class="k">new</span> <span class="n">IllegalArgumentException</span><span class="o">(</span><span class="s">"Redemption transactions must be timestamped"</span><span class="o">);</span>
|
|
<span class="k">if</span> <span class="o">(</span><span class="n">received</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
|
|
<span class="k">throw</span> <span class="k">new</span> <span class="n">IllegalStateException</span><span class="o">(</span><span class="s">"Failed requirement: no cash being redeemed"</span><span class="o">);</span>
|
|
<span class="k">if</span> <span class="o">(</span><span class="n">input</span><span class="o">.</span><span class="na">getMaturityDate</span><span class="o">().</span><span class="na">isAfter</span><span class="o">(</span><span class="n">time</span><span class="o">))</span>
|
|
<span class="k">throw</span> <span class="k">new</span> <span class="n">IllegalStateException</span><span class="o">(</span><span class="s">"Failed requirement: the paper must have matured"</span><span class="o">);</span>
|
|
<span class="k">if</span> <span class="o">(!</span><span class="n">input</span><span class="o">.</span><span class="na">getFaceValue</span><span class="o">().</span><span class="na">equals</span><span class="o">(</span><span class="n">received</span><span class="o">))</span>
|
|
<span class="k">throw</span> <span class="k">new</span> <span class="n">IllegalStateException</span><span class="o">(</span><span class="s">"Failed requirement: the received amount equals the face value"</span><span class="o">);</span>
|
|
<span class="k">if</span> <span class="o">(!</span><span class="n">outputs</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">())</span>
|
|
<span class="k">throw</span> <span class="k">new</span> <span class="n">IllegalStateException</span><span class="o">(</span><span class="s">"Failed requirement: the paper must be destroyed"</span><span class="o">);</span>
|
|
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">cmd</span><span class="o">.</span><span class="na">getValue</span><span class="o">()</span> <span class="k">instanceof</span> <span class="n">JavaCommercialPaper</span><span class="o">.</span><span class="na">Commands</span><span class="o">.</span><span class="na">Issue</span><span class="o">)</span> <span class="o">{</span>
|
|
<span class="c1">// .. etc .. (see Kotlin for full definition)</span>
|
|
<span class="o">}</span>
|
|
<span class="o">}</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>This loop is the core logic of the contract.</p>
|
|
<p>The first line simply gets the timestamp out of the transaction. Timestamping of transactions is optional, so a time
|
|
may be missing here. We check for it being null later.</p>
|
|
<div class="admonition note">
|
|
<p class="first admonition-title">Note</p>
|
|
<p class="last">In the Kotlin version, as long as we write a comparison with the transaction time first, the compiler will
|
|
verify we didn’t forget to check if it’s missing. Unfortunately due to the need for smooth Java interop, this
|
|
check won’t happen if we write e.g. <code class="docutils literal"><span class="pre">someDate</span> <span class="pre">></span> <span class="pre">time</span></code>, it has to be <code class="docutils literal"><span class="pre">time</span> <span class="pre"><</span> <span class="pre">someDate</span></code>. So it’s good practice to
|
|
always write the transaction timestamp first.</p>
|
|
</div>
|
|
<p>The first line (first three lines in Java) impose a requirement that there be a single piece of commercial paper in
|
|
this group. We do not allow multiple units of CP to be split or merged even if they are owned by the same owner. The
|
|
<code class="docutils literal"><span class="pre">single()</span></code> method is a static <em>extension method</em> defined by the Kotlin standard library: given a list, it throws an
|
|
exception if the list size is not 1, otherwise it returns the single item in that list. In Java, this appears as a
|
|
regular static method of the type familiar from many FooUtils type singleton classes. In Kotlin, it appears as a
|
|
method that can be called on any JDK list. The syntax is slightly different but behind the scenes, the code compiles
|
|
to the same bytecodes.</p>
|
|
<p>Next, we check that the transaction was signed by the public key that’s marked as the current owner of the commercial
|
|
paper. Because the platform has already verified all the digital signatures before the contract begins execution,
|
|
all we have to do is verify that the owner’s public key was one of the keys that signed the transaction. The Java code
|
|
is straightforward. The Kotlin version looks a little odd: we have a <em>requireThat</em> construct that looks like it’s
|
|
built into the language. In fact <em>requireThat</em> is an ordinary function provided by the platform’s contract API. Kotlin
|
|
supports the creation of <em>domain specific languages</em> through the intersection of several features of the language, and
|
|
we use it here to support the natural listing of requirements. To see what it compiles down to, look at the Java version.
|
|
Each <code class="docutils literal"><span class="pre">"string"</span> <span class="pre">by</span> <span class="pre">(expression)</span></code> statement inside a <code class="docutils literal"><span class="pre">requireThat</span></code> turns into an assertion that the given expression is
|
|
true, with an exception being thrown that contains the string if not. It’s just another way to write out a regular
|
|
assertion, but with the English-language requirement being put front and center.</p>
|
|
<p>Next, we take one of two paths, depending on what the type of the command object is.</p>
|
|
<p>If the command is a <code class="docutils literal"><span class="pre">Move</span></code> command, then we simply verify that the output state is actually present: a move is not
|
|
allowed to delete the CP from the ledger. The grouping logic already ensured that the details are identical and haven’t
|
|
been changed, save for the public key of the owner.</p>
|
|
<p>If the command is a <code class="docutils literal"><span class="pre">Redeem</span></code> command, then the requirements are more complex:</p>
|
|
<ol class="arabic simple">
|
|
<li>We want to see that the face value of the CP is being moved as a cash claim against some party, that is, the
|
|
issuer of the CP is really paying back the face value.</li>
|
|
<li>The transaction must be happening after the maturity date.</li>
|
|
<li>The commercial paper must <em>not</em> be propagated by this transaction: it must be deleted, by the group having no
|
|
output state. This prevents the same CP being considered redeemable multiple times.</li>
|
|
</ol>
|
|
<p>To calculate how much cash is moving, we use the <code class="docutils literal"><span class="pre">sumCashOrNull</span></code> utility method. Again, this is an extension method,
|
|
so in Kotlin code it appears as if it was a method on the <code class="docutils literal"><span class="pre">List<Cash.State></span></code> type even though JDK provides no such
|
|
method. In Java we see its true nature: it is actually a static method named <code class="docutils literal"><span class="pre">CashKt.sumCashOrNull</span></code>. This method simply
|
|
returns an <code class="docutils literal"><span class="pre">Amount</span></code> object containing the sum of all the cash states in the transaction output, or null if there were
|
|
no such states <em>or</em> if there were different currencies represented in the outputs! So we can see that this contract
|
|
imposes a limitation on the structure of a redemption transaction: you are not allowed to move currencies in the same
|
|
transaction that the CP does not involve. This limitation could be addressed with better APIs, if it were to be a
|
|
real limitation.</p>
|
|
<p>Finally, we support an <code class="docutils literal"><span class="pre">Issue</span></code> command, to create new instances of commercial paper on the ledger. It likewise
|
|
enforces various invariants upon the issuance.</p>
|
|
<p>This contract is extremely simple and does not implement all the business logic a real commercial paper lifecycle
|
|
management program would. For instance, there is no logic requiring a signature from the issuer for redemption:
|
|
it is assumed that any transfer of money that takes place at the same time as redemption is good enough. Perhaps
|
|
that is something that should be tightened. Likewise, there is no logic handling what happens if the issuer has gone
|
|
bankrupt, if there is a dispute, and so on.</p>
|
|
<p>As the prototype evolves, these requirements will be explored and this tutorial updated to reflect improvements in the
|
|
contracts API.</p>
|
|
</div>
|
|
<div class="section" id="how-to-test-your-contract">
|
|
<h2>How to test your contract<a class="headerlink" href="#how-to-test-your-contract" title="Permalink to this headline">¶</a></h2>
|
|
<p>Of course, it is essential to unit test your new nugget of business logic to ensure that it behaves as you expect.
|
|
Although you can write traditional unit tests in Java, the platform also provides a <em>domain specific language</em>
|
|
(DSL) for writing contract unit tests that automates many of the common patterns. This DSL builds on top of JUnit yet
|
|
is a Kotlin DSL, and therefore this section will not show Java equivalent code (for Java unit tests you would not
|
|
benefit from the DSL and would write them by hand).</p>
|
|
<p>We start by defining a new test class, with a basic CP state:</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">CommercialPaperTests</span> <span class="p">{</span>
|
|
<span class="k">val</span> <span class="py">PAPER_1</span> <span class="p">=</span> <span class="n">CommercialPaper</span><span class="p">.</span><span class="n">State</span><span class="p">(</span>
|
|
<span class="n">issuance</span> <span class="p">=</span> <span class="n">InstitutionReference</span><span class="p">(</span><span class="n">MEGA_CORP</span><span class="p">,</span> <span class="n">OpaqueBytes</span><span class="p">.</span><span class="n">of</span><span class="p">(</span><span class="m">123</span><span class="p">)),</span>
|
|
<span class="n">owner</span> <span class="p">=</span> <span class="n">MEGA_CORP_KEY</span><span class="p">,</span>
|
|
<span class="n">faceValue</span> <span class="p">=</span> <span class="m">1000.</span><span class="n">DOLLARS</span><span class="p">,</span>
|
|
<span class="n">maturityDate</span> <span class="p">=</span> <span class="n">TEST_TX_TIME</span> <span class="p">+</span> <span class="m">7.</span><span class="n">days</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="n">@Test</span>
|
|
<span class="k">fun</span> <span class="nf">key_mismatch_at_issue</span><span class="p">()</span> <span class="p">{</span>
|
|
<span class="n">transactionGroup</span> <span class="p">{</span>
|
|
<span class="n">transaction</span> <span class="p">{</span>
|
|
<span class="n">output</span> <span class="p">{</span> <span class="n">PAPER_1</span> <span class="p">}</span>
|
|
<span class="n">arg</span><span class="p">(</span><span class="n">DUMMY_PUBKEY_1</span><span class="p">)</span> <span class="p">{</span> <span class="n">CommercialPaper</span><span class="p">.</span><span class="n">Commands</span><span class="p">.</span><span class="n">Issue</span><span class="p">()</span> <span class="p">}</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="n">expectFailureOfTx</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="s">"signed by the claimed issuer"</span><span class="p">)</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>We start by defining a commercial paper state. It will be owned by a pre-defined unit test party, affectionately
|
|
called <code class="docutils literal"><span class="pre">MEGA_CORP</span></code> (this constant, along with many others, is defined in <code class="docutils literal"><span class="pre">TestUtils.kt</span></code>). Due to Kotin’s extensive
|
|
type inference, many types are not written out explicitly in this code and it has the feel of a scripting language.
|
|
But the types are there, and you can ask IntelliJ to reveal them by pressing Alt-Enter on a “val” or “var” and selecting
|
|
“Specify type explicitly”.</p>
|
|
<p>There are a few things that are unusual here:</p>
|
|
<ul class="simple">
|
|
<li>We can specify quantities of money by writing 1000.DOLLARS or 1000.POUNDS</li>
|
|
<li>We can specify quantities of time by writing 7.days</li>
|
|
<li>We can add quantities of time to the TEST_TX_TIME constant, which merely defines an arbitrary java.time.Instant</li>
|
|
</ul>
|
|
<p>If you examine the code in the actual repository, you will also notice that it makes use of method names with spaces
|
|
in them by surrounding the name with backticks, rather than using underscores. We don’t show this here as it breaks the
|
|
doc website’s syntax highlighting engine.</p>
|
|
<p>The <code class="docutils literal"><span class="pre">1000.DOLLARS</span></code> construct is quite simple: Kotlin allows you to define extension functions on primitive types like
|
|
Int or Double. So by writing 7.days, for instance, the compiler will emit a call to a static method that takes an int
|
|
and returns a <code class="docutils literal"><span class="pre">java.time.Duration</span></code>.</p>
|
|
<p>As this is JUnit, we must remember to annotate each test method with @Test. Let’s examine the contents of the first test.
|
|
We are trying to check that it’s not possible for just anyone to issue commercial paper in MegaCorp’s name. That would
|
|
be bad!</p>
|
|
<p>The <code class="docutils literal"><span class="pre">transactionGroup</span></code> function works the same way as the <code class="docutils literal"><span class="pre">requireThat</span></code> construct above.</p>
|
|
<div class="admonition note">
|
|
<p class="first admonition-title">Note</p>
|
|
<p class="last">This DSL is an example of what Kotlin calls a type safe builder, which you can read about in <a class="reference external" href="https://kotlinlang.org/docs/reference/type-safe-builders.html">the
|
|
documentation for builders</a>. You can mix and match
|
|
ordinary code inside such DSLs so please read the linked page to make sure you fully understand what they are capable
|
|
of.</p>
|
|
</div>
|
|
<p>The code block that follows it is run in the scope of a freshly created <code class="docutils literal"><span class="pre">TransactionGroupForTest</span></code> object, which assists
|
|
you with building little transaction graphs and verifying them as a whole. Here, our “group” only actually has a
|
|
single transaction in it, with a single output, no inputs, and an Issue command signed by <code class="docutils literal"><span class="pre">DUMMY_PUBKEY_1</span></code> which is just
|
|
an arbitrary public key. As the paper claims to be issued by <code class="docutils literal"><span class="pre">MEGA_CORP</span></code>, this doesn’t match and should cause a
|
|
failure. The <code class="docutils literal"><span class="pre">expectFailureOfTx</span></code> method takes a 1-based index (in this case we expect the first transaction to fail)
|
|
and a string that should appear in the exception message. Then it runs the <code class="docutils literal"><span class="pre">TransactionGroup.verify()</span></code> method to
|
|
invoke all the involved contracts.</p>
|
|
<p>It’s worth bearing in mind that even though this code may look like a totally different language to normal Kotlin or
|
|
Java, it’s actually not, and so you can embed arbitrary code anywhere inside any of these blocks.</p>
|
|
<p>Let’s set up a full trade and ensure it works:</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span> <span class="c1">// Generate a trade lifecycle with various parameters.</span>
|
|
<span class="k">private</span> <span class="k">fun</span> <span class="nf">trade</span><span class="p">(</span><span class="n">redemptionTime</span><span class="p">:</span> <span class="n">Instant</span> <span class="p">=</span> <span class="n">TEST_TX_TIME</span> <span class="p">+</span> <span class="m">8.</span><span class="n">days</span><span class="p">,</span>
|
|
<span class="n">aliceGetsBack</span><span class="p">:</span> <span class="n">Amount</span> <span class="p">=</span> <span class="m">1000.</span><span class="n">DOLLARS</span><span class="p">,</span>
|
|
<span class="n">destroyPaperAtRedemption</span><span class="p">:</span> <span class="n">Boolean</span> <span class="p">=</span> <span class="k">true</span><span class="p">):</span> <span class="n">TransactionGroupForTest</span> <span class="p">{</span>
|
|
<span class="k">val</span> <span class="py">someProfits</span> <span class="p">=</span> <span class="m">1200.</span><span class="n">DOLLARS</span>
|
|
<span class="k">return</span> <span class="n">transactionGroup</span> <span class="p">{</span>
|
|
<span class="n">roots</span> <span class="p">{</span>
|
|
<span class="n">transaction</span><span class="p">(</span><span class="m">900.</span><span class="n">DOLLARS</span><span class="p">.</span><span class="n">CASH</span> <span class="n">owned_by</span> <span class="n">ALICE</span> <span class="n">label</span> <span class="s">"alice's $900"</span><span class="p">)</span>
|
|
<span class="n">transaction</span><span class="p">(</span><span class="n">someProfits</span><span class="p">.</span><span class="n">CASH</span> <span class="n">owned_by</span> <span class="n">MEGA_CORP_KEY</span> <span class="n">label</span> <span class="s">"some profits"</span><span class="p">)</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="c1">// Some CP is issued onto the ledger by MegaCorp.</span>
|
|
<span class="n">transaction</span> <span class="p">{</span>
|
|
<span class="n">output</span><span class="p">(</span><span class="s">"paper"</span><span class="p">)</span> <span class="p">{</span> <span class="n">PAPER_1</span> <span class="p">}</span>
|
|
<span class="n">arg</span><span class="p">(</span><span class="n">MEGA_CORP_KEY</span><span class="p">)</span> <span class="p">{</span> <span class="n">CommercialPaper</span><span class="p">.</span><span class="n">Commands</span><span class="p">.</span><span class="n">Issue</span><span class="p">()</span> <span class="p">}</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="c1">// The CP is sold to alice for her $900, $100 less than the face value. At 10% interest after only 7 days,</span>
|
|
<span class="c1">// that sounds a bit too good to be true!</span>
|
|
<span class="n">transaction</span> <span class="p">{</span>
|
|
<span class="n">input</span><span class="p">(</span><span class="s">"paper"</span><span class="p">)</span>
|
|
<span class="n">input</span><span class="p">(</span><span class="s">"alice's $900"</span><span class="p">)</span>
|
|
<span class="n">output</span> <span class="p">{</span> <span class="m">900.</span><span class="n">DOLLARS</span><span class="p">.</span><span class="n">CASH</span> <span class="n">owned_by</span> <span class="n">MEGA_CORP_KEY</span> <span class="p">}</span>
|
|
<span class="n">output</span><span class="p">(</span><span class="s">"alice's paper"</span><span class="p">)</span> <span class="p">{</span> <span class="n">PAPER_1</span> <span class="n">owned_by</span> <span class="n">ALICE</span> <span class="p">}</span>
|
|
<span class="n">arg</span><span class="p">(</span><span class="n">ALICE</span><span class="p">)</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="n">arg</span><span class="p">(</span><span class="n">MEGA_CORP_KEY</span><span class="p">)</span> <span class="p">{</span> <span class="n">CommercialPaper</span><span class="p">.</span><span class="n">Commands</span><span class="p">.</span><span class="n">Move</span> <span class="p">}</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="c1">// Time passes, and Alice redeem's her CP for $1000, netting a $100 profit. MegaCorp has received $1200</span>
|
|
<span class="c1">// as a single payment from somewhere and uses it to pay Alice off, keeping the remaining $200 as change.</span>
|
|
<span class="n">transaction</span><span class="p">(</span><span class="n">time</span> <span class="p">=</span> <span class="n">redemptionTime</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="n">input</span><span class="p">(</span><span class="s">"alice's paper"</span><span class="p">)</span>
|
|
<span class="n">input</span><span class="p">(</span><span class="s">"some profits"</span><span class="p">)</span>
|
|
|
|
<span class="n">output</span> <span class="p">{</span> <span class="n">aliceGetsBack</span><span class="p">.</span><span class="n">CASH</span> <span class="n">owned_by</span> <span class="n">ALICE</span> <span class="p">}</span>
|
|
<span class="n">output</span> <span class="p">{</span> <span class="p">(</span><span class="n">someProfits</span> <span class="p">-</span> <span class="n">aliceGetsBack</span><span class="p">).</span><span class="n">CASH</span> <span class="n">owned_by</span> <span class="n">MEGA_CORP_KEY</span> <span class="p">}</span>
|
|
<span class="k">if</span> <span class="p">(!</span><span class="n">destroyPaperAtRedemption</span><span class="p">)</span>
|
|
<span class="n">output</span> <span class="p">{</span> <span class="n">PAPER_1</span> <span class="n">owned_by</span> <span class="n">ALICE</span> <span class="p">}</span>
|
|
|
|
<span class="n">arg</span><span class="p">(</span><span class="n">MEGA_CORP_KEY</span><span class="p">)</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="n">arg</span><span class="p">(</span><span class="n">ALICE</span><span class="p">)</span> <span class="p">{</span> <span class="n">CommercialPaper</span><span class="p">.</span><span class="n">Commands</span><span class="p">.</span><span class="n">Redeem</span> <span class="p">}</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>In this example we see some new features of the DSL:</p>
|
|
<ul class="simple">
|
|
<li>The <code class="docutils literal"><span class="pre">roots</span></code> construct. Sometimes you don’t want to write transactions that laboriously issue everything you need
|
|
in a formally correct way. Inside <code class="docutils literal"><span class="pre">roots</span></code> you can create a bunch of states without any contract checking what you’re
|
|
doing. As states may not exist outside of transactions, each line inside defines a fake/invalid transaction with the
|
|
given output states, which may be <em>labelled</em> with a short string. Those labels can be used later to join transactions
|
|
together.</li>
|
|
<li>The <code class="docutils literal"><span class="pre">.CASH</span></code> suffix. This is a part of the unit test DSL specific to the cash contract. It takes a monetary amount
|
|
like 1000.DOLLARS and then wraps it in a cash ledger state, with some fake data.</li>
|
|
<li>The owned_by <a class="reference external" href="https://kotlinlang.org/docs/reference/functions.html#infix-notation">infix function</a>. This is just
|
|
a normal function that we’re allowed to write in a slightly different way, which returns a copy of the cash state
|
|
with the owner field altered to be the given public key. <code class="docutils literal"><span class="pre">ALICE</span></code> is a constant defined by the test utilities that
|
|
is, like <code class="docutils literal"><span class="pre">DUMMY_PUBKEY_1</span></code>, just an arbitrary keypair.</li>
|
|
<li>We are now defining several transactions that chain together. We can optionally label any output we create. Obviously
|
|
then, the <code class="docutils literal"><span class="pre">input</span></code> method requires us to give the label of some other output that it connects to.</li>
|
|
<li>The <code class="docutils literal"><span class="pre">transaction</span></code> function can also be given a time, to override the default timestamp on a transaction.</li>
|
|
</ul>
|
|
<p>The <code class="docutils literal"><span class="pre">trade</span></code> function is not itself a unit test. Instead it builds up a trade/transaction group, with some slight
|
|
differences depending on the parameters provided (Kotlin allows parameters to have default values). Then it returns
|
|
it, unexecuted.</p>
|
|
<p>We use it like this:</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="n">@Test</span>
|
|
<span class="k">fun</span> <span class="nf">ok</span><span class="p">()</span> <span class="p">{</span>
|
|
<span class="n">trade</span><span class="p">().</span><span class="n">verify</span><span class="p">()</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="n">@Test</span>
|
|
<span class="k">fun</span> <span class="nf">not_matured_at_redemption</span><span class="p">()</span> <span class="p">{</span>
|
|
<span class="n">trade</span><span class="p">(</span><span class="n">redemptionTime</span> <span class="p">=</span> <span class="n">TEST_TX_TIME</span> <span class="p">+</span> <span class="m">2.</span><span class="n">days</span><span class="p">).</span><span class="n">expectFailureOfTx</span><span class="p">(</span><span class="m">3</span><span class="p">,</span> <span class="s">"must have matured"</span><span class="p">)</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>That’s pretty simple: we just call <code class="docutils literal"><span class="pre">verify</span></code> in order to check all the transactions in the group. If any are invalid,
|
|
an exception will be thrown indicating which transaction failed and why. In the second case, we call <code class="docutils literal"><span class="pre">expectFailureOfTx</span></code>
|
|
again to ensure the third transaction fails with a message that contains “must have matured” (it doesn’t have to be
|
|
the exact message).</p>
|
|
</div>
|
|
<div class="section" id="adding-a-generation-api-to-your-contract">
|
|
<h2>Adding a generation API to your contract<a class="headerlink" href="#adding-a-generation-api-to-your-contract" title="Permalink to this headline">¶</a></h2>
|
|
<p>Contract classes <strong>must</strong> provide a verify function, but they may optionally also provide helper functions to simplify
|
|
their usage. A simple class of functions most contracts provide are <em>generation functions</em>, which either create or
|
|
modify a transaction to perform certain actions (an action is normally mappable 1:1 to a command, but doesn’t have to
|
|
be so).</p>
|
|
<p>Generation may involve complex logic. For example, the cash contract has a <code class="docutils literal"><span class="pre">generateSpend</span></code> method that is given a set of
|
|
cash states and chooses a way to combine them together to satisfy the amount of money that is being sent. In the
|
|
immutable-state model that we are using ledger entries (states) can only be created and deleted, but never modified.
|
|
Therefore to send $1200 when we have only $900 and $500 requires combining both states together, and then creating
|
|
two new output states of $1200 and $200 back to ourselves. This latter state is called the <em>change</em> and is a concept
|
|
that should be familiar to anyone who has worked with Bitcoin.</p>
|
|
<p>As another example, we can imagine code that implements a netting algorithm may generate complex transactions that must
|
|
be signed by many people. Whilst such code might be too big for a single utility method (it’d probably be sized more
|
|
like a module), the basic concept is the same: preparation of a transaction using complex logic.</p>
|
|
<p>For our commercial paper contract however, the things that can be done with it are quite simple. Let’s start with
|
|
a method to wrap up the issuance process:</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">fun</span> <span class="nf">generateIssue</span><span class="p">(</span><span class="n">issuance</span><span class="p">:</span> <span class="n">InstitutionReference</span><span class="p">,</span> <span class="n">faceValue</span><span class="p">:</span> <span class="n">Amount</span><span class="p">,</span> <span class="n">maturityDate</span><span class="p">:</span> <span class="n">Instant</span><span class="p">):</span> <span class="n">TransactionBuilder</span> <span class="p">{</span>
|
|
<span class="k">val</span> <span class="py">state</span> <span class="p">=</span> <span class="n">State</span><span class="p">(</span><span class="n">issuance</span><span class="p">,</span> <span class="n">issuance</span><span class="p">.</span><span class="n">party</span><span class="p">.</span><span class="n">owningKey</span><span class="p">,</span> <span class="n">faceValue</span><span class="p">,</span> <span class="n">maturityDate</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">TransactionBuilder</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">WireCommand</span><span class="p">(</span><span class="n">Commands</span><span class="p">.</span><span class="n">Issue</span><span class="p">,</span> <span class="n">issuance</span><span class="p">.</span><span class="n">party</span><span class="p">.</span><span class="n">owningKey</span><span class="p">))</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>We take a reference that points to the issuing party (i.e. the caller) and which can contain any internal
|
|
bookkeeping/reference numbers that we may require. Then the face value of the paper, and the maturity date. It
|
|
returns a <code class="docutils literal"><span class="pre">TransactionBuilder</span></code>. A <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> is one of the few mutable classes the platform provides.
|
|
It allows you to add inputs, outputs and commands to it and is designed to be passed around, potentially between
|
|
multiple contracts.</p>
|
|
<div class="admonition note">
|
|
<p class="first admonition-title">Note</p>
|
|
<p class="last">Generation methods should ideally be written to compose with each other, that is, they should take a
|
|
<code class="docutils literal"><span class="pre">TransactionBuilder</span></code> as an argument instead of returning one, unless you are sure it doesn’t make sense to
|
|
combine this type of transaction with others. In this case, issuing CP at the same time as doing other things
|
|
would just introduce complexity that isn’t likely to be worth it, so we return a fresh object each time: instead,
|
|
an issuer should issue the CP (starting out owned by themselves), and then sell it in a separate transaction.</p>
|
|
</div>
|
|
<p>The function we define creates a <code class="docutils literal"><span class="pre">CommercialPaper.State</span></code> object that mostly just uses the arguments we were given,
|
|
but it fills out the owner field of the state to be the same public key as the issuing party. If the caller wants
|
|
to issue CP onto the ledger that’s immediately owned by someone else, they’ll have to create the state themselves.</p>
|
|
<p>The returned partial transaction has a <code class="docutils literal"><span class="pre">WireCommand</span></code> object as a parameter. This is a container for any object
|
|
that implements the <code class="docutils literal"><span class="pre">Command</span></code> interface, along with a key that is expected to sign this transaction. In this case,
|
|
issuance requires that the issuing party sign, so we put the key of the party there.</p>
|
|
<p>The <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> constructor we used above takes a variable argument list for convenience. You can pass in
|
|
any <code class="docutils literal"><span class="pre">ContractStateRef</span></code> (input), <code class="docutils literal"><span class="pre">ContractState</span></code> (output) or <code class="docutils literal"><span class="pre">Command</span></code> objects and it’ll build up the transaction
|
|
for you.</p>
|
|
<p>What about moving the paper, i.e. reassigning ownership to someone else?</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">fun</span> <span class="nf">generateMove</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">TransactionBuilder</span><span class="p">,</span> <span class="n">paper</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p"><</span><span class="n">State</span><span class="p">>,</span> <span class="n">newOwner</span><span class="p">:</span> <span class="n">PublicKey</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="n">tx</span><span class="p">.</span><span class="n">addInputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">ref</span><span class="p">)</span>
|
|
<span class="n">tx</span><span class="p">.</span><span class="n">addOutputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">copy</span><span class="p">(</span><span class="n">owner</span> <span class="p">=</span> <span class="n">newOwner</span><span class="p">))</span>
|
|
<span class="n">tx</span><span class="p">.</span><span class="n">addArg</span><span class="p">(</span><span class="n">WireCommand</span><span class="p">(</span><span class="n">Commands</span><span class="p">.</span><span class="n">Move</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">))</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>Here, the method takes a pre-existing <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> and adds to it. This is correct because typically
|
|
you will want to combine a sale of CP atomically with the movement of some other asset, such as cash. So both
|
|
generate methods should operate on the same transaction. You can see an example of this being done in the unit tests
|
|
for the commercial paper contract.</p>
|
|
<p>The paper is given to us as a <code class="docutils literal"><span class="pre">StateAndRef<CommercialPaper.State></span></code> object. This is exactly what it sounds like:
|
|
a small object that has a (copy of) a state object, and also the (txhash, index) that indicates the location of this
|
|
state on the ledger.</p>
|
|
<p>Finally, we can do redemption.</p>
|
|
<div class="codeset container">
|
|
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="n">@Throws</span><span class="p">(</span><span class="n">InsufficientBalanceException</span><span class="o">::</span><span class="k">class</span><span class="p">)</span>
|
|
<span class="k">fun</span> <span class="nf">generateRedeem</span><span class="p">(</span><span class="n">tx</span><span class="p">:</span> <span class="n">TransactionBuilder</span><span class="p">,</span> <span class="n">paper</span><span class="p">:</span> <span class="n">StateAndRef</span><span class="p"><</span><span class="n">State</span><span class="p">>,</span> <span class="n">wallet</span><span class="p">:</span> <span class="n">List</span><span class="p"><</span><span class="n">StateAndRef</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="p">{</span>
|
|
<span class="c1">// Add the cash movement using the states in our wallet.</span>
|
|
<span class="n">Cash</span><span class="p">().</span><span class="n">generateSpend</span><span class="p">(</span><span class="n">tx</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">faceValue</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">,</span> <span class="n">wallet</span><span class="p">)</span>
|
|
<span class="n">tx</span><span class="p">.</span><span class="n">addInputState</span><span class="p">(</span><span class="n">paper</span><span class="p">.</span><span class="n">ref</span><span class="p">)</span>
|
|
<span class="n">tx</span><span class="p">.</span><span class="n">addArg</span><span class="p">(</span><span class="n">WireCommand</span><span class="p">(</span><span class="n">CommercialPaper</span><span class="p">.</span><span class="n">Commands</span><span class="p">.</span><span class="n">Redeem</span><span class="p">,</span> <span class="n">paper</span><span class="p">.</span><span class="n">state</span><span class="p">.</span><span class="n">owner</span><span class="p">))</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
</div>
|
|
<p>Here we can see an example of composing contracts together. When an owner wishes to redeem the commercial paper, the
|
|
issuer (i.e. the caller) must gather cash from its wallet and send the face value to the owner of the paper.</p>
|
|
<div class="admonition note">
|
|
<p class="first admonition-title">Note</p>
|
|
<p class="last"><strong>Exercise for the reader</strong>: In this early, simplified model of CP there is no built in support
|
|
for rollover. Extend the contract code to support rollover as well as redemption (reissuance of the paper with a
|
|
higher face value without any transfer of cash)</p>
|
|
</div>
|
|
<p>The <em>wallet</em> is a concept that may be familiar from Bitcoin and Ethereum. It is simply a set of cash states that are
|
|
owned by the caller. Here, we use the wallet to update the partial transaction we are handed with a movement of cash
|
|
from the issuer of the commercial paper to the current owner. If we don’t have enough quantity of cash in our wallet,
|
|
an exception is thrown. And then we add the paper itself as an input, but, not an output (as we wish to delete it
|
|
from the ledger permanently). Finally, we add a Redeem command that should be signed by the owner of the commercial
|
|
paper.</p>
|
|
<p>A <code class="docutils literal"><span class="pre">TransactionBuilder</span></code> is not by itself ready to be used anywhere, so first, we must convert it to something that
|
|
is recognised by the network. The most important next step is for the participating entities to sign it using the
|
|
<code class="docutils literal"><span class="pre">signWith()</span></code> method. This takes a keypair, serialises the transaction, signs the serialised form and then stores the
|
|
signature inside the <code class="docutils literal"><span class="pre">TransactionBuilder</span></code>. Once all parties have signed, you can call <code class="docutils literal"><span class="pre">TransactionBuilder.toSignedTransaction()</span></code>
|
|
to get a <code class="docutils literal"><span class="pre">SignedTransaction</span></code> object. This is an immutable form of the transaction that’s ready for <em>timestamping</em>,
|
|
which can be done using a <code class="docutils literal"><span class="pre">TimestamperClient</span></code>. To learn more about that, please refer to the
|
|
<a class="reference internal" href="protocol-state-machines.html"><span class="doc">Protocol state machines</span></a> document.</p>
|
|
<p>You can see how transactions flow through the different stages of construction by examining the commercial paper
|
|
unit tests.</p>
|
|
</div>
|
|
<div class="section" id="non-asset-oriented-based-smart-contracts">
|
|
<h2>Non-asset-oriented based smart contracts<a class="headerlink" href="#non-asset-oriented-based-smart-contracts" title="Permalink to this headline">¶</a></h2>
|
|
<p>It is important to distinguish between the idea of a legal contract vs a code contract. In this document we use the
|
|
term <em>contract</em> as a shorthand for code contract: a small module of widely shared, simultaneously executed business
|
|
logic that uses standardised APIs and runs in a sandbox.</p>
|
|
<p>Although this tutorial covers how to implement an owned asset, there is no requirement that states and code contracts
|
|
<em>must</em> be concerned with ownership of an asset. It is better to think of states as representing useful facts about the
|
|
world, and (code) contracts as imposing logical relations on how facts combine to produce new facts.</p>
|
|
<p>For example, in the case that the transfer of an asset cannot be performed entirely on-ledger, one possible usage of
|
|
the model is to implement a delivery-vs-payment lifecycle in which there is a state representing an intention to trade
|
|
and two other states that can be interpreted by off-ledger platforms as firm instructions to move the respective asset
|
|
or cash - and a final state in which the exchange is marked as complete. The key point here is that the two off-platform
|
|
instructions form pa rt of the same Transaction and so either both are signed (and can be processed by the off-ledger
|
|
systems) or neither are.</p>
|
|
<p>As another example, consider multi-signature transactions, a feature which is commonly used in Bitcoin to implement
|
|
various kinds of useful protocols. This technique allows you to lock an asset to ownership of a group, in which a
|
|
threshold of signers (e.g. 3 out of 4) must all sign simultaneously to enable the asset to move. It is initially
|
|
tempting to simply add this as another feature to each existing contract which someone might want to treat in this way.
|
|
But that could lead to unnecessary duplication of work.</p>
|
|
<p>A better approach is to model the fact of joint ownership as a new contract with its own state. In this approach, to
|
|
lock up your commercial paper under multi-signature ownership you would make a transaction that looks like this:</p>
|
|
<ul class="simple">
|
|
<li><strong>Input</strong>: the CP state</li>
|
|
<li><strong>Output</strong>: a multi-sig state that contains the list of keys and the signing threshold desired (e.g. 3 of 4). The state has a hash of H.</li>
|
|
<li><strong>Output</strong>: the same CP state, with a marker that says a state with hash H must exist in any transaction that spends it.</li>
|
|
</ul>
|
|
<p>The CP contract then needs to be extended only to verify that a state with the required hash is present as an input.
|
|
The logic that implements measurement of the threshold, different signing combinations that may be allowed etc can then
|
|
be implemented once in a separate contract, with the controlling data being held in the named state.</p>
|
|
<p>Future versions of the prototype will explore these concepts in more depth.</p>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
<footer>
|
|
|
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
|
|
|
<a href="protocol-state-machines.html" class="btn btn-neutral float-right" title="Protocol state machines" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
|
|
|
|
|
|
<a href="node-administration.html" class="btn btn-neutral" title="Node administration" 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:'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> |