<!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>Using attachments — R3 Corda latest documentation</title> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="top" title="R3 Corda latest documentation" href="index.html"/> <link rel="next" title="Event scheduling" href="event-scheduling.html"/> <link rel="prev" title="Writing oracle services" href="oracles.html"/> <script src="_static/js/modernizr.min.js"></script> </head> <body class="wy-body-for-nav" role="document"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search"> <a href="index.html" class="icon icon-home"> R3 Corda </a> <div class="version"> latest </div> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> <br> <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="transaction-data-types.html">Data types</a></li> <li class="toctree-l1"><a class="reference internal" href="consensus.html">Consensus 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="persistence.html">Persistence</a></li> <li class="toctree-l1"><a class="reference internal" href="creating-a-cordapp.html">Creating a Cordapp</a></li> <li class="toctree-l1"><a class="reference internal" href="creating-a-cordapp.html#gradle-plugins-for-cordapps">Gradle Plugins for Cordapps</a></li> <li class="toctree-l1"><a class="reference internal" href="creating-a-cordapp.html#template-build-gradle">Template build.gradle</a></li> <li class="toctree-l1"><a class="reference internal" href="creating-a-cordapp.html#cordformation">Cordformation</a></li> <li class="toctree-l1"><a class="reference internal" href="running-the-demos.html">Running the demos</a></li> <li class="toctree-l1"><a class="reference internal" href="node-administration.html">Node administration</a></li> <li class="toctree-l1"><a class="reference internal" href="corda-configuration-files.html">The Corda Configuration File</a></li> </ul> <p class="caption"><span class="caption-text">Tutorials</span></p> <ul class="current"> <li class="toctree-l1"><a class="reference internal" href="where-to-start.html">Where to start</a></li> <li class="toctree-l1"><a class="reference internal" href="tutorial-contract.html">Writing a contract</a></li> <li class="toctree-l1"><a class="reference internal" href="tutorial-contract-clauses.html">Writing a contract using clauses</a></li> <li class="toctree-l1"><a class="reference internal" href="tutorial-test-dsl.html">Writing a contract test</a></li> <li class="toctree-l1"><a class="reference internal" href="tutorial-clientrpc-api.html">Client RPC API</a></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> <li class="toctree-l1 current"><a class="current reference internal" href="#">Using attachments</a><ul> <li class="toctree-l2"><a class="reference internal" href="#attachments-demo">Attachments demo</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="event-scheduling.html">Event scheduling</a></li> <li class="toctree-l1"><a class="reference internal" href="secure-coding-guidelines.html">Secure coding guidelines</a></li> </ul> <p class="caption"><span class="caption-text">Contracts</span></p> <ul> <li class="toctree-l1"><a class="reference internal" href="contract-catalogue.html">Contract catalogue</a></li> <li class="toctree-l1"><a class="reference internal" href="contract-irs.html">Interest Rate Swaps</a></li> </ul> <p class="caption"><span class="caption-text">Node API</span></p> <ul> <li class="toctree-l1"><a class="reference internal" href="clientrpc.html">Client RPC</a></li> </ul> <p class="caption"><span class="caption-text">Appendix</span></p> <ul> <li class="toctree-l1"><a class="reference internal" href="release-process.html">Release process</a></li> <li class="toctree-l1"><a class="reference internal" href="release-process.html#steps-to-cut-a-release">Steps to cut a release</a></li> <li class="toctree-l1"><a class="reference internal" href="release-notes.html">Release notes</a></li> <li class="toctree-l1"><a class="reference internal" href="network-simulator.html">Network Simulator</a></li> <li class="toctree-l1"><a class="reference internal" href="codestyle.html">Code style guide</a></li> <li class="toctree-l1"><a class="reference internal" href="building-the-docs.html">Building the documentation</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"> <nav class="wy-nav-top" role="navigation" aria-label="top navigation"> <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">R3 Corda</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="breadcrumbs navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html">Docs</a> »</li> <li>Using attachments</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/tutorial-attachments.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <div class="section" id="using-attachments"> <h1>Using attachments<a class="headerlink" href="#using-attachments" title="Permalink to this headline">¶</a></h1> <p>Attachments are (typically large) Zip/Jar files referenced within a transaction, but not included in the transaction itself. These files can be requested from the originating node as needed, although in many cases will be cached within nodes already. Examples include:</p> <ul class="simple"> <li>Contract executable code</li> <li>Metadata about a transaction, such as PDF version of an invoice being settled</li> <li>Shared information to be permanently recorded on the ledger</li> </ul> <p>To add attachments the file must first be added to the node’s storage service using <code class="docutils literal"><span class="pre">StorageService.importAttachment()</span></code>, which returns a unique ID that can be added using <code class="docutils literal"><span class="pre">TransactionBuilder.addAttachment()</span></code>. Attachments can also be uploaded and downloaded via HTTP, to enable integration with external systems. For instructions on HTTP upload/download please see “<a class="reference internal" href="node-administration.html"><span class="doc">Node administration</span></a>”.</p> <p>Normally attachments on transactions are fetched automatically via the <code class="docutils literal"><span class="pre">ResolveTransactionsProtocol</span></code> when verifying received transactions. Attachments are needed in order to validate a transaction (they include, for example, the contract code), so must be fetched before the validation process can run. <code class="docutils literal"><span class="pre">ResolveTransactionsProtocol</span></code> calls <code class="docutils literal"><span class="pre">FetchTransactionsProtocol</span></code> to perform the actual retrieval.</p> <p>It is encouraged that where possible attachments are reusable data, so that nodes can meaningfully cache them.</p> <div class="section" id="attachments-demo"> <h2>Attachments demo<a class="headerlink" href="#attachments-demo" title="Permalink to this headline">¶</a></h2> <p>There is a worked example of attachments, which relays a simple document from one node to another. The “two party trade protocol” also includes an attachment, however it is a significantly more complex demo, and less well suited for a tutorial.</p> <p>The demo code is in the file “src/main/kotlin/com/r3corda/demos/attachment/AttachmentDemo.kt”, with the core logic contained within the two functions <code class="docutils literal"><span class="pre">runRecipient()</span></code> and <code class="docutils literal"><span class="pre">runSender()</span></code>. We’ll look at the recipient function first; this subscribes to notifications of new validated transactions, and if it receives a transaction containing attachments, loads the first attachment from storage, and checks it matches the expected attachment ID. <code class="docutils literal"><span class="pre">ResolveTransactionsProtocol</span></code> has already fetched all attachments from the remote node, and as such the attachments are available from the node’s storage service. Once the attachment is verified, the node shuts itself down.</p> <div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">private</span> <span class="k">fun</span> <span class="nf">runRecipient</span><span class="p">(</span><span class="n">node</span><span class="p">:</span> <span class="n">Node</span><span class="p">)</span> <span class="p">{</span> <span class="k">val</span> <span class="py">serviceHub</span> <span class="p">=</span> <span class="n">node</span><span class="p">.</span><span class="n">services</span> <span class="c1">// Normally we would receive the transaction from a more specific protocol, but in this case we let [FinalityProtocol]</span> <span class="c1">// handle receiving it for us.</span> <span class="n">serviceHub</span><span class="p">.</span><span class="n">storageService</span><span class="p">.</span><span class="n">validatedTransactions</span><span class="p">.</span><span class="n">updates</span><span class="p">.</span><span class="n">subscribe</span> <span class="p">{</span> <span class="n">event</span> <span class="p">-></span> <span class="c1">// When the transaction is received, it's passed through [ResolveTransactionsProtocol], which first fetches any</span> <span class="c1">// attachments for us, then verifies the transaction. As such, by the time it hits the validated transaction store,</span> <span class="c1">// we have a copy of the attachment.</span> <span class="k">val</span> <span class="py">tx</span> <span class="p">=</span> <span class="n">event</span><span class="p">.</span><span class="n">tx</span> <span class="k">if</span> <span class="p">(</span><span class="n">tx</span><span class="p">.</span><span class="n">attachments</span><span class="p">.</span><span class="n">isNotEmpty</span><span class="p">())</span> <span class="p">{</span> <span class="k">val</span> <span class="py">attachment</span> <span class="p">=</span> <span class="n">serviceHub</span><span class="p">.</span><span class="n">storageService</span><span class="p">.</span><span class="n">attachments</span><span class="p">.</span><span class="n">openAttachment</span><span class="p">(</span><span class="n">tx</span><span class="p">.</span><span class="n">attachments</span><span class="p">.</span><span class="n">first</span><span class="p">())</span> <span class="n">assertEquals</span><span class="p">(</span><span class="n">PROSPECTUS_HASH</span><span class="p">,</span> <span class="n">attachment</span><span class="o">?.</span><span class="n">id</span><span class="p">)</span> <span class="n">println</span><span class="p">(</span><span class="s">"File received - we're happy!\n\nFinal transaction is:\n\n${Emoji.renderIfSupported(event.tx)}"</span><span class="p">)</span> <span class="n">thread</span> <span class="p">{</span> <span class="n">node</span><span class="p">.</span><span class="n">stop</span><span class="p">()</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> </pre></div> </div> <p>The sender correspondingly builds a transaction with the attachment, then calls <code class="docutils literal"><span class="pre">FinalityProtocol</span></code> to complete the transaction and send it to the recipient node:</p> <div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">private</span> <span class="k">fun</span> <span class="nf">runSender</span><span class="p">(</span><span class="n">node</span><span class="p">:</span> <span class="n">Node</span><span class="p">,</span> <span class="n">otherSide</span><span class="p">:</span> <span class="n">Party</span><span class="p">)</span> <span class="p">{</span> <span class="k">val</span> <span class="py">serviceHub</span> <span class="p">=</span> <span class="n">node</span><span class="p">.</span><span class="n">services</span> <span class="c1">// Make sure we have the file in storage</span> <span class="k">if</span> <span class="p">(</span><span class="n">serviceHub</span><span class="p">.</span><span class="n">storageService</span><span class="p">.</span><span class="n">attachments</span><span class="p">.</span><span class="n">openAttachment</span><span class="p">(</span><span class="n">PROSPECTUS_HASH</span><span class="p">)</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span> <span class="n">com</span><span class="p">.</span><span class="n">r3corda</span><span class="p">.</span><span class="n">demos</span><span class="p">.</span><span class="n">Role</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">.</span><span class="n">getResourceAsStream</span><span class="p">(</span><span class="s">"bank-of-london-cp.jar"</span><span class="p">).</span><span class="n">use</span> <span class="p">{</span> <span class="k">val</span> <span class="py">id</span> <span class="p">=</span> <span class="n">node</span><span class="p">.</span><span class="n">storage</span><span class="p">.</span><span class="n">attachments</span><span class="p">.</span><span class="n">importAttachment</span><span class="p">(</span><span class="n">it</span><span class="p">)</span> <span class="n">assertEquals</span><span class="p">(</span><span class="n">PROSPECTUS_HASH</span><span class="p">,</span> <span class="n">id</span><span class="p">)</span> <span class="p">}</span> <span class="p">}</span> <span class="c1">// Create a trivial transaction that just passes across the attachment - in normal cases there would be</span> <span class="c1">// inputs, outputs and commands that refer to this attachment.</span> <span class="k">val</span> <span class="py">ptx</span> <span class="p">=</span> <span class="n">TransactionType</span><span class="p">.</span><span class="n">General</span><span class="p">.</span><span class="n">Builder</span><span class="p">(</span><span class="n">notary</span> <span class="p">=</span> <span class="k">null</span><span class="p">)</span> <span class="n">ptx</span><span class="p">.</span><span class="n">addAttachment</span><span class="p">(</span><span class="n">serviceHub</span><span class="p">.</span><span class="n">storageService</span><span class="p">.</span><span class="n">attachments</span><span class="p">.</span><span class="n">openAttachment</span><span class="p">(</span><span class="n">PROSPECTUS_HASH</span><span class="p">)</span><span class="o">!!</span><span class="p">.</span><span class="n">id</span><span class="p">)</span> <span class="c1">// Despite not having any states, we have to have at least one signature on the transaction</span> <span class="n">ptx</span><span class="p">.</span><span class="n">signWith</span><span class="p">(</span><span class="n">ALICE_KEY</span><span class="p">)</span> <span class="c1">// Send the transaction to the other recipient</span> <span class="k">val</span> <span class="py">tx</span> <span class="p">=</span> <span class="n">ptx</span><span class="p">.</span><span class="n">toSignedTransaction</span><span class="p">()</span> <span class="n">serviceHub</span><span class="p">.</span><span class="n">startProtocol</span><span class="p">(</span><span class="n">LOG_SENDER</span><span class="p">,</span> <span class="n">FinalityProtocol</span><span class="p">(</span><span class="n">tx</span><span class="p">,</span> <span class="n">emptySet</span><span class="p">(),</span> <span class="n">setOf</span><span class="p">(</span><span class="n">otherSide</span><span class="p">))).</span><span class="n">success</span> <span class="p">{</span> <span class="n">thread</span> <span class="p">{</span> <span class="n">Thread</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="m">1000L</span><span class="p">)</span> <span class="c1">// Give the other side time to request the attachment</span> <span class="n">node</span><span class="p">.</span><span class="n">stop</span><span class="p">()</span> <span class="p">}</span> <span class="p">}.</span><span class="n">failure</span> <span class="p">{</span> <span class="n">println</span><span class="p">(</span><span class="s">"Failed to relay message "</span><span class="p">)</span> <span class="p">}</span> <span class="p">}</span> </pre></div> </div> </div> </div> </div> </div> <footer> <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation"> <a href="event-scheduling.html" class="btn btn-neutral float-right" title="Event scheduling" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a> <a href="oracles.html" class="btn btn-neutral" title="Writing oracle services" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a> </div> <hr/> <div role="contentinfo"> <p> © Copyright 2016, Distributed Ledger Group, LLC. </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>