diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index d2e589c55e..0000000000 --- a/docs/Makefile +++ /dev/null @@ -1,197 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -HTMLSPHINXOPTS = $(ALLSPHINXOPTS) -t htmlmode -PDFSPHINXOPTS = $(ALLSPHINXOPTS) -t pdfmode -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - @echo " coverage to run coverage check of the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(HTMLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(HTMLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(HTMLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(HTMLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Playground.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Playground.qhc" - -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/Playground" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Playground" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(PDFSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(PDFSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(PDFSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." - -pdf: - $(SPHINXBUILD) -b pdf $(PDFSPHINXOPTS) $(BUILDDIR)/pdf diff --git a/docs/README.md b/docs/README.md index cb2baf76d7..529486b539 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,41 +1,23 @@ -# Corda Documentation Build +# Docs -This Readme describes how to build the Corda documentation for the current version. The output html files will be written to the `corda\docs\build\html` directory. +## Released documentation -## Prerequisites / First time build +All released Corda documentation has now been moved to a standalone public documentation repository where the doc source can be found: -Before you begin, you need to: -1. Install Docker. -1. Ensure that Docker is running. -1. Select **Expose daemon on tcp://localhost:2375 without TLS** in the Docker Settings (which you can open from the **System Tray** by right-clicking the **Docker symbol** and then selecting **Settings**) +[corda/corda-docs](https://github.com/corda/corda-docs) -## Build process -1. Open a cmd dialogue. -1. Navigate to the root location (this is the `\corda` directory) -1. Run the documentation build (`gradlew makeDocs` or `./gradlew makeDocs`) +See the [readme](https://github.com/corda/corda-docs/blob/master/README.md) and [usage docs](https://github.com/corda/corda-docs/tree/master/usage-docs) pages for instructions on how to use the new repo and build the docs locally. -**Windows users:** *If this task fails because Docker can't find make-docsite.sh, go to Settings > Shared Drives in the Docker system tray -agent, make sure the relevant drive is shared, and click 'Reset credentials'.* +You can contribute to the docs source as before via fork & PR. We now use `markdown` to write/edit (instead of `rst`) and `Hugo` to build (instead of `Sphinx`). -# RST style guide +The published documentation is available at https://docs.corda.net. -The Corda documentation is described using the ReStructured Text (RST) markup language. For details of the syntax, see [this](http://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html). +## Documentation for future releases -# Version placeholders +R3's technical writing team, R3 engineering, and other R3 teams use a separate, private docs repo for working on draft documentation content targeting future releases: -We currently support the following placeholders; they get substituted with the correct value at build time: +[corda/corda-docs-develop](https://github.com/corda/corda-docs-develop) -```groovy - "|corda_version|" - "|corda_version_lower|" - "|java_version|" - "|kotlin_version|" - "|gradle_plugins_version|" - "|quasar_version|" -``` +These docs are published as part of each quarterly release of Corda. At that point their doc source becomes available and open for contributions in the [public docs repo](https://github.com/corda/corda-docs). -If you put one of these in an rst file anywhere (including in a code tag), it will be substituted with the value from `constants.properties` -(which is in the root of the project) at build time. `corda_version_lower` returns the current Corda version in lowercase which is useful -for case sensitive artifacts such as docker images. - -The code for this can be found near the top of the conf.py file in the `docs/source` directory. +The new documentation process is described in the technical writing team's space on [R3's internal confluence wiki](https://r3-cev.atlassian.net/wiki/spaces/EN/pages/1701249087/Technical+Writing). diff --git a/docs/build.gradle b/docs/build.gradle deleted file mode 100644 index 28c7629bfb..0000000000 --- a/docs/build.gradle +++ /dev/null @@ -1,80 +0,0 @@ -import org.apache.tools.ant.taskdefs.condition.Os - -import java.nio.file.Files - -apply plugin: 'org.jetbrains.dokka' -apply plugin: 'kotlin' - -dependencies { - compile rootProject -} - -def internalPackagePrefixes(sourceDirs) { - def prefixes = [] - // Kotlin allows packages to deviate from the directory structure, but let's assume they don't: - sourceDirs.collect { sourceDir -> - sourceDir.traverse(type: groovy.io.FileType.DIRECTORIES) { - if (it.name == 'internal') { - prefixes.add sourceDir.toPath().relativize(it.toPath()).toString().replace(File.separator, '.') - } - } - } - prefixes -} - -ext { - // TODO: Add '../client/jfx/src/main/kotlin' and '../client/mock/src/main/kotlin' if we decide to make them into public API - dokkaSourceDirs = files('../core/src/main/kotlin', '../client/rpc/src/main/kotlin', '../finance/workflows/src/main/kotlin', '../finance/contracts/src/main/kotlin', '../client/jackson/src/main/kotlin', - '../testing/test-utils/src/main/kotlin', '../testing/node-driver/src/main/kotlin') - internalPackagePrefixes = internalPackagePrefixes(dokkaSourceDirs) -} - -dokka { - outputDirectory = file("${rootProject.rootDir}/docs/build/html/api/kotlin") -} - -task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) { - outputFormat = "javadoc" - outputDirectory = file("${rootProject.rootDir}/docs/build/html/api/javadoc") -} - -[dokka, dokkaJavadoc].collect { - it.configure { - moduleName = 'corda' - processConfigurations = ['compile'] - sourceDirs = dokkaSourceDirs - includes = ['packages.md'] - jdkVersion = 8 - externalDocumentationLink { - url = new URL("http://fasterxml.github.io/jackson-core/javadoc/2.9/") - } - externalDocumentationLink { - url = new URL("https://docs.oracle.com/javafx/2/api/") - } - externalDocumentationLink { - url = new URL("http://www.bouncycastle.org/docs/docs1.5on/") - } - internalPackagePrefixes.collect { packagePrefix -> - packageOptions { - prefix = packagePrefix - suppress = true - } - } - } -} - -task buildDocs(dependsOn: ['apidocs', 'makeDocs']) -task apidocs(dependsOn: ['dokka', 'dokkaJavadoc']) - -task makeDocs(type: Exec) { - // 2 volumes are mounted: - // - the docs project to /opt/docs_builder, where docs building is executed - // - the rest of the projects in /opt, so that code references to other projects are valid - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - commandLine "docker", "run", "--rm", "-v", "${project.projectDir}:/opt/docs_builder", "-v", "${project.projectDir}/..:/opt", "corda/docs-builder:latest", "bash", "-c", "make-docsite.sh" - } else { - commandLine "bash", "-c", "docker run --rm --user \$(id -u):\$(id -g) -v ${project.projectDir}:/opt/docs_builder -v ${project.projectDir}/..:/opt corda/docs-builder:latest bash -c make-docsite.sh" - } -} - -apidocs.shouldRunAfter makeDocs diff --git a/docs/docs_builder/Dockerfile b/docs/docs_builder/Dockerfile deleted file mode 100644 index bcca03dbd8..0000000000 --- a/docs/docs_builder/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:2-stretch - -RUN apt-get update \ - && apt-get --no-install-recommends install -y texlive preview-latex-style texlive-generic-extra texlive-latex-extra latexmk dos2unix \ - && apt-get -y clean \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -ENV PATH="/opt/docs_builder:${PATH}" -WORKDIR /opt/docs_builder -COPY requirements.txt requirements.txt -RUN pip install -r requirements.txt diff --git a/docs/docs_builder/lexer-fix/.gitignore b/docs/docs_builder/lexer-fix/.gitignore deleted file mode 100644 index bbbc5efc2a..0000000000 --- a/docs/docs_builder/lexer-fix/.gitignore +++ /dev/null @@ -1 +0,0 @@ -Pygments*.whl \ No newline at end of file diff --git a/docs/docs_builder/lexer-fix/Dockerfile b/docs/docs_builder/lexer-fix/Dockerfile deleted file mode 100644 index 642dd07f6b..0000000000 --- a/docs/docs_builder/lexer-fix/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM python:2-stretch - -RUN apt-get update \ - && apt-get --no-install-recommends install -y texlive preview-latex-style texlive-generic-extra texlive-latex-extra latexmk dos2unix \ - && apt-get -y clean \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -ENV PATH="/opt/docs_builder:${PATH}" -WORKDIR /opt/docs_builder -COPY requirements.txt requirements.txt -COPY docs_builder/lexer-fix/Pygments*.whl . -RUN pip install -r requirements.txt -RUN pip install Pygments*.whl --force-reinstall diff --git a/docs/docs_builder/lexer-fix/jvm.py b/docs/docs_builder/lexer-fix/jvm.py deleted file mode 100644 index fdd437ebf4..0000000000 --- a/docs/docs_builder/lexer-fix/jvm.py +++ /dev/null @@ -1,1654 +0,0 @@ -# -*- coding: utf-8 -*- -""" - pygments.lexers.jvm - ~~~~~~~~~~~~~~~~~~~ - - Pygments lexers for JVM languages. - - :copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -import re - -from pygments.lexer import Lexer, RegexLexer, include, bygroups, using, \ - this, combined, default, words -from pygments.token import Text, Comment, Operator, Keyword, Name, String, \ - Number, Punctuation -from pygments.util import shebang_matches -from pygments import unistring as uni - -__all__ = ['JavaLexer', 'ScalaLexer', 'GosuLexer', 'GosuTemplateLexer', - 'GroovyLexer', 'IokeLexer', 'ClojureLexer', 'ClojureScriptLexer', - 'KotlinLexer', 'XtendLexer', 'AspectJLexer', 'CeylonLexer', - 'PigLexer', 'GoloLexer', 'JasminLexer', 'SarlLexer'] - - -class JavaLexer(RegexLexer): - """ - For `Java `_ source code. - """ - - name = 'Java' - aliases = ['java'] - filenames = ['*.java'] - mimetypes = ['text/x-java'] - - flags = re.MULTILINE | re.DOTALL | re.UNICODE - - tokens = { - 'root': [ - (r'[^\S\n]+', Text), - (r'//.*?\n', Comment.Single), - (r'/\*.*?\*/', Comment.Multiline), - # keywords: go before method names to avoid lexing "throw new XYZ" - # as a method signature - (r'(assert|break|case|catch|continue|default|do|else|finally|for|' - r'if|goto|instanceof|new|return|switch|this|throw|try|while)\b', - Keyword), - # method names - (r'((?:(?:[^\W\d]|\$)[\w.\[\]$<>]*\s+)+?)' # return arguments - r'((?:[^\W\d]|\$)[\w$]*)' # method name - r'(\s*)(\()', # signature start - bygroups(using(this), Name.Function, Text, Operator)), - (r'@[^\W\d][\w.]*', Name.Decorator), - (r'(abstract|const|enum|extends|final|implements|native|private|' - r'protected|public|static|strictfp|super|synchronized|throws|' - r'transient|volatile)\b', Keyword.Declaration), - (r'(boolean|byte|char|double|float|int|long|short|void)\b', - Keyword.Type), - (r'(package)(\s+)', bygroups(Keyword.Namespace, Text), 'import'), - (r'(true|false|null)\b', Keyword.Constant), - (r'(class|interface)(\s+)', bygroups(Keyword.Declaration, Text), - 'class'), - (r'(import(?:\s+static)?)(\s+)', bygroups(Keyword.Namespace, Text), - 'import'), - (r'"(\\\\|\\"|[^"])*"', String), - (r"'\\.'|'[^\\]'|'\\u[0-9a-fA-F]{4}'", String.Char), - (r'(\.)((?:[^\W\d]|\$)[\w$]*)', bygroups(Operator, Name.Attribute)), - (r'^\s*([^\W\d]|\$)[\w$]*:', Name.Label), - (r'([^\W\d]|\$)[\w$]*', Name), - (r'([0-9][0-9_]*\.([0-9][0-9_]*)?|' - r'\.[0-9][0-9_]*)' - r'([eE][+\-]?[0-9][0-9_]*)?[fFdD]?|' - r'[0-9][eE][+\-]?[0-9][0-9_]*[fFdD]?|' - r'[0-9]([eE][+\-]?[0-9][0-9_]*)?[fFdD]|' - r'0[xX]([0-9a-fA-F][0-9a-fA-F_]*\.?|' - r'([0-9a-fA-F][0-9a-fA-F_]*)?\.[0-9a-fA-F][0-9a-fA-F_]*)' - r'[pP][+\-]?[0-9][0-9_]*[fFdD]?', Number.Float), - (r'0[xX][0-9a-fA-F][0-9a-fA-F_]*[lL]?', Number.Hex), - (r'0[bB][01][01_]*[lL]?', Number.Bin), - (r'0[0-7_]+[lL]?', Number.Oct), - (r'0|[1-9][0-9_]*[lL]?', Number.Integer), - (r'[~^*!%&\[\](){}<>|+=:;,./?-]', Operator), - (r'\n', Text) - ], - 'class': [ - (r'([^\W\d]|\$)[\w$]*', Name.Class, '#pop') - ], - 'import': [ - (r'[\w.]+\*?', Name.Namespace, '#pop') - ], - } - - -class AspectJLexer(JavaLexer): - """ - For `AspectJ `_ source code. - - .. versionadded:: 1.6 - """ - - name = 'AspectJ' - aliases = ['aspectj'] - filenames = ['*.aj'] - mimetypes = ['text/x-aspectj'] - - aj_keywords = set(( - 'aspect', 'pointcut', 'privileged', 'call', 'execution', - 'initialization', 'preinitialization', 'handler', 'get', 'set', - 'staticinitialization', 'target', 'args', 'within', 'withincode', - 'cflow', 'cflowbelow', 'annotation', 'before', 'after', 'around', - 'proceed', 'throwing', 'returning', 'adviceexecution', 'declare', - 'parents', 'warning', 'error', 'soft', 'precedence', 'thisJoinPoint', - 'thisJoinPointStaticPart', 'thisEnclosingJoinPointStaticPart', - 'issingleton', 'perthis', 'pertarget', 'percflow', 'percflowbelow', - 'pertypewithin', 'lock', 'unlock', 'thisAspectInstance' - )) - aj_inter_type = set(('parents:', 'warning:', 'error:', 'soft:', 'precedence:')) - aj_inter_type_annotation = set(('@type', '@method', '@constructor', '@field')) - - def get_tokens_unprocessed(self, text): - for index, token, value in JavaLexer.get_tokens_unprocessed(self, text): - if token is Name and value in self.aj_keywords: - yield index, Keyword, value - elif token is Name.Label and value in self.aj_inter_type: - yield index, Keyword, value[:-1] - yield index, Operator, value[-1] - elif token is Name.Decorator and value in self.aj_inter_type_annotation: - yield index, Keyword, value - else: - yield index, token, value - - -class ScalaLexer(RegexLexer): - """ - For `Scala `_ source code. - """ - - name = 'Scala' - aliases = ['scala'] - filenames = ['*.scala'] - mimetypes = ['text/x-scala'] - - flags = re.MULTILINE | re.DOTALL - - # don't use raw unicode strings! - op = (u'[-~\\^\\*!%&\\\\<>\\|+=:/?@\u00a6-\u00a7\u00a9\u00ac\u00ae\u00b0-\u00b1' - u'\u00b6\u00d7\u00f7\u03f6\u0482\u0606-\u0608\u060e-\u060f\u06e9' - u'\u06fd-\u06fe\u07f6\u09fa\u0b70\u0bf3-\u0bf8\u0bfa\u0c7f\u0cf1-\u0cf2' - u'\u0d79\u0f01-\u0f03\u0f13-\u0f17\u0f1a-\u0f1f\u0f34\u0f36\u0f38' - u'\u0fbe-\u0fc5\u0fc7-\u0fcf\u109e-\u109f\u1360\u1390-\u1399\u1940' - u'\u19e0-\u19ff\u1b61-\u1b6a\u1b74-\u1b7c\u2044\u2052\u207a-\u207c' - u'\u208a-\u208c\u2100-\u2101\u2103-\u2106\u2108-\u2109\u2114\u2116-\u2118' - u'\u211e-\u2123\u2125\u2127\u2129\u212e\u213a-\u213b\u2140-\u2144' - u'\u214a-\u214d\u214f\u2190-\u2328\u232b-\u244a\u249c-\u24e9\u2500-\u2767' - u'\u2794-\u27c4\u27c7-\u27e5\u27f0-\u2982\u2999-\u29d7\u29dc-\u29fb' - u'\u29fe-\u2b54\u2ce5-\u2cea\u2e80-\u2ffb\u3004\u3012-\u3013\u3020' - u'\u3036-\u3037\u303e-\u303f\u3190-\u3191\u3196-\u319f\u31c0-\u31e3' - u'\u3200-\u321e\u322a-\u3250\u3260-\u327f\u328a-\u32b0\u32c0-\u33ff' - u'\u4dc0-\u4dff\ua490-\ua4c6\ua828-\ua82b\ufb29\ufdfd\ufe62\ufe64-\ufe66' - u'\uff0b\uff1c-\uff1e\uff5c\uff5e\uffe2\uffe4\uffe8-\uffee\ufffc-\ufffd]+') - - letter = (u'[a-zA-Z\\$_\u00aa\u00b5\u00ba\u00c0-\u00d6\u00d8-\u00f6' - u'\u00f8-\u02af\u0370-\u0373\u0376-\u0377\u037b-\u037d\u0386' - u'\u0388-\u03f5\u03f7-\u0481\u048a-\u0556\u0561-\u0587\u05d0-\u05f2' - u'\u0621-\u063f\u0641-\u064a\u066e-\u066f\u0671-\u06d3\u06d5' - u'\u06ee-\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5' - u'\u07b1\u07ca-\u07ea\u0904-\u0939\u093d\u0950\u0958-\u0961' - u'\u0972-\u097f\u0985-\u09b9\u09bd\u09ce\u09dc-\u09e1\u09f0-\u09f1' - u'\u0a05-\u0a39\u0a59-\u0a5e\u0a72-\u0a74\u0a85-\u0ab9\u0abd' - u'\u0ad0-\u0ae1\u0b05-\u0b39\u0b3d\u0b5c-\u0b61\u0b71\u0b83-\u0bb9' - u'\u0bd0\u0c05-\u0c3d\u0c58-\u0c61\u0c85-\u0cb9\u0cbd\u0cde-\u0ce1' - u'\u0d05-\u0d3d\u0d60-\u0d61\u0d7a-\u0d7f\u0d85-\u0dc6\u0e01-\u0e30' - u'\u0e32-\u0e33\u0e40-\u0e45\u0e81-\u0eb0\u0eb2-\u0eb3\u0ebd-\u0ec4' - u'\u0edc-\u0f00\u0f40-\u0f6c\u0f88-\u0f8b\u1000-\u102a\u103f' - u'\u1050-\u1055\u105a-\u105d\u1061\u1065-\u1066\u106e-\u1070' - u'\u1075-\u1081\u108e\u10a0-\u10fa\u1100-\u135a\u1380-\u138f' - u'\u13a0-\u166c\u166f-\u1676\u1681-\u169a\u16a0-\u16ea\u16ee-\u1711' - u'\u1720-\u1731\u1740-\u1751\u1760-\u1770\u1780-\u17b3\u17dc' - u'\u1820-\u1842\u1844-\u18a8\u18aa-\u191c\u1950-\u19a9\u19c1-\u19c7' - u'\u1a00-\u1a16\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae-\u1baf' - u'\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c77\u1d00-\u1d2b\u1d62-\u1d77' - u'\u1d79-\u1d9a\u1e00-\u1fbc\u1fbe\u1fc2-\u1fcc\u1fd0-\u1fdb' - u'\u1fe0-\u1fec\u1ff2-\u1ffc\u2071\u207f\u2102\u2107\u210a-\u2113' - u'\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139' - u'\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c7c' - u'\u2c80-\u2ce4\u2d00-\u2d65\u2d80-\u2dde\u3006-\u3007\u3021-\u3029' - u'\u3038-\u303a\u303c\u3041-\u3096\u309f\u30a1-\u30fa\u30ff-\u318e' - u'\u31a0-\u31b7\u31f0-\u31ff\u3400-\u4db5\u4e00-\ua014\ua016-\ua48c' - u'\ua500-\ua60b\ua610-\ua61f\ua62a-\ua66e\ua680-\ua697\ua722-\ua76f' - u'\ua771-\ua787\ua78b-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822' - u'\ua840-\ua873\ua882-\ua8b3\ua90a-\ua925\ua930-\ua946\uaa00-\uaa28' - u'\uaa40-\uaa42\uaa44-\uaa4b\uac00-\ud7a3\uf900-\ufb1d\ufb1f-\ufb28' - u'\ufb2a-\ufd3d\ufd50-\ufdfb\ufe70-\ufefc\uff21-\uff3a\uff41-\uff5a' - u'\uff66-\uff6f\uff71-\uff9d\uffa0-\uffdc]') - - upper = (u'[A-Z\\$_\u00c0-\u00d6\u00d8-\u00de\u0100\u0102\u0104\u0106\u0108' - u'\u010a\u010c\u010e\u0110\u0112\u0114\u0116\u0118\u011a\u011c' - u'\u011e\u0120\u0122\u0124\u0126\u0128\u012a\u012c\u012e\u0130' - u'\u0132\u0134\u0136\u0139\u013b\u013d\u013f\u0141\u0143\u0145' - u'\u0147\u014a\u014c\u014e\u0150\u0152\u0154\u0156\u0158\u015a' - u'\u015c\u015e\u0160\u0162\u0164\u0166\u0168\u016a\u016c\u016e' - u'\u0170\u0172\u0174\u0176\u0178-\u0179\u017b\u017d\u0181-\u0182' - u'\u0184\u0186-\u0187\u0189-\u018b\u018e-\u0191\u0193-\u0194' - u'\u0196-\u0198\u019c-\u019d\u019f-\u01a0\u01a2\u01a4\u01a6-\u01a7' - u'\u01a9\u01ac\u01ae-\u01af\u01b1-\u01b3\u01b5\u01b7-\u01b8\u01bc' - u'\u01c4\u01c7\u01ca\u01cd\u01cf\u01d1\u01d3\u01d5\u01d7\u01d9' - u'\u01db\u01de\u01e0\u01e2\u01e4\u01e6\u01e8\u01ea\u01ec\u01ee' - u'\u01f1\u01f4\u01f6-\u01f8\u01fa\u01fc\u01fe\u0200\u0202\u0204' - u'\u0206\u0208\u020a\u020c\u020e\u0210\u0212\u0214\u0216\u0218' - u'\u021a\u021c\u021e\u0220\u0222\u0224\u0226\u0228\u022a\u022c' - u'\u022e\u0230\u0232\u023a-\u023b\u023d-\u023e\u0241\u0243-\u0246' - u'\u0248\u024a\u024c\u024e\u0370\u0372\u0376\u0386\u0388-\u038f' - u'\u0391-\u03ab\u03cf\u03d2-\u03d4\u03d8\u03da\u03dc\u03de\u03e0' - u'\u03e2\u03e4\u03e6\u03e8\u03ea\u03ec\u03ee\u03f4\u03f7' - u'\u03f9-\u03fa\u03fd-\u042f\u0460\u0462\u0464\u0466\u0468\u046a' - u'\u046c\u046e\u0470\u0472\u0474\u0476\u0478\u047a\u047c\u047e' - u'\u0480\u048a\u048c\u048e\u0490\u0492\u0494\u0496\u0498\u049a' - u'\u049c\u049e\u04a0\u04a2\u04a4\u04a6\u04a8\u04aa\u04ac\u04ae' - u'\u04b0\u04b2\u04b4\u04b6\u04b8\u04ba\u04bc\u04be\u04c0-\u04c1' - u'\u04c3\u04c5\u04c7\u04c9\u04cb\u04cd\u04d0\u04d2\u04d4\u04d6' - u'\u04d8\u04da\u04dc\u04de\u04e0\u04e2\u04e4\u04e6\u04e8\u04ea' - u'\u04ec\u04ee\u04f0\u04f2\u04f4\u04f6\u04f8\u04fa\u04fc\u04fe' - u'\u0500\u0502\u0504\u0506\u0508\u050a\u050c\u050e\u0510\u0512' - u'\u0514\u0516\u0518\u051a\u051c\u051e\u0520\u0522\u0531-\u0556' - u'\u10a0-\u10c5\u1e00\u1e02\u1e04\u1e06\u1e08\u1e0a\u1e0c\u1e0e' - u'\u1e10\u1e12\u1e14\u1e16\u1e18\u1e1a\u1e1c\u1e1e\u1e20\u1e22' - u'\u1e24\u1e26\u1e28\u1e2a\u1e2c\u1e2e\u1e30\u1e32\u1e34\u1e36' - u'\u1e38\u1e3a\u1e3c\u1e3e\u1e40\u1e42\u1e44\u1e46\u1e48\u1e4a' - u'\u1e4c\u1e4e\u1e50\u1e52\u1e54\u1e56\u1e58\u1e5a\u1e5c\u1e5e' - u'\u1e60\u1e62\u1e64\u1e66\u1e68\u1e6a\u1e6c\u1e6e\u1e70\u1e72' - u'\u1e74\u1e76\u1e78\u1e7a\u1e7c\u1e7e\u1e80\u1e82\u1e84\u1e86' - u'\u1e88\u1e8a\u1e8c\u1e8e\u1e90\u1e92\u1e94\u1e9e\u1ea0\u1ea2' - u'\u1ea4\u1ea6\u1ea8\u1eaa\u1eac\u1eae\u1eb0\u1eb2\u1eb4\u1eb6' - u'\u1eb8\u1eba\u1ebc\u1ebe\u1ec0\u1ec2\u1ec4\u1ec6\u1ec8\u1eca' - u'\u1ecc\u1ece\u1ed0\u1ed2\u1ed4\u1ed6\u1ed8\u1eda\u1edc\u1ede' - u'\u1ee0\u1ee2\u1ee4\u1ee6\u1ee8\u1eea\u1eec\u1eee\u1ef0\u1ef2' - u'\u1ef4\u1ef6\u1ef8\u1efa\u1efc\u1efe\u1f08-\u1f0f\u1f18-\u1f1d' - u'\u1f28-\u1f2f\u1f38-\u1f3f\u1f48-\u1f4d\u1f59-\u1f5f' - u'\u1f68-\u1f6f\u1fb8-\u1fbb\u1fc8-\u1fcb\u1fd8-\u1fdb' - u'\u1fe8-\u1fec\u1ff8-\u1ffb\u2102\u2107\u210b-\u210d\u2110-\u2112' - u'\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u2130-\u2133' - u'\u213e-\u213f\u2145\u2183\u2c00-\u2c2e\u2c60\u2c62-\u2c64\u2c67' - u'\u2c69\u2c6b\u2c6d-\u2c6f\u2c72\u2c75\u2c80\u2c82\u2c84\u2c86' - u'\u2c88\u2c8a\u2c8c\u2c8e\u2c90\u2c92\u2c94\u2c96\u2c98\u2c9a' - u'\u2c9c\u2c9e\u2ca0\u2ca2\u2ca4\u2ca6\u2ca8\u2caa\u2cac\u2cae' - u'\u2cb0\u2cb2\u2cb4\u2cb6\u2cb8\u2cba\u2cbc\u2cbe\u2cc0\u2cc2' - u'\u2cc4\u2cc6\u2cc8\u2cca\u2ccc\u2cce\u2cd0\u2cd2\u2cd4\u2cd6' - u'\u2cd8\u2cda\u2cdc\u2cde\u2ce0\u2ce2\ua640\ua642\ua644\ua646' - u'\ua648\ua64a\ua64c\ua64e\ua650\ua652\ua654\ua656\ua658\ua65a' - u'\ua65c\ua65e\ua662\ua664\ua666\ua668\ua66a\ua66c\ua680\ua682' - u'\ua684\ua686\ua688\ua68a\ua68c\ua68e\ua690\ua692\ua694\ua696' - u'\ua722\ua724\ua726\ua728\ua72a\ua72c\ua72e\ua732\ua734\ua736' - u'\ua738\ua73a\ua73c\ua73e\ua740\ua742\ua744\ua746\ua748\ua74a' - u'\ua74c\ua74e\ua750\ua752\ua754\ua756\ua758\ua75a\ua75c\ua75e' - u'\ua760\ua762\ua764\ua766\ua768\ua76a\ua76c\ua76e\ua779\ua77b' - u'\ua77d-\ua77e\ua780\ua782\ua784\ua786\ua78b\uff21-\uff3a]') - - idrest = u'%s(?:%s|[0-9])*(?:(?<=_)%s)?' % (letter, letter, op) - letter_letter_digit = u'%s(?:%s|\\d)*' % (letter, letter) - - tokens = { - 'root': [ - # method names - (r'(class|trait|object)(\s+)', bygroups(Keyword, Text), 'class'), - (r'[^\S\n]+', Text), - (r'//.*?\n', Comment.Single), - (r'/\*', Comment.Multiline, 'comment'), - (u'@%s' % idrest, Name.Decorator), - (u'(abstract|ca(?:se|tch)|d(?:ef|o)|e(?:lse|xtends)|' - u'f(?:inal(?:ly)?|or(?:Some)?)|i(?:f|mplicit)|' - u'lazy|match|new|override|pr(?:ivate|otected)' - u'|re(?:quires|turn)|s(?:ealed|uper)|' - u't(?:h(?:is|row)|ry)|va[lr]|w(?:hile|ith)|yield)\\b|' - u'(<[%:-]|=>|>:|[#=@_\u21D2\u2190])(\\b|(?=\\s)|$)', Keyword), - (u':(?!%s)' % op, Keyword, 'type'), - (u'%s%s\\b' % (upper, idrest), Name.Class), - (r'(true|false|null)\b', Keyword.Constant), - (r'(import|package)(\s+)', bygroups(Keyword, Text), 'import'), - (r'(type)(\s+)', bygroups(Keyword, Text), 'type'), - (r'""".*?"""(?!")', String), - (r'"(\\\\|\\"|[^"])*"', String), - (r"'\\.'|'[^\\]'|'\\u[0-9a-fA-F]{4}'", String.Char), - (u"'%s" % idrest, Text.Symbol), - (r'[fs]"""', String, 'interptriplestring'), # interpolated strings - (r'[fs]"', String, 'interpstring'), # interpolated strings - (r'raw"(\\\\|\\"|[^"])*"', String), # raw strings - # (ur'(\.)(%s|%s|`[^`]+`)' % (idrest, op), bygroups(Operator, - # Name.Attribute)), - (idrest, Name), - (r'`[^`]+`', Name), - (r'\[', Operator, 'typeparam'), - (r'[(){};,.#]', Operator), - (op, Operator), - (r'([0-9][0-9]*\.[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?[fFdD]?', - Number.Float), - (r'0x[0-9a-fA-F]+', Number.Hex), - (r'[0-9]+L?', Number.Integer), - (r'\n', Text) - ], - 'class': [ - (u'(%s|%s|`[^`]+`)(\\s*)(\\[)' % (idrest, op), - bygroups(Name.Class, Text, Operator), 'typeparam'), - (r'\s+', Text), - (r'\{', Operator, '#pop'), - (r'\(', Operator, '#pop'), - (r'//.*?\n', Comment.Single, '#pop'), - (u'%s|%s|`[^`]+`' % (idrest, op), Name.Class, '#pop'), - ], - 'type': [ - (r'\s+', Text), - (r'<[%:]|>:|[#_]|forSome|type', Keyword), - (u'([,);}]|=>|=|\u21d2)(\\s*)', bygroups(Operator, Text), '#pop'), - (r'[({]', Operator, '#push'), - (u'((?:%s|%s|`[^`]+`)(?:\\.(?:%s|%s|`[^`]+`))*)(\\s*)(\\[)' % - (idrest, op, idrest, op), - bygroups(Keyword.Type, Text, Operator), ('#pop', 'typeparam')), - (u'((?:%s|%s|`[^`]+`)(?:\\.(?:%s|%s|`[^`]+`))*)(\\s*)$' % - (idrest, op, idrest, op), - bygroups(Keyword.Type, Text), '#pop'), - (r'//.*?\n', Comment.Single, '#pop'), - (u'\\.|%s|%s|`[^`]+`' % (idrest, op), Keyword.Type) - ], - 'typeparam': [ - (r'[\s,]+', Text), - (u'<[%:]|=>|>:|[#_\u21D2]|forSome|type', Keyword), - (r'([\])}])', Operator, '#pop'), - (r'[(\[{]', Operator, '#push'), - (u'\\.|%s|%s|`[^`]+`' % (idrest, op), Keyword.Type) - ], - 'comment': [ - (r'[^/*]+', Comment.Multiline), - (r'/\*', Comment.Multiline, '#push'), - (r'\*/', Comment.Multiline, '#pop'), - (r'[*/]', Comment.Multiline) - ], - 'import': [ - (u'(%s|\\.)+' % idrest, Name.Namespace, '#pop') - ], - 'interpstringcommon': [ - (r'[^"$\\]+', String), - (r'\$\$', String), - (r'\$' + letter_letter_digit, String.Interpol), - (r'\$\{', String.Interpol, 'interpbrace'), - (r'\\.', String), - ], - 'interptriplestring': [ - (r'"""(?!")', String, '#pop'), - (r'"', String), - include('interpstringcommon'), - ], - 'interpstring': [ - (r'"', String, '#pop'), - include('interpstringcommon'), - ], - 'interpbrace': [ - (r'\}', String.Interpol, '#pop'), - (r'\{', String.Interpol, '#push'), - include('root'), - ], - } - - -class GosuLexer(RegexLexer): - """ - For Gosu source code. - - .. versionadded:: 1.5 - """ - - name = 'Gosu' - aliases = ['gosu'] - filenames = ['*.gs', '*.gsx', '*.gsp', '*.vark'] - mimetypes = ['text/x-gosu'] - - flags = re.MULTILINE | re.DOTALL - - tokens = { - 'root': [ - # method names - (r'^(\s*(?:[a-zA-Z_][\w.\[\]]*\s+)+?)' # modifiers etc. - r'([a-zA-Z_]\w*)' # method name - r'(\s*)(\()', # signature start - bygroups(using(this), Name.Function, Text, Operator)), - (r'[^\S\n]+', Text), - (r'//.*?\n', Comment.Single), - (r'/\*.*?\*/', Comment.Multiline), - (r'@[a-zA-Z_][\w.]*', Name.Decorator), - (r'(in|as|typeof|statictypeof|typeis|typeas|if|else|foreach|for|' - r'index|while|do|continue|break|return|try|catch|finally|this|' - r'throw|new|switch|case|default|eval|super|outer|classpath|' - r'using)\b', Keyword), - (r'(var|delegate|construct|function|private|internal|protected|' - r'public|abstract|override|final|static|extends|transient|' - r'implements|represents|readonly)\b', Keyword.Declaration), - (r'(property\s+)(get|set)?', Keyword.Declaration), - (r'(boolean|byte|char|double|float|int|long|short|void|block)\b', - Keyword.Type), - (r'(package)(\s+)', bygroups(Keyword.Namespace, Text)), - (r'(true|false|null|NaN|Infinity)\b', Keyword.Constant), - (r'(class|interface|enhancement|enum)(\s+)([a-zA-Z_]\w*)', - bygroups(Keyword.Declaration, Text, Name.Class)), - (r'(uses)(\s+)([\w.]+\*?)', - bygroups(Keyword.Namespace, Text, Name.Namespace)), - (r'"', String, 'string'), - (r'(\??[.#])([a-zA-Z_]\w*)', - bygroups(Operator, Name.Attribute)), - (r'(:)([a-zA-Z_]\w*)', - bygroups(Operator, Name.Attribute)), - (r'[a-zA-Z_$]\w*', Name), - (r'and|or|not|[\\~^*!%&\[\](){}<>|+=:;,./?-]', Operator), - (r'[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?', Number.Float), - (r'[0-9]+', Number.Integer), - (r'\n', Text) - ], - 'templateText': [ - (r'(\\<)|(\\\$)', String), - (r'(<%@\s+)(extends|params)', - bygroups(Operator, Name.Decorator), 'stringTemplate'), - (r'<%!--.*?--%>', Comment.Multiline), - (r'(<%)|(<%=)', Operator, 'stringTemplate'), - (r'\$\{', Operator, 'stringTemplateShorthand'), - (r'.', String) - ], - 'string': [ - (r'"', String, '#pop'), - include('templateText') - ], - 'stringTemplate': [ - (r'"', String, 'string'), - (r'%>', Operator, '#pop'), - include('root') - ], - 'stringTemplateShorthand': [ - (r'"', String, 'string'), - (r'\{', Operator, 'stringTemplateShorthand'), - (r'\}', Operator, '#pop'), - include('root') - ], - } - - -class GosuTemplateLexer(Lexer): - """ - For Gosu templates. - - .. versionadded:: 1.5 - """ - - name = 'Gosu Template' - aliases = ['gst'] - filenames = ['*.gst'] - mimetypes = ['text/x-gosu-template'] - - def get_tokens_unprocessed(self, text): - lexer = GosuLexer() - stack = ['templateText'] - for item in lexer.get_tokens_unprocessed(text, stack): - yield item - - -class GroovyLexer(RegexLexer): - """ - For `Groovy `_ source code. - - .. versionadded:: 1.5 - """ - - name = 'Groovy' - aliases = ['groovy'] - filenames = ['*.groovy','*.gradle'] - mimetypes = ['text/x-groovy'] - - flags = re.MULTILINE | re.DOTALL - - tokens = { - 'root': [ - # Groovy allows a file to start with a shebang - (r'#!(.*?)$', Comment.Preproc, 'base'), - default('base'), - ], - 'base': [ - # method names - (r'^(\s*(?:[a-zA-Z_][\w.\[\]]*\s+)+?)' # return arguments - r'([a-zA-Z_]\w*)' # method name - r'(\s*)(\()', # signature start - bygroups(using(this), Name.Function, Text, Operator)), - (r'[^\S\n]+', Text), - (r'//.*?\n', Comment.Single), - (r'/\*.*?\*/', Comment.Multiline), - (r'@[a-zA-Z_][\w.]*', Name.Decorator), - (r'(assert|break|case|catch|continue|default|do|else|finally|for|' - r'if|goto|instanceof|new|return|switch|this|throw|try|while|in|as)\b', - Keyword), - (r'(abstract|const|enum|extends|final|implements|native|private|' - r'protected|public|static|strictfp|super|synchronized|throws|' - r'transient|volatile)\b', Keyword.Declaration), - (r'(def|boolean|byte|char|double|float|int|long|short|void)\b', - Keyword.Type), - (r'(package)(\s+)', bygroups(Keyword.Namespace, Text)), - (r'(true|false|null)\b', Keyword.Constant), - (r'(class|interface)(\s+)', bygroups(Keyword.Declaration, Text), - 'class'), - (r'(import)(\s+)', bygroups(Keyword.Namespace, Text), 'import'), - (r'""".*?"""', String.Double), - (r"'''.*?'''", String.Single), - (r'"(\\\\|\\"|[^"])*"', String.Double), - (r"'(\\\\|\\'|[^'])*'", String.Single), - (r'\$/((?!/\$).)*/\$', String), - (r'/(\\\\|\\"|[^/])*/', String), - (r"'\\.'|'[^\\]'|'\\u[0-9a-fA-F]{4}'", String.Char), - (r'(\.)([a-zA-Z_]\w*)', bygroups(Operator, Name.Attribute)), - (r'[a-zA-Z_]\w*:', Name.Label), - (r'[a-zA-Z_$]\w*', Name), - (r'[~^*!%&\[\](){}<>|+=:;,./?-]', Operator), - (r'[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?', Number.Float), - (r'0x[0-9a-fA-F]+', Number.Hex), - (r'[0-9]+L?', Number.Integer), - (r'\n', Text) - ], - 'class': [ - (r'[a-zA-Z_]\w*', Name.Class, '#pop') - ], - 'import': [ - (r'[\w.]+\*?', Name.Namespace, '#pop') - ], - } - - def analyse_text(text): - return shebang_matches(text, r'groovy') - - -class IokeLexer(RegexLexer): - """ - For `Ioke `_ (a strongly typed, dynamic, - prototype based programming language) source. - - .. versionadded:: 1.4 - """ - name = 'Ioke' - filenames = ['*.ik'] - aliases = ['ioke', 'ik'] - mimetypes = ['text/x-iokesrc'] - tokens = { - 'interpolatableText': [ - (r'(\\b|\\e|\\t|\\n|\\f|\\r|\\"|\\\\|\\#|\\\Z|\\u[0-9a-fA-F]{1,4}' - r'|\\[0-3]?[0-7]?[0-7])', String.Escape), - (r'#\{', Punctuation, 'textInterpolationRoot') - ], - - 'text': [ - (r'(?>|\|\|>>|\*\*>>|:::|::|\.\.\.|===|\*\*>|\*\*=|&&>|&&=|' - r'\|\|>|\|\|=|\->>|\+>>|!>>|<>>>|<>>|&>>|%>>|#>>|@>>|/>>|\*>>|' - r'\?>>|\|>>|\^>>|~>>|\$>>|=>>|<<=|>>=|<=>|<\->|=~|!~|=>|\+\+|' - r'\-\-|<=|>=|==|!=|&&|\.\.|\+=|\-=|\*=|\/=|%=|&=|\^=|\|=|<\-|' - r'\+>|!>|<>|&>|%>|#>|\@>|\/>|\*>|\?>|\|>|\^>|~>|\$>|<\->|\->|' - r'<<|>>|\*\*|\?\||\?&|\|\||>|<|\*|\/|%|\+|\-|&|\^|\||=|\$|!|~|' - u'\\?|#|\u2260|\u2218|\u2208|\u2209)', Operator), - (r'(and|nand|or|xor|nor|return|import)(?![\w!?])', - Operator), - - # Punctuation - (r'(\`\`|\`|\'\'|\'|\.|\,|@@|@|\[|\]|\(|\)|\{|\})', Punctuation), - - # kinds - (r'[A-Z][\w!:?]*', Name.Class), - - # default cellnames - (r'[a-z_][\w!:?]*', Name) - ] - } - - -class ClojureLexer(RegexLexer): - """ - Lexer for `Clojure `_ source code. - - .. versionadded:: 0.11 - """ - name = 'Clojure' - aliases = ['clojure', 'clj'] - filenames = ['*.clj'] - mimetypes = ['text/x-clojure', 'application/x-clojure'] - - special_forms = ( - '.', 'def', 'do', 'fn', 'if', 'let', 'new', 'quote', 'var', 'loop' - ) - - # It's safe to consider 'ns' a declaration thing because it defines a new - # namespace. - declarations = ( - 'def-', 'defn', 'defn-', 'defmacro', 'defmulti', 'defmethod', - 'defstruct', 'defonce', 'declare', 'definline', 'definterface', - 'defprotocol', 'defrecord', 'deftype', 'defproject', 'ns' - ) - - builtins = ( - '*', '+', '-', '->', '/', '<', '<=', '=', '==', '>', '>=', '..', - 'accessor', 'agent', 'agent-errors', 'aget', 'alength', 'all-ns', - 'alter', 'and', 'append-child', 'apply', 'array-map', 'aset', - 'aset-boolean', 'aset-byte', 'aset-char', 'aset-double', 'aset-float', - 'aset-int', 'aset-long', 'aset-short', 'assert', 'assoc', 'await', - 'await-for', 'bean', 'binding', 'bit-and', 'bit-not', 'bit-or', - 'bit-shift-left', 'bit-shift-right', 'bit-xor', 'boolean', 'branch?', - 'butlast', 'byte', 'cast', 'char', 'children', 'class', - 'clear-agent-errors', 'comment', 'commute', 'comp', 'comparator', - 'complement', 'concat', 'conj', 'cons', 'constantly', 'cond', 'if-not', - 'construct-proxy', 'contains?', 'count', 'create-ns', 'create-struct', - 'cycle', 'dec', 'deref', 'difference', 'disj', 'dissoc', 'distinct', - 'doall', 'doc', 'dorun', 'doseq', 'dosync', 'dotimes', 'doto', - 'double', 'down', 'drop', 'drop-while', 'edit', 'end?', 'ensure', - 'eval', 'every?', 'false?', 'ffirst', 'file-seq', 'filter', 'find', - 'find-doc', 'find-ns', 'find-var', 'first', 'float', 'flush', 'for', - 'fnseq', 'frest', 'gensym', 'get-proxy-class', 'get', - 'hash-map', 'hash-set', 'identical?', 'identity', 'if-let', 'import', - 'in-ns', 'inc', 'index', 'insert-child', 'insert-left', 'insert-right', - 'inspect-table', 'inspect-tree', 'instance?', 'int', 'interleave', - 'intersection', 'into', 'into-array', 'iterate', 'join', 'key', 'keys', - 'keyword', 'keyword?', 'last', 'lazy-cat', 'lazy-cons', 'left', - 'lefts', 'line-seq', 'list*', 'list', 'load', 'load-file', - 'locking', 'long', 'loop', 'macroexpand', 'macroexpand-1', - 'make-array', 'make-node', 'map', 'map-invert', 'map?', 'mapcat', - 'max', 'max-key', 'memfn', 'merge', 'merge-with', 'meta', 'min', - 'min-key', 'name', 'namespace', 'neg?', 'new', 'newline', 'next', - 'nil?', 'node', 'not', 'not-any?', 'not-every?', 'not=', 'ns-imports', - 'ns-interns', 'ns-map', 'ns-name', 'ns-publics', 'ns-refers', - 'ns-resolve', 'ns-unmap', 'nth', 'nthrest', 'or', 'parse', 'partial', - 'path', 'peek', 'pop', 'pos?', 'pr', 'pr-str', 'print', 'print-str', - 'println', 'println-str', 'prn', 'prn-str', 'project', 'proxy', - 'proxy-mappings', 'quot', 'rand', 'rand-int', 'range', 're-find', - 're-groups', 're-matcher', 're-matches', 're-pattern', 're-seq', - 'read', 'read-line', 'reduce', 'ref', 'ref-set', 'refer', 'rem', - 'remove', 'remove-method', 'remove-ns', 'rename', 'rename-keys', - 'repeat', 'replace', 'replicate', 'resolve', 'rest', 'resultset-seq', - 'reverse', 'rfirst', 'right', 'rights', 'root', 'rrest', 'rseq', - 'second', 'select', 'select-keys', 'send', 'send-off', 'seq', - 'seq-zip', 'seq?', 'set', 'short', 'slurp', 'some', 'sort', - 'sort-by', 'sorted-map', 'sorted-map-by', 'sorted-set', - 'special-symbol?', 'split-at', 'split-with', 'str', 'string?', - 'struct', 'struct-map', 'subs', 'subvec', 'symbol', 'symbol?', - 'sync', 'take', 'take-nth', 'take-while', 'test', 'time', 'to-array', - 'to-array-2d', 'tree-seq', 'true?', 'union', 'up', 'update-proxy', - 'val', 'vals', 'var-get', 'var-set', 'var?', 'vector', 'vector-zip', - 'vector?', 'when', 'when-first', 'when-let', 'when-not', - 'with-local-vars', 'with-meta', 'with-open', 'with-out-str', - 'xml-seq', 'xml-zip', 'zero?', 'zipmap', 'zipper') - - # valid names for identifiers - # well, names can only not consist fully of numbers - # but this should be good enough for now - - # TODO / should divide keywords/symbols into namespace/rest - # but that's hard, so just pretend / is part of the name - valid_name = r'(?!#)[\w!$%*+<=>?/.#|-]+' - - tokens = { - 'root': [ - # the comments - always starting with semicolon - # and going to the end of the line - (r';.*$', Comment.Single), - - # whitespaces - usually not relevant - (r'[,\s]+', Text), - - # numbers - (r'-?\d+\.\d+', Number.Float), - (r'-?\d+', Number.Integer), - (r'0x-?[abcdef\d]+', Number.Hex), - - # strings, symbols and characters - (r'"(\\\\|\\"|[^"])*"', String), - (r"'" + valid_name, String.Symbol), - (r"\\(.|[a-z]+)", String.Char), - - # keywords - (r'::?#?' + valid_name, String.Symbol), - - # special operators - (r'~@|[`\'#^~&@]', Operator), - - # highlight the special forms - (words(special_forms, suffix=' '), Keyword), - - # Technically, only the special forms are 'keywords'. The problem - # is that only treating them as keywords means that things like - # 'defn' and 'ns' need to be highlighted as builtins. This is ugly - # and weird for most styles. So, as a compromise we're going to - # highlight them as Keyword.Declarations. - (words(declarations, suffix=' '), Keyword.Declaration), - - # highlight the builtins - (words(builtins, suffix=' '), Name.Builtin), - - # the remaining functions - (r'(?<=\()' + valid_name, Name.Function), - - # find the remaining variables - (valid_name, Name.Variable), - - # Clojure accepts vector notation - (r'(\[|\])', Punctuation), - - # Clojure accepts map notation - (r'(\{|\})', Punctuation), - - # the famous parentheses! - (r'(\(|\))', Punctuation), - ], - } - - -class ClojureScriptLexer(ClojureLexer): - """ - Lexer for `ClojureScript `_ - source code. - - .. versionadded:: 2.0 - """ - name = 'ClojureScript' - aliases = ['clojurescript', 'cljs'] - filenames = ['*.cljs'] - mimetypes = ['text/x-clojurescript', 'application/x-clojurescript'] - - -class TeaLangLexer(RegexLexer): - """ - For `Tea `_ source code. Only used within a - TeaTemplateLexer. - - .. versionadded:: 1.5 - """ - - flags = re.MULTILINE | re.DOTALL - - tokens = { - 'root': [ - # method names - (r'^(\s*(?:[a-zA-Z_][\w\.\[\]]*\s+)+?)' # return arguments - r'([a-zA-Z_]\w*)' # method name - r'(\s*)(\()', # signature start - bygroups(using(this), Name.Function, Text, Operator)), - (r'[^\S\n]+', Text), - (r'//.*?\n', Comment.Single), - (r'/\*.*?\*/', Comment.Multiline), - (r'@[a-zA-Z_][\w\.]*', Name.Decorator), - (r'(and|break|else|foreach|if|in|not|or|reverse)\b', - Keyword), - (r'(as|call|define)\b', Keyword.Declaration), - (r'(true|false|null)\b', Keyword.Constant), - (r'(template)(\s+)', bygroups(Keyword.Declaration, Text), 'template'), - (r'(import)(\s+)', bygroups(Keyword.Namespace, Text), 'import'), - (r'"(\\\\|\\"|[^"])*"', String), - (r'\'(\\\\|\\\'|[^\'])*\'', String), - (r'(\.)([a-zA-Z_]\w*)', bygroups(Operator, Name.Attribute)), - (r'[a-zA-Z_]\w*:', Name.Label), - (r'[a-zA-Z_\$]\w*', Name), - (r'(isa|[.]{3}|[.]{2}|[=#!<>+-/%&;,.\*\\\(\)\[\]\{\}])', Operator), - (r'[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?', Number.Float), - (r'0x[0-9a-fA-F]+', Number.Hex), - (r'[0-9]+L?', Number.Integer), - (r'\n', Text) - ], - 'template': [ - (r'[a-zA-Z_]\w*', Name.Class, '#pop') - ], - 'import': [ - (r'[\w.]+\*?', Name.Namespace, '#pop') - ], - } - - -class CeylonLexer(RegexLexer): - """ - For `Ceylon `_ source code. - - .. versionadded:: 1.6 - """ - - name = 'Ceylon' - aliases = ['ceylon'] - filenames = ['*.ceylon'] - mimetypes = ['text/x-ceylon'] - - flags = re.MULTILINE | re.DOTALL - - #: optional Comment or Whitespace - _ws = r'(?:\s|//.*?\n|/[*].*?[*]/)+' - - tokens = { - 'root': [ - # method names - (r'^(\s*(?:[a-zA-Z_][\w.\[\]]*\s+)+?)' # return arguments - r'([a-zA-Z_]\w*)' # method name - r'(\s*)(\()', # signature start - bygroups(using(this), Name.Function, Text, Operator)), - (r'[^\S\n]+', Text), - (r'//.*?\n', Comment.Single), - (r'/\*', Comment.Multiline, 'comment'), - (r'(shared|abstract|formal|default|actual|variable|deprecated|small|' - r'late|literal|doc|by|see|throws|optional|license|tagged|final|native|' - r'annotation|sealed)\b', Name.Decorator), - (r'(break|case|catch|continue|else|finally|for|in|' - r'if|return|switch|this|throw|try|while|is|exists|dynamic|' - r'nonempty|then|outer|assert|let)\b', Keyword), - (r'(abstracts|extends|satisfies|' - r'super|given|of|out|assign)\b', Keyword.Declaration), - (r'(function|value|void|new)\b', - Keyword.Type), - (r'(assembly|module|package)(\s+)', bygroups(Keyword.Namespace, Text)), - (r'(true|false|null)\b', Keyword.Constant), - (r'(class|interface|object|alias)(\s+)', - bygroups(Keyword.Declaration, Text), 'class'), - (r'(import)(\s+)', bygroups(Keyword.Namespace, Text), 'import'), - (r'"(\\\\|\\"|[^"])*"', String), - (r"'\\.'|'[^\\]'|'\\\{#[0-9a-fA-F]{4}\}'", String.Char), - (r'".*``.*``.*"', String.Interpol), - (r'(\.)([a-z_]\w*)', - bygroups(Operator, Name.Attribute)), - (r'[a-zA-Z_]\w*:', Name.Label), - (r'[a-zA-Z_]\w*', Name), - (r'[~^*!%&\[\](){}<>|+=:;,./?-]', Operator), - (r'\d{1,3}(_\d{3})+\.\d{1,3}(_\d{3})+[kMGTPmunpf]?', Number.Float), - (r'\d{1,3}(_\d{3})+\.[0-9]+([eE][+-]?[0-9]+)?[kMGTPmunpf]?', - Number.Float), - (r'[0-9][0-9]*\.\d{1,3}(_\d{3})+[kMGTPmunpf]?', Number.Float), - (r'[0-9][0-9]*\.[0-9]+([eE][+-]?[0-9]+)?[kMGTPmunpf]?', - Number.Float), - (r'#([0-9a-fA-F]{4})(_[0-9a-fA-F]{4})+', Number.Hex), - (r'#[0-9a-fA-F]+', Number.Hex), - (r'\$([01]{4})(_[01]{4})+', Number.Bin), - (r'\$[01]+', Number.Bin), - (r'\d{1,3}(_\d{3})+[kMGTP]?', Number.Integer), - (r'[0-9]+[kMGTP]?', Number.Integer), - (r'\n', Text) - ], - 'class': [ - (r'[A-Za-z_]\w*', Name.Class, '#pop') - ], - 'import': [ - (r'[a-z][\w.]*', - Name.Namespace, '#pop') - ], - 'comment': [ - (r'[^*/]', Comment.Multiline), - (r'/\*', Comment.Multiline, '#push'), - (r'\*/', Comment.Multiline, '#pop'), - (r'[*/]', Comment.Multiline) - ], - } - - -class KotlinLexer(RegexLexer): - """ - For `Kotlin `_ - source code. - - .. versionadded:: 1.5 - """ - - name = 'Kotlin' - aliases = ['kotlin'] - filenames = ['*.kt'] - mimetypes = ['text/x-kotlin'] - - flags = re.MULTILINE | re.DOTALL | re.UNICODE - - kt_name = ('@?[_' + uni.combine('Lu', 'Ll', 'Lt', 'Lm', 'Nl') + ']' + - '[' + uni.combine('Lu', 'Ll', 'Lt', 'Lm', 'Nl', 'Nd', 'Pc', 'Cf', - 'Mn', 'Mc') + ']*') - - kt_space_name = ('@?[_' + uni.combine('Lu', 'Ll', 'Lt', 'Lm', 'Nl') + ']' + - '[' + uni.combine('Lu', 'Ll', 'Lt', 'Lm', 'Nl', 'Nd', 'Pc', 'Cf', - 'Mn', 'Mc', 'Zs') + ',-]*') - - kt_id = '(' + kt_name + '|`' + kt_space_name + '`)' - - tokens = { - 'root': [ - (r'^\s*\[.*?\]', Name.Attribute), - (r'[^\S\n]+', Text), - (r'\s+', Text), - (r'\\\n', Text), # line continuation - (r'//.*?\n', Comment.Single), - (r'/[*].*?[*]/', Comment.Multiline), - (r'""".*?"""', String), - (r'\n', Text), - (r'::|!!|\?[:.]', Operator), - (r'[~!%^&*()+=|\[\]:;,.<>/?-]', Punctuation), - (r'[{}]', Punctuation), - (r'@"(""|[^"])*"', String), - (r'"(\\\\|\\"|[^"\n])*["\n]', String), - (r"'\\.'|'[^\\]'", String.Char), - (r"[0-9](\.[0-9]*)?([eE][+-][0-9]+)?[flFL]?|" - r"0[xX][0-9a-fA-F]+[Ll]?", Number), - (r'(object)(\s+)(:)(\s+)', bygroups(Keyword, Text, Punctuation, Text), 'class'), - (r'(companion)(\s+)(object)', bygroups(Keyword, Text, Keyword)), - (r'(class|interface|object)(\s+)', bygroups(Keyword, Text), 'class'), - (r'(package|import)(\s+)', bygroups(Keyword, Text), 'package'), - (r'(val|var)(\s+)([(])', bygroups(Keyword, Text, Punctuation), 'property_dec'), - (r'(val|var)(\s+)', bygroups(Keyword, Text), 'property'), - (r'(fun)(\s+)', bygroups(Keyword, Text), 'function'), - (r'(inline fun)(\s+)', bygroups(Keyword, Text), 'function'), - (r'(abstract|annotation|as|break|by|catch|class|companion|const|' - r'constructor|continue|crossinline|data|do|dynamic|else|enum|' - r'external|false|final|finally|for|fun|get|if|import|in|infix|' - r'inline|inner|interface|internal|is|lateinit|noinline|null|' - r'object|open|operator|out|override|package|private|protected|' - r'public|reified|return|sealed|set|super|tailrec|this|throw|' - r'true|try|val|var|vararg|when|where|while)\b', Keyword), - (kt_id, Name), - ], - 'package': [ - (r'\S+', Name.Namespace, '#pop') - ], - 'class': [ - (kt_id, Name.Class, '#pop') - ], - 'property': [ - (kt_id, Name.Property, '#pop') - ], - 'property_dec': [ - (r'(,)(\s*)', bygroups(Punctuation, Text)), - (r'(:)(\s*)', bygroups(Punctuation, Text)), - (r'<', Punctuation, 'generic'), - (r'([)])', Punctuation, '#pop'), - (kt_id, Name.Property) - ], - 'function': [ - (r'<', Punctuation, 'generic'), - (r''+kt_id+'([.])'+kt_id, bygroups(Name.Class, Punctuation, Name.Function), '#pop'), - (kt_id, Name.Function, '#pop') - ], - 'generic': [ - (r'(>)(\s*)', bygroups(Punctuation, Text), '#pop'), - (r':',Punctuation), - (r'(reified|out|in)\b', Keyword), - (r',',Text), - (r'\s+',Text), - (kt_id,Name) - ] - } - - -class XtendLexer(RegexLexer): - """ - For `Xtend `_ source code. - - .. versionadded:: 1.6 - """ - - name = 'Xtend' - aliases = ['xtend'] - filenames = ['*.xtend'] - mimetypes = ['text/x-xtend'] - - flags = re.MULTILINE | re.DOTALL - - tokens = { - 'root': [ - # method names - (r'^(\s*(?:[a-zA-Z_][\w.\[\]]*\s+)+?)' # return arguments - r'([a-zA-Z_$][\w$]*)' # method name - r'(\s*)(\()', # signature start - bygroups(using(this), Name.Function, Text, Operator)), - (r'[^\S\n]+', Text), - (r'//.*?\n', Comment.Single), - (r'/\*.*?\*/', Comment.Multiline), - (r'@[a-zA-Z_][\w.]*', Name.Decorator), - (r'(assert|break|case|catch|continue|default|do|else|finally|for|' - r'if|goto|instanceof|new|return|switch|this|throw|try|while|IF|' - r'ELSE|ELSEIF|ENDIF|FOR|ENDFOR|SEPARATOR|BEFORE|AFTER)\b', - Keyword), - (r'(def|abstract|const|enum|extends|final|implements|native|private|' - r'protected|public|static|strictfp|super|synchronized|throws|' - r'transient|volatile)\b', Keyword.Declaration), - (r'(boolean|byte|char|double|float|int|long|short|void)\b', - Keyword.Type), - (r'(package)(\s+)', bygroups(Keyword.Namespace, Text)), - (r'(true|false|null)\b', Keyword.Constant), - (r'(class|interface)(\s+)', bygroups(Keyword.Declaration, Text), - 'class'), - (r'(import)(\s+)', bygroups(Keyword.Namespace, Text), 'import'), - (r"(''')", String, 'template'), - (u'(\u00BB)', String, 'template'), - (r'"(\\\\|\\"|[^"])*"', String), - (r"'(\\\\|\\'|[^'])*'", String), - (r'[a-zA-Z_]\w*:', Name.Label), - (r'[a-zA-Z_$]\w*', Name), - (r'[~^*!%&\[\](){}<>\|+=:;,./?-]', Operator), - (r'[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?', Number.Float), - (r'0x[0-9a-fA-F]+', Number.Hex), - (r'[0-9]+L?', Number.Integer), - (r'\n', Text) - ], - 'class': [ - (r'[a-zA-Z_]\w*', Name.Class, '#pop') - ], - 'import': [ - (r'[\w.]+\*?', Name.Namespace, '#pop') - ], - 'template': [ - (r"'''", String, '#pop'), - (u'\u00AB', String, '#pop'), - (r'.', String) - ], - } - - -class PigLexer(RegexLexer): - """ - For `Pig Latin `_ source code. - - .. versionadded:: 2.0 - """ - - name = 'Pig' - aliases = ['pig'] - filenames = ['*.pig'] - mimetypes = ['text/x-pig'] - - flags = re.MULTILINE | re.IGNORECASE - - tokens = { - 'root': [ - (r'\s+', Text), - (r'--.*', Comment), - (r'/\*[\w\W]*?\*/', Comment.Multiline), - (r'\\\n', Text), - (r'\\', Text), - (r'\'(?:\\[ntbrf\\\']|\\u[0-9a-f]{4}|[^\'\\\n\r])*\'', String), - include('keywords'), - include('types'), - include('builtins'), - include('punct'), - include('operators'), - (r'[0-9]*\.[0-9]+(e[0-9]+)?[fd]?', Number.Float), - (r'0x[0-9a-f]+', Number.Hex), - (r'[0-9]+L?', Number.Integer), - (r'\n', Text), - (r'([a-z_]\w*)(\s*)(\()', - bygroups(Name.Function, Text, Punctuation)), - (r'[()#:]', Text), - (r'[^(:#\'")\s]+', Text), - (r'\S+\s+', Text) # TODO: make tests pass without \s+ - ], - 'keywords': [ - (r'(assert|and|any|all|arrange|as|asc|bag|by|cache|CASE|cat|cd|cp|' - r'%declare|%default|define|dense|desc|describe|distinct|du|dump|' - r'eval|exex|explain|filter|flatten|foreach|full|generate|group|' - r'help|if|illustrate|import|inner|input|into|is|join|kill|left|' - r'limit|load|ls|map|matches|mkdir|mv|not|null|onschema|or|order|' - r'outer|output|parallel|pig|pwd|quit|register|returns|right|rm|' - r'rmf|rollup|run|sample|set|ship|split|stderr|stdin|stdout|store|' - r'stream|through|union|using|void)\b', Keyword) - ], - 'builtins': [ - (r'(AVG|BinStorage|cogroup|CONCAT|copyFromLocal|copyToLocal|COUNT|' - r'cross|DIFF|MAX|MIN|PigDump|PigStorage|SIZE|SUM|TextLoader|' - r'TOKENIZE)\b', Name.Builtin) - ], - 'types': [ - (r'(bytearray|BIGINTEGER|BIGDECIMAL|chararray|datetime|double|float|' - r'int|long|tuple)\b', Keyword.Type) - ], - 'punct': [ - (r'[;(){}\[\]]', Punctuation), - ], - 'operators': [ - (r'[#=,./%+\-?]', Operator), - (r'(eq|gt|lt|gte|lte|neq|matches)\b', Operator), - (r'(==|<=|<|>=|>|!=)', Operator), - ], - } - - -class GoloLexer(RegexLexer): - """ - For `Golo `_ source code. - - .. versionadded:: 2.0 - """ - - name = 'Golo' - filenames = ['*.golo'] - aliases = ['golo'] - - tokens = { - 'root': [ - (r'[^\S\n]+', Text), - - (r'#.*$', Comment), - - (r'(\^|\.\.\.|:|\?:|->|==|!=|=|\+|\*|%|/|<=|<|>=|>|=|\.)', - Operator), - (r'(?<=[^-])(-)(?=[^-])', Operator), - - (r'(?<=[^`])(is|isnt|and|or|not|oftype|in|orIfNull)\b', Operator.Word), - (r'[]{}|(),[]', Punctuation), - - (r'(module|import)(\s+)', - bygroups(Keyword.Namespace, Text), - 'modname'), - (r'\b([a-zA-Z_][\w$.]*)(::)', bygroups(Name.Namespace, Punctuation)), - (r'\b([a-zA-Z_][\w$]*(?:\.[a-zA-Z_][\w$]*)+)\b', Name.Namespace), - - (r'(let|var)(\s+)', - bygroups(Keyword.Declaration, Text), - 'varname'), - (r'(struct)(\s+)', - bygroups(Keyword.Declaration, Text), - 'structname'), - (r'(function)(\s+)', - bygroups(Keyword.Declaration, Text), - 'funcname'), - - (r'(null|true|false)\b', Keyword.Constant), - (r'(augment|pimp' - r'|if|else|case|match|return' - r'|case|when|then|otherwise' - r'|while|for|foreach' - r'|try|catch|finally|throw' - r'|local' - r'|continue|break)\b', Keyword), - - (r'(map|array|list|set|vector|tuple)(\[)', - bygroups(Name.Builtin, Punctuation)), - (r'(print|println|readln|raise|fun' - r'|asInterfaceInstance)\b', Name.Builtin), - (r'(`?[a-zA-Z_][\w$]*)(\()', - bygroups(Name.Function, Punctuation)), - - (r'-?[\d_]*\.[\d_]*([eE][+-]?\d[\d_]*)?F?', Number.Float), - (r'0[0-7]+j?', Number.Oct), - (r'0[xX][a-fA-F0-9]+', Number.Hex), - (r'-?\d[\d_]*L', Number.Integer.Long), - (r'-?\d[\d_]*', Number.Integer), - - (r'`?[a-zA-Z_][\w$]*', Name), - (r'@[a-zA-Z_][\w$.]*', Name.Decorator), - - (r'"""', String, combined('stringescape', 'triplestring')), - (r'"', String, combined('stringescape', 'doublestring')), - (r"'", String, combined('stringescape', 'singlestring')), - (r'----((.|\n)*?)----', String.Doc) - - ], - - 'funcname': [ - (r'`?[a-zA-Z_][\w$]*', Name.Function, '#pop'), - ], - 'modname': [ - (r'[a-zA-Z_][\w$.]*\*?', Name.Namespace, '#pop') - ], - 'structname': [ - (r'`?[\w.]+\*?', Name.Class, '#pop') - ], - 'varname': [ - (r'`?[a-zA-Z_][\w$]*', Name.Variable, '#pop'), - ], - 'string': [ - (r'[^\\\'"\n]+', String), - (r'[\'"\\]', String) - ], - 'stringescape': [ - (r'\\([\\abfnrtv"\']|\n|N\{.*?\}|u[a-fA-F0-9]{4}|' - r'U[a-fA-F0-9]{8}|x[a-fA-F0-9]{2}|[0-7]{1,3})', String.Escape) - ], - 'triplestring': [ - (r'"""', String, '#pop'), - include('string'), - (r'\n', String), - ], - 'doublestring': [ - (r'"', String.Double, '#pop'), - include('string'), - ], - 'singlestring': [ - (r"'", String, '#pop'), - include('string'), - ], - 'operators': [ - (r'[#=,./%+\-?]', Operator), - (r'(eq|gt|lt|gte|lte|neq|matches)\b', Operator), - (r'(==|<=|<|>=|>|!=)', Operator), - ], - } - - -class JasminLexer(RegexLexer): - """ - For `Jasmin `_ assembly code. - - .. versionadded:: 2.0 - """ - - name = 'Jasmin' - aliases = ['jasmin', 'jasminxt'] - filenames = ['*.j'] - - _whitespace = r' \n\t\r' - _ws = r'(?:[%s]+)' % _whitespace - _separator = r'%s:=' % _whitespace - _break = r'(?=[%s]|$)' % _separator - _name = r'[^%s]+' % _separator - _unqualified_name = r'(?:[^%s.;\[/]+)' % _separator - - tokens = { - 'default': [ - (r'\n', Text, '#pop'), - (r"'", String.Single, ('#pop', 'quote')), - (r'"', String.Double, 'string'), - (r'=', Punctuation), - (r':', Punctuation, 'label'), - (_ws, Text), - (r';.*', Comment.Single), - (r'(\$[-+])?0x-?[\da-fA-F]+%s' % _break, Number.Hex), - (r'(\$[-+]|\+)?-?\d+%s' % _break, Number.Integer), - (r'-?(\d+\.\d*|\.\d+)([eE][-+]?\d+)?[fFdD]?' - r'[\x00-\x08\x0b\x0c\x0e-\x1f]*%s' % _break, Number.Float), - (r'\$%s' % _name, Name.Variable), - - # Directives - (r'\.annotation%s' % _break, Keyword.Reserved, 'annotation'), - (r'(\.attribute|\.bytecode|\.debug|\.deprecated|\.enclosing|' - r'\.interface|\.line|\.signature|\.source|\.stack|\.var|abstract|' - r'annotation|bridge|class|default|enum|field|final|fpstrict|' - r'interface|native|private|protected|public|signature|static|' - r'synchronized|synthetic|transient|varargs|volatile)%s' % _break, - Keyword.Reserved), - (r'\.catch%s' % _break, Keyword.Reserved, 'caught-exception'), - (r'(\.class|\.implements|\.inner|\.super|inner|invisible|' - r'invisibleparam|outer|visible|visibleparam)%s' % _break, - Keyword.Reserved, 'class/convert-dots'), - (r'\.field%s' % _break, Keyword.Reserved, - ('descriptor/convert-dots', 'field')), - (r'(\.end|\.limit|use)%s' % _break, Keyword.Reserved, - 'no-verification'), - (r'\.method%s' % _break, Keyword.Reserved, 'method'), - (r'\.set%s' % _break, Keyword.Reserved, 'var'), - (r'\.throws%s' % _break, Keyword.Reserved, 'exception'), - (r'(from|offset|to|using)%s' % _break, Keyword.Reserved, 'label'), - (r'is%s' % _break, Keyword.Reserved, - ('descriptor/convert-dots', 'var')), - (r'(locals|stack)%s' % _break, Keyword.Reserved, 'verification'), - (r'method%s' % _break, Keyword.Reserved, 'enclosing-method'), - - # Instructions - (words(( - 'aaload', 'aastore', 'aconst_null', 'aload', 'aload_0', 'aload_1', 'aload_2', - 'aload_3', 'aload_w', 'areturn', 'arraylength', 'astore', 'astore_0', 'astore_1', - 'astore_2', 'astore_3', 'astore_w', 'athrow', 'baload', 'bastore', 'bipush', - 'breakpoint', 'caload', 'castore', 'd2f', 'd2i', 'd2l', 'dadd', 'daload', 'dastore', - 'dcmpg', 'dcmpl', 'dconst_0', 'dconst_1', 'ddiv', 'dload', 'dload_0', 'dload_1', - 'dload_2', 'dload_3', 'dload_w', 'dmul', 'dneg', 'drem', 'dreturn', 'dstore', 'dstore_0', - 'dstore_1', 'dstore_2', 'dstore_3', 'dstore_w', 'dsub', 'dup', 'dup2', 'dup2_x1', - 'dup2_x2', 'dup_x1', 'dup_x2', 'f2d', 'f2i', 'f2l', 'fadd', 'faload', 'fastore', 'fcmpg', - 'fcmpl', 'fconst_0', 'fconst_1', 'fconst_2', 'fdiv', 'fload', 'fload_0', 'fload_1', - 'fload_2', 'fload_3', 'fload_w', 'fmul', 'fneg', 'frem', 'freturn', 'fstore', 'fstore_0', - 'fstore_1', 'fstore_2', 'fstore_3', 'fstore_w', 'fsub', 'i2b', 'i2c', 'i2d', 'i2f', 'i2l', - 'i2s', 'iadd', 'iaload', 'iand', 'iastore', 'iconst_0', 'iconst_1', 'iconst_2', - 'iconst_3', 'iconst_4', 'iconst_5', 'iconst_m1', 'idiv', 'iinc', 'iinc_w', 'iload', - 'iload_0', 'iload_1', 'iload_2', 'iload_3', 'iload_w', 'imul', 'ineg', 'int2byte', - 'int2char', 'int2short', 'ior', 'irem', 'ireturn', 'ishl', 'ishr', 'istore', 'istore_0', - 'istore_1', 'istore_2', 'istore_3', 'istore_w', 'isub', 'iushr', 'ixor', 'l2d', 'l2f', - 'l2i', 'ladd', 'laload', 'land', 'lastore', 'lcmp', 'lconst_0', 'lconst_1', 'ldc2_w', - 'ldiv', 'lload', 'lload_0', 'lload_1', 'lload_2', 'lload_3', 'lload_w', 'lmul', 'lneg', - 'lookupswitch', 'lor', 'lrem', 'lreturn', 'lshl', 'lshr', 'lstore', 'lstore_0', - 'lstore_1', 'lstore_2', 'lstore_3', 'lstore_w', 'lsub', 'lushr', 'lxor', - 'monitorenter', 'monitorexit', 'nop', 'pop', 'pop2', 'ret', 'ret_w', 'return', 'saload', - 'sastore', 'sipush', 'swap'), suffix=_break), Keyword.Reserved), - (r'(anewarray|checkcast|instanceof|ldc|ldc_w|new)%s' % _break, - Keyword.Reserved, 'class/no-dots'), - (r'invoke(dynamic|interface|nonvirtual|special|' - r'static|virtual)%s' % _break, Keyword.Reserved, - 'invocation'), - (r'(getfield|putfield)%s' % _break, Keyword.Reserved, - ('descriptor/no-dots', 'field')), - (r'(getstatic|putstatic)%s' % _break, Keyword.Reserved, - ('descriptor/no-dots', 'static')), - (words(( - 'goto', 'goto_w', 'if_acmpeq', 'if_acmpne', 'if_icmpeq', - 'if_icmpge', 'if_icmpgt', 'if_icmple', 'if_icmplt', 'if_icmpne', - 'ifeq', 'ifge', 'ifgt', 'ifle', 'iflt', 'ifne', 'ifnonnull', - 'ifnull', 'jsr', 'jsr_w'), suffix=_break), - Keyword.Reserved, 'label'), - (r'(multianewarray|newarray)%s' % _break, Keyword.Reserved, - 'descriptor/convert-dots'), - (r'tableswitch%s' % _break, Keyword.Reserved, 'table') - ], - 'quote': [ - (r"'", String.Single, '#pop'), - (r'\\u[\da-fA-F]{4}', String.Escape), - (r"[^'\\]+", String.Single) - ], - 'string': [ - (r'"', String.Double, '#pop'), - (r'\\([nrtfb"\'\\]|u[\da-fA-F]{4}|[0-3]?[0-7]{1,2})', - String.Escape), - (r'[^"\\]+', String.Double) - ], - 'root': [ - (r'\n+', Text), - (r"'", String.Single, 'quote'), - include('default'), - (r'(%s)([ \t\r]*)(:)' % _name, - bygroups(Name.Label, Text, Punctuation)), - (_name, String.Other) - ], - 'annotation': [ - (r'\n', Text, ('#pop', 'annotation-body')), - (r'default%s' % _break, Keyword.Reserved, - ('#pop', 'annotation-default')), - include('default') - ], - 'annotation-body': [ - (r'\n+', Text), - (r'\.end%s' % _break, Keyword.Reserved, '#pop'), - include('default'), - (_name, String.Other, ('annotation-items', 'descriptor/no-dots')) - ], - 'annotation-default': [ - (r'\n+', Text), - (r'\.end%s' % _break, Keyword.Reserved, '#pop'), - include('default'), - default(('annotation-items', 'descriptor/no-dots')) - ], - 'annotation-items': [ - (r"'", String.Single, 'quote'), - include('default'), - (_name, String.Other) - ], - 'caught-exception': [ - (r'all%s' % _break, Keyword, '#pop'), - include('exception') - ], - 'class/convert-dots': [ - include('default'), - (r'(L)((?:%s[/.])*)(%s)(;)' % (_unqualified_name, _name), - bygroups(Keyword.Type, Name.Namespace, Name.Class, Punctuation), - '#pop'), - (r'((?:%s[/.])*)(%s)' % (_unqualified_name, _name), - bygroups(Name.Namespace, Name.Class), '#pop') - ], - 'class/no-dots': [ - include('default'), - (r'\[+', Punctuation, ('#pop', 'descriptor/no-dots')), - (r'(L)((?:%s/)*)(%s)(;)' % (_unqualified_name, _name), - bygroups(Keyword.Type, Name.Namespace, Name.Class, Punctuation), - '#pop'), - (r'((?:%s/)*)(%s)' % (_unqualified_name, _name), - bygroups(Name.Namespace, Name.Class), '#pop') - ], - 'descriptor/convert-dots': [ - include('default'), - (r'\[+', Punctuation), - (r'(L)((?:%s[/.])*)(%s?)(;)' % (_unqualified_name, _name), - bygroups(Keyword.Type, Name.Namespace, Name.Class, Punctuation), - '#pop'), - (r'[^%s\[)L]+' % _separator, Keyword.Type, '#pop'), - default('#pop') - ], - 'descriptor/no-dots': [ - include('default'), - (r'\[+', Punctuation), - (r'(L)((?:%s/)*)(%s)(;)' % (_unqualified_name, _name), - bygroups(Keyword.Type, Name.Namespace, Name.Class, Punctuation), - '#pop'), - (r'[^%s\[)L]+' % _separator, Keyword.Type, '#pop'), - default('#pop') - ], - 'descriptors/convert-dots': [ - (r'\)', Punctuation, '#pop'), - default('descriptor/convert-dots') - ], - 'enclosing-method': [ - (_ws, Text), - (r'(?=[^%s]*\()' % _separator, Text, ('#pop', 'invocation')), - default(('#pop', 'class/convert-dots')) - ], - 'exception': [ - include('default'), - (r'((?:%s[/.])*)(%s)' % (_unqualified_name, _name), - bygroups(Name.Namespace, Name.Exception), '#pop') - ], - 'field': [ - (r'static%s' % _break, Keyword.Reserved, ('#pop', 'static')), - include('default'), - (r'((?:%s[/.](?=[^%s]*[/.]))*)(%s[/.])?(%s)' % - (_unqualified_name, _separator, _unqualified_name, _name), - bygroups(Name.Namespace, Name.Class, Name.Variable.Instance), - '#pop') - ], - 'invocation': [ - include('default'), - (r'((?:%s[/.](?=[^%s(]*[/.]))*)(%s[/.])?(%s)(\()' % - (_unqualified_name, _separator, _unqualified_name, _name), - bygroups(Name.Namespace, Name.Class, Name.Function, Punctuation), - ('#pop', 'descriptor/convert-dots', 'descriptors/convert-dots', - 'descriptor/convert-dots')) - ], - 'label': [ - include('default'), - (_name, Name.Label, '#pop') - ], - 'method': [ - include('default'), - (r'(%s)(\()' % _name, bygroups(Name.Function, Punctuation), - ('#pop', 'descriptor/convert-dots', 'descriptors/convert-dots', - 'descriptor/convert-dots')) - ], - 'no-verification': [ - (r'(locals|method|stack)%s' % _break, Keyword.Reserved, '#pop'), - include('default') - ], - 'static': [ - include('default'), - (r'((?:%s[/.](?=[^%s]*[/.]))*)(%s[/.])?(%s)' % - (_unqualified_name, _separator, _unqualified_name, _name), - bygroups(Name.Namespace, Name.Class, Name.Variable.Class), '#pop') - ], - 'table': [ - (r'\n+', Text), - (r'default%s' % _break, Keyword.Reserved, '#pop'), - include('default'), - (_name, Name.Label) - ], - 'var': [ - include('default'), - (_name, Name.Variable, '#pop') - ], - 'verification': [ - include('default'), - (r'(Double|Float|Integer|Long|Null|Top|UninitializedThis)%s' % - _break, Keyword, '#pop'), - (r'Object%s' % _break, Keyword, ('#pop', 'class/no-dots')), - (r'Uninitialized%s' % _break, Keyword, ('#pop', 'label')) - ] - } - - def analyse_text(text): - score = 0 - if re.search(r'^\s*\.class\s', text, re.MULTILINE): - score += 0.5 - if re.search(r'^\s*[a-z]+_[a-z]+\b', text, re.MULTILINE): - score += 0.3 - if re.search(r'^\s*\.(attribute|bytecode|debug|deprecated|enclosing|' - r'inner|interface|limit|set|signature|stack)\b', text, - re.MULTILINE): - score += 0.6 - return score - - -class SarlLexer(RegexLexer): - """ - For `SARL `_ source code. - - .. versionadded:: 2.4 - """ - - name = 'SARL' - aliases = ['sarl'] - filenames = ['*.sarl'] - mimetypes = ['text/x-sarl'] - - flags = re.MULTILINE | re.DOTALL - - tokens = { - 'root': [ - # method names - (r'^(\s*(?:[a-zA-Z_][\w.\[\]]*\s+)+?)' # return arguments - r'([a-zA-Z_$][\w$]*)' # method name - r'(\s*)(\()', # signature start - bygroups(using(this), Name.Function, Text, Operator)), - (r'[^\S\n]+', Text), - (r'//.*?\n', Comment.Single), - (r'/\*.*?\*/', Comment.Multiline), - (r'@[a-zA-Z_][\w.]*', Name.Decorator), - (r'(as|break|case|catch|default|do|else|extends|extension|finally|fires|for|if|implements|instanceof|new|on|requires|return|super|switch|throw|throws|try|typeof|uses|while|with)\b', - Keyword), - (r'(abstract|def|dispatch|final|native|override|private|protected|public|static|strictfp|synchronized|transient|val|var|volatile)\b', Keyword.Declaration), - (r'(boolean|byte|char|double|float|int|long|short|void)\b', - Keyword.Type), - (r'(package)(\s+)', bygroups(Keyword.Namespace, Text)), - (r'(false|it|null|occurrence|this|true|void)\b', Keyword.Constant), - (r'(agent|annotation|artifact|behavior|capacity|class|enum|event|interface|skill|space)(\s+)', bygroups(Keyword.Declaration, Text), - 'class'), - (r'(import)(\s+)', bygroups(Keyword.Namespace, Text), 'import'), - (r'"(\\\\|\\"|[^"])*"', String), - (r"'(\\\\|\\'|[^'])*'", String), - (r'[a-zA-Z_]\w*:', Name.Label), - (r'[a-zA-Z_$]\w*', Name), - (r'[~^*!%&\[\](){}<>\|+=:;,./?-]', Operator), - (r'[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?', Number.Float), - (r'0x[0-9a-fA-F]+', Number.Hex), - (r'[0-9]+L?', Number.Integer), - (r'\n', Text) - ], - 'class': [ - (r'[a-zA-Z_]\w*', Name.Class, '#pop') - ], - 'import': [ - (r'[\w.]+\*?', Name.Namespace, '#pop') - ], - } diff --git a/docs/docs_builder/lexer-fix/readme.md b/docs/docs_builder/lexer-fix/readme.md deleted file mode 100644 index 84775f81a2..0000000000 --- a/docs/docs_builder/lexer-fix/readme.md +++ /dev/null @@ -1,35 +0,0 @@ -# Pygments lexer - -We were getting a lot of warnings in the docs build, and people were unable to see the real warnings due to this. So we're on a mission -to sort all of these out. - -A lot of the errors were because the kotlin lexer in Pygments (the syntax highlighter that sphinx uses) didn't cope with a lot of the -kotlin syntax that we use. - -We have fixes for the kotlin lexer that we are trying to get checked into Pygments, but while this is taking place we need to maintain a -slightly hacked corda/docs-build docker image in which to build the docs. - -## Some notes on building and testing - -The sphinx/pygments brigade have delightfully decided that mercurial is a good idea. So broadly speaking, to build/test a fix: - - * checkout pygments from [here](https://bitbucket.org/birkenfeld/pygments-main/overview) - * copy the two python files in (might be worth diffing - they're based on 2.3.1 - nb the kotlin test is entirely new) - * build pygments whl file - - ``` - cd /path/to/pygments/ - python setup.py install - pip install wheel - wheel convert dist/Pygments-2.3.1.dev20190 # obviously use your version - cp Pygments-2.3.1.dev20190401-py27-none-any.whl /path/to/corda/docs/source/docs_builder/lexer-fix - ``` - * build the latest docker build (see docs readme) - - ``` - cd docs - docker build -t corda/docs-builder:latest -f docs_builder/lexer-fix/Dockerfile . - ``` - - * push the new image up to docker hub (nb you can also test by going to /opt/docs and running `./make-docsite.sh`) - diff --git a/docs/docs_builder/lexer-fix/test_kotlin.py b/docs/docs_builder/lexer-fix/test_kotlin.py deleted file mode 100644 index 36e9793a73..0000000000 --- a/docs/docs_builder/lexer-fix/test_kotlin.py +++ /dev/null @@ -1,131 +0,0 @@ -# -*- coding: utf-8 -*- -""" - Basic JavaLexer Test - ~~~~~~~~~~~~~~~~~~~~ - - :copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -import unittest - -from pygments.token import Text, Name, Operator, Keyword, Number, Punctuation, String -from pygments.lexers import KotlinLexer - -class KotlinTest(unittest.TestCase): - - def setUp(self): - self.lexer = KotlinLexer() - self.maxDiff = None - - def testCanCopeWithBackTickNamesInFunctions(self): - fragment = u'fun `wo bble`' - tokens = [ - (Keyword, u'fun'), - (Text, u' '), - (Name.Function, u'`wo bble`'), - (Text, u'\n') - ] - self.assertEqual(tokens, list(self.lexer.get_tokens(fragment))) - - def testCanCopeWithCommasAndDashesInBackTickNames(self): - fragment = u'fun `wo,-bble`' - tokens = [ - (Keyword, u'fun'), - (Text, u' '), - (Name.Function, u'`wo,-bble`'), - (Text, u'\n') - ] - self.assertEqual(tokens, list(self.lexer.get_tokens(fragment))) - - def testCanCopeWithDestructuring(self): - fragment = u'val (a, b) = ' - tokens = [ - (Keyword, u'val'), - (Text, u' '), - (Punctuation, u'('), - (Name.Property, u'a'), - (Punctuation, u','), - (Text, u' '), - (Name.Property, u'b'), - (Punctuation, u')'), - (Text, u' '), - (Punctuation, u'='), - (Text, u' '), - (Text, u'\n') - ] - self.assertEqual(tokens, list(self.lexer.get_tokens(fragment))) - - def testCanCopeGenericsInDestructuring(self): - fragment = u'val (a: List, b: Set) =' - tokens = [ - (Keyword, u'val'), - (Text, u' '), - (Punctuation, u'('), - (Name.Property, u'a'), - (Punctuation, u':'), - (Text, u' '), - (Name.Property, u'List'), - (Punctuation, u'<'), - (Name, u'Something'), - (Punctuation, u'>'), - (Punctuation, u','), - (Text, u' '), - (Name.Property, u'b'), - (Punctuation, u':'), - (Text, u' '), - (Name.Property, u'Set'), - (Punctuation, u'<'), - (Name, u'Wobble'), - (Punctuation, u'>'), - (Punctuation, u')'), - (Text, u' '), - (Punctuation, u'='), - (Text, u'\n') - ] - self.assertEqual(tokens, list(self.lexer.get_tokens(fragment))) - - def testCanCopeWithGenerics(self): - fragment = u'inline fun VaultService.queryBy(): Vault.Page {' - tokens = [ - (Keyword, u'inline fun'), - (Text, u' '), - (Punctuation, u'<'), - (Keyword, u'reified'), - (Text, u' '), - (Name, u'T'), - (Text, u' '), - (Punctuation, u':'), - (Text, u' '), - (Name, u'ContractState'), - (Punctuation, u'>'), - (Text, u' '), - (Name.Class, u'VaultService'), - (Punctuation, u'.'), - (Name.Function, u'queryBy'), - (Punctuation, u'('), - (Punctuation, u')'), - (Punctuation, u':'), - (Text, u' '), - (Name, u'Vault'), - (Punctuation, u'.'), - (Name, u'Page'), - (Punctuation, u'<'), - (Name, u'T'), - (Punctuation, u'>'), - (Text, u' '), - (Punctuation, u'{'), - (Text, u'\n') - ] - self.assertEqual(tokens, list(self.lexer.get_tokens(fragment))) - - def testShouldCopeWithMultilineComments(self): - fragment = u'"""\nthis\nis\na\ncomment"""' - tokens = [ - (String, u'"""\nthis\nis\na\ncomment"""'), - (Text, u'\n') - ] - self.assertEqual(tokens, list(self.lexer.get_tokens(fragment))) - -if __name__ == '__main__': - unittest.main() diff --git a/docs/source/example-code/build.gradle b/docs/example-code/build.gradle similarity index 100% rename from docs/source/example-code/build.gradle rename to docs/example-code/build.gradle diff --git a/docs/source/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/JavaIntegrationTestingTutorial.java b/docs/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/JavaIntegrationTestingTutorial.java similarity index 100% rename from docs/source/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/JavaIntegrationTestingTutorial.java rename to docs/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/JavaIntegrationTestingTutorial.java diff --git a/docs/source/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/TutorialFlowAsyncOperationTest.java b/docs/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/TutorialFlowAsyncOperationTest.java similarity index 100% rename from docs/source/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/TutorialFlowAsyncOperationTest.java rename to docs/example-code/src/integration-test/java/net/corda/docs/java/tutorial/test/TutorialFlowAsyncOperationTest.java diff --git a/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/KotlinIntegrationTestingTutorial.kt b/docs/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/KotlinIntegrationTestingTutorial.kt similarity index 100% rename from docs/source/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/KotlinIntegrationTestingTutorial.kt rename to docs/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/KotlinIntegrationTestingTutorial.kt diff --git a/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/TutorialFlowAsyncOperationTest.kt b/docs/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/TutorialFlowAsyncOperationTest.kt similarity index 100% rename from docs/source/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/TutorialFlowAsyncOperationTest.kt rename to docs/example-code/src/integration-test/kotlin/net/corda/docs/kotlin/tutorial/test/TutorialFlowAsyncOperationTest.kt diff --git a/docs/source/example-code/src/main/java/com/template/TemplateContract.java b/docs/example-code/src/main/java/com/template/TemplateContract.java similarity index 100% rename from docs/source/example-code/src/main/java/com/template/TemplateContract.java rename to docs/example-code/src/main/java/com/template/TemplateContract.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/ClientRpcExample.java b/docs/example-code/src/main/java/net/corda/docs/java/ClientRpcExample.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/ClientRpcExample.java rename to docs/example-code/src/main/java/net/corda/docs/java/ClientRpcExample.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java b/docs/example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java rename to docs/example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java b/docs/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java rename to docs/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/LaunchSpaceshipFlow.java b/docs/example-code/src/main/java/net/corda/docs/java/LaunchSpaceshipFlow.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/LaunchSpaceshipFlow.java rename to docs/example-code/src/main/java/net/corda/docs/java/LaunchSpaceshipFlow.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java b/docs/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java rename to docs/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/contract/CommercialPaper.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/contract/CommercialPaper.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/contract/CommercialPaper.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/contract/CommercialPaper.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/contract/State.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/contract/State.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/contract/State.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/contract/State.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/ExampleSummingFlow.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/ExampleSummingFlow.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/ExampleSummingFlow.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/ExampleSummingFlow.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperation.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperation.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperation.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperation.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperationThrowing.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperationThrowing.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperationThrowing.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/SummingOperationThrowing.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/TutorialFlowStateMachines.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/TutorialFlowStateMachines.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/TutorialFlowStateMachines.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/flowstatemachines/TutorialFlowStateMachines.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlowResponder.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlowResponder.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlowResponder.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlowResponder.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUState.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUState.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUState.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUState.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUContract.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUContract.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUContract.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUContract.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlowResponder.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlowResponder.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlowResponder.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlowResponder.java diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUState.java b/docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUState.java similarity index 100% rename from docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUState.java rename to docs/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUState.java diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcExample.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcExample.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcExample.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcExample.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcTutorial.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcTutorial.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcTutorial.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/ClientRpcTutorial.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorial.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorial.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorial.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorial.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/LaunchSpaceshipFlow.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/LaunchSpaceshipFlow.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/LaunchSpaceshipFlow.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/LaunchSpaceshipFlow.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/contract/TutorialContract.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/contract/TutorialContract.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/contract/TutorialContract.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/contract/TutorialContract.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowAsyncOperation.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowAsyncOperation.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowAsyncOperation.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowAsyncOperation.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowStateMachines.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowStateMachines.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowStateMachines.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/flowstatemachines/TutorialFlowStateMachines.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlow.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlow.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlow.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlow.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlowResponder.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlowResponder.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlowResponder.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUFlowResponder.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/tearoffs/TutorialTearOffs.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/tearoffs/TutorialTearOffs.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/tearoffs/TutorialTearOffs.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/tearoffs/TutorialTearOffs.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUContract.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUContract.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUContract.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUContract.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUState.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUState.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUState.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUState.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorial.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorial.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorial.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorial.kt diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/vault/CustomVaultQuery.kt b/docs/example-code/src/main/kotlin/net/corda/docs/kotlin/vault/CustomVaultQuery.kt similarity index 100% rename from docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/vault/CustomVaultQuery.kt rename to docs/example-code/src/main/kotlin/net/corda/docs/kotlin/vault/CustomVaultQuery.kt diff --git a/docs/source/example-code/src/main/resources/example-node-with-networkservices.conf b/docs/example-code/src/main/resources/example-node-with-networkservices.conf similarity index 100% rename from docs/source/example-code/src/main/resources/example-node-with-networkservices.conf rename to docs/example-code/src/main/resources/example-node-with-networkservices.conf diff --git a/docs/source/example-code/src/main/resources/example-node.conf b/docs/example-code/src/main/resources/example-node.conf similarity index 100% rename from docs/source/example-code/src/main/resources/example-node.conf rename to docs/example-code/src/main/resources/example-node.conf diff --git a/docs/source/example-code/src/main/resources/example-verifier.conf b/docs/example-code/src/main/resources/example-verifier.conf similarity index 100% rename from docs/source/example-code/src/main/resources/example-verifier.conf rename to docs/example-code/src/main/resources/example-verifier.conf diff --git a/docs/source/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java b/docs/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java similarity index 100% rename from docs/source/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java rename to docs/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java diff --git a/docs/source/example-code/src/test/kotlin/net/corda/docs/ExampleConfigTest.kt b/docs/example-code/src/test/kotlin/net/corda/docs/ExampleConfigTest.kt similarity index 100% rename from docs/source/example-code/src/test/kotlin/net/corda/docs/ExampleConfigTest.kt rename to docs/example-code/src/test/kotlin/net/corda/docs/ExampleConfigTest.kt diff --git a/docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorialTest.kt b/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorialTest.kt similarity index 100% rename from docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorialTest.kt rename to docs/example-code/src/test/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorialTest.kt diff --git a/docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt b/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt similarity index 100% rename from docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt rename to docs/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt diff --git a/docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorialTest.kt b/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorialTest.kt similarity index 100% rename from docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorialTest.kt rename to docs/example-code/src/test/kotlin/net/corda/docs/kotlin/txbuild/WorkflowTransactionBuildTutorialTest.kt diff --git a/docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/vault/CustomVaultQueryTest.kt b/docs/example-code/src/test/kotlin/net/corda/docs/kotlin/vault/CustomVaultQueryTest.kt similarity index 100% rename from docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/vault/CustomVaultQueryTest.kt rename to docs/example-code/src/test/kotlin/net/corda/docs/kotlin/vault/CustomVaultQueryTest.kt diff --git a/docs/ext/conditional_toctree.py b/docs/ext/conditional_toctree.py deleted file mode 100644 index 3b1e65d4cd..0000000000 --- a/docs/ext/conditional_toctree.py +++ /dev/null @@ -1,37 +0,0 @@ -import re -from docutils.parsers.rst import directives -from sphinx.directives.other import TocTree - -def setup(app): - app.add_directive('conditional-toctree', ConditionalTocTree) - ConditionalTocTree.defined_tags = app.tags.tags.keys() - return {'version': '1.0.0'} - -def tag(argument): - return directives.choice(argument, ('htmlmode', 'pdfmode')) - -class ConditionalTocTree(TocTree): - - defined_tags = [] - has_content = True - required_arguments = 0 - optional_arguments = 0 - final_argument_whitespace = False - option_spec = { - 'maxdepth': int, - 'name': directives.unchanged, - 'caption': directives.unchanged_required, - 'glob': directives.flag, - 'hidden': directives.flag, - 'includehidden': directives.flag, - 'titlesonly': directives.flag, - 'reversed': directives.flag, - 'if_tag': tag, - } - - def run(self): - if_tag = self.options.get('if_tag') - if if_tag in self.defined_tags: - return TocTree.run(self) - else: - return [] diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index f2675a2c7d..0000000000 --- a/docs/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/docs/install-docsite-requirements.sh b/docs/install-docsite-requirements.sh deleted file mode 100755 index 454b875056..0000000000 --- a/docs/install-docsite-requirements.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash -# The purpose of this file is to install the requirements for the docsite -# You can call it manually if running make manually, otherwise gradle will run it for you - -set -xeo pipefail - -# Install the virtualenv -if [ ! -d "virtualenv" ] -then - # If the canonical working directory contains whitespace, virtualenv installs broken scripts. - # But if we pass in an absolute path that uses symlinks to avoid whitespace, that fixes the problem. - # If you run this script manually (not via gradle) from such a path alias, it's available in PWD: - absolutevirtualenv="$PWD/virtualenv" - # Check if python2.7 is installed explicitly otherwise fall back to the default python - if type "python2.7" > /dev/null; then - virtualenv -p python2.7 "$absolutevirtualenv" - else - virtualenv "$absolutevirtualenv" - fi -fi - -# Activate the virtualenv -if [ -d "virtualenv/bin" ] -then - # it's a Unix system - source virtualenv/bin/activate -else - source virtualenv/Scripts/activate -fi - -# Install PIP requirements -if [ ! -d "virtualenv/lib/python2.7/site-packages/sphinx" ] -then - echo "Installing pip dependencies ... " - pip install -r requirements.txt -fi diff --git a/docs/make-docsite.sh b/docs/make-docsite.sh deleted file mode 100755 index 2aedeb5ceb..0000000000 --- a/docs/make-docsite.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -echo "Generating PDF document ..." -make latexpdf LATEXMKOPTS="-quiet" - -echo "Generating HTML pages ..." -make html - -echo "Moving PDF file from $(eval echo $PWD/build/latex/corda-developer-site.pdf) to $(eval echo $PWD/build/html/_static/corda-developer-site.pdf)" -mv $PWD/build/latex/corda-developer-site.pdf $PWD/build/html/_static/corda-developer-site.pdf \ No newline at end of file diff --git a/docs/packages.md b/docs/packages.md deleted file mode 100644 index ddcfe77327..0000000000 --- a/docs/packages.md +++ /dev/null @@ -1,191 +0,0 @@ -# Package net.corda.client.jackson - -Utilities and serialisers for working with JSON representations of basic types. This adds Jackson support for -the java.time API, some core types, and Kotlin data classes. - -# Package net.corda.client.rpc - -RPC client interface to Corda, for use both by user-facing client and integration with external systems. - -# Package net.corda.client.rpc.internal - -Internal, do not use. These APIs and implementations which are currently being revised and are subject to future change. - -# Package net.corda.core - -Exception types and some utilities for working with observables and futures. - -# Package net.corda.core.concurrent - -Provides a simplified [java.util.concurrent.Future] class that allows registration of a callback to execute when the future -is complete. - -# Package net.corda.core.contracts - -This package contains the base data types for smarts contracts implemented in Corda. To implement a new contract start -with [Contract], or see the examples in `net.corda.finance.contracts`. - -Corda smart contracts are a combination of state held on the distributed ledger, and verification logic which defines -which transformations of state are valid. - -# Package net.corda.core.cordapp - -This package contains the interface to CorDapps from within a node. A CorDapp can access it's own context by using -the CordappProvider.getAppContext() class. These classes are not intended to be constructed manually and no interface -to do this will be provided. - -# Package net.corda.core.crypto - -Cryptography data and utility classes used for signing, verifying, key management and data integrity checks. - -# Package net.corda.core.flows - -Base data types and abstract classes for implementing Corda flows. To implement a new flow start with [FlowLogic], or -see [CollectSignaturesFlow] for a simple example flow. Flows are started via a node's [ServiceHub]. - -Corda flows are a tool for modelling the interactions between two or more nodes as they negotiate a workflow. -This can range from a simple case of completing a trade which has been agreed upon externally, to more complex -processes such as handling fixing of interest rate swaps. - -# Package net.corda.core.identity - -Data classes which model different forms of identity (potentially with supporting evidence) for legal entities and services. - -# Package net.corda.core.messaging - -Data types used by the Corda messaging layer to manage state of messaging and sessions between nodes. - -# Package net.corda.core.node.services - -Services which run within a Corda node and provide various pieces of functionality such as identity management, transaction storage, etc. - -# Package net.corda.core.node.services.vault - -Supporting data types for the vault services. - -# Package net.corda.core.schemas - -Data types representing database schemas for storing Corda data via an object mapper such as Hibernate. Modifying Corda -state in the database directly is not a supported approach, however these can be used to read state for integrations with -external systems. - -# Package net.corda.core.serialization - -Supporting data types and classes for serialization of Corda data types. - -# Package net.corda.core.transactions - -Base data types for transactions which modify contract state on the distributed ledger. - -The core transaction on the ledger is [WireTransaction], which is constructed by [TransactionBuilder]. Once signed a transaction is stored -in [SignedTransaction] which encapsulates [WireTransaction]. Finally there is a special-case [LedgerTransaction] which is used by contracts -validating transactions, and is built from the wire transaction by resolving all references into their underlying data (i.e. inputs are -actual states rather than state references). - -# Package net.corda.core.utilities - -Corda utility classes, providing a broad range of functionality to help implement both Corda nodes and CorDapps. - - -# Package net.corda.finance - -Some simple testing utilities like pre-defined top-level values for common currencies. Mostly useful for -writing unit tests in Kotlin. - -__WARNING:__ This library is not suitable for production use and should not be used in real CorDapps. -Instead, use the [Token SDK](https://github.com/corda/token-sdk), or implement your own library. This -library may be removed in a future release without warning. - -# Package net.corda.finance.utils - -A collection of utilities for summing financial states, for example, summing obligations to get total debts. - -__WARNING:__ This library is not suitable for production use and should not be used in real CorDapps. -Instead, use the [Token SDK](https://github.com/corda/token-sdk), or implement your own library. This -library may be removed in a future release without warning. - -# Package net.corda.finance.contracts - -Various types for common financial concepts like day roll conventions, fixes, etc. - -__WARNING:__ This library is not suitable for production use and should not be used in real CorDapps. -Instead, use the [Token SDK](https://github.com/corda/token-sdk), or implement your own library. This -library may be removed in a future release without warning. - -# Package net.corda.finance.contracts.asset - -Cash states, obligations and commodities. - -__WARNING:__ This library is not suitable for production use and should not be used in real CorDapps. -Instead, use the [Token SDK](https://github.com/corda/token-sdk), or implement your own library. This -library may be removed in a future release without warning. - -# Package net.corda.finance.contracts.asset.cash.selection - -Provisional support for pluggable cash selectors, needed for different database backends. - -__WARNING:__ This library is not suitable for production use and should not be used in real CorDapps. -Instead, use the [Token SDK](https://github.com/corda/token-sdk), or implement your own library. This -library may be removed in a future release without warning. - -# Package net.corda.finance.contracts.math - -Splines and interpolation. - -__WARNING:__ This library is not suitable for production use and should not be used in real CorDapps. -Instead, use the [Token SDK](https://github.com/corda/token-sdk), or implement your own library. This -library may be removed in a future release without warning. - -# Package net.corda.finance.flows - -Cash payments and issuances. Two party "delivery vs payment" atomic asset swaps. - -__WARNING:__ This library is not suitable for production use and should not be used in real CorDapps. -Instead, use the [Token SDK](https://github.com/corda/token-sdk), or implement your own library. This -library may be removed in a future release without warning. - -# Package net.corda.finance.plugin - -JSON/Jackson plugin for business calendars. - -__WARNING:__ This library is not suitable for production use and should not be used in real CorDapps. -Instead, use the [Token SDK](https://github.com/corda/token-sdk), or implement your own library. This -library may be removed in a future release without warning. - -# Package net.corda.finance.schemas - -JPA (Java Persistence Architecture) schemas for the financial state types. - -__WARNING:__ This library is not suitable for production use and should not be used in real CorDapps. -Instead, use the [Token SDK](https://github.com/corda/token-sdk), or implement your own library. This -library may be removed in a future release without warning. - -# Package net.corda.testing.core - -Generic test utilities for contracts and flows - -# Package net.corda.testing.node - -Test utilites to help running nodes programmatically for tests - -# Package net.corda.testing.driver - -Test utilites to help running nodes programmatically for tests - -# Package net.corda.testing.dsl - -A simple DSL for building pseudo-transactions (not the same as the wire protocol) for testing purposes - -# Package net.corda.testing.contracts - -Dummy state and contracts for testing purposes - -# Package net.corda.testing.services - -Mock service implementations for testing purposes - -# Package net.corda.testing.http - -A small set of utilities for working with http calls. - -WARNING: NOT API STABLE. \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index fbd1ac71e7..0000000000 --- a/docs/requirements.txt +++ /dev/null @@ -1,29 +0,0 @@ -alabaster==0.7.8 -Babel==2.3.4 -certifi==2018.4.16 -chardet==3.0.4 -CommonMark==0.5.5 -docutils==0.12 -future==0.16.0 -idna==2.6 -imagesize==0.7.1 -Jinja2==2.10.1 -m2r==0.1.14 -MarkupSafe==0.23 -mistune==0.8.3 -packaging==17.1 -pdfrw==0.4 -Pillow==6.2.0 -Pygments==2.3.1 -pyparsing==2.2.0 -pytz==2016.4 -reportlab==3.4.0 -requests==2.20.0 -rst2pdf==0.93 -six==1.10.0 -snowballstemmer==1.2.1 -Sphinx==1.7.4 -sphinx-rtd-theme==0.1.9 -sphinxcontrib-websupport==1.0.1 -typing==3.6.4 -urllib3==1.24.2 diff --git a/docs/source/_static/codesets.js b/docs/source/_static/codesets.js deleted file mode 100644 index c8dba38ee0..0000000000 --- a/docs/source/_static/codesets.js +++ /dev/null @@ -1,27 +0,0 @@ -$(document).ready(function() { - $(".codeset").each(function(index, el) { - var c = $("
JavaKotlin
"); - var javaButton = c.children()[0]; - var kotlinButton = c.children()[1]; - kotlinButton.onclick = function() { - $(el).children(".highlight-java")[0].style.display = "none"; - $(el).children(".highlight-kotlin")[0].style.display = "block"; - javaButton.setAttribute("class", ""); - kotlinButton.setAttribute("class", "current"); - }; - javaButton.onclick = function() { - $(el).children(".highlight-java")[0].style.display = "block"; - $(el).children(".highlight-kotlin")[0].style.display = "none"; - kotlinButton.setAttribute("class", ""); - javaButton.setAttribute("class", "current"); - }; - - if ($(el).children(".highlight-java").length == 0) { - // No Java for this example. - javaButton.style.display = "none"; - // In this case, display Kotlin by default - $(el).children(".highlight-kotlin")[0].style.display = "block"; - } - c.insertBefore(el); - }); -}); \ No newline at end of file diff --git a/docs/source/_static/corda-cheat-sheet.pdf b/docs/source/_static/corda-cheat-sheet.pdf deleted file mode 100644 index 382a2d8005..0000000000 Binary files a/docs/source/_static/corda-cheat-sheet.pdf and /dev/null differ diff --git a/docs/source/_static/corda-introductory-whitepaper-jp.pdf b/docs/source/_static/corda-introductory-whitepaper-jp.pdf deleted file mode 100644 index 495ced5e2e..0000000000 Binary files a/docs/source/_static/corda-introductory-whitepaper-jp.pdf and /dev/null differ diff --git a/docs/source/_static/corda-introductory-whitepaper-zhs.pdf b/docs/source/_static/corda-introductory-whitepaper-zhs.pdf deleted file mode 100644 index 2c02bec5c5..0000000000 Binary files a/docs/source/_static/corda-introductory-whitepaper-zhs.pdf and /dev/null differ diff --git a/docs/source/_static/corda-introductory-whitepaper-zht.pdf b/docs/source/_static/corda-introductory-whitepaper-zht.pdf deleted file mode 100644 index 1038b6b9b4..0000000000 Binary files a/docs/source/_static/corda-introductory-whitepaper-zht.pdf and /dev/null differ diff --git a/docs/source/_static/corda-introductory-whitepaper.pdf b/docs/source/_static/corda-introductory-whitepaper.pdf deleted file mode 100644 index a185724937..0000000000 Binary files a/docs/source/_static/corda-introductory-whitepaper.pdf and /dev/null differ diff --git a/docs/source/_static/corda-technical-whitepaper.pdf b/docs/source/_static/corda-technical-whitepaper.pdf deleted file mode 100644 index 2386aa128e..0000000000 Binary files a/docs/source/_static/corda-technical-whitepaper.pdf and /dev/null differ diff --git a/docs/source/_static/css/custom.css b/docs/source/_static/css/custom.css deleted file mode 100644 index 6b171e5b9a..0000000000 --- a/docs/source/_static/css/custom.css +++ /dev/null @@ -1,221 +0,0 @@ -@import "theme.css"; - -/* Highlights */ - -.highlight .k, -.highlight .kd { - color: #263673; -} - - -/* Text */ - -body, -h1, -h2, -.rst-content .toctree-wrapper p.caption, -h3, -h4, -h5, -h6, -legend, -input { - color: #010101; - letter-spacing: 0.3px -} - -p.caption { - margin-top: 2em; -} -span.caption-text { - font-size: larger; -} - -p { - font-size: 100%; /* Get rid of RTD rule that assumes nobody changes their browser font size */ -} - - -/* Links */ - -a { - color: #263673 -} - -a:hover { - color: #005CAB -} - -a:visited { - color: #ADAFB3 -} - - -/* Side navigation bar */ - -.wy-side-nav-search { - background-color: #252627; -} - -.wy-side-nav-search a.icon-home { - color: transparent; - background-image: url('../images/fg002_corda_w3.png'); - background-repeat: no-repeat; - background-size: Auto 20px; - background-position: center top; - background-origin: content box; - height: 20px; - width: 100% -} - -.wy-side-nav-search input[type=text] { - border-radius: 5px -} - -.wy-menu-vertical a:hover { - background-color: #ADAFB3; - color: #FFF -} - -.wy-nav-content { - background-color: #fff; - max-width: none; -} - -.wy-nav-side { - background-color: #252627; -} - - -/* Navigation headers */ - -.rst-content tt.literal, -.rst-content tt.literal, -.rst-content code.literal { - color: #EC1D24; - text-transform: none; -} - -.wy-menu-vertical header, -.wy-menu-vertical p.caption { - color: #EC1D24; -} - - -/* Code snippets */ - -.codesnippet-widgets { - min-width: 100%; - display: block; - background: #005CAB; - color: white; - padding: 10px 0; - margin: 0 0 -1px 0; -} - -.codesnippet-widgets > span { - padding: 10px; - cursor: pointer; -} - -.codesnippet-widgets > .current { - background: #263673; -} - -.codeset > .highlight-kotlin { - display: none; -} - - -/* Notification boxes */ - -.wy-alert.wy-alert-warning .wy-alert-title, -.rst-content .wy-alert-warning.note .wy-alert-title, -.rst-content .attention .wy-alert-title, -.rst-content .caution .wy-alert-title, -.rst-content .wy-alert-warning.danger .wy-alert-title, -.rst-content .wy-alert-warning.error .wy-alert-title, -.rst-content .wy-alert-warning.hint .wy-alert-title, -.rst-content .wy-alert-warning.important .wy-alert-title, -.rst-content .wy-alert-warning.tip .wy-alert-title, -.rst-content .warning .wy-alert-title, -.rst-content .wy-alert-warning.seealso .wy-alert-title, -.rst-content .admonition-todo .wy-alert-title, -.wy-alert.wy-alert-warning .rst-content .admonition-title, -.rst-content .wy-alert.wy-alert-warning .admonition-title, -.rst-content .wy-alert-warning.note .admonition-title, -.rst-content .attention .admonition-title, -.rst-content .caution .admonition-title, -.rst-content .wy-alert-warning.danger .admonition-title, -.rst-content .wy-alert-warning.error .admonition-title, -.rst-content .wy-alert-warning.hint .admonition-title, -.rst-content .wy-alert-warning.important .admonition-title, -.rst-content .wy-alert-warning.tip .admonition-title, -.rst-content .warning .admonition-title, -.rst-content .wy-alert-warning.seealso .admonition-title, -.rst-content .admonition-todo .admonition-title { - background-color: #263673 -} - -.wy-alert, -.rst-content .note, -.rst-content .attention, -.rst-content .caution, -.rst-content .danger, -.rst-content .error, -.rst-content .hint, -.rst-content .important, -.rst-content .tip, -.rst-content .warning, -.rst-content .seealso, -.rst-content .admonition-todo { - background-color: #d9e5ef -} - - -/* Mobile view */ - -.wy-nav-top { - background-color: #252627; -} - -.wy-nav-top a { - color: transparent; - background-image: url('../images/fg002_corda_w3.png'); - background-repeat: no-repeat; - background-size: Auto 19px; - background-position: center top; - background-origin: content box; -} - - -/* Version dropdown */ - -.version-dropdown { - border-radius: 4px; - border-color: #263673; -} - -/* Hover buttons */ -.button { - background-color: #4CAF50; /* Green */ - border: none; - color: white; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - cursor: pointer; - -webkit-transition-duration: 0.4s; /* Safari */ - transition-duration: 0.4s; -} - -.button1 { - box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19); -} - -.button2:hover { - box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24),0 17px 50px 0 rgba(0,0,0,0.19); -} \ No newline at end of file diff --git a/docs/source/_static/favicon.ico b/docs/source/_static/favicon.ico deleted file mode 100644 index 46f71069c7..0000000000 Binary files a/docs/source/_static/favicon.ico and /dev/null differ diff --git a/docs/source/_static/images/fg002_corda_w3.png b/docs/source/_static/images/fg002_corda_w3.png deleted file mode 100644 index e17c885fb3..0000000000 Binary files a/docs/source/_static/images/fg002_corda_w3.png and /dev/null differ diff --git a/docs/source/_static/images/network-builder-v4.png b/docs/source/_static/images/network-builder-v4.png deleted file mode 100644 index f95f1c3589..0000000000 Binary files a/docs/source/_static/images/network-builder-v4.png and /dev/null differ diff --git a/docs/source/_static/irs.png b/docs/source/_static/irs.png deleted file mode 100644 index 11ee25f144..0000000000 Binary files a/docs/source/_static/irs.png and /dev/null differ diff --git a/docs/source/_static/versions b/docs/source/_static/versions deleted file mode 100644 index 13e98ab34b..0000000000 --- a/docs/source/_static/versions +++ /dev/null @@ -1,20 +0,0 @@ -{ - "https://docs.corda.net/releases/release-M6.0": "M6.0", - "https://docs.corda.net/releases/release-M7.0": "M7.0", - "https://docs.corda.net/releases/release-M8.2": "M8.2", - "https://docs.corda.net/releases/release-M9.2": "M9.2", - "https://docs.corda.net/releases/release-M10.1": "M10.1", - "https://docs.corda.net/releases/release-M11.2": "M11.2", - "https://docs.corda.net/releases/release-M12.1": "M12.1", - "https://docs.corda.net/releases/release-M13.0": "M13.0", - "https://docs.corda.net/releases/release-M14.0": "M14.0", - "https://docs.corda.net/releases/release-V1.0": "V1.0", - "https://docs.corda.net/releases/release-V2.0": "V2.0", - "https://docs.corda.net/releases/release-V3.0": "V3.0", - "https://docs.corda.net/releases/release-V3.1": "V3.1", - "https://docs.corda.net/releases/release-V3.2": "V3.2", - "https://docs.corda.net/releases/release-V3.3": "V3.3", - "https://docs.corda.net/releases/release-V4.0": "V4.0", - "https://docs.corda.net/releases/release-V4.1": "V4.1", - "https://docs.corda.net/head/": "Master" -} diff --git a/docs/source/_templates/layout.html b/docs/source/_templates/layout.html deleted file mode 100644 index 25db2f8b36..0000000000 --- a/docs/source/_templates/layout.html +++ /dev/null @@ -1,15 +0,0 @@ - - - -{% extends "!layout.html" %} -{% block sidebartitle %} -{{ super() }} -
-API reference: Kotlin/ JavaDoc -
-Slack -
-Stack Overflow -
-{% endblock %} \ No newline at end of file diff --git a/docs/source/_templates/layout_for_doc_website.html b/docs/source/_templates/layout_for_doc_website.html deleted file mode 100644 index f0992030c9..0000000000 --- a/docs/source/_templates/layout_for_doc_website.html +++ /dev/null @@ -1,46 +0,0 @@ - - -{% extends "!layout.html" %} -{% block sidebartitle %} -{{ super() }} -
-API reference: Kotlin/ JavaDoc -
-Slack -
-Stack Overflow -
- -
- -{% endblock %} - -{% block footer %} - - - -{% endblock %} diff --git a/docs/source/api-contract-constraints.rst b/docs/source/api-contract-constraints.rst deleted file mode 100644 index f019212989..0000000000 --- a/docs/source/api-contract-constraints.rst +++ /dev/null @@ -1,422 +0,0 @@ -.. highlight:: kotlin -.. role:: kotlin(code) - :language: kotlin -.. raw:: html - - - - - -API: Contract Constraints -========================= - -.. note:: Before reading this page, you should be familiar with the key concepts of :doc:`key-concepts-contracts`. - -.. note:: As of Corda |corda_version| the `minimumPlatformVersion` required to use these features is 4 - (see :ref:`Network Parameters ` and :doc:`features-versions` for more details). - -.. contents:: - -Reasons for Contract Constraints --------------------------------- - -*Contract constraints* solve two problems faced by any decentralised ledger that supports evolution of data and code: - -1. Controlling and agreeing upon upgrades -2. Preventing attacks - -Upgrades and security are intimately related because if an attacker can "upgrade" your data to a version of an app that gives them -a back door, they would be able to do things like print money or edit states in any way they want. That's why it's important for -participants of a state to agree on what kind of upgrades will be allowed. - -Every state on the ledger contains the fully qualified class name of a ``Contract`` implementation, and also a *constraint*. -This constraint specifies which versions of an application can be used to provide the named class, when the transaction is built. -New versions released after a transaction is signed and finalised won't affect prior transactions because the old code is attached -to it. - -.. _implicit_vs_explicit_upgrades: - -Implicit vs Explicit Contract upgrades -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Constraints are not the only way to manage upgrades to transactions. There are two ways of handling -upgrades to a smart contract in Corda: - -* **Implicit**: By pre-authorising multiple implementations of the contract ahead of time, using constraints. -* **Explicit**: By creating a special *contract upgrade transaction* and getting all participants of a state to sign it using the - contract upgrade flows. - -The advantage of pre-authorising upgrades using constraints is that you don't need the heavyweight process of creating -upgrade transactions for every state on the ledger. The disadvantage is that you place more faith in third parties, -who could potentially change the app in ways you did not expect or agree with. The advantage of using the explicit -upgrade approach is that you can upgrade states regardless of their constraint, including in cases where you didn't -anticipate a need to do so. But it requires everyone to sign, manually authorise the upgrade, -consumes notary and ledger resources, and is just in general more complex. - -This article focuses on the first approach. To learn about the second please see :doc:`upgrading-cordapps`. - -.. _implicit_constraint_types: - -Types of Contract Constraints ------------------------------ - -Corda supports several types of constraints to cover a wide set of client requirements: - -* **Hash constraint**: Exactly one version of the app can be used with this state. This prevents the app from being upgraded in the future while still - making use of the state created with the original version. -* **Compatibility zone whitelisted (or CZ whitelisted) constraint**: The compatibility zone operator lists the hashes of the versions that can be used with a contract class name. -* **Signature constraint**: Any version of the app signed by the given ``CompositeKey`` can be used. This allows app issuers to express the - complex social and business relationships that arise around code ownership. For example, a Signature Constraint allows a new version of an - app to be produced and applied to an existing state as long as it has been signed by the same key(s) as the original version. -* **Always accept constraint**: Any version of the app can be used. This is insecure but convenient for testing. - -.. _signature_constraints: - -Signature Constraints ---------------------- - -The best kind of constraint to use is the **Signature Constraint**. If you sign your application it will be used automatically. -We recommend signature constraints because they let you express complex social and business relationships while allowing -smooth migration of existing data to new versions of your application. - -Signature constraints can specify flexible threshold policies, but if you use the automatic support then a state will -require the attached app to be signed by every key that the first attachment was signed by. Thus if the app that was used -to issue the states was signed by Alice and Bob, every transaction must use an attachment signed by Alice and Bob. Doing so allows the -app to be upgraded and changed while still remaining valid for use with the previously issued states. - -More complex policies can be expressed through Signature Constraints if required. Allowing policies where only a number of the possible -signers must sign the new version of an app that is interacting with previously issued states. Accepting different versions of apps in this -way makes it possible for multiple versions to be valid across the network as long as the majority (or possibly a minority) agree with the -logic provided by the apps. - -Hash and zone whitelist constraints are left over from earlier Corda versions before Signature Constraints were -implemented. They make it harder to upgrade applications than when using signature constraints, so they're best avoided. - -.. _signing_cordapps_for_use_with_signature_constraints: - -Signing CorDapps for use with Signature Constraints -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Expanding on the previous section, for an app to use Signature Constraints, it must be signed by a ``CompositeKey`` or a simpler ``PublicKey``. -The signers of the app can consist of a single organisation or multiple organisations. Once the app has been signed, it can be distributed -across the nodes that intend to use it. - -.. note:: The platform currently supports ``CompositeKey``\s with up to 20 keys maximum. - This maximum limit is assuming keys that are either 2048-bit ``RSA`` keys or 256-bit elliptic curve (``EC``) keys. - -Each transaction received by a node will then verify that the apps attached to it have the correct signers as specified by its -Signature Constraints. This ensures that the version of each app is acceptable to the transaction's input states. - -If a node receives a transaction that uses an attachment that it doesn't trust, but there is another attachment present on the node with -at least one common signature, then the node will trust the received attachment. This means that nodes -are no longer required to have every version of a CorDapp uploaded to them in order to verify transactions running older versions of a CorDapp. -Instead, it is sufficient to have any version of the CorDapp contract installed. - -.. note:: An attachment is considered trusted if it was manually installed or uploaded via RPC. - -Signers can also be blacklisted to prevent attachments received from a peer from being loaded and used in processing transactions. Only a -single signer of an attachment needs to be blacklisted for an attachment to be considered untrusted. CorDapps -and other attachments installed on a node can still be used without issue, even if they are signed by a blacklisted key. Only attachments -received from a peer are affected. - -Below are two examples of possible scenarios around blacklisting signing keys: - - - The statements below are true for both examples: - - - ``Alice`` has ``Contracts CorDapp`` installed - - ``Bob`` has an upgraded version of ``Contracts CorDapp`` (known as ``Contracts CorDapp V2``) installed - - Both ``Alice`` and ``Bob`` have the ``Workflows CorDapp`` allowing them to transact with each other - - ``Contracts CorDapp`` is signed by both ``Alice`` and ``Bob`` - - ``Contracts CorDapp V2`` is signed by both ``Alice`` and ``Bob`` - - - Example 1: - - - ``Alice`` has not blacklisted any attachment signing keys - - ``Bob`` transacts with ``Alice`` - - ``Alice`` receives ``Contracts CorDapp V2`` and stores it - - When verifying the attachments loaded into the contract verification code, ``Contracts CorDapp V2`` is accepted and used - - The contract verification code in ``Contracts CorDapp V2`` is run - - - Example 2: - - - ``Alice`` blacklists ``Bob``'s attachment signing key - - ``Bob`` transacts with ``Alice`` - - ``Alice`` receives ``Contracts CorDapp V2`` and stores it - - When verifying the attachments loaded in the contract verification code, ``Contracts CorDapp V2`` is declined because it is signed - by ``Bob``'s blacklisted key - - The contract verification code in ``Contracts CorDapp V2`` is not run and the transaction fails - -Information on blacklisting attachment signing keys can be found in the -:ref:`node configuration documentation `. - -More information on how to sign an app directly from Gradle can be found in the -:ref:`CorDapp Jar signing ` section of the documentation. - -Using Signature Constraints in transactions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If the app is signed, Signature Constraints will be used by default (in most situations) by the ``TransactionBuilder`` when adding output states. -This is expanded upon in :ref:`contract_constraints_in_transactions`. - -.. note:: Signature Constraints are used by default except when a new transaction contains an input state with a Hash Constraint. In this - situation the Hash Constraint is used. - -App versioning with Signature Constraints -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Signed apps require a version number to be provided, see :doc:`versioning`. - -Hash Constraints ----------------- - -Issues when using the HashAttachmentConstraint -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When setting up a new network, it is possible to encounter errors when states are issued with the ``HashAttachmentConstraint``, -but not all nodes have that same version of the CorDapp installed locally. - -In this case, flows will fail with a ``ContractConstraintRejection``, and are sent to the flow hospital. -From there, they are suspended, waiting to be retried on node restart. -This gives the node operator the opportunity to recover from those errors, which in the case of constraint violations means -adding the right cordapp jar to the ``cordapps`` folder. - -.. _relax_hash_constraints_checking_ref: - -Hash constrained states in private networks -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Where private networks started life using CorDapps with hash constrained states, we have introduced a mechanism to relax the checking of -these hash constrained states when upgrading to signed CorDapps using signature constraints. - -The Java system property ``-Dnet.corda.node.disableHashConstraints="true"`` may be set to relax the hash constraint checking behaviour. For -this to work, every participant of the network must set the property to the same value. Therefore, this mode should only be used upon -"out of band" agreement by all participants in a network. - -.. warning:: This flag should remain enabled until every hash constrained state is exited from the ledger. - -.. _contract_state_agreement: - -Contract/State Agreement ------------------------- - -Starting with Corda 4, a ``ContractState`` must explicitly indicate which ``Contract`` it belongs to. When a transaction is -verified, the contract bundled with each state in the transaction must be its "owning" contract, otherwise we cannot guarantee that -the transition of the ``ContractState`` will be verified against the business rules that should apply to it. - -There are two mechanisms for indicating ownership. One is to annotate the ``ContractState`` with the ``BelongsToContract`` annotation, -indicating the ``Contract`` class to which it is tied: - -.. container:: codeset - - .. sourcecode:: java - - @BelongsToContract(MyContract.class) - public class MyState implements ContractState { - // implementation goes here - } - - - .. sourcecode:: kotlin - - @BelongsToContract(MyContract::class) - data class MyState(val value: Int) : ContractState { - // implementation goes here - } - -The other is to define the ``ContractState`` class as an inner class of the ``Contract`` class: - - -.. container:: codeset - - .. sourcecode:: java - - public class MyContract implements Contract { - - public static class MyState implements ContractState { - // state implementation goes here - } - - // contract implementation goes here - } - - - .. sourcecode:: kotlin - - class MyContract : Contract { - - data class MyState(val value: Int) : ContractState { - // state implementation goes here - } - - // contract implementation goes here - } - -If a ``ContractState``'s owning ``Contract`` cannot be identified by either of these mechanisms, and the ``targetVersion`` of the -CorDapp is 4 or greater, then transaction verification will fail with a ``TransactionRequiredContractUnspecifiedException``. If -the owning ``Contract`` *can* be identified, but the ``ContractState`` has been bundled with a different contract, then -transaction verification will fail with a ``TransactionContractConflictException``. - -.. _contract_constraints_in_transactions: - -Using Contract Constraints in Transactions ------------------------------------------- - -The app version used by a transaction is defined by its attachments. The JAR containing the state and contract classes, and optionally its -dependencies, are all attached to the transaction. Nodes will download this JAR from other nodes if they haven't seen it before, -so it can be used for verification. - -The ``TransactionBuilder`` will manage the details of constraints for you, by selecting both constraints -and attachments to ensure they line up correctly. Therefore you only need to have a basic understanding of this topic unless you are -doing something sophisticated. - -By default the ``TransactionBuilder`` will use :ref:`signature_constraints` for any issuance transactions if the app attached to it is -signed. - -To manually define the Contract Constraint of an output state, see the example below: - -.. container:: codeset - - .. sourcecode:: java - - TransactionBuilder transaction() { - TransactionBuilder transaction = new TransactionBuilder(notary()); - // Signature Constraint used if app is signed - transaction.addOutputState(state); - // Explicitly using a Signature Constraint - transaction.addOutputState(state, CONTRACT_ID, new SignatureAttachmentConstraint(getOurIdentity().getOwningKey())); - // Explicitly using a Hash Constraint - transaction.addOutputState(state, CONTRACT_ID, new HashAttachmentConstraint(getServiceHub().getCordappProvider().getContractAttachmentID(CONTRACT_ID))); - // Explicitly using a Whitelisted by Zone Constraint - transaction.addOutputState(state, CONTRACT_ID, WhitelistedByZoneAttachmentConstraint.INSTANCE); - // Explicitly using an Always Accept Constraint - transaction.addOutputState(state, CONTRACT_ID, AlwaysAcceptAttachmentConstraint.INSTANCE); - - // other transaction stuff - return transaction; - } - - - .. sourcecode:: kotlin - - private fun transaction(): TransactionBuilder { - val transaction = TransactionBuilder(notary()) - // Signature Constraint used if app is signed - transaction.addOutputState(state) - // Explicitly using a Signature Constraint - transaction.addOutputState(state, constraint = SignatureAttachmentConstraint(ourIdentity.owningKey)) - // Explicitly using a Hash Constraint - transaction.addOutputState(state, constraint = HashAttachmentConstraint(serviceHub.cordappProvider.getContractAttachmentID(CONTRACT_ID)!!)) - // Explicitly using a Whitelisted by Zone Constraint - transaction.addOutputState(state, constraint = WhitelistedByZoneAttachmentConstraint) - // Explicitly using an Always Accept Constraint - transaction.addOutputState(state, constraint = AlwaysAcceptAttachmentConstraint) - - // other transaction stuff - return transaction - } - -CorDapps as attachments ------------------------ - -CorDapp JARs (see :doc:`cordapp-overview`) that contain classes implementing the ``Contract`` interface are automatically -loaded into the ``AttachmentStorage`` of a node, and made available as ``ContractAttachments``. - -They are retrievable by hash using ``AttachmentStorage.openAttachment``. These JARs can either be installed on the -node or will be automatically fetched over the network when receiving a transaction. - -.. warning:: The obvious way to write a CorDapp is to put all you states, contracts, flows and support code into a single - Java module. This will work but it will effectively publish your entire app onto the ledger. That has two problems: - (1) it is inefficient, and (2) it means changes to your flows or other parts of the app will be seen by the ledger - as a "new app", which may end up requiring essentially unnecessary upgrade procedures. It's better to split your - app into multiple modules: one which contains just states, contracts and core data types. And another which contains - the rest of the app. See :ref:`cordapp-structure`. - -.. _constraints_propagation: - -Constraints propagation ------------------------ - -As was mentioned above, the ``TransactionBuilder`` API gives the CorDapp developer or even malicious node owner the possibility -to construct output states with a constraint of their choosing. - -For the ledger to remain in a consistent state, the expected behavior is for output state to inherit the constraints of input states. -This guarantees that for example, a transaction can't output a state with the ``AlwaysAcceptAttachmentConstraint`` when the -corresponding input state was the ``SignatureAttachmentConstraint``. Translated, this means that if this rule is enforced, it ensures -that the output state will be spent under similar conditions as it was created. - -Before version 4, the constraint propagation logic was expected to be enforced in the contract verify code, as it has access to the entire Transaction. - -Starting with version 4 of Corda the constraint propagation logic has been implemented and enforced directly by the platform, -unless disabled by putting ``@NoConstraintPropagation`` on the ``Contract`` class which reverts to the previous behavior of expecting -apps to do this. - -For contracts that are not annotated with ``@NoConstraintPropagation``, the platform implements a fairly simple constraint transition policy -to ensure security and also allow the possibility to transition to the new ``SignatureAttachmentConstraint``. - -During transaction building the ``AutomaticPlaceholderConstraint`` for output states will be resolved and the best contract attachment versions -will be selected based on a variety of factors so that the above holds true. If it can't find attachments in storage or there are no -possible constraints, the ``TransactionBuilder`` will throw an exception. - -Constraints migration to Corda 4 --------------------------------- - -Please read :doc:`cordapp-constraint-migration` to understand how to consume and evolve pre-Corda 4 issued hash or CZ whitelisted constrained states -using a Corda 4 signed CorDapp (using signature constraints). - -Debugging ---------- -If an attachment constraint cannot be resolved, a ``MissingContractAttachments`` exception is thrown. There are three common sources of -``MissingContractAttachments`` exceptions: - -Not setting CorDapp packages in tests -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -You are running a test and have not specified the CorDapp packages to scan. -When using ``MockNetwork`` ensure you have provided a package containing the contract class in ``MockNetworkParameters``. See :doc:`api-testing`. - -Similarly package names need to be provided when testing using ``DriverDSl``. ``DriverParameters`` has a property ``cordappsForAllNodes`` (Kotlin) -or method ``withCordappsForAllNodes`` in Java. Pass the collection of ``TestCordapp`` created by utility method ``TestCordapp.findCordapp(String)``. - -Example of creation of two Cordapps with Finance App Flows and Finance App Contracts: - -.. container:: codeset - - .. sourcecode:: kotlin - - Driver.driver(DriverParameters( - cordappsForAllNodes = listOf( - TestCordapp.findCordapp("net.corda.finance.schemas"), - TestCordapp.findCordapp("net.corda.finance.flows") - ) - ) { - // Your test code goes here - }) - - .. sourcecode:: java - - Driver.driver( - new DriverParameters() - .withCordappsForAllNodes( - Arrays.asList( - TestCordapp.findCordapp("net.corda.finance.schemas"), - TestCordapp.findCordapp("net.corda.finance.flows") - ) - ), - dsl -> { - // Your test code goes here - } - ); - -Starting a node missing CorDapp(s) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When running the Corda node ensure all CordDapp JARs are placed in ``cordapps`` directory of each node. -By default Gradle Cordform task ``deployNodes`` copies all JARs if CorDapps to deploy are specified. -See :doc:`generating-a-node` for detailed instructions. - -Wrong fully-qualified contract name -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -You are specifying the fully-qualified name of the contract incorrectly. For example, you've defined ``MyContract`` in -the package ``com.mycompany.myapp.contracts``, but the fully-qualified contract name you pass to the -``TransactionBuilder`` is ``com.mycompany.myapp.MyContract`` (instead of ``com.mycompany.myapp.contracts.MyContract``). diff --git a/docs/source/api-contracts.rst b/docs/source/api-contracts.rst deleted file mode 100644 index e0dc3356eb..0000000000 --- a/docs/source/api-contracts.rst +++ /dev/null @@ -1,236 +0,0 @@ -.. highlight:: kotlin -.. raw:: html - - - - -API: Contracts -============== - -.. note:: Before reading this page, you should be familiar with the key concepts of :doc:`key-concepts-contracts`. - -.. contents:: - -Contract --------- -Contracts are classes that implement the ``Contract`` interface. The ``Contract`` interface is defined as follows: - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt - :language: kotlin - :start-after: DOCSTART 5 - :end-before: DOCEND 5 - -``Contract`` has a single method, ``verify``, which takes a ``LedgerTransaction`` as input and returns -nothing. This function is used to check whether a transaction proposal is valid, as follows: - -* We gather together the contracts of each of the transaction's input and output states -* We call each contract's ``verify`` function, passing in the transaction as an input -* The proposal is only valid if none of the ``verify`` calls throw an exception - -``verify`` is executed in a sandbox: - -* It does not have access to the enclosing scope -* The libraries available to it are whitelisted to disallow: - * Network access - * I/O such as disk or database access - * Sources of randomness such as the current time or random number generators - -This means that ``verify`` only has access to the properties defined on ``LedgerTransaction`` when deciding whether a -transaction is valid. - -Here are the two simplest ``verify`` functions: - -* A ``verify`` that **accepts** all possible transactions: - -.. container:: codeset - - .. sourcecode:: kotlin - - override fun verify(tx: LedgerTransaction) { - // Always accepts! - } - - .. sourcecode:: java - - @Override - public void verify(LedgerTransaction tx) { - // Always accepts! - } - -* A ``verify`` that **rejects** all possible transactions: - -.. container:: codeset - - .. sourcecode:: kotlin - - override fun verify(tx: LedgerTransaction) { - throw IllegalArgumentException("Always rejects!") - } - - .. sourcecode:: java - - @Override - public void verify(LedgerTransaction tx) { - throw new IllegalArgumentException("Always rejects!"); - } - -LedgerTransaction ------------------ -The ``LedgerTransaction`` object passed into ``verify`` has the following properties: - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - -Where: - -* ``inputs`` are the transaction's inputs as ``List>`` -* ``outputs`` are the transaction's outputs as ``List>`` -* ``commands`` are the transaction's commands and associated signers, as ``List>`` -* ``attachments`` are the transaction's attachments as ``List`` -* ``notary`` is the transaction's notary. This must match the notary of all the inputs -* ``timeWindow`` defines the window during which the transaction can be notarised - -``LedgerTransaction`` exposes a large number of utility methods to access the transaction's contents: - -* ``inputStates`` extracts the input ``ContractState`` objects from the list of ``StateAndRef`` -* ``getInput``/``getOutput``/``getCommand``/``getAttachment`` extracts a component by index -* ``getAttachment`` extracts an attachment by ID -* ``inputsOfType``/``inRefsOfType``/``outputsOfType``/``outRefsOfType``/``commandsOfType`` extracts components based on - their generic type -* ``filterInputs``/``filterInRefs``/``filterOutputs``/``filterOutRefs``/``filterCommands`` extracts components based on - a predicate -* ``findInput``/``findInRef``/``findOutput``/``findOutRef``/``findCommand`` extracts the single component that matches - a predicate, or throws an exception if there are multiple matches - -requireThat ------------ -``verify`` can be written to manually throw an exception for each constraint: - -.. container:: codeset - - .. sourcecode:: kotlin - - override fun verify(tx: LedgerTransaction) { - if (tx.inputs.size > 0) - throw IllegalArgumentException("No inputs should be consumed when issuing an X.") - - if (tx.outputs.size != 1) - throw IllegalArgumentException("Only one output state should be created.") - } - - .. sourcecode:: java - - public void verify(LedgerTransaction tx) { - if (tx.getInputs().size() > 0) - throw new IllegalArgumentException("No inputs should be consumed when issuing an X."); - - if (tx.getOutputs().size() != 1) - throw new IllegalArgumentException("Only one output state should be created."); - } - -However, this is verbose. To impose a series of constraints, we can use ``requireThat`` instead: - -.. container:: codeset - - .. sourcecode:: kotlin - - requireThat { - "No inputs should be consumed when issuing an X." using (tx.inputs.isEmpty()) - "Only one output state should be created." using (tx.outputs.size == 1) - val out = tx.outputs.single() as XState - "The sender and the recipient cannot be the same entity." using (out.sender != out.recipient) - "All of the participants must be signers." using (command.signers.containsAll(out.participants)) - "The X's value must be non-negative." using (out.x.value > 0) - } - - .. sourcecode:: java - - requireThat(require -> { - require.using("No inputs should be consumed when issuing an X.", tx.getInputs().isEmpty()); - require.using("Only one output state should be created.", tx.getOutputs().size() == 1); - final XState out = (XState) tx.getOutputs().get(0); - require.using("The sender and the recipient cannot be the same entity.", out.getSender() != out.getRecipient()); - require.using("All of the participants must be signers.", command.getSigners().containsAll(out.getParticipants())); - require.using("The X's value must be non-negative.", out.getX().getValue() > 0); - return null; - }); - -For each <``String``, ``Boolean``> pair within ``requireThat``, if the boolean condition is false, an -``IllegalArgumentException`` is thrown with the corresponding string as the exception message. In turn, this -exception will cause the transaction to be rejected. - -Commands --------- -``LedgerTransaction`` contains the commands as a list of ``CommandWithParties`` instances. ``CommandWithParties`` pairs -a ``CommandData`` with a list of required signers for the transaction: - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt - :language: kotlin - :start-after: DOCSTART 6 - :end-before: DOCEND 6 - -Where: - -* ``signers`` is the list of each signer's ``PublicKey`` -* ``signingParties`` is the list of the signer's identities, if known -* ``value`` is the object being signed (a command, in this case) - -Branching verify with commands -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Generally, we will want to impose different constraints on a transaction based on its commands. For example, we will -want to impose different constraints on a cash issuance transaction to on a cash transfer transaction. - -We can achieve this by extracting the command and using standard branching logic within ``verify``. Here, we extract -the single command of type ``XContract.Commands`` from the transaction, and branch ``verify`` accordingly: - -.. container:: codeset - - .. sourcecode:: kotlin - - class XContract : Contract { - interface Commands : CommandData { - class Issue : TypeOnlyCommandData(), Commands - class Transfer : TypeOnlyCommandData(), Commands - } - - override fun verify(tx: LedgerTransaction) { - val command = tx.findCommand { true } - - when (command.value) { - is Commands.Issue -> { - // Issuance verification logic. - } - is Commands.Transfer -> { - // Transfer verification logic. - } - } - } - } - - .. sourcecode:: java - - public class XContract implements Contract { - public interface Commands extends CommandData { - class Issue extends TypeOnlyCommandData implements Commands {} - class Transfer extends TypeOnlyCommandData implements Commands {} - } - - @Override - public void verify(LedgerTransaction tx) { - final Commands command = tx.findCommand(Commands.class, cmd -> true).getValue(); - - if (command instanceof Commands.Issue) { - // Issuance verification logic. - } else if (command instanceof Commands.Transfer) { - // Transfer verification logic. - } - } - } diff --git a/docs/source/api-core-types.rst b/docs/source/api-core-types.rst deleted file mode 100644 index e8f57793bf..0000000000 --- a/docs/source/api-core-types.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. highlight:: kotlin -.. raw:: html - - - - -API: Core types -=============== - -.. contents:: - -Corda provides several more core classes as part of its API. - -SecureHash ----------- -The ``SecureHash`` class is used to uniquely identify objects such as transactions and attachments by their hash. -Any object that needs to be identified by its hash should implement the ``NamedByHash`` interface: - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - -``SecureHash`` is a sealed class that only defines a single subclass, ``SecureHash.SHA256``. There are utility methods -to create and parse ``SecureHash.SHA256`` objects. - -.. _composite_keys: - -CompositeKey ------------- -Corda supports scenarios where more than one signature is required to authorise a state object transition. For example: -"Either the CEO or 3 out of 5 of his assistants need to provide signatures". - -This is achieved using a ``CompositeKey``, which uses public-key composition to organise the various public keys into a -tree data structure. A ``CompositeKey`` is a tree that stores the cryptographic public key primitives in its leaves and -the composition logic in the intermediary nodes. Every intermediary node specifies a *threshold* of how many child -signatures it requires. - -An illustration of an *"either Alice and Bob, or Charlie"* composite key: - -.. image:: resources/composite-key.png - :align: center - :width: 300px - -To allow further flexibility, each child node can have an associated custom *weight* (the default is 1). The *threshold* -then specifies the minimum total weight of all children required. Our previous example can also be expressed as: - -.. image:: resources/composite-key-2.png - :align: center - :width: 300px - -Signature verification is performed in two stages: - - 1. Given a list of signatures, each signature is verified against the expected content. - 2. The public keys corresponding to the signatures are matched against the leaves of the composite key tree in question, - and the total combined weight of all children is calculated for every intermediary node. If all thresholds are satisfied, - the composite key requirement is considered to be met. \ No newline at end of file diff --git a/docs/source/api-flows.rst b/docs/source/api-flows.rst deleted file mode 100644 index 05d6033c74..0000000000 --- a/docs/source/api-flows.rst +++ /dev/null @@ -1,1496 +0,0 @@ -.. highlight:: kotlin -.. raw:: html - - - - -API: Flows -========== - -.. note:: Before reading this page, you should be familiar with the key concepts of :doc:`key-concepts-flows`. - -.. contents:: - -An example flow ---------------- -Before we discuss the API offered by the flow, let's consider what a standard flow may look like. - -Imagine a flow for agreeing a basic ledger update between Alice and Bob. This flow will have two sides: - -* An ``Initiator`` side, that will initiate the request to update the ledger -* A ``Responder`` side, that will respond to the request to update the ledger - -Initiator -^^^^^^^^^ -In our flow, the Initiator flow class will be doing the majority of the work: - -*Part 1 - Build the transaction* - -1. Choose a notary for the transaction -2. Create a transaction builder -3. Extract any input states from the vault and add them to the builder -4. Create any output states and add them to the builder -5. Add any commands, attachments and time-window to the builder - -*Part 2 - Sign the transaction* - -6. Sign the transaction builder -7. Convert the builder to a signed transaction - -*Part 3 - Verify the transaction* - -8. Verify the transaction by running its contracts - -*Part 4 - Gather the counterparty's signature* - -9. Send the transaction to the counterparty -10. Wait to receive back the counterparty's signature -11. Add the counterparty's signature to the transaction -12. Verify the transaction's signatures - -*Part 5 - Finalize the transaction* - -13. Send the transaction to the notary -14. Wait to receive back the notarised transaction -15. Record the transaction locally -16. Store any relevant states in the vault -17. Send the transaction to the counterparty for recording - -We can visualize the work performed by initiator as follows: - -.. image:: resources/flow-overview.png - -Responder -^^^^^^^^^ -To respond to these actions, the responder takes the following steps: - -*Part 1 - Sign the transaction* - -1. Receive the transaction from the counterparty -2. Verify the transaction's existing signatures -3. Verify the transaction by running its contracts -4. Generate a signature over the transaction -5. Send the signature back to the counterparty - -*Part 2 - Record the transaction* - -6. Receive the notarised transaction from the counterparty -7. Record the transaction locally -8. Store any relevant states in the vault - -FlowLogic ---------- -In practice, a flow is implemented as one or more communicating ``FlowLogic`` subclasses. The ``FlowLogic`` -subclass's constructor can take any number of arguments of any type. The generic of ``FlowLogic`` (e.g. -``FlowLogic``) indicates the flow's return type. - -.. container:: codeset - - .. sourcecode:: kotlin - - class Initiator(val arg1: Boolean, - val arg2: Int, - val counterparty: Party): FlowLogic() { } - - class Responder(val otherParty: Party) : FlowLogic() { } - - .. sourcecode:: java - - public static class Initiator extends FlowLogic { - private final boolean arg1; - private final int arg2; - private final Party counterparty; - - public Initiator(boolean arg1, int arg2, Party counterparty) { - this.arg1 = arg1; - this.arg2 = arg2; - this.counterparty = counterparty; - } - - } - - public static class Responder extends FlowLogic { } - -FlowLogic annotations ---------------------- -Any flow from which you want to initiate other flows must be annotated with the ``@InitiatingFlow`` annotation. -Additionally, if you wish to start the flow via RPC, you must annotate it with the ``@StartableByRPC`` annotation: - -.. container:: codeset - - .. sourcecode:: kotlin - - @InitiatingFlow - @StartableByRPC - class Initiator(): FlowLogic() { } - - .. sourcecode:: java - - @InitiatingFlow - @StartableByRPC - public static class Initiator extends FlowLogic { } - -Meanwhile, any flow that responds to a message from another flow must be annotated with the ``@InitiatedBy`` annotation. -``@InitiatedBy`` takes the class of the flow it is responding to as its single parameter: - -.. container:: codeset - - .. sourcecode:: kotlin - - @InitiatedBy(Initiator::class) - class Responder(val otherSideSession: FlowSession) : FlowLogic() { } - - .. sourcecode:: java - - @InitiatedBy(Initiator.class) - public static class Responder extends FlowLogic { } - -Additionally, any flow that is started by a ``SchedulableState`` must be annotated with the ``@SchedulableFlow`` -annotation. - -Call ----- -Each ``FlowLogic`` subclass must override ``FlowLogic.call()``, which describes the actions it will take as part of -the flow. For example, the actions of the initiator's side of the flow would be defined in ``Initiator.call``, and the -actions of the responder's side of the flow would be defined in ``Responder.call``. - -In order for nodes to be able to run multiple flows concurrently, and to allow flows to survive node upgrades and -restarts, flows need to be checkpointable and serializable to disk. This is achieved by marking ``FlowLogic.call()``, -as well as any function invoked from within ``FlowLogic.call()``, with an ``@Suspendable`` annotation. - -.. container:: codeset - - .. sourcecode:: kotlin - - class Initiator(val counterparty: Party): FlowLogic() { - @Suspendable - override fun call() { } - } - - .. sourcecode:: java - - public static class InitiatorFlow extends FlowLogic { - private final Party counterparty; - - public Initiator(Party counterparty) { - this.counterparty = counterparty; - } - - @Suspendable - @Override - public Void call() throws FlowException { } - - } - -ServiceHub ----------- -Within ``FlowLogic.call``, the flow developer has access to the node's ``ServiceHub``, which provides access to the -various services the node provides. We will use the ``ServiceHub`` extensively in the examples that follow. You can -also see :doc:`api-service-hub` for information about the services the ``ServiceHub`` offers. - -Common flow tasks ------------------ -There are a number of common tasks that you will need to perform within ``FlowLogic.call`` in order to agree ledger -updates. This section details the API for common tasks. - -Transaction building -^^^^^^^^^^^^^^^^^^^^ -The majority of the work performed during a flow will be to build, verify and sign a transaction. This is covered -in :doc:`api-transactions`. - -Extracting states from the vault -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -When building a transaction, you'll often need to extract the states you wish to consume from the vault. This is -covered in :doc:`api-vault-query`. - -Retrieving information about other nodes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -We can retrieve information about other nodes on the network and the services they offer using -``ServiceHub.networkMapCache``. - -Notaries -~~~~~~~~ -Remember that a transaction generally needs a notary to: - -* Prevent double-spends if the transaction has inputs -* Serve as a timestamping authority if the transaction has a time-window - -A notary can be retrieved from the network map as follows: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 01 - :end-before: DOCEND 01 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 01 - :end-before: DOCEND 01 - :dedent: 12 - -Specific counterparties -~~~~~~~~~~~~~~~~~~~~~~~ -We can also use the network map to retrieve a specific counterparty: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 02 - :end-before: DOCEND 02 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 02 - :end-before: DOCEND 02 - :dedent: 12 - -Communication between parties -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In order to create a communication session between your initiator flow and the receiver flow you must call -``initiateFlow(party: Party): FlowSession`` - -``FlowSession`` instances in turn provide three functions: - -* ``send(payload: Any)`` - * Sends the ``payload`` object -* ``receive(receiveType: Class): R`` - * Receives an object of type ``receiveType`` -* ``sendAndReceive(receiveType: Class, payload: Any): R`` - * Sends the ``payload`` object and receives an object of type ``receiveType`` back - -In addition ``FlowLogic`` provides functions that can receive messages from multiple sessions and send messages to multiple sessions: - -* ``receiveAllMap(sessions: Map>): Map>`` - * Receives from all ``FlowSession`` objects specified in the passed in map. The received types may differ. -* ``receiveAll(receiveType: Class, sessions: List): List>`` - * Receives from all ``FlowSession`` objects specified in the passed in list. The received types must be the same. -* ``sendAll(payload: Any, sessions: Set)`` - * Sends the ``payload`` object to all the provided ``FlowSession``\s. -* ``sendAllMap(payloadsPerSession: Map)`` - * Sends a potentially different payload to each ``FlowSession``, as specified by the provided ``payloadsPerSession``. - -.. note:: It's more efficient to call ``sendAndReceive`` instead of calling ``send`` and then ``receive``. It's also more efficient to call ``sendAll``/``receiveAll`` instead of multiple ``send``/``receive`` respectively. - -InitiateFlow -~~~~~~~~~~~~ - -``initiateFlow`` creates a communication session with the passed in ``Party``. - - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART initiateFlow - :end-before: DOCEND initiateFlow - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART initiateFlow - :end-before: DOCEND initiateFlow - :dedent: 12 - -Note that at the time of call to this function no actual communication is done, this is deferred to the first -send/receive, at which point the counterparty will either: - -1. Ignore the message if they are not registered to respond to messages from this flow. -2. Start the flow they have registered to respond to this flow. - -Send -~~~~ - -Once we have a ``FlowSession`` object we can send arbitrary data to a counterparty: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 04 - :end-before: DOCEND 04 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 04 - :end-before: DOCEND 04 - :dedent: 12 - -The flow on the other side must eventually reach a corresponding ``receive`` call to get this message. - -Receive -~~~~~~~ -We can also wait to receive arbitrary data of a specific type from a counterparty. Again, this implies a corresponding -``send`` call in the counterparty's flow. A few scenarios: - -* We never receive a message back. In the current design, the flow is paused until the node's owner kills the flow. -* Instead of sending a message back, the counterparty throws a ``FlowException``. This exception is propagated back - to us, and we can use the error message to establish what happened. -* We receive a message back, but it's of the wrong type. In this case, a ``FlowException`` is thrown. -* We receive back a message of the correct type. All is good. - -Upon calling ``receive`` (or ``sendAndReceive``), the ``FlowLogic`` is suspended until it receives a response. - -We receive the data wrapped in an ``UntrustworthyData`` instance. This is a reminder that the data we receive may not -be what it appears to be! We must unwrap the ``UntrustworthyData`` using a lambda: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 05 - :end-before: DOCEND 05 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 05 - :end-before: DOCEND 05 - :dedent: 12 - -We're not limited to sending to and receiving from a single counterparty. A flow can send messages to as many parties -as it likes, and each party can invoke a different response flow: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 06 - :end-before: DOCEND 06 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 06 - :end-before: DOCEND 06 - :dedent: 12 - -.. warning:: If you initiate several flows from the same ``@InitiatingFlow`` flow then on the receiving side you must be - prepared to be initiated by any of the corresponding ``initiateFlow()`` calls! A good way of handling this ambiguity - is to send as a first message a "role" message to the initiated flow, indicating which part of the initiating flow - the rest of the counter-flow should conform to. For example send an enum, and on the other side start with a switch - statement. - -SendAndReceive -~~~~~~~~~~~~~~ -We can also use a single call to send data to a counterparty and wait to receive data of a specific type back. The -type of data sent doesn't need to match the type of the data received back: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 07 - :end-before: DOCEND 07 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 07 - :end-before: DOCEND 07 - :dedent: 12 - -Counterparty response -~~~~~~~~~~~~~~~~~~~~~ -Suppose we're now on the ``Responder`` side of the flow. We just received the following series of messages from the -``Initiator``: - -1. They sent us an ``Any`` instance -2. They waited to receive an ``Integer`` instance back -3. They sent a ``String`` instance and waited to receive a ``Boolean`` instance back - -Our side of the flow must mirror these calls. We could do this as follows: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 08 - :end-before: DOCEND 08 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 08 - :end-before: DOCEND 08 - :dedent: 12 - -Why sessions? -^^^^^^^^^^^^^ - -Before ``FlowSession`` s were introduced the send/receive API looked a bit different. They were functions on -``FlowLogic`` and took the address ``Party`` as argument. The platform internally maintained a mapping from ``Party`` to -session, hiding sessions from the user completely. - -Although this is a convenient API it introduces subtle issues where a message that was originally meant for a specific -session may end up in another. - -Consider the following contrived example using the old ``Party`` based API: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/LaunchSpaceshipFlow.kt - :language: kotlin - :start-after: DOCSTART LaunchSpaceshipFlow - :end-before: DOCEND LaunchSpaceshipFlow - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/LaunchSpaceshipFlow.java - :language: java - :start-after: DOCSTART LaunchSpaceshipFlow - :end-before: DOCEND LaunchSpaceshipFlow - -The intention of the flows is very clear: LaunchSpaceshipFlow asks the president whether a spaceship should be launched. -It is expecting a boolean reply. The president in return first tells the secretary that they need coffee, which is also -communicated with a boolean. Afterwards the president replies to the launcher that they don't want to launch. - -However the above can go horribly wrong when the ``launcher`` happens to be the same party ``getSecretary`` returns. In -this case the boolean meant for the secretary will be received by the launcher! - -This indicates that ``Party`` is not a good identifier for the communication sequence, and indeed the ``Party`` based -API may introduce ways for an attacker to fish for information and even trigger unintended control flow like in the -above case. - -Hence we introduced ``FlowSession``, which identifies the communication sequence. With ``FlowSession`` s the above set -of flows would look like this: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/LaunchSpaceshipFlow.kt - :language: kotlin - :start-after: DOCSTART LaunchSpaceshipFlowCorrect - :end-before: DOCEND LaunchSpaceshipFlowCorrect - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/LaunchSpaceshipFlow.java - :language: java - :start-after: DOCSTART LaunchSpaceshipFlowCorrect - :end-before: DOCEND LaunchSpaceshipFlowCorrect - -Note how the president is now explicit about which session it wants to send to. - -Porting from the old Party-based API -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In the old API the first ``send`` or ``receive`` to a ``Party`` was the one kicking off the counter-flow. This is now -explicit in the ``initiateFlow`` function call. To port existing code: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART FlowSession porting - :end-before: DOCEND FlowSession porting - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART FlowSession porting - :end-before: DOCEND FlowSession porting - :dedent: 12 - -Subflows --------- -Subflows are pieces of reusable flows that may be run by calling ``FlowLogic.subFlow``. There are two broad categories -of subflows, inlined and initiating ones. The main difference lies in the counter-flow's starting method, initiating -ones initiate counter-flows automatically, while inlined ones expect some parent counter-flow to run the inlined -counterpart. - -Inlined subflows -^^^^^^^^^^^^^^^^ -Inlined subflows inherit their calling flow's type when initiating a new session with a counterparty. For example, say -we have flow A calling an inlined subflow B, which in turn initiates a session with a party. The FlowLogic type used to -determine which counter-flow should be kicked off will be A, not B. Note that this means that the other side of this -inlined flow must therefore be implemented explicitly in the kicked off flow as well. This may be done by calling a -matching inlined counter-flow, or by implementing the other side explicitly in the kicked off parent flow. - -An example of such a flow is ``CollectSignaturesFlow``. It has a counter-flow ``SignTransactionFlow`` that isn't -annotated with ``InitiatedBy``. This is because both of these flows are inlined; the kick-off relationship will be -defined by the parent flows calling ``CollectSignaturesFlow`` and ``SignTransactionFlow``. - -In the code inlined subflows appear as regular ``FlowLogic`` instances, `without` either of the ``@InitiatingFlow`` or -``@InitiatedBy`` annotation. - -.. note:: Inlined flows aren't versioned; they inherit their parent flow's version. - -Initiating subflows -^^^^^^^^^^^^^^^^^^^ -Initiating subflows are ones annotated with the ``@InitiatingFlow`` annotation. When such a flow initiates a session its -type will be used to determine which ``@InitiatedBy`` flow to kick off on the counterparty. - -An example is the ``@InitiatingFlow InitiatorFlow``/``@InitiatedBy ResponderFlow`` flow pair in the ``FlowCookbook``. - -.. note:: Initiating flows are versioned separately from their parents. - -.. note:: The only exception to this rule is ``FinalityFlow`` which is annotated with ``@InitiatingFlow`` but is an inlined flow. This flow - was previously initiating and the annotation exists to maintain backwards compatibility with old code. - -Core initiating subflows -~~~~~~~~~~~~~~~~~~~~~~~~ -Corda-provided initiating subflows are a little different to standard ones as they are versioned together with the -platform, and their initiated counter-flows are registered explicitly, so there is no need for the ``InitiatedBy`` -annotation. - -Library flows -^^^^^^^^^^^^^ -Corda installs four initiating subflow pairs on each node by default: - -* ``NotaryChangeFlow``/``NotaryChangeHandler``, which should be used to change a state's notary -* ``ContractUpgradeFlow.Initiate``/``ContractUpgradeHandler``, which should be used to change a state's contract -* ``SwapIdentitiesFlow``/``SwapIdentitiesHandler``, which is used to exchange confidential identities with a - counterparty - -.. warning:: ``SwapIdentitiesFlow``/``SwapIdentitiesHandler`` are only installed if the ``confidential-identities`` module - is included. The ``confidential-identities`` module is still not stabilised, so the - ``SwapIdentitiesFlow``/``SwapIdentitiesHandler`` API may change in future releases. See :doc:`api-stability-guarantees`. - -Corda also provides a number of built-in inlined subflows that should be used for handling common tasks. The most -important are: - -* ``FinalityFlow`` which is used to notarise, record locally and then broadcast a signed transaction to its participants - and any extra parties. -* ``ReceiveFinalityFlow`` to receive these notarised transactions from the ``FinalityFlow`` sender and record locally. -* ``CollectSignaturesFlow`` , which should be used to collect a transaction's required signatures -* ``SendTransactionFlow`` , which should be used to send a signed transaction if it needed to be resolved on - the other side. -* ``ReceiveTransactionFlow``, which should be used receive a signed transaction - -Let's look at some of these flows in more detail. - -FinalityFlow -~~~~~~~~~~~~ -``FinalityFlow`` allows us to notarise the transaction and get it recorded in the vault of the participants of all -the transaction's states: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 09 - :end-before: DOCEND 09 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 09 - :end-before: DOCEND 09 - :dedent: 12 - -We can also choose to send the transaction to additional parties who aren't one of the state's participants: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 10 - :end-before: DOCEND 10 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 10 - :end-before: DOCEND 10 - :dedent: 12 - -Only one party has to call ``FinalityFlow`` for a given transaction to be recorded by all participants. It **must not** -be called by every participant. Instead, every other particpant **must** call ``ReceiveFinalityFlow`` in their responder -flow to receive the transaction: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART ReceiveFinalityFlow - :end-before: DOCEND ReceiveFinalityFlow - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART ReceiveFinalityFlow - :end-before: DOCEND ReceiveFinalityFlow - :dedent: 12 - -``idOfTxWeSigned`` is an optional parameter used to confirm that we got the right transaction. It comes from using ``SignTransactionFlow`` -which is described in the error handling behaviour section. - -Finalizing transactions with only one participant -................................................. - -In some cases, transactions will only have one participant, the initiator. In these instances, there are no other -parties to send the transactions to during ``FinalityFlow``. In these cases the ``counterpartySession`` list must exist, -but be empty. - -Error handling behaviour -........................ - -Once a transaction has been notarised and its input states consumed by the flow initiator (eg. sender), should the participant(s) receiving the -transaction fail to verify it, or the receiving flow (the finality handler) fails due to some other error, we then have a scenario where not -all parties have the correct up to date view of the ledger (a condition where eventual consistency between participants takes longer than is -normally the case under Corda's `eventual consistency model `_). To recover from this scenario, -the receiver's finality handler will automatically be sent to the :doc:`node-flow-hospital` where it's suspended and retried from its last checkpoint -upon node restart, or according to other conditional retry rules explained in :ref:`flow hospital runtime behaviour `. -This gives the node operator the opportunity to recover from the error. Until the issue is resolved the node will continue to retry the flow -on each startup. Upon successful completion by the receiver's finality flow, the ledger will become fully consistent once again. - -.. warning:: It's possible to forcibly terminate the erroring finality handler using the ``killFlow`` RPC but at the risk of an inconsistent view of the ledger. - -.. note:: A future release will allow retrying hospitalised flows without restarting the node, i.e. via RPC. - -CollectSignaturesFlow/SignTransactionFlow -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The list of parties who need to sign a transaction is dictated by the transaction's commands. Once we've signed a -transaction ourselves, we can automatically gather the signatures of the other required signers using -``CollectSignaturesFlow``: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 15 - :end-before: DOCEND 15 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 15 - :end-before: DOCEND 15 - :dedent: 12 - -Each required signer will need to respond by invoking its own ``SignTransactionFlow`` subclass to check the -transaction (by implementing the ``checkTransaction`` method) and provide their signature if they are satisfied: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 16 - :end-before: DOCEND 16 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 16 - :end-before: DOCEND 16 - :dedent: 12 - -Types of things to check include: - - * Ensuring that the transaction received is the expected type, i.e. has the expected type of inputs and outputs - * Checking that the properties of the outputs are expected, this is in the absence of integrating reference - data sources to facilitate this - * Checking that the transaction is not incorrectly spending (perhaps maliciously) asset states, as potentially - the transaction creator has access to some of signer's state references - -SendTransactionFlow/ReceiveTransactionFlow -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Verifying a transaction received from a counterparty also requires verification of every transaction in its -dependency chain. This means the receiving party needs to be able to ask the sender all the details of the chain. -The sender will use ``SendTransactionFlow`` for sending the transaction and then for processing all subsequent -transaction data vending requests as the receiver walks the dependency chain using ``ReceiveTransactionFlow``: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 12 - :end-before: DOCEND 12 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 12 - :end-before: DOCEND 12 - :dedent: 12 - -We can receive the transaction using ``ReceiveTransactionFlow``, which will automatically download all the -dependencies and verify the transaction: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 13 - :end-before: DOCEND 13 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 13 - :end-before: DOCEND 13 - :dedent: 12 - -We can also send and receive a ``StateAndRef`` dependency chain and automatically resolve its dependencies: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 14 - :end-before: DOCEND 14 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 14 - :end-before: DOCEND 14 - :dedent: 12 - -Why inlined subflows? -^^^^^^^^^^^^^^^^^^^^^ -Inlined subflows provide a way to share commonly used flow code `while forcing users to create a parent flow`. Take for -example ``CollectSignaturesFlow``. Say we made it an initiating flow that automatically kicks off -``SignTransactionFlow`` that signs the transaction. This would mean malicious nodes can just send any old transaction to -us using ``CollectSignaturesFlow`` and we would automatically sign it! - -By making this pair of flows inlined we provide control to the user over whether to sign the transaction or not by -forcing them to nest it in their own parent flows. - -In general if you're writing a subflow the decision of whether you should make it initiating should depend on whether -the counter-flow needs broader context to achieve its goal. - -FlowException -------------- -Suppose a node throws an exception while running a flow. Any counterparty flows waiting for a message from the node -(i.e. as part of a call to ``receive`` or ``sendAndReceive``) will be notified that the flow has unexpectedly -ended and will themselves end. However, the exception thrown will not be propagated back to the counterparties. - -If you wish to notify any waiting counterparties of the cause of the exception, you can do so by throwing a -``FlowException``: - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/flows/FlowException.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - -The flow framework will automatically propagate the ``FlowException`` back to the waiting counterparties. - -There are many scenarios in which throwing a ``FlowException`` would be appropriate: - -* A transaction doesn't ``verify()`` -* A transaction's signatures are invalid -* The transaction does not match the parameters of the deal as discussed -* You are reneging on a deal - -Below is an example using ``FlowException``: - -.. container:: codeset - - .. sourcecode:: kotlin - - @InitiatingFlow - class SendMoneyFlow(private val moneyRecipient: Party) : FlowLogic() { - @Suspendable - override fun call() { - val money = Money(10.0, USD) - try { - initiateFlow(moneyRecipient).sendAndReceive(money) - } catch (e: FlowException) { - if (e.cause is WrongCurrencyException) { - log.info(e.message, e) - } - } - } - } - - @InitiatedBy(SendMoneyFlow::class) - class ReceiveMoneyFlow(private val moneySender: FlowSession) : FlowLogic() { - @Suspendable - override fun call() { - val receivedMoney = moneySender.receive().unwrap { it } - if (receivedMoney.currency != GBP) { - // Wrap a thrown Exception with a FlowException for the counter party to receive it. - throw FlowException(WrongCurrencyException("I only accept GBP, sorry!")) - } - } - } - - class WrongCurrencyException(message: String) : CordaRuntimeException(message) - -HospitalizeFlowException ------------------------- -Some operations can fail intermittently and will succeed if they are tried again at a later time. Flows have the ability to halt their -execution in such situations. By throwing a ``HospitalizeFlowException`` a flow will stop and retry at a later time (on the next node restart). - -A ``HospitalizeFlowException`` can be defined in various ways: - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/flows/HospitalizeFlowException.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - -.. note:: If a ``HospitalizeFlowException`` is wrapping or extending an exception already being handled by the :doc:`node-flow-hospital`, the outcome of a flow may change. For example, the flow - could instantly retry or terminate if a critical error occurred. - -.. note:: ``HospitalizeFlowException`` can be extended for customized exceptions. These exceptions will be treated in the same way when thrown. - -Below is an example of a flow that should retry again in the future if an error occurs: - -.. container:: codeset - - .. sourcecode:: kotlin - - class TryAccessServiceFlow(): FlowLogic() { - override fun call() { - try { - val code = serviceHub.cordaService(HTTPService::class.java).get() // throws UnknownHostException. - } catch (e: UnknownHostException) { - // Accessing the service failed! It might be offline. Let's hospitalize this flow, and have it retry again on next node startup. - throw HospitalizeFlowException("Service might be offline!", e) - } - } - } - -ProgressTracker ---------------- -We can give our flow a progress tracker. This allows us to see the flow's progress visually in our node's CRaSH shell. - -To provide a progress tracker, we have to override ``FlowLogic.progressTracker`` in our flow: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 17 - :end-before: DOCEND 17 - :dedent: 4 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 17 - :end-before: DOCEND 17 - :dedent: 8 - -We then update the progress tracker's current step as we progress through the flow as follows: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 18 - :end-before: DOCEND 18 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 18 - :end-before: DOCEND 18 - :dedent: 12 - -.. _api_flows_external_operations: - -Calling external systems inside of flows ------------------------------------------- -Flows provide the ability to await the result of an external operation running outside of the context of a flow. A flow will suspend while -awaiting a result. This frees up a flow worker thread to continuing processing other flows. - -.. note:: - - Flow worker threads belong to the thread pool that executes flows. - -Examples of where this functionality is useful include: - - * Triggering a long running process on an external system - * Retrieving information from a external service that might go down - -``FlowLogic`` provides two ``await`` functions that allow custom operations to be defined and executed outside of the context of a flow. -Below are the interfaces that must be implemented and passed into ``await``, along with brief descriptions of what they do: - - * ``FlowExternalOperation`` - An operation that returns a result which should be run using a thread from one of the node's - thread pools. - - * ``FlowExternalAsyncOperation`` - An operation that returns a future which should be run on a thread provided to its implementation. - Threading needs to be explicitly handled when using ``FlowExternalAsyncOperation``. - -FlowExternalOperation -^^^^^^^^^^^^^^^^^^^^^ - -``FlowExternalOperation`` allows developers to write an operation that will run on a thread provided by the node's flow external operation -thread pool. - -.. note:: - - The size of the external operation thread pool can be configured, see :ref:`the node configuration documentation `. - -Below is an example of how ``FlowExternalOperation`` can be called from a flow to run an operation on a new thread, allowing the flow to suspend: - -.. container:: codeset - - .. sourcecode:: kotlin - - @StartableByRPC - class FlowUsingFlowExternalOperation : FlowLogic() { - - @Suspendable - override fun call() { - // Other flow operations - - // Call [FlowLogic.await] to execute an external operation - // The result of the operation is returned to the flow - val response: Response = await( - // Pass in an implementation of [FlowExternalOperation] - RetrieveDataFromExternalSystem( - serviceHub.cordaService(ExternalService::class.java), - Data("amount", 1) - ) - ) - // Other flow operations - } - - class RetrieveDataFromExternalSystem( - private val externalService: ExternalService, - private val data: Data - ) : FlowExternalOperation { - - // Implement [execute] which will be run on a thread outside of the flow's context - override fun execute(deduplicationId: String): Response { - return externalService.retrieveDataFromExternalSystem(deduplicationId, data) - } - } - } - - @CordaService - class ExternalService(serviceHub: AppServiceHub) : SingletonSerializeAsToken() { - - private val client: OkHttpClient = OkHttpClient() - - fun retrieveDataFromExternalSystem(deduplicationId: String, data: Data): Response { - return try { - // [DeduplicationId] passed into the request so the external system can handle deduplication - client.newCall( - Request.Builder().url("https://externalsystem.com/endpoint/$deduplicationId").post( - RequestBody.create( - MediaType.parse("text/plain"), data.toString() - ) - ).build() - ).execute() - } catch (e: IOException) { - // Handle checked exception - throw HospitalizeFlowException("External API call failed", e) - } - } - } - - data class Data(val name: String, val value: Any) - - .. sourcecode:: java - - @StartableByRPC - public class FlowUsingFlowExternalOperation extends FlowLogic { - - @Override - @Suspendable - public Void call() { - // Other flow operations - - // Call [FlowLogic.await] to execute an external operation - // The result of the operation is returned to the flow - Response response = await( - // Pass in an implementation of [FlowExternalOperation] - new RetrieveDataFromExternalSystem( - getServiceHub().cordaService(ExternalService.class), - new Data("amount", 1) - ) - ); - // Other flow operations - return null; - } - - public class RetrieveDataFromExternalSystem implements FlowExternalOperation { - - private ExternalService externalService; - private Data data; - - public RetrieveDataFromExternalSystem(ExternalService externalService, Data data) { - this.externalService = externalService; - this.data = data; - } - - // Implement [execute] which will be run on a thread outside of the flow's context - @Override - public Response execute(String deduplicationId) { - return externalService.retrieveDataFromExternalSystem(deduplicationId, data); - } - } - } - - @CordaService - public class ExternalService extends SingletonSerializeAsToken { - - private OkHttpClient client = new OkHttpClient(); - - public ExternalService(AppServiceHub serviceHub) { } - - public Response retrieveDataFromExternalSystem(String deduplicationId, Data data) { - try { - // [DeduplicationId] passed into the request so the external system can handle deduplication - return client.newCall( - new Request.Builder().url("https://externalsystem.com/endpoint/" + deduplicationId).post( - RequestBody.create( - MediaType.parse("text/plain"), data.toString() - ) - ).build() - ).execute(); - } catch (IOException e) { - // Must handle checked exception - throw new HospitalizeFlowException("External API call failed", e); - } - } - } - - public class Data { - - private String name; - private Object value; - - public Data(String name, Object value) { - this.name = name; - this.value = value; - } - - public String getName() { - return name; - } - - public Object getValue() { - return value; - } - } - -In summary, the following steps are taken in the code above: - - * ``ExternalService`` is a Corda service that provides a way to contact an external system (by HTTP in this example). - * ``ExternalService.retrieveDataFromExternalSystem`` is passed a ``deduplicationId`` which is included as part of the request to the - external system. The external system, in this example, will handle deduplication and return the previous result if it was already - computed. - * An implementation of ``FlowExternalOperation`` (``RetrieveDataFromExternalSystem``) is created that calls ``ExternalService.retrieveDataFromExternalSystem``. - * ``RetrieveDataFromExternalSystem`` is then passed into ``await`` to execute the code contained in ``RetrieveDataFromExternalSystem.execute``. - * The result of ``RetrieveDataFromExternalSystem.execute`` is then returned to the flow once its execution finishes. - -FlowExternalAsyncOperation -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -``FlowExternalAsyncOperation`` allows developers to write an operation that returns a future whose threading is handled within the CorDapp. - -.. warning:: - - Threading must be explicitly controlled when using ``FlowExternalAsyncOperation``. A future will be run on its current flow worker - thread if a new thread is not spawned or provided by a thread pool. This prevents the flow worker thread from freeing up and allowing - another flow to take control and run. - -Implementations of ``FlowExternalAsyncOperation`` must return a ``CompletableFuture``. How this future is created is up to the developer. -It is recommended to use ``CompletableFuture.supplyAsync`` and supply an executor to run the future on. Other libraries can be used to -generate futures, as long as a ``CompletableFuture`` is returned out of ``FlowExternalAsyncOperation``. An example of creating a future -using :ref:`Guava's ListenableFuture ` is given in a following section. - -.. note:: - - The future can be chained to execute further operations that continue using the same thread the future started on. For example, - ``CompletableFuture``'s ``whenComplete``, ``exceptionally`` or ``thenApply`` could be used (their async versions are also valid). - -Below is an example of how ``FlowExternalAsyncOperation`` can be called from a flow: - -.. container:: codeset - - .. sourcecode:: kotlin - - @StartableByRPC - class FlowUsingFlowExternalAsyncOperation : FlowLogic() { - - @Suspendable - override fun call() { - // Other flow operations - - // Call [FlowLogic.await] to execute an external operation - // The result of the operation is returned to the flow - val response: Response = await( - // Pass in an implementation of [FlowExternalAsyncOperation] - RetrieveDataFromExternalSystem( - serviceHub.cordaService(ExternalService::class.java), - Data("amount", 1) - ) - ) - // Other flow operations - } - - class RetrieveDataFromExternalSystem( - private val externalService: ExternalService, - private val data: Data - ) : FlowExternalAsyncOperation { - - // Implement [execute] which needs to be provided with a new thread to benefit from suspending the flow - override fun execute(deduplicationId: String): CompletableFuture { - return externalService.retrieveDataFromExternalSystem(deduplicationId, data) - } - } - } - - @CordaService - class ExternalService(serviceHub: AppServiceHub) : SingletonSerializeAsToken() { - - private val client: OkHttpClient = OkHttpClient() - - // [ExecutorService] created to provide a fixed number of threads to the futures created in this service - private val executor: ExecutorService = Executors.newFixedThreadPool( - 4, - ThreadFactoryBuilder().setNameFormat("external-service-thread").build() - ) - - fun retrieveDataFromExternalSystem(deduplicationId: String, data: Data): CompletableFuture { - // Create a [CompletableFuture] to be executed by the [FlowExternalAsyncOperation] - return CompletableFuture.supplyAsync( - Supplier { - try { - // [DeduplicationId] passed into the request so the external system can handle deduplication - client.newCall( - Request.Builder().url("https://externalsystem.com/endpoint/$deduplicationId").post( - RequestBody.create( - MediaType.parse("text/plain"), data.toString() - ) - ).build() - ).execute() - } catch (e: IOException) { - // Handle checked exception - throw HospitalizeFlowException("External API call failed", e) - } - }, - // The future must run on a new thread - executor - ) - } - } - - data class Data(val name: String, val value: Any) - - .. sourcecode:: java - - @StartableByRPC - public class FlowUsingFlowExternalAsyncOperation extends FlowLogic { - - @Override - @Suspendable - public Void call() { - // Other flow operations - - // Call [FlowLogic.await] to execute an external operation - // The result of the operation is returned to the flow - Response response = await( - // Pass in an implementation of [FlowExternalAsyncOperation] - new RetrieveDataFromExternalSystem( - getServiceHub().cordaService(ExternalService.class), - new Data("amount", 1) - ) - ); - // Other flow operations - return null; - } - - public class RetrieveDataFromExternalSystem implements FlowExternalAsyncOperation { - - private ExternalService externalService; - private Data data; - - public RetrieveDataFromExternalSystem(ExternalService externalService, Data data) { - this.externalService = externalService; - this.data = data; - } - - // Implement [execute] which needs to be provided with a new thread to benefit from suspending the flow - @Override - public CompletableFuture execute(String deduplicationId) { - return externalService.retrieveDataFromExternalSystem(deduplicationId, data); - } - } - } - - @CordaService - public class ExternalService extends SingletonSerializeAsToken { - - private OkHttpClient client = new OkHttpClient(); - - // [ExecutorService] created to provide a fixed number of threads to the futures created in this service - private ExecutorService executor = Executors.newFixedThreadPool( - 4, - new ThreadFactoryBuilder().setNameFormat("external-service-thread").build() - ); - - public ExternalService(AppServiceHub serviceHub) { } - - public CompletableFuture retrieveDataFromExternalSystem(String deduplicationId, Data data) { - // Create a [CompletableFuture] to be executed by the [FlowExternalAsyncOperation] - return CompletableFuture.supplyAsync( - () -> { - try { - // [DeduplicationId] passed into the request so the external system can handle deduplication - return client.newCall( - new Request.Builder().url("https://externalsystem.com/endpoint/" + deduplicationId).post( - RequestBody.create( - MediaType.parse("text/plain"), data.toString() - ) - ).build() - ).execute(); - } catch (IOException e) { - // Must handle checked exception - throw new HospitalizeFlowException("External API call failed", e); - } - }, - // The future must run on a new thread - executor - ); - } - } - - public class Data { - - private String name; - private Object value; - - public Data(String name, Object value) { - this.name = name; - this.value = value; - } - - public String getName() { - return name; - } - - public Object getValue() { - return value; - } - } - -In summary, the following steps are taken in the code above: - - * ``ExternalService`` is a Corda service that provides a way to contact an external system (by HTTP in this example). - * ``ExternalService.retrieveDataFromExternalSystem`` is passed a ``deduplicationId`` which is included as part of the request to the - external system. The external system, in this example, will handle deduplication and return the previous result if it was already - computed. - * A ``CompletableFuture`` is created that contacts the external system. ``CompletableFuture.supplyAsync`` takes in a reference to the - ``ExecutorService`` which will provide a thread for the external operation to run on. - * An implementation of ``FlowExternalAsyncOperation`` (``RetrieveDataFromExternalSystem``) is created that calls the ``ExternalService.retrieveDataFromExternalSystem``. - * ``RetrieveDataFromExternalSystem`` is then passed into ``await`` to execute the code contained in ``RetrieveDataFromExternalSystem.execute``. - * The result of ``RetrieveDataFromExternalSystem.execute`` is then returned to the flow once its execution finishes. - -Handling deduplication in external operations -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -A Flow has the ability to rerun from any point where it suspends. Due to this, a flow can execute code multiple times depending on where it -retries. For context contained inside a flow, values will be reset to their state recorded at the last suspension point. This makes most -properties existing inside a flow safe when retrying. External operations do not have the same guarantees as they are executed outside of -the context of flows. - -External operations are provided with a ``deduplicationId`` to allow CorDapps to decide whether to run the operation again or return a -result retrieved from a previous attempt. How deduplication is handled depends on the CorDapp and how the external system works. For -example, an external system might already handle this scenario and return the result from a previous calculation or it could be idempotent -and can be safely executed multiple times. - -.. warning:: - - There is no inbuilt deduplication for external operations. Any deduplication must be explicitly handled in whatever way is - appropriate for the CorDapp and external system. - -The ``deduplicationId`` passed to an external operation is constructed from its calling flow's ID and the number of suspends the flow has -made. Therefore, the ``deduplicationId`` is guaranteed to be the same on a retry and will never be used again once the flow has successfully -reached its next suspension point. - -.. note:: - - Any external operations that did not finish processing (or were kept in the flow hospital due to an error) will be retried upon node - restart. - -Below are examples of how deduplication could be handled: - - * The external system records successful computations and returns previous results if requested again. - * The external system is idempotent, meaning the computation can be made multiple times without altering any state (similar to the point above). - * An extra external service maintains a record of deduplication IDs. - * Recorded inside of the node's database. - -.. note:: - - Handling deduplication on the external system's side is preferred compared to handling it inside of the node. - -.. warning:: - - In-memory data structures should not be used for handling deduplication as their state will not survive node restarts. - -.. _api_flows_guava_future_conversion: - -Creating CompletableFutures from Guava's ListenableFutures -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The code below demonstrates how to convert a ``ListenableFuture`` into a ``CompletableFuture``, allowing the result to be executed using a -``FlowExternalAsyncOperation``. - -.. container:: codeset - - .. sourcecode:: kotlin - - @CordaService - class ExternalService(serviceHub: AppServiceHub) : SingletonSerializeAsToken() { - - private val client: OkHttpClient = OkHttpClient() - - // Guava's [ListeningExecutorService] created to supply a fixed number of threads - private val guavaExecutor: ListeningExecutorService = MoreExecutors.listeningDecorator( - Executors.newFixedThreadPool( - 4, - ThreadFactoryBuilder().setNameFormat("guava-thread").build() - ) - ) - - fun retrieveDataFromExternalSystem(deduplicationId: String, data: Data): CompletableFuture { - // Create a Guava [ListenableFuture] - val guavaFuture: ListenableFuture = guavaExecutor.submit(Callable { - try { - // [DeduplicationId] passed into the request so the external system can handle deduplication - client.newCall( - Request.Builder().url("https://externalsystem.com/endpoint/$deduplicationId").post( - RequestBody.create( - MediaType.parse("text/plain"), data.toString() - ) - ).build() - ).execute() - } catch (e: IOException) { - // Handle checked exception - throw HospitalizeFlowException("External API call failed", e) - } - }) - // Create a [CompletableFuture] - return object : CompletableFuture() { - override fun cancel(mayInterruptIfRunning: Boolean): Boolean { - return guavaFuture.cancel(mayInterruptIfRunning).also { - super.cancel(mayInterruptIfRunning) - } - } - }.also { completableFuture -> - // Create a callback that completes the returned [CompletableFuture] when the underlying [ListenableFuture] finishes - val callback = object : FutureCallback { - override fun onSuccess(result: Response?) { - completableFuture.complete(result) - } - - override fun onFailure(t: Throwable) { - completableFuture.completeExceptionally(t) - } - } - // Register the callback - Futures.addCallback(guavaFuture, callback, guavaExecutor) - } - } - } - - .. sourcecode:: java - - @CordaService - public class ExternalService extends SingletonSerializeAsToken { - - private OkHttpClient client = new OkHttpClient(); - - public ExternalService(AppServiceHub serviceHub) { } - - private ListeningExecutorService guavaExecutor = MoreExecutors.listeningDecorator( - Executors.newFixedThreadPool( - 4, - new ThreadFactoryBuilder().setNameFormat("guava-thread").build() - ) - ); - - public CompletableFuture retrieveDataFromExternalSystem(String deduplicationId, Data data) { - // Create a Guava [ListenableFuture] - ListenableFuture guavaFuture = guavaExecutor.submit(() -> { - try { - // [DeduplicationId] passed into the request so the external system can handle deduplication - return client.newCall( - new Request.Builder().url("https://externalsystem.com/endpoint/" + deduplicationId).post( - RequestBody.create( - MediaType.parse("text/plain"), data.toString() - ) - ).build() - ).execute(); - } catch (IOException e) { - // Must handle checked exception - throw new HospitalizeFlowException("External API call failed", e); - } - }); - // Create a [CompletableFuture] - CompletableFuture completableFuture = new CompletableFuture() { - // If the returned [CompletableFuture] is cancelled then the underlying [ListenableFuture] must be cancelled as well - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - boolean result = guavaFuture.cancel(mayInterruptIfRunning); - super.cancel(mayInterruptIfRunning); - return result; - } - }; - // Create a callback that completes the returned [CompletableFuture] when the underlying [ListenableFuture] finishes - FutureCallback callback = new FutureCallback() { - @Override - public void onSuccess(Response result) { - completableFuture.complete(result); - } - - @Override - public void onFailure(Throwable t) { - completableFuture.completeExceptionally(t); - } - }; - // Register the callback - Futures.addCallback(guavaFuture, callback, guavaExecutor); - - return completableFuture; - } - } - -In the code above: - - * A ``ListenableFuture`` is created and receives a thread from the ``ListeningExecutorService``. This future does all the processing. - * A ``CompletableFuture`` is created, so that it can be returned to and executed by a ``FlowExternalAsyncOperation``. - * A ``FutureCallback`` is registered to the ``ListenableFuture``, which will complete the ``CompletableFuture`` (either successfully or - exceptionally) depending on the outcome of the ``ListenableFuture``. - * ``CompletableFuture.cancel`` is overridden to propagate its cancellation down to the underlying ``ListenableFuture``. - -Concurrency, Locking and Waiting --------------------------------- -Corda is designed to: - -* run many flows in parallel -* persist flows to storage and resurrect those flows much later -* (in the future) migrate flows between JVMs - -Because of this, care must be taken when performing locking or waiting operations. - -Locking -^^^^^^^ -Flows should avoid using locks or interacting with objects that are shared between flows (except for ``ServiceHub`` and other -carefully crafted services such as Oracles. See :doc:`oracles`). Locks will significantly reduce the scalability of the -node, and can cause the node to deadlock if they remain locked across flow context switch boundaries (such as when sending -and receiving from peers, as discussed above, or sleeping, as discussed below). - -Waiting -^^^^^^^ -A flow can wait until a specific transaction has been received and verified by the node using `FlowLogic.waitForLedgerCommit`. -Outside of this, scheduling an activity to occur at some future time should be achieved using ``SchedulableState``. - -However, if there is a need for brief pauses in flows, you have the option of using ``FlowLogic.sleep`` in place of where you -might have used ``Thread.sleep``. Flows should expressly not use ``Thread.sleep``, since this will prevent the node from -processing other flows in the meantime, significantly impairing the performance of the node. - -Even ``FlowLogic.sleep`` should not be used to create long running flows or as a substitute to using the ``SchedulableState`` -scheduler, since the Corda ethos is for short-lived flows (long-lived flows make upgrading nodes or CorDapps much more -complicated). - -For example, the ``finance`` package currently uses ``FlowLogic.sleep`` to make several attempts at coin selection when -many states are soft locked, to wait for states to become unlocked: - - .. literalinclude:: ../../finance/workflows/src/main/kotlin/net/corda/finance/workflows/asset/selection/AbstractCashSelection.kt - :language: kotlin - :start-after: DOCSTART CASHSELECT 1 - :end-before: DOCEND CASHSELECT 1 - :dedent: 8 diff --git a/docs/source/api-identity.rst b/docs/source/api-identity.rst deleted file mode 100644 index 28f1a7d898..0000000000 --- a/docs/source/api-identity.rst +++ /dev/null @@ -1,155 +0,0 @@ -.. highlight:: kotlin -.. raw:: html - - - - -API: Identity -============= - -.. contents:: - -Party ------ -Parties on the network are represented using the ``AbstractParty`` class. There are two types of ``AbstractParty``: - -* ``Party``, identified by a ``PublicKey`` and a ``CordaX500Name`` -* ``AnonymousParty``, identified by a ``PublicKey`` only - -Using ``AnonymousParty`` to identify parties in states and commands prevents nodes from learning the identities -of the parties involved in a transaction when they verify the transaction's dependency chain. When preserving the -anonymity of each party is not required (e.g. for internal processing), ``Party`` can be used instead. - -The identity service allows flows to resolve ``AnonymousParty`` to ``Party``, but only if the anonymous party's -identity has already been registered with the node (typically handled by ``SwapIdentitiesFlow`` or -``IdentitySyncFlow``, discussed below). - -Party names use the ``CordaX500Name`` data class, which enforces the structure of names within Corda, as well as -ensuring a consistent rendering of the names in plain text. - -Support for both ``Party`` and ``AnonymousParty`` classes in Corda enables sophisticated selective disclosure of -identity information. For example, it is possible to construct a transaction using an ``AnonymousParty`` (so nobody can -learn of your involvement by inspection of the transaction), yet prove to specific counterparts that this -``AnonymousParty`` actually corresponds to your well-known identity. This is achieved using the -``PartyAndCertificate`` data class, which contains the X.509 certificate path proving that a given ``AnonymousParty`` -corresponds to a given ``Party``. Each ``PartyAndCertificate`` can be propagated to counterparties on a need-to-know -basis. - -The ``PartyAndCertificate`` class is also used by the network map service to represent well-known identities, with the -certificate path proving the certificate was issued by the doorman service. - -.. _confidential_identities_ref: - -Confidential identities ------------------------ - -.. warning:: The ``confidential-identities`` module is still not stabilised, so this API may change in future releases. - See :doc:`api-stability-guarantees`. - -Confidential identities are key pairs where the corresponding X.509 certificate (and path) are not made public, so that -parties who are not involved in the transaction cannot identify the owner. They are owned by a well-known identity, -which must sign the X.509 certificate. Before constructing a new transaction the involved parties must generate and -exchange new confidential identities, a process which is managed using ``SwapIdentitiesFlow`` (discussed below). The -public keys of these confidential identities are then used when generating output states and commands for the -transaction. - -Where using outputs from a previous transaction in a new transaction, counterparties may need to know who the involved -parties are. One example is the ``TwoPartyTradeFlow``, where an existing asset is exchanged for cash. If confidential -identities are being used, the buyer will want to ensure that the asset being transferred is owned by the seller, and -the seller will likewise want to ensure that the cash being transferred is owned by the buyer. Verifying this requires -both nodes to have a copy of the confidential identities for the asset and cash input states. ``IdentitySyncFlow`` -manages this process. It takes as inputs a transaction and a counterparty, and for every confidential identity involved -in that transaction for which the calling node holds the certificate path, it sends this certificate path to the -counterparty. - -SwapIdentitiesFlow -~~~~~~~~~~~~~~~~~~ -``SwapIdentitiesFlow`` is typically run as a subflow of another flow. It takes as its sole constructor argument the -counterparty we want to exchange confidential identities with. It returns a mapping from the identities of the caller -and the counterparty to their new confidential identities. In the future, this flow will be extended to handle swapping -identities with multiple parties at once. - -You can see an example of using ``SwapIdentitiesFlow`` in ``TwoPartyDealFlow.kt``: - -.. container:: codeset - - .. literalinclude:: ../../finance/workflows/src/main/kotlin/net/corda/finance/flows/TwoPartyDealFlow.kt - :language: kotlin - :start-after: DOCSTART 2 - :end-before: DOCEND 2 - :dedent: 8 - -``SwapIdentitiesFlow`` goes through the following key steps: - -1. Generate a new confidential identity from our well-known identity -2. Create a ``CertificateOwnershipAssertion`` object containing the new confidential identity (X500 name, public key) -3. Sign this object with the confidential identity's private key -4. Send the confidential identity and aforementioned signature to counterparties, while receiving theirs -5. Verify the signatures to ensure that identities were generated by the involved set of parties -6. Verify the confidential identities are owned by the expected well known identities -7. Store the confidential identities and return them to the calling flow - -This ensures not only that the confidential identity X.509 certificates are signed by the correct well-known -identities, but also that the confidential identity private key is held by the counterparty, and that a party cannot -claim ownership of another party's confidential identities. - -IdentitySyncFlow -~~~~~~~~~~~~~~~~ -When constructing a transaction whose input states reference confidential identities, it is common for counterparties -to require knowledge of which well-known identity each confidential identity maps to. ``IdentitySyncFlow`` handles this -process. You can see an example of its use in ``TwoPartyTradeFlow.kt``. - -``IdentitySyncFlow`` is divided into two parts: - -* ``IdentitySyncFlow.Send`` -* ``IdentitySyncFlow.Receive`` - -``IdentitySyncFlow.Send`` is invoked by the party initiating the identity synchronization: - -.. container:: codeset - - .. literalinclude:: ../../finance/workflows/src/main/kotlin/net/corda/finance/flows/TwoPartyTradeFlow.kt - :language: kotlin - :start-after: DOCSTART 6 - :end-before: DOCEND 6 - :dedent: 12 - -The identity synchronization flow goes through the following key steps: - -1. Extract participant identities from all input and output states and remove any well known identities. Required - signers on commands are currently ignored as they are presumed to be included in the participants on states, or to - be well-known identities of services (such as an oracle service) -2. For each counterparty node, send a list of the public keys of the confidential identities, and receive back a list - of those the counterparty needs the certificate path for -3. Verify the requested list of identities contains only confidential identities in the offered list, and abort - otherwise -4. Send the requested confidential identities as ``PartyAndCertificate`` instances to the counterparty - -.. note:: ``IdentitySyncFlow`` works on a push basis. The initiating node can only send confidential identities it has - the X.509 certificates for, and the remote nodes can only request confidential identities being offered (are - referenced in the transaction passed to the initiating flow). There is no standard flow for nodes to collect - confidential identities before assembling a transaction, and this is left for individual flows to manage if - required. - -Meanwhile, ``IdentitySyncFlow.Receive`` is invoked by all the other (non-initiating) parties involved in the identity -synchronization process: - -.. container:: codeset - - .. literalinclude:: ../../finance/workflows/src/main/kotlin/net/corda/finance/flows/TwoPartyTradeFlow.kt - :language: kotlin - :start-after: DOCSTART 07 - :end-before: DOCEND 07 - :dedent: 12 - -``IdentitySyncFlow`` will serve all confidential identities in the provided transaction, irrespective of well-known -identity. This is important for more complex transaction cases with 3+ parties, for example: - -* Alice is building the transaction, and provides some input state *x* owned by a confidential identity of Alice -* Bob provides some input state *y* owned by a confidential identity of Bob -* Charlie provides some input state *z* owned by a confidential identity of Charlie - -Alice may know all of the confidential identities ahead of time, but Bob not know about Charlie's and vice-versa. -The assembled transaction therefore has three input states *x*, *y* and *z*, for which only Alice possesses -certificates for all confidential identities. ``IdentitySyncFlow`` must send not just Alice's confidential identity but -also any other identities in the transaction to the Bob and Charlie. \ No newline at end of file diff --git a/docs/source/api-persistence.rst b/docs/source/api-persistence.rst deleted file mode 100644 index ab2a745671..0000000000 --- a/docs/source/api-persistence.rst +++ /dev/null @@ -1,467 +0,0 @@ -.. highlight:: kotlin -.. raw:: html - - - - -API: Persistence -================ - -.. contents:: - -Corda offers developers the option to expose all or some parts of a contract state to an *Object Relational Mapping* -(ORM) tool to be persisted in a *Relational Database Management System* (RDBMS). - -The purpose of this, is to assist :doc:`key-concepts-vault` -development and allow for the persistence of state data to a custom database table. Persisted states held in the -vault are indexed for the purposes of executing queries. This also allows for relational joins between Corda tables -and the organization's existing data. - -The Object Relational Mapping is specified using `Java Persistence API `_ -(JPA) annotations. This mapping is persisted to the database as a table row (a single, implicitly structured data item) by the node -automatically every time a state is recorded in the node's local vault as part of a transaction. - -.. note:: By default, nodes use an H2 database which is accessed using *Java Database Connectivity* JDBC. Any database - with a JDBC driver is a candidate and several integrations have been contributed to by the community. - Please see the info in ":doc:`node-database`" for details. - -Schemas -------- -Every ``ContractState`` may implement the ``QueryableState`` interface if it wishes to be inserted into a custom table in the node's -database and made accessible using SQL. - -.. literalinclude:: ../../core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt - :language: kotlin - :start-after: DOCSTART QueryableState - :end-before: DOCEND QueryableState - -The ``QueryableState`` interface requires the state to enumerate the different relational schemas it supports, for -instance in situations where the schema has evolved. Each relational schema is represented as a ``MappedSchema`` -object returned by the state's ``supportedSchemas`` method. - -Nodes have an internal ``SchemaService`` which decides what data to persist by selecting the ``MappedSchema`` to use. -Once a ``MappedSchema`` is selected, the ``SchemaService`` will delegate to the ``QueryableState`` to generate a corresponding -representation (mapped object) via the ``generateMappedObject`` method, the output of which is then passed to the *ORM*. - -.. literalinclude:: ../../node/src/main/kotlin/net/corda/node/services/api/SchemaService.kt - :language: kotlin - :start-after: DOCSTART SchemaService - :end-before: DOCEND SchemaService - -.. literalinclude:: ../../core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt - :language: kotlin - :start-after: DOCSTART MappedSchema - :end-before: DOCEND MappedSchema - -With this framework, the relational view of ledger states can evolve in a controlled fashion in lock-step with internal systems or other -integration points and is not dependant on changes to the contract code. - -It is expected that multiple contract state implementations might provide mappings within a single schema. -For example an Interest Rate Swap contract and an Equity OTC Option contract might both provide a mapping to -a Derivative contract within the same schema. The schemas should typically not be part of the contract itself and should exist independently -to encourage re-use of a common set within a particular business area or CorDapp. - -.. note:: It's advisable to avoid cross-references between different schemas as this may cause issues when evolving ``MappedSchema`` - or migrating its data. At startup, nodes log such violations as warnings stating that there's a cross-reference between ``MappedSchema``'s. - The detailed messages incorporate information about what schemas, entities and fields are involved. - -``MappedSchema`` offer a family name that is disambiguated using Java package style name-spacing derived from the -class name of a *schema family* class that is constant across versions, allowing the ``SchemaService`` to select a -preferred version of a schema. - -The ``SchemaService`` is also responsible for the ``SchemaOptions`` that can be configured for a particular -``MappedSchema``. These allow the configuration of database schemas or table name prefixes to avoid clashes with -other ``MappedSchema``. - -.. note:: It is intended that there should be plugin support for the ``SchemaService`` to offer version upgrading, implementation - of additional schemas, and enable active schemas as being configurable. The present implementation does not include these features - and simply results in all versions of all schemas supported by a ``QueryableState`` being persisted. - This will change in due course. Similarly, the service does not currently support - configuring ``SchemaOptions`` but will do so in the future. - -Custom schema registration --------------------------- -Custom contract schemas are automatically registered at startup time for CorDapps. The node bootstrap process will scan for states that implement -the Queryable state interface. Tables are then created as specified by the ``MappedSchema`` identified by each state's ``supportedSchemas`` method. - -For testing purposes it is necessary to manually register the packages containing custom schemas as follows: - -- Tests using ``MockNetwork`` and ``MockNode`` must explicitly register packages using the `cordappPackages` parameter of ``MockNetwork`` -- Tests using ``MockServices`` must explicitly register packages using the `cordappPackages` parameter of the ``MockServices`` `makeTestDatabaseAndMockServices()` helper method. - -.. note:: Tests using the `DriverDSL` will automatically register your custom schemas if they are in the same project structure as the driver call. - -Object relational mapping -------------------------- -To facilitate the ORM, the persisted representation of a ``QueryableState`` should be an instance of a ``PersistentState`` subclass, -constructed either by the state itself or a plugin to the ``SchemaService``. This allows the ORM layer to always -associate a ``StateRef`` with a persisted representation of a ``ContractState`` and allows joining with the set of -unconsumed states in the vault. - -The ``PersistentState`` subclass should be marked up as a JPA 2.1 *Entity* with a defined table name and having -properties (in Kotlin, getters/setters in Java) annotated to map to the appropriate columns and SQL types. Additional -entities can be included to model these properties where they are more complex, for example collections (:ref:`Persisting Hierarchical Data`), so -the mapping does not have to be *flat*. The ``MappedSchema`` constructor accepts a list of all JPA entity classes for that schema in -the ``MappedTypes`` parameter. It must provide this list in order to initialise the ORM layer. - -Several examples of entities and mappings are provided in the codebase, including ``Cash.State`` and -``CommercialPaper.State``. For example, here's the first version of the cash schema. - -.. container:: codeset - - .. literalinclude:: ../../finance/contracts/src/main/kotlin/net/corda/finance/schemas/CashSchemaV1.kt - :language: kotlin - -.. note:: If Cordapp needs to be portable between Corda OS (running against H2) and Corda Enterprise (running against a standalone database), - consider database vendors specific requirements. - Ensure that table and column names are compatible with the naming convention of the database vendors for which the Cordapp will be deployed, - e.g. for Oracle database, prior to version 12.2 the maximum length of table/column name is 30 bytes (the exact number of characters depends on the database encoding). - -Persisting Hierarchical Data ----------------------------- - -You may wish to persist hierarchical relationships within states using multiple database tables - -You may wish to persist hierarchical relationships within state data using multiple database tables. In order to facillitate this, multiple ``PersistentState`` -subclasses may be implemented. The relationship between these classes is defined using JPA annotations. It is important to note that the ``MappedSchema`` -constructor requires a list of *all* of these subclasses. - -An example Schema implementing hierarchical relationships with JPA annotations has been implemented below. This Schema will cause ``parent_data`` and ``child_data`` tables to be -created. - -.. container:: codeset - - .. sourcecode:: java - - @CordaSerializable - public class SchemaV1 extends MappedSchema { - - /** - * This class must extend the MappedSchema class. Its name is based on the SchemaFamily name and the associated version number abbreviation (V1, V2... Vn). - * In the constructor, use the super keyword to call the constructor of MappedSchema with the following arguments: a class literal representing the schema family, - * a version number and a collection of mappedTypes (class literals) which represent JPA entity classes that the ORM layer needs to be configured with for this schema. - */ - - public SchemaV1() { - super(Schema.class, 1, ImmutableList.of(PersistentParentToken.class, PersistentChildToken.class)); - } - - /** - * The @entity annotation signifies that the specified POJO class' non-transient fields should be persisted to a relational database using the services - * of an entity manager. The @table annotation specifies properties of the table that will be created to contain the persisted data, in this case we have - * specified a name argument which will be used the table's title. - */ - - @Entity - @Table(name = "parent_data") - public static class PersistentParentToken extends PersistentState { - - /** - * The @Column annotations specify the columns that will comprise the inserted table and specify the shape of the fields and associated - * data types of each database entry. - */ - - @Column(name = "owner") private final String owner; - @Column(name = "issuer") private final String issuer; - @Column(name = "amount") private final int amount; - @Column(name = "linear_id") public final UUID linearId; - - /** - * The @OneToMany annotation specifies a one-to-many relationship between this class and a collection included as a field. - * The @JoinColumn and @JoinColumns annotations specify on which columns these tables will be joined on. - */ - - @OneToMany(cascade = CascadeType.PERSIST) - @JoinColumns({ - @JoinColumn(name = "output_index", referencedColumnName = "output_index"), - @JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id"), - }) - private final List listOfPersistentChildTokens; - - public PersistentParentToken(String owner, String issuer, int amount, UUID linearId, List listOfPersistentChildTokens) { - this.owner = owner; - this.issuer = issuer; - this.amount = amount; - this.linearId = linearId; - this.listOfPersistentChildTokens = listOfPersistentChildTokens; - } - - // Default constructor required by hibernate. - public PersistentParentToken() { - this.owner = ""; - this.issuer = ""; - this.amount = 0; - this.linearId = UUID.randomUUID(); - this.listOfPersistentChildTokens = null; - } - - public String getOwner() { - return owner; - } - - public String getIssuer() { - return issuer; - } - - public int getAmount() { - return amount; - } - - public UUID getLinearId() { - return linearId; - } - - public List getChildTokens() { return listOfPersistentChildTokens; } - } - - @Entity - @CordaSerializable - @Table(name = "child_data") - public static class PersistentChildToken { - // The @Id annotation marks this field as the primary key of the persisted entity. - @Id - private final UUID Id; - @Column(name = "owner") - private final String owner; - @Column(name = "issuer") - private final String issuer; - @Column(name = "amount") - private final int amount; - - /** - * The @ManyToOne annotation specifies that this class will be present as a member of a collection on a parent class and that it should - * be persisted with the joining columns specified in the parent class. It is important to note the targetEntity parameter which should correspond - * to a class literal of the parent class. - */ - - @ManyToOne(targetEntity = PersistentParentToken.class) - private final TokenState persistentParentToken; - - - public PersistentChildToken(String owner, String issuer, int amount) { - this.Id = UUID.randomUUID(); - this.owner = owner; - this.issuer = issuer; - this.amount = amount; - this.persistentParentToken = null; - } - - // Default constructor required by hibernate. - public PersistentChildToken() { - this.Id = UUID.randomUUID(); - this.owner = ""; - this.issuer = ""; - this.amount = 0; - this.persistentParentToken = null; - } - - public UUID getId() { - return Id; - } - - public String getOwner() { - return owner; - } - - public String getIssuer() { - return issuer; - } - - public int getAmount() { - return amount; - } - - public TokenState getPersistentToken() { - return persistentToken; - } - - } - - } - - .. sourcecode:: kotlin - - @CordaSerializable - object SchemaV1 : MappedSchema(schemaFamily = Schema::class.java, version = 1, mappedTypes = listOf(PersistentParentToken::class.java, PersistentChildToken::class.java)) { - - @Entity - @Table(name = "parent_data") - class PersistentParentToken( - @Column(name = "owner") - var owner: String, - - @Column(name = "issuer") - var issuer: String, - - @Column(name = "amount") - var currency: Int, - - @Column(name = "linear_id") - var linear_id: UUID, - - @JoinColumns(JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id"), JoinColumn(name = "output_index", referencedColumnName = "output_index")) - - var listOfPersistentChildTokens: MutableList - ) : PersistentState() - - @Entity - @CordaSerializable - @Table(name = "child_data") - class PersistentChildToken( - @Id - var Id: UUID = UUID.randomUUID(), - - @Column(name = "owner") - var owner: String, - - @Column(name = "issuer") - var issuer: String, - - @Column(name = "amount") - var currency: Int, - - @Column(name = "linear_id") - var linear_id: UUID, - - @ManyToOne(targetEntity = PersistentParentToken::class) - var persistentParentToken: TokenState - - ) : PersistentState() - - -Identity mapping ----------------- -Schema entity attributes defined by identity types (``AbstractParty``, ``Party``, ``AnonymousParty``) are automatically -processed to ensure only the ``X500Name`` of the identity is persisted where an identity is well known, otherwise a null -value is stored in the associated column. To preserve privacy, identity keys are never persisted. Developers should use -the ``IdentityService`` to resolve keys from well know X500 identity names. - -.. _jdbc_session_ref: - -JDBC session ------------- -Apps may also interact directly with the underlying Node's database by using a standard -JDBC connection (session) as described by the `Java SQL Connection API `_ - -Use the ``ServiceHub`` ``jdbcSession`` function to obtain a JDBC connection as illustrated in the following example: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt - :language: kotlin - :start-after: DOCSTART JdbcSession - :end-before: DOCEND JdbcSession - -JDBC sessions can be used in flows and services (see ":doc:`flow-state-machines`"). - -The following example illustrates the creation of a custom Corda service using a ``jdbcSession``: - -.. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/vault/CustomVaultQuery.kt - :language: kotlin - :start-after: DOCSTART CustomVaultQuery - :end-before: DOCEND CustomVaultQuery - -which is then referenced within a custom flow: - -.. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/vault/CustomVaultQuery.kt - :language: kotlin - :start-after: DOCSTART TopupIssuer - :end-before: DOCEND TopupIssuer - -For examples on testing ``@CordaService`` implementations, see the oracle example :doc:`here `. - -JPA Support ------------ -In addition to ``jdbcSession``, ``ServiceHub`` also exposes the Java Persistence API to flows via the ``withEntityManager`` -method. This method can be used to persist and query entities which inherit from ``MappedSchema``. This is particularly -useful if off-ledger data must be maintained in conjunction with on-ledger state data. - - .. note:: Your entity must be included as a mappedType as part of a ``MappedSchema`` for it to be added to Hibernate - as a custom schema. If it's not included as a mappedType, a corresponding table will not be created. See Samples below. - -The code snippet below defines a ``PersistentFoo`` type inside ``FooSchemaV1``. Note that ``PersistentFoo`` is added to -a list of mapped types which is passed to ``MappedSchema``. This is exactly how state schemas are defined, except that -the entity in this case should not subclass ``PersistentState`` (as it is not a state object). See examples: - -.. container:: codeset - - .. sourcecode:: java - - public class FooSchema {} - - public class FooSchemaV1 extends MappedSchema { - FooSchemaV1() { - super(FooSchema.class, 1, ImmutableList.of(PersistentFoo.class)); - } - - @Entity - @Table(name = "foos") - class PersistentFoo implements Serializable { - @Id - @Column(name = "foo_id") - String fooId; - - @Column(name = "foo_data") - String fooData; - } - } - - .. sourcecode:: kotlin - - object FooSchema - - object FooSchemaV1 : MappedSchema(schemaFamily = FooSchema.javaClass, version = 1, mappedTypes = listOf(PersistentFoo::class.java)) { - @Entity - @Table(name = "foos") - class PersistentFoo(@Id @Column(name = "foo_id") var fooId: String, @Column(name = "foo_data") var fooData: String) : Serializable - } - -Instances of ``PersistentFoo`` can be manually persisted inside a flow as follows: - -.. container:: codeset - - .. sourcecode:: java - - PersistentFoo foo = new PersistentFoo(new UniqueIdentifier().getId().toString(), "Bar"); - serviceHub.withEntityManager(entityManager -> { - entityManager.persist(foo); - return null; - }); - - .. sourcecode:: kotlin - - val foo = FooSchemaV1.PersistentFoo(UniqueIdentifier().id.toString(), "Bar") - serviceHub.withEntityManager { - persist(foo) - } - -And retrieved via a query, as follows: - -.. container:: codeset - - .. sourcecode:: java - - node.getServices().withEntityManager((EntityManager entityManager) -> { - CriteriaQuery query = entityManager.getCriteriaBuilder().createQuery(PersistentFoo.class); - Root type = query.from(PersistentFoo.class); - query.select(type); - return entityManager.createQuery(query).getResultList(); - }); - - .. sourcecode:: kotlin - - val result: MutableList = services.withEntityManager { - val query = criteriaBuilder.createQuery(FooSchemaV1.PersistentFoo::class.java) - val type = query.from(FooSchemaV1.PersistentFoo::class.java) - query.select(type) - createQuery(query).resultList - } - -Please note that suspendable flow operations such as: - -* ``FlowSession.send`` -* ``FlowSession.receive`` -* ``FlowLogic.receiveAll`` -* ``FlowLogic.sendAll`` -* ``FlowLogic.sleep`` -* ``FlowLogic.subFlow`` - -Cannot be used within the lambda function passed to ``withEntityManager``. diff --git a/docs/source/api-rpc.rst b/docs/source/api-rpc.rst deleted file mode 100644 index f55e467d94..0000000000 --- a/docs/source/api-rpc.rst +++ /dev/null @@ -1,29 +0,0 @@ -API: RPC operations -=================== -The node's owner interacts with the node solely via remote procedure calls (RPC). The node's owner does not have -access to the node's ``ServiceHub``. - -The key RPC operations exposed by the node are: - -* ``CordaRPCOps.vaultQueryBy`` - * Extract states from the node's vault based on a query criteria -* ``CordaRPCOps.vaultTrackBy`` - * As above, but also returns an observable of future states matching the query -* ``CordaRPCOps.networkMapFeed`` - * A list of network nodes, and an observable of changes to the network map -* ``CordaRPCOps.registeredFlows`` - * See a list of registered flows on the node -* ``CordaRPCOps.startFlowDynamic`` - * Start one of the node's registered flows -* ``CordaRPCOps.startTrackedFlowDynamic`` - * As above, but also returns a progress handle for the flow -* ``CordaRPCOps.nodeDiagnosticInfo`` - * Returns diagnostic information about the node, including the version and CorDapp details -* ``CordaRPCOps.nodeInfo`` - * Returns the network map entry of the node, including its address and identity details as well as the platform version information -* ``CordaRPCOps.currentNodeTime`` - * Returns the current time according to the node's clock -* ``CordaRPCOps.partyFromKey/CordaRPCOps.wellKnownPartyFromX500Name`` - * Retrieves a party on the network based on a public key or X500 name -* ``CordaRPCOps.uploadAttachment``/``CordaRPCOps.openAttachment``/``CordaRPCOps.attachmentExists`` - * Uploads, opens and checks for the existence of attachments \ No newline at end of file diff --git a/docs/source/api-scanner.rst b/docs/source/api-scanner.rst deleted file mode 100644 index e9446001cd..0000000000 --- a/docs/source/api-scanner.rst +++ /dev/null @@ -1,58 +0,0 @@ -Checking API stability -====================== - -We have committed not to alter Corda's API so that developers will not have to keep rewriting their CorDapps with each -new Corda release. The stable Corda modules are listed :ref:`here `. Our CI process runs an "API Stability" -check for each GitHub pull request in order to check that we don't accidentally introduce an API-breaking change. - -Build Process -------------- - -As part of the build process the following commands are run for each PR: - -.. code-block:: shell - - $ gradlew generateApi - $ .ci/check-api-changes.sh - -This ``bash`` script has been tested on both MacOS and various Linux distributions, it can also be run on Windows with the -use of a suitable bash emulator such as git bash. The script's return value is the number of API-breaking changes that it -has detected, and this should be zero for the check to pass. The maximum return value is 255, although the script will still -correctly report higher numbers of breaking changes. - -There are three kinds of breaking change: - -* Removal or modification of existing API, i.e. an existing class, method or field has been either deleted or renamed, or - its signature somehow altered. -* Addition of a new method to an interface or abstract class. Types that have been annotated as ``@DoNotImplement`` are - excluded from this check. (This annotation is also inherited across subclasses and sub-interfaces.) -* Exposure of an internal type via a public API. Internal types are considered to be anything in a ``*.internal.`` package - or anything in a module that isn't in the stable modules list :ref:`here `. - -Developers can execute these commands themselves before submitting their PR, to ensure that they haven't inadvertently -broken Corda's API. - - -How it works ------------- - -The ``generateApi`` Gradle task writes a summary of Corda's public API into the file ``build/api/api-corda-|corda_version|.txt``. -The ``.ci/check-api-changes.sh`` script then compares this file with the contents of ``.ci/api-current.txt``, which is a -managed file within the Corda repository. - -The Gradle task itself is implemented by the API Scanner plugin. More information on the API Scanner plugin is available `here `_. - - -Updating the API ----------------- - -As a rule, ``api-current.txt`` should only be updated by the release manager for each Corda release. - -We do not expect modifications to ``api-current.txt`` as part of normal development. However, we may sometimes need to adjust -the public API in ways that would not break developers' CorDapps but which would be blocked by the API Stability check. -For example, migrating a method from an interface into a superinterface. Any changes to the API summary file should be -included in the PR, which would then need explicit approval from either `Mike Hearn `_, `Rick Parker `_ or `Matthew Nesbit `_. - -.. note:: If you need to modify ``api-current.txt``, do not re-generate the file on the master branch. This will include new API that - hasn't been released or committed to, and may be subject to change. Manually change the specific line or lines of the - existing committed API that has changed. \ No newline at end of file diff --git a/docs/source/api-service-classes.rst b/docs/source/api-service-classes.rst deleted file mode 100644 index a5da2cf6d0..0000000000 --- a/docs/source/api-service-classes.rst +++ /dev/null @@ -1,131 +0,0 @@ -.. highlight:: kotlin -.. raw:: html - - - - -API: Service Classes -==================== - -Service classes are long-lived instances that can trigger or be triggered by flows from within a node. A Service class is limited to a -single instance per node. During startup, the node handles the creation of the service. If there is problem when instantiating service -the node will report in the log what the problem was and terminate. - -Services allow related, reusable, functions to be separated into their own class where their functionality is -grouped together. These functions can then be called from other services or flows. - -Creating a Service ------------------- - -To define a Service class: - - * Add the ``CordaService`` annotation - * Add a constructor with a single parameter of ``AppServiceHub`` - * Extend ``SingletonSerializeAsToken`` - -Below is an empty implementation of a Service class: - -.. container:: codeset - - .. sourcecode:: kotlin - - @CordaService - class MyCordaService(private val serviceHub: AppServiceHub) : SingletonSerializeAsToken() { - - init { - // Custom code ran at service creation - - // Optional: Express interest in receiving lifecycle events - services.register { processEvent(it) } - } - - private fun processEvent(event: ServiceLifecycleEvent) { - // Lifecycle event handling code including full use of serviceHub - when (event) { - STATE_MACHINE_STARTED -> { - services.vaultService.queryBy(...) - services.startFlow(...) - } - else -> { - // Process other types of events - } - } - } - - // public api of service - } - - .. sourcecode:: java - - @CordaService - public class MyCordaService extends SingletonSerializeAsToken { - - private final AppServiceHub serviceHub; - - public MyCordaService(AppServiceHub serviceHub) { - this.serviceHub = serviceHub; - // Custom code ran at service creation - - // Optional: Express interest in receiving lifecycle events - serviceHub.register(SERVICE_PRIORITY_NORMAL, this::processEvent); - } - - private void processEvent(ServiceLifecycleEvent event) { - switch (event) { - case STATE_MACHINE_STARTED: - serviceHub.getVaultService().queryBy(...) - serviceHub.startFlow(...) - break; - default: - // Process other types of events - break; - } - } - - // public api of service - } - -The ``AppServiceHub`` provides the ``ServiceHub`` functionality to the Service class, with the extra ability to start flows. Starting flows -from ``AppServiceHub`` is explained further in :ref:`Starting Flows from a Service `. - -The ``AppServiceHub`` also provides access to ``database`` which will enable the Service class to perform DB transactions from the threads -managed by the Service. - -Also the ``AppServiceHub`` provides ability for ``CordaService`` to subscribe for lifecycle events of the node, such that it will get notified -about node finishing initialisation and when the node is shutting down such that ``CordaService`` will be able to perform clean-up of some -critical resources. For more details please have refer to KDocs for ``ServiceLifecycleObserver``. - -Retrieving a Service --------------------- - -A Service class can be retrieved by calling ``ServiceHub.cordaService`` which returns the single instance of the class passed into the function: - -.. container:: codeset - - .. sourcecode:: kotlin - - val service: MyCordaService = serviceHub.cordaService(MyCordaService::class.java) - - .. sourcecode:: java - - MyCordaService service = serviceHub.cordaService(MyCordaService.class); - -.. warning:: ``ServiceHub.cordaService`` should not be called during initialisation of a flow and should instead be called in line where - needed or set after the flow's ``call`` function has been triggered. - -.. _starting_flows_from_a_service: - -Starting Flows from a Service ------------------------------ - -Starting flows via a service can lead to deadlock within the node's flow worker queue, which will prevent new flows from -starting. To avoid this, the rules bellow should be followed: - - * When called from a running flow, the service must invoke the new flow from another thread. The existing flow cannot await the - execution of the new flow. - * When ``ServiceHub.trackBy`` is placed inside the service, flows started inside the observable must be placed onto another thread. - * Flows started by other means, do not require any special treatment. - -.. note:: It is possible to avoid deadlock without following these rules depending on the number of flows running within the node. But, if the - number of flows violating these rules reaches the flow worker queue size, then the node will deadlock. It is best practice to - abide by these rules to remove this possibility. \ No newline at end of file diff --git a/docs/source/api-service-hub.rst b/docs/source/api-service-hub.rst deleted file mode 100644 index d97dfc7fc3..0000000000 --- a/docs/source/api-service-hub.rst +++ /dev/null @@ -1,33 +0,0 @@ -API: ServiceHub -=============== -Within ``FlowLogic.call``, the flow developer has access to the node's ``ServiceHub``, which provides access to the -various services the node provides. The services offered by the ``ServiceHub`` are split into the following categories: - -* ``ServiceHub.networkMapCache`` - * Provides information on other nodes on the network (e.g. notaries…) -* ``ServiceHub.identityService`` - * Allows you to resolve anonymous identities to well-known identities if you have the required certificates -* ``ServiceHub.attachments`` - * Gives you access to the node's attachments -* ``ServiceHub.validatedTransactions`` - * Gives you access to the transactions stored in the node -* ``ServiceHub.vaultService`` - * Stores the node’s current and historic states -* ``ServiceHub.keyManagementService`` - * Manages signing transactions and generating fresh public keys -* ``ServiceHub.myInfo`` - * Other information about the node -* ``ServiceHub.clock`` - * Provides access to the node’s internal time and date -* ``ServiceHub.diagnosticsService`` - * Provides diagnostic information about the node, including the node version and currently running apps. Note that this data should be - used for diagnostic purposes ONLY -* ``ServiceHub.contractUpgradeService`` - * Provides functionality for secure contract upgrades - -Additional, ``ServiceHub`` exposes the following properties: - -* ``ServiceHub.loadState`` and ``ServiceHub.toStateAndRef`` to resolve a ``StateRef`` into a ``TransactionState`` or - a ``StateAndRef`` -* ``ServiceHub.signInitialTransaction`` to sign a ``TransactionBuilder`` and convert it into a ``SignedTransaction`` -* ``ServiceHub.createSignature`` and ``ServiceHub.addSignature`` to create and add signatures to a ``SignedTransaction`` \ No newline at end of file diff --git a/docs/source/api-stability-guarantees.rst b/docs/source/api-stability-guarantees.rst deleted file mode 100644 index 1ba572a2c9..0000000000 --- a/docs/source/api-stability-guarantees.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. _internal-apis-and-stability-guarantees: - -API stability guarantees --------------------------------------- - -Corda makes certain commitments about what parts of the API will preserve backwards compatibility as they change and -which will not. Over time, more of the API will fall under the stability guarantees. Thus, APIs can be categorized in the following 2 broad categories: - -* **public APIs**, for which API/`ABI `_ backwards compatibility guarantees are provided. See: :ref:`public-api` -* **non-public APIs**, for which no backwards compatibility guarantees are provided. See: :ref:`non-public-api` - -.. _public-api: - -Public API ----------- - -The following modules form part of Corda's public API and we commit to API/ABI backwards compatibility in following releases, unless an incompatible change is required for security reasons: - -* **Core (net.corda.core)**: core Corda libraries such as crypto functions, types for Corda's building blocks: states, contracts, transactions, attachments, etc. and some interfaces for nodes and protocols -* **Client RPC (net.corda.client.rpc)**: client RPC -* **Client Jackson (net.corda.client.jackson)**: JSON support for client applications -* **DSL Test Utils (net.corda.testing.dsl)**: a simple DSL for building pseudo-transactions (not the same as the wire protocol) for testing purposes. -* **Test Node Driver (net.corda.testing.node, net.corda.testing.driver)**: test utilities to run nodes programmatically -* **Test Utils (net.corda.testing.core)**: generic test utilities -* **Http Test Utils (net.corda.testing.http)**: a small set of utilities for making HttpCalls, aimed at demos and tests. -* **Dummy Contracts (net.corda.testing.contracts)**: dummy state and contracts for testing purposes -* **Mock Services (net.corda.testing.services)**: mock service implementations for testing purposes - -Additionally, the **Tokens SDK (com.r3.corda.lib.tokens)** available in `the Tokens GitHub repository `_ -has a stable API. - -.. _non-public-api: - -Non-public API (experimental) ------------------------------ - -The following are not part of the Corda's public API and no backwards compatibility guarantees are provided: - -* Incubating modules, for which we will do our best to minimise disruption to developers using them until we are able to graduate them into the public API -* Internal modules, which are not to be used, and will change without notice -* Anything defined in a package containing ``.internal`` (for example, ``net.corda.core.internal`` and sub-packages should - not be used) -* Any interfaces, classes or methods whose name contains the word ``internal`` or ``Internal`` - -The **finance module** was the first CorDapp ever written and is a legacy module. Although it is not a part of our API guarantees, we also -don't anticipate much future change to it. Users should use the tokens SDK instead. - -Corda incubating modules -~~~~~~~~~~~~~~~~~~~~~~~~ - -* **net.corda.confidential**: experimental support for confidential identities on the ledger -* **net.corda.client.jfx**: support for Java FX UI -* **net.corda.client.mock**: client mock utilities -* **Cordformation**: Gradle integration plugins - -Corda internal modules -~~~~~~~~~~~~~~~~~~~~~~ - -Every other module is internal and will change without notice, even deleted, and should not be used. - -Some of the public modules may depend on internal modules, so be careful to not rely on these transitive dependencies. In particular, the -testing modules depend on the node module and so you may end having the node in your test classpath. - -.. warning:: The web server module will be removed in future. You should call Corda nodes through RPC from your web server of choice e.g., Spring Boot, Vertx, Undertow. - -The ``@DoNotImplement`` annotation ----------------------------------- - -Certain interfaces and abstract classes within the Corda API have been annotated -as ``@DoNotImplement``. While we undertake not to remove or modify any of these classes' existing -functionality, the annotation is a warning that we may need to extend them in future versions of Corda. -Cordapp developers should therefore just use these classes "as is", and *not* attempt to extend or implement any of them themselves. - -This annotation is inherited by subclasses and sub-interfaces. - diff --git a/docs/source/api-states.rst b/docs/source/api-states.rst deleted file mode 100644 index d13f0fc651..0000000000 --- a/docs/source/api-states.rst +++ /dev/null @@ -1,272 +0,0 @@ -.. highlight:: kotlin -.. raw:: html - - - - -API: States -=========== - -.. note:: Before reading this page, you should be familiar with the key concepts of :doc:`key-concepts-states`. - -.. contents:: - -ContractState -------------- -In Corda, states are instances of classes that implement ``ContractState``. The ``ContractState`` interface is defined -as follows: - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/ContractState.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - -``ContractState`` has a single field, ``participants``. ``participants`` is a ``List`` of the ``AbstractParty`` that -are considered to have a stake in the state. Among other things, the ``participants`` will: - -* Usually store the state in their vault (see below) - -* Need to sign any notary-change and contract-upgrade transactions involving this state - -* Receive any finalised transactions involving this state as part of ``FinalityFlow`` / ``ReceiveFinalityFlow`` - -ContractState sub-interfaces ----------------------------- -The behaviour of the state can be further customised by implementing sub-interfaces of ``ContractState``. The two most -common sub-interfaces are: - -* ``LinearState`` - -* ``OwnableState`` - -``LinearState`` models shared facts for which there is only one current version at any point in time. ``LinearState`` -states evolve in a straight line by superseding themselves. On the other hand, ``OwnableState`` is meant to represent -assets that can be freely split and merged over time. Cash is a good example of an ``OwnableState`` - two existing $5 -cash states can be combined into a single $10 cash state, or split into five $1 cash states. With ``OwnableState``, its -the total amount held that is important, rather than the actual units held. - -We can picture the hierarchy as follows: - -.. image:: resources/state-hierarchy.png - -LinearState -^^^^^^^^^^^ -The ``LinearState`` interface is defined as follows: - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt - :language: kotlin - :start-after: DOCSTART 2 - :end-before: DOCEND 2 - -Remember that in Corda, states are immutable and can't be updated directly. Instead, we represent an evolving fact as a -sequence of ``LinearState`` states that share the same ``linearId`` and represent an audit trail for the lifecycle of -the fact over time. - -When we want to extend a ``LinearState`` chain (i.e. a sequence of states sharing a ``linearId``), we: - -* Use the ``linearId`` to extract the latest state in the chain from the vault - -* Create a new state that has the same ``linearId`` - -* Create a transaction with: - - * The current latest state in the chain as an input - - * The newly-created state as an output - -The new state will now become the latest state in the chain, representing the new current state of the agreement. - -``linearId`` is of type ``UniqueIdentifier``, which is a combination of: - -* A Java ``UUID`` representing a globally unique 128 bit random number -* An optional external-reference string for referencing the state in external systems - -OwnableState -^^^^^^^^^^^^ -The ``OwnableState`` interface is defined as follows: - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt - :language: kotlin - :start-after: DOCSTART 3 - :end-before: DOCEND 3 - -Where: - -* ``owner`` is the ``PublicKey`` of the asset's owner - -* ``withNewOwner(newOwner: AbstractParty)`` creates an copy of the state with a new owner - -Because ``OwnableState`` models fungible assets that can be merged and split over time, ``OwnableState`` instances do -not have a ``linearId``. $5 of cash created by one transaction is considered to be identical to $5 of cash produced by -another transaction. - -FungibleState -~~~~~~~~~~~~~ - -``FungibleState`` is an interface to represent things which are fungible, this means that there is an expectation that -these things can be split and merged. That's the only assumption made by this interface. This interface should be -implemented if you want to represent fractional ownership in a thing, or if you have many things. Examples: - -* There is only one Mona Lisa which you wish to issue 100 tokens, each representing a 1% interest in the Mona Lisa -* A company issues 1000 shares with a nominal value of 1, in one batch of 1000. This means the single batch of 1000 - shares could be split up into 1000 units of 1 share. - -The interface is defined as follows: - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/FungibleState.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - -As seen, the interface takes a type parameter ``T`` that represents the fungible thing in question. This should describe -the basic type of the asset e.g. GBP, USD, oil, shares in company , etc. and any additional metadata (issuer, grade, -class, etc.). An upper-bound is not specified for ``T`` to ensure flexibility. Typically, a class would be provided that -implements `TokenizableAssetInfo` so the thing can be easily added and subtracted using the ``Amount`` class. - -This interface has been added in addition to ``FungibleAsset`` to provide some additional flexibility which -``FungibleAsset`` lacks, in particular: - -* ``FungibleAsset`` defines an amount property of type ``Amount>``, therefore there is an assumption that all - fungible things are issued by a single well known party but this is not always the case. -* ``FungibleAsset`` implements ``OwnableState``, as such there is an assumption that all fungible things are ownable. - -Other interfaces -^^^^^^^^^^^^^^^^ -You can also customize your state by implementing the following interfaces: - -* ``QueryableState``, which allows the state to be queried in the node's database using custom attributes (see - :doc:`api-persistence`) - -* ``SchedulableState``, which allows us to schedule future actions for the state (e.g. a coupon payment on a bond) (see - :doc:`event-scheduling`) - -User-defined fields -------------------- -Beyond implementing ``ContractState`` or a sub-interface, a state is allowed to have any number of additional fields -and methods. For example, here is the relatively complex definition for a state representing cash: - -.. container:: codeset - - .. literalinclude:: ../../finance/contracts/src/main/kotlin/net/corda/finance/contracts/asset/Cash.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - -The vault ---------- -Whenever a node records a new transaction, it also decides whether it should store each of the transaction's output -states in its vault. The default vault implementation makes the decision based on the following rules: - - * If the state is an ``OwnableState``, the vault will store the state if the node is the state's ``owner`` - * Otherwise, the vault will store the state if it is one of the ``participants`` - -States that are not considered relevant are not stored in the node's vault. However, the node will still store the -transactions that created the states in its transaction storage. - -.. _transaction_state: - -TransactionState ----------------- -When a ``ContractState`` is added to a ``TransactionBuilder``, it is wrapped in a ``TransactionState``: - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/TransactionState.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - -Where: - -* ``data`` is the state to be stored on-ledger -* ``contract`` is the contract governing evolutions of this state -* ``notary`` is the notary service for this state -* ``encumbrance`` points to another state that must also appear as an input to any transaction consuming this - state -* ``constraint`` is a constraint on which contract-code attachments can be used with this state - -.. _reference_states: - -Reference States ----------------- - -A reference input state is a ``ContractState`` which can be referred to in a transaction by the contracts of input and -output states but whose contract is not executed as part of the transaction verification process. Furthermore, -reference states are not consumed when the transaction is committed to the ledger but they are checked for -"current-ness". In other words, the contract logic isn't run for the referencing transaction only. It's still a normal -state when it occurs in an input or output position. - -Reference data states enable many parties to reuse the same state in their transactions as reference data whilst -still allowing the reference data state owner the capability to update the state. A standard example would be the -creation of financial instrument reference data and the use of such reference data by parties holding the related -financial instruments. - -Just like regular input states, the chain of provenance for reference states is resolved and all dependency transactions -verified. This is because users of reference data must be satisfied that the data they are referring to is valid as per -the rules of the contract which governs it and that all previous participants of the state assented to updates of it. - -**Known limitations:** - -*Notary change:* It is likely the case that users of reference states do not have permission to change the notary -assigned to a reference state. Even if users *did* have this permission the result would likely be a bunch of -notary change races. As such, if a reference state is added to a transaction which is assigned to a -different notary to the input and output states then all those inputs and outputs must be moved to the -notary which the reference state uses. - -If two or more reference states assigned to different notaries are added to a transaction then it follows that this -transaction cannot be committed to the ledger. This would also be the case for transactions not containing reference -states. There is an additional complication for transactions including reference states; it is however, unlikely that the -party using the reference states has the authority to change the notary for the state (in other words, the party using the -reference state would not be listed as a participant on it). Therefore, it is likely that a transaction containing -reference states with two different notaries cannot be committed to the ledger. - -As such, if reference states assigned to multiple different notaries are added to a transaction builder -then the check below will fail. - -.. warning:: Currently, encumbrances should not be used with reference states. In the case where a state is - encumbered by an encumbrance state, the encumbrance state should also be referenced in the same - transaction that references the encumbered state. This is because the data contained within the - encumbered state may take on a different meaning, and likely would do, once the encumbrance state - is taken into account. - -.. _state_pointers: - -State Pointers --------------- - -A ``StatePointer`` contains a pointer to a ``ContractState``. The ``StatePointer`` can be included in a ``ContractState`` as a -property, or included in an off-ledger data structure. ``StatePointer`` s can be resolved to a ``StateAndRef`` by performing -a look-up. There are two types of pointers; linear and static. - -1. ``StaticPointer`` s are for use with any type of ``ContractState``. The ``StaticPointer`` does as it suggests, it always - points to the same ``ContractState``. -2. The ``LinearPointer`` is for use with LinearStates. They are particularly useful because due to the way LinearStates - work, the pointer will automatically point you to the latest version of a LinearState that the node performing ``resolve`` - is aware of. In effect, the pointer "moves" as the LinearState is updated. - -State pointers use ``Reference States`` to enable the functionality described above. They can be conceptualized as a mechanism to -formalise a development pattern where one needs to refer to a specific state from another transaction (StaticPointer) or a particular lineage -of states (LinearPointer). In other words, ``StatePointers`` do not enable a feature in Corda which was previously unavailable. -Rather, they help to formalise a pattern which was already possible. In that light, it is worth noting some issues which you may encounter -in its application: - -* If the node calling ``resolve`` has not seen any transactions containing a ``ContractState`` which the ``StatePointer`` - points to, then ``resolve`` will throw an exception. Here, the node calling ``resolve`` might be missing some crucial data. -* The node calling ``resolve`` for a ``LinearPointer`` may have seen and stored transactions containing a ``LinearState`` with - the specified ``linearId``. However, there is no guarantee the ``StateAndRef`` returned by ``resolve`` is the most recent - version of the ``LinearState``. The node only returns the most recent version that _it_ is aware of. - -**Resolving state pointers in TransactionBuilder** - -When building transactions, any ``StatePointer`` s contained within inputs or outputs added to a ``TransactionBuilder`` can -be optionally resolved to reference states using the ``resolveStatePointers`` method. The effect is that the pointed to -data is carried along with the transaction. This may or may not be appropriate in all circumstances, which is why -calling the method is optional. \ No newline at end of file diff --git a/docs/source/api-testing.rst b/docs/source/api-testing.rst deleted file mode 100644 index 05338834db..0000000000 --- a/docs/source/api-testing.rst +++ /dev/null @@ -1,384 +0,0 @@ -.. highlight:: kotlin -.. raw:: html - - - - -API: Testing -============ - -.. contents:: - -Flow testing ------------- - -MockNetwork -^^^^^^^^^^^ - -Flow testing can be fully automated using a ``MockNetwork`` composed of ``StartedMockNode`` nodes. Each -``StartedMockNode`` behaves like a regular Corda node, but its services are either in-memory or mocked out. - -A ``MockNetwork`` is created as follows: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java - :language: java - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - -The ``MockNetwork`` requires at a minimum a list of CorDapps to be installed on each ``StartedMockNode``. The CorDapps are looked up on the -classpath by package name, using ``TestCordapp.findCordapp``. ``TestCordapp.findCordapp`` scans the current classpath to find the CorDapp that contains the given package. -This includes all the associated CorDapp metadata present in its MANIFEST. - -``MockNetworkParameters`` provides other properties for the network which can be tweaked. They default to sensible values if not specified. - -Adding nodes to the network -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Nodes are created on the ``MockNetwork`` using: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt - :language: kotlin - :start-after: DOCSTART 2 - :end-before: DOCEND 2 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java - :language: java - :start-after: DOCSTART 2 - :end-before: DOCEND 2 - -Nodes added using ``createNode`` are provided a default set of node parameters. However, it is also possible to -provide different parameters to each node using ``MockNodeParameters``. Of particular interest are ``configOverrides`` which allow you to -override some of the default node configuration options. Please refer to the ``MockNodeConfigOverrides`` class for details what can currently -be overridden. Also, the ``additionalCordapps`` parameter allows you to add extra CorDapps to a specific node. This is useful when you wish -for all nodes to load a common CorDapp but for a subset of nodes to load CorDapps specific to their role in the network. - -Running the network -^^^^^^^^^^^^^^^^^^^ -When using a ``MockNetwork``, you must be careful to ensure that all the nodes have processed all the relevant messages -before making assertions about the result of performing some action. For example, if you start a flow to update the ledger -but don't wait until all the nodes involved have processed all the resulting messages, your nodes' vaults may not be in -the state you expect. - -When ``networkSendManuallyPumped`` is set to ``false``, you must manually initiate the processing of received messages. -You manually process received messages as follows: - -* ``StartedMockNode.pumpReceive()`` processes a single message from the node's queue -* ``MockNetwork.runNetwork()`` processes all the messages in every node's queue until there are no further messages to - process - -When ``networkSendManuallyPumped`` is set to ``true``, nodes will automatically process the messages they receive. You -can block until all messages have been processed using ``MockNetwork.waitQuiescent()``. - -.. warning:: If ``threadPerNode`` is set to ``true``, ``networkSendManuallyPumped`` must also be set to ``true``. - -Running flows -^^^^^^^^^^^^^ - -A ``StartedMockNode`` starts a flow using the ``StartedNodeServices.startFlow`` method. This method returns a future -representing the output of running the flow. - -.. container:: codeset - - .. sourcecode:: kotlin - - val signedTransactionFuture = nodeA.services.startFlow(IOUFlow(iouValue = 99, otherParty = nodeBParty)) - - .. sourcecode:: java - - CordaFuture future = startFlow(a.getServices(), new ExampleFlow.Initiator(1, nodeBParty)); - -The network must then be manually run before retrieving the future's value: - -.. container:: codeset - - .. sourcecode:: kotlin - - val signedTransactionFuture = nodeA.services.startFlow(IOUFlow(iouValue = 99, otherParty = nodeBParty)) - // Assuming network.networkSendManuallyPumped == false. - network.runNetwork() - val signedTransaction = future.get(); - - .. sourcecode:: java - - CordaFuture future = startFlow(a.getServices(), new ExampleFlow.Initiator(1, nodeBParty)); - // Assuming network.networkSendManuallyPumped == false. - network.runNetwork(); - SignedTransaction signedTransaction = future.get(); - -Accessing ``StartedMockNode`` internals -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Querying a node's vault -~~~~~~~~~~~~~~~~~~~~~~~ - -Recorded states can be retrieved from the vault of a ``StartedMockNode`` using: - -.. container:: codeset - - .. sourcecode:: kotlin - - val myStates = nodeA.services.vaultService.queryBy().states - - .. sourcecode:: java - - List myStates = node.getServices().getVaultService().queryBy(MyStateType.class).getStates(); - -This allows you to check whether a given state has (or has not) been stored, and whether it has the correct attributes. - - -Examining a node's transaction storage -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Recorded transactions can be retrieved from the transaction storage of a ``StartedMockNode`` using: - -.. container:: codeset - - .. sourcecode:: kotlin - - val transaction = nodeA.services.validatedTransactions.getTransaction(transaction.id) - - .. sourcecode:: java - - SignedTransaction transaction = nodeA.getServices().getValidatedTransactions().getTransaction(transaction.getId()) - -This allows you to check whether a given transaction has (or has not) been stored, and whether it has the correct -attributes. - -This allows you to check whether a given state has (or has not) been stored, and whether it has the correct attributes. - -Further examples -^^^^^^^^^^^^^^^^ - -* See the flow testing tutorial :doc:`here ` -* See the oracle tutorial :doc:`here ` for information on testing ``@CordaService`` classes -* Further examples are available in the Example CorDapp in - `Java <|os_samples_branch|/cordapp-example/workflows-java/src/test/java/com/example/test/flow/IOUFlowTests.java>`_ and - `Kotlin <|os_samples_branch|/cordapp-example/workflows-kotlin/src/test/kotlin/com/example/test/flow/IOUFlowTests.kt>`_ - -Contract testing ----------------- - -The Corda test framework includes the ability to create a test ledger by calling the ``ledger`` function -on an implementation of the ``ServiceHub`` interface. - -Test identities -^^^^^^^^^^^^^^^ - -You can create dummy identities to use in test transactions using the ``TestIdentity`` class: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt - :language: kotlin - :start-after: DOCSTART 14 - :end-before: DOCEND 14 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java - :language: java - :start-after: DOCSTART 14 - :end-before: DOCEND 14 - :dedent: 4 - -``TestIdentity`` exposes the following fields and methods: - -.. container:: codeset - - .. sourcecode:: kotlin - - val identityParty: Party = bigCorp.party - val identityName: CordaX500Name = bigCorp.name - val identityPubKey: PublicKey = bigCorp.publicKey - val identityKeyPair: KeyPair = bigCorp.keyPair - val identityPartyAndCertificate: PartyAndCertificate = bigCorp.identity - - .. sourcecode:: java - - Party identityParty = bigCorp.getParty(); - CordaX500Name identityName = bigCorp.getName(); - PublicKey identityPubKey = bigCorp.getPublicKey(); - KeyPair identityKeyPair = bigCorp.getKeyPair(); - PartyAndCertificate identityPartyAndCertificate = bigCorp.getIdentity(); - -You can also create a unique ``TestIdentity`` using the ``fresh`` method: - -.. container:: codeset - - .. sourcecode:: kotlin - - val uniqueTestIdentity: TestIdentity = TestIdentity.fresh("orgName") - - .. sourcecode:: java - - TestIdentity uniqueTestIdentity = TestIdentity.Companion.fresh("orgName"); - -MockServices -^^^^^^^^^^^^ - -A mock implementation of ``ServiceHub`` is provided in ``MockServices``. This is a minimal ``ServiceHub`` that -suffices to test contract logic. It has the ability to insert states into the vault, query the vault, and -construct and check transactions. - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt - :language: kotlin - :start-after: DOCSTART 11 - :end-before: DOCEND 11 - :dedent: 4 - - .. literalinclude:: ../../docs/source/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java - :language: java - :start-after: DOCSTART 11 - :end-before: DOCEND 11 - :dedent: 4 - - -Alternatively, there is a helper constructor which just accepts a list of ``TestIdentity``. The first identity provided is -the identity of the node whose ``ServiceHub`` is being mocked, and any subsequent identities are identities that the node -knows about. Only the calling package is scanned for cordapps and a test ``IdentityService`` is created -for you, using all the given identities. - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt - :language: kotlin - :start-after: DOCSTART 12 - :end-before: DOCEND 12 - :dedent: 4 - - .. literalinclude:: ../../docs/source/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java - :language: java - :start-after: DOCSTART 12 - :end-before: DOCEND 12 - :dedent: 4 - - -Writing tests using a test ledger -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The ``ServiceHub.ledger`` extension function allows you to create a test ledger. Within the ledger wrapper you can create -transactions using the ``transaction`` function. Within a transaction you can define the ``input`` and -``output`` states for the transaction, alongside any commands that are being executed, the ``timeWindow`` in which the -transaction has been executed, and any ``attachments``, as shown in this example test: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt - :language: kotlin - :start-after: DOCSTART 13 - :end-before: DOCEND 13 - :dedent: 4 - - .. literalinclude:: ../../docs/source/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java - :language: java - :start-after: DOCSTART 13 - :end-before: DOCEND 13 - :dedent: 4 - -Once all the transaction components have been specified, you can run ``verifies()`` to check that the given transaction is valid. - -Checking for failure states -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In order to test for failures, you can use the ``failsWith`` method, or in Kotlin the ``fails with`` helper method, which -assert that the transaction fails with a specific error. If you just want to assert that the transaction has failed without -verifying the message, there is also a ``fails`` method. - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt - :language: kotlin - :start-after: DOCSTART 4 - :end-before: DOCEND 4 - :dedent: 4 - - .. literalinclude:: ../../docs/source/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java - :language: java - :start-after: DOCSTART 4 - :end-before: DOCEND 4 - :dedent: 4 - -.. note:: - - The transaction DSL forces the last line of the test to be either a ``verifies`` or ``fails with`` statement. - -Testing multiple scenarios at once -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Within a single transaction block, you can assert several times that the transaction constructed so far either passes or -fails verification. For example, you could test that a contract fails to verify because it has no output states, and then -add the relevant output state and check that the contract verifies successfully, as in the following example: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt - :language: kotlin - :start-after: DOCSTART 5 - :end-before: DOCEND 5 - :dedent: 4 - - .. literalinclude:: ../../docs/source/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java - :language: java - :start-after: DOCSTART 5 - :end-before: DOCEND 5 - :dedent: 4 - -You can also use the ``tweak`` function to create a locally scoped transaction that you can make changes to -and then return to the original, unmodified transaction. As in the following example: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt - :language: kotlin - :start-after: DOCSTART 7 - :end-before: DOCEND 7 - :dedent: 4 - - .. literalinclude:: ../../docs/source/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java - :language: java - :start-after: DOCSTART 7 - :end-before: DOCEND 7 - :dedent: 4 - - -Chaining transactions -~~~~~~~~~~~~~~~~~~~~~ - -The following example shows that within a ``ledger``, you can create more than one ``transaction`` in order to test chains -of transactions. In addition to ``transaction``, ``unverifiedTransaction`` can be used, as in the example below, to create -transactions on the ledger without verifying them, for pre-populating the ledger with existing data. When chaining transactions, -it is important to note that even though a ``transaction`` ``verifies`` successfully, the overall ledger may not be valid. This can -be verified separately by placing a ``verifies`` or ``fails`` statement within the ``ledger`` block. - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/tutorial/testdsl/TutorialTestDSL.kt - :language: kotlin - :start-after: DOCSTART 9 - :end-before: DOCEND 9 - :dedent: 4 - - .. literalinclude:: ../../docs/source/example-code/src/test/java/net/corda/docs/java/tutorial/testdsl/TutorialTestDSL.java - :language: java - :start-after: DOCSTART 9 - :end-before: DOCEND 9 - :dedent: 4 - - -Further examples -^^^^^^^^^^^^^^^^ - -* See the flow testing tutorial :doc:`here ` -* Further examples are available in the Example CorDapp in - `Java <|os_samples_branch|/cordapp-example/workflows-java/src/test/java/com/example/test/flow/IOUFlowTests.java>`_ and - `Kotlin <|os_samples_branch|/cordapp-example/workflows-kotlin/src/test/kotlin/com/example/test/flow/IOUFlowTests.kt>`_ diff --git a/docs/source/api-transactions.rst b/docs/source/api-transactions.rst deleted file mode 100644 index 69927d88e3..0000000000 --- a/docs/source/api-transactions.rst +++ /dev/null @@ -1,783 +0,0 @@ -.. highlight:: kotlin -.. raw:: html - - - - -API: Transactions -================= - -.. note:: Before reading this page, you should be familiar with the key concepts of :doc:`key-concepts-transactions`. - -.. contents:: - -Transaction lifecycle ---------------------- -Between its creation and its final inclusion on the ledger, a transaction will generally occupy one of three states: - -* ``TransactionBuilder``. A transaction's initial state. This is the only state during which the transaction is - mutable, so we must add all the required components before moving on. - -* ``SignedTransaction``. The transaction now has one or more digital signatures, making it immutable. This is the - transaction type that is passed around to collect additional signatures and that is recorded on the ledger. - -* ``LedgerTransaction``. The transaction has been "resolved" - for example, its inputs have been converted from - references to actual states - allowing the transaction to be fully inspected. - -We can visualise the transitions between the three stages as follows: - -.. image:: resources/transaction-flow.png - -Transaction components ----------------------- -A transaction consists of six types of components: - -* 1+ states: - - * 0+ input states - * 0+ output states - * 0+ reference input states - -* 1+ commands -* 0+ attachments -* 0 or 1 time-window - - * A transaction with a time-window must also have a notary - -Each component corresponds to a specific class in the Corda API. The following section describes each component class, -and how it is created. - -Input states -^^^^^^^^^^^^ -An input state is added to a transaction as a ``StateAndRef``, which combines: - -* The ``ContractState`` itself -* A ``StateRef`` identifying this ``ContractState`` as the output of a specific transaction - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 21 - :end-before: DOCEND 21 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 21 - :end-before: DOCEND 21 - :dedent: 12 - -A ``StateRef`` uniquely identifies an input state, allowing the notary to mark it as historic. It is made up of: - -* The hash of the transaction that generated the state -* The state's index in the outputs of that transaction - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 20 - :end-before: DOCEND 20 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 20 - :end-before: DOCEND 20 - :dedent: 12 - -The ``StateRef`` links an input state back to the transaction that created it. This means that transactions form -"chains" linking each input back to an original issuance transaction. This allows nodes verifying the transaction -to "walk the chain" and verify that each input was generated through a valid sequence of transactions. - -Reference input states -~~~~~~~~~~~~~~~~~~~~~~ - -.. warning:: Reference states are only available on Corda networks with a minimum platform version >= 4. - -A reference input state is added to a transaction as a ``ReferencedStateAndRef``. A ``ReferencedStateAndRef`` can be -obtained from a ``StateAndRef`` by calling the ``StateAndRef.referenced()`` method which returns a ``ReferencedStateAndRef``. - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 55 - :end-before: DOCEND 55 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 55 - :end-before: DOCEND 55 - :dedent: 12 - -**Handling of update races:** - -When using reference states in a transaction, it may be the case that a notarisation failure occurs. This is most likely -because the creator of the state (being used as a reference state in your transaction), has just updated it. - -Typically, the creator of such reference data will have implemented flows for syndicating the updates out to users. -However it is inevitable that there will be a delay between the state being used as a reference being consumed, and the -nodes using it receiving the update. - -This is where the ``WithReferencedStatesFlow`` comes in. Given a flow which uses reference states, the -``WithReferencedStatesFlow`` will execute the the flow as a subFlow. If the flow fails due to a ``NotaryError.Conflict`` -for a reference state, then it will be suspended until the state refs for the reference states are consumed. In this -case, a consumption means that: - -1. the owner of the reference state has updated the state with a valid, notarised transaction -2. the owner of the reference state has shared the update with the node attempting to run the flow which uses the - reference state -3. The node has successfully committed the transaction updating the reference state (and all the dependencies), and - added the updated reference state to the vault. - -At the point where the transaction updating the state being used as a reference is committed to storage and the vault -update occurs, then the ``WithReferencedStatesFlow`` will wake up and re-execute the provided flow. - -.. warning:: Caution should be taken when using this flow as it facilitates automated re-running of flows which use - reference states. The flow using reference states should include checks to ensure that the reference data is - reasonable, especially if the economics of the transaction depends upon the data contained within a reference state. - -Output states -^^^^^^^^^^^^^ -Since a transaction's output states do not exist until the transaction is committed, they cannot be referenced as the -outputs of previous transactions. Instead, we create the desired output states as ``ContractState`` instances, and -add them to the transaction directly: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 22 - :end-before: DOCEND 22 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 22 - :end-before: DOCEND 22 - :dedent: 12 - -In cases where an output state represents an update of an input state, we may want to create the output state by basing -it on the input state: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 23 - :end-before: DOCEND 23 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 23 - :end-before: DOCEND 23 - :dedent: 12 - -Before our output state can be added to a transaction, we need to associate it with a contract. We can do this by -wrapping the output state in a ``StateAndContract``, which combines: - -* The ``ContractState`` representing the output states -* A ``String`` identifying the contract governing the state - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 47 - :end-before: DOCEND 47 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 47 - :end-before: DOCEND 47 - :dedent: 12 - -Commands -^^^^^^^^ -A command is added to the transaction as a ``Command``, which combines: - -* A ``CommandData`` instance indicating the command's type -* A ``List`` representing the command's required signers - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 24 - :end-before: DOCEND 24 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 24 - :end-before: DOCEND 24 - :dedent: 12 - -Attachments -^^^^^^^^^^^ -Attachments are identified by their hash: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 25 - :end-before: DOCEND 25 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 25 - :end-before: DOCEND 25 - :dedent: 12 - -The attachment with the corresponding hash must have been uploaded ahead of time via the node's RPC interface. - -Time-windows -^^^^^^^^^^^^ -Time windows represent the period during which the transaction must be notarised. They can have a start and an end -time, or be open at either end: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 26 - :end-before: DOCEND 26 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 26 - :end-before: DOCEND 26 - :dedent: 12 - -We can also define a time window as an ``Instant`` plus/minus a time tolerance (e.g. 30 seconds): - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 42 - :end-before: DOCEND 42 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 42 - :end-before: DOCEND 42 - :dedent: 12 - -Or as a start-time plus a duration: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 43 - :end-before: DOCEND 43 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 43 - :end-before: DOCEND 43 - :dedent: 12 - -TransactionBuilder ------------------- - -Creating a builder -^^^^^^^^^^^^^^^^^^ -The first step when creating a transaction proposal is to instantiate a ``TransactionBuilder``. - -If the transaction has input states or a time-window, we need to instantiate the builder with a reference to the notary -that will notarise the inputs and verify the time-window: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 19 - :end-before: DOCEND 19 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 19 - :end-before: DOCEND 19 - :dedent: 12 - -We discuss the selection of a notary in :doc:`api-flows`. - -If the transaction does not have any input states or a time-window, it does not require a notary, and can be -instantiated without one: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 46 - :end-before: DOCEND 46 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 46 - :end-before: DOCEND 46 - :dedent: 12 - -Adding items -^^^^^^^^^^^^ -The next step is to build up the transaction proposal by adding the desired components. - -We can add components to the builder using the ``TransactionBuilder.withItems`` method: - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - -``withItems`` takes a ``vararg`` of objects and adds them to the builder based on their type: - -* ``StateAndRef`` objects are added as input states -* ``ReferencedStateAndRef`` objects are added as reference input states -* ``TransactionState`` and ``StateAndContract`` objects are added as output states - - * Both ``TransactionState`` and ``StateAndContract`` are wrappers around a ``ContractState`` output that link the - output to a specific contract - -* ``Command`` objects are added as commands -* ``SecureHash`` objects are added as attachments -* A ``TimeWindow`` object replaces the transaction's existing ``TimeWindow``, if any - -Passing in objects of any other type will cause an ``IllegalArgumentException`` to be thrown. - -Here's an example usage of ``TransactionBuilder.withItems``: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 27 - :end-before: DOCEND 27 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 27 - :end-before: DOCEND 27 - :dedent: 12 - -There are also individual methods for adding components. - -Here are the methods for adding inputs and attachments: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 28 - :end-before: DOCEND 28 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 28 - :end-before: DOCEND 28 - :dedent: 12 - -An output state can be added as a ``ContractState``, contract class name and notary: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 49 - :end-before: DOCEND 49 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 49 - :end-before: DOCEND 49 - :dedent: 12 - -We can also leave the notary field blank, in which case the transaction's default notary is used: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 50 - :end-before: DOCEND 50 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 50 - :end-before: DOCEND 50 - :dedent: 12 - -Or we can add the output state as a ``TransactionState``, which already specifies the output's contract and notary: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 51 - :end-before: DOCEND 51 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 51 - :end-before: DOCEND 51 - :dedent: 12 - -Commands can be added as a ``Command``: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 52 - :end-before: DOCEND 52 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 52 - :end-before: DOCEND 52 - :dedent: 12 - -Or as ``CommandData`` and a ``vararg PublicKey``: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 53 - :end-before: DOCEND 53 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 53 - :end-before: DOCEND 53 - :dedent: 12 - -For the time-window, we can set a time-window directly: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 44 - :end-before: DOCEND 44 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 44 - :end-before: DOCEND 44 - :dedent: 12 - -Or define the time-window as a time plus a duration (e.g. 45 seconds): - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 45 - :end-before: DOCEND 45 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 45 - :end-before: DOCEND 45 - :dedent: 12 - -Signing the builder -^^^^^^^^^^^^^^^^^^^ -Once the builder is ready, we finalize it by signing it and converting it into a ``SignedTransaction``. - -We can either sign with our legal identity key: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 29 - :end-before: DOCEND 29 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 29 - :end-before: DOCEND 29 - :dedent: 12 - -Or we can also choose to use another one of our public keys: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 30 - :end-before: DOCEND 30 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 30 - :end-before: DOCEND 30 - :dedent: 12 - -Either way, the outcome of this process is to create an immutable ``SignedTransaction`` with our signature over it. - -SignedTransaction ------------------ -A ``SignedTransaction`` is a combination of: - -* An immutable transaction -* A list of signatures over that transaction - -.. container:: codeset - - .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - -Before adding our signature to the transaction, we'll want to verify both the transaction's contents and the -transaction's signatures. - -Verifying the transaction's contents -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If a transaction has inputs, we need to retrieve all the states in the transaction's dependency chain before we can -verify the transaction's contents. This is because the transaction is only valid if its dependency chain is also valid. -We do this by requesting any states in the chain that our node doesn't currently have in its local storage from the -proposer(s) of the transaction. This process is handled by a built-in flow called ``ReceiveTransactionFlow``. -See :doc:`api-flows` for more details. - -We can now verify the transaction's contents to ensure that it satisfies the contracts of all the transaction's input -and output states: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 33 - :end-before: DOCEND 33 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 33 - :end-before: DOCEND 33 - :dedent: 16 - -Checking that the transaction meets the contract constraints is only part of verifying the transaction's contents. We -will usually also want to perform our own additional validation of the transaction contents before signing, to ensure -that the transaction proposal represents an agreement we wish to enter into. - -However, the ``SignedTransaction`` holds its inputs as ``StateRef`` instances, and its attachments as ``SecureHash`` -instances, which do not provide enough information to properly validate the transaction's contents. We first need to -resolve the ``StateRef`` and ``SecureHash`` instances into actual ``ContractState`` and ``Attachment`` instances, which -we can then inspect. - -We achieve this by using the ``ServiceHub`` to convert the ``SignedTransaction`` into a ``LedgerTransaction``: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 32 - :end-before: DOCEND 32 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 32 - :end-before: DOCEND 32 - :dedent: 16 - -We can now perform our additional verification. Here's a simple example: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 34 - :end-before: DOCEND 34 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 34 - :end-before: DOCEND 34 - :dedent: 16 - -Verifying the transaction's signatures -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Aside from verifying that the transaction's contents are valid, we also need to check that the signatures are valid. A -valid signature over the hash of the transaction prevents tampering. - -We can verify that all the transaction's required signatures are present and valid as follows: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 35 - :end-before: DOCEND 35 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 35 - :end-before: DOCEND 35 - :dedent: 16 - -However, we'll often want to verify the transaction's existing signatures before all of them have been collected. For -this we can use ``SignedTransaction.verifySignaturesExcept``, which takes a ``vararg`` of the public keys for -which the signatures are allowed to be missing: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 36 - :end-before: DOCEND 36 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 36 - :end-before: DOCEND 36 - :dedent: 16 - -There is also an overload of ``SignedTransaction.verifySignaturesExcept``, which takes a ``Collection`` of the -public keys for which the signatures are allowed to be missing: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 54 - :end-before: DOCEND 54 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 54 - :end-before: DOCEND 54 - :dedent: 16 - - -If the transaction is missing any signatures without the corresponding public keys being passed in, a -``SignaturesMissingException`` is thrown. - -We can also choose to simply verify the signatures that are present: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 37 - :end-before: DOCEND 37 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 37 - :end-before: DOCEND 37 - :dedent: 16 - -Be very careful, however - this function neither guarantees that the signatures that are present are required, nor -checks whether any signatures are missing. - -Signing the transaction -^^^^^^^^^^^^^^^^^^^^^^^ -Once we are satisfied with the contents and existing signatures over the transaction, we add our signature to the -``SignedTransaction`` to indicate that we approve the transaction. - -We can sign using our legal identity key, as follows: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 38 - :end-before: DOCEND 38 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 38 - :end-before: DOCEND 38 - :dedent: 12 - -Or we can choose to sign using another one of our public keys: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 39 - :end-before: DOCEND 39 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 39 - :end-before: DOCEND 39 - :dedent: 12 - -We can also generate a signature over the transaction without adding it to the transaction directly. - -We can do this with our legal identity key: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 40 - :end-before: DOCEND 40 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 40 - :end-before: DOCEND 40 - :dedent: 12 - -Or using another one of our public keys: - -.. container:: codeset - - .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt - :language: kotlin - :start-after: DOCSTART 41 - :end-before: DOCEND 41 - :dedent: 8 - - .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java - :language: java - :start-after: DOCSTART 41 - :end-before: DOCEND 41 - :dedent: 12 - -Notarising and recording -^^^^^^^^^^^^^^^^^^^^^^^^ -Notarising and recording a transaction is handled by a built-in flow called ``FinalityFlow``. See :doc:`api-flows` for -more details. \ No newline at end of file diff --git a/docs/source/api-vault-query.rst b/docs/source/api-vault-query.rst deleted file mode 100644 index 35846b261a..0000000000 --- a/docs/source/api-vault-query.rst +++ /dev/null @@ -1,675 +0,0 @@ -.. highlight:: kotlin -.. raw:: html - - - - -API: Vault Query -================ - -.. contents:: - -Overview --------- -Corda has been architected from the ground up to encourage usage of industry standard, proven query frameworks and -libraries for accessing RDBMS backed transactional stores (including the Vault). - -Corda provides a number of flexible query mechanisms for accessing the Vault: - -- Vault Query API -- Using a JDBC session (as described in :ref:`Persistence `) -- Custom JPA_/JPQL_ queries -- Custom 3rd party Data Access frameworks such as `Spring Data `_ - -The majority of query requirements can be satisfied by using the Vault Query API, which is exposed via the -``VaultService`` for use directly by flows: - -.. literalinclude:: ../../core/src/main/kotlin/net/corda/core/node/services/VaultService.kt - :language: kotlin - :start-after: DOCSTART VaultQueryAPI - :end-before: DOCEND VaultQueryAPI - :dedent: 4 - -And via ``CordaRPCOps`` for use by RPC client applications: - -.. literalinclude:: ../../core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt - :language: kotlin - :start-after: DOCSTART VaultQueryByAPI - :end-before: DOCEND VaultQueryByAPI - :dedent: 4 - -.. literalinclude:: ../../core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt - :language: kotlin - :start-after: DOCSTART VaultTrackByAPI - :end-before: DOCEND VaultTrackByAPI - :dedent: 4 - -Helper methods are also provided with default values for arguments: - -.. literalinclude:: ../../core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt - :language: kotlin - :start-after: DOCSTART VaultQueryAPIHelpers - :end-before: DOCEND VaultQueryAPIHelpers - :dedent: 4 - -.. literalinclude:: ../../core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt - :language: kotlin - :start-after: DOCSTART VaultTrackAPIHelpers - :end-before: DOCEND VaultTrackAPIHelpers - :dedent: 4 - -The API provides both static (snapshot) and dynamic (snapshot with streaming updates) methods for a defined set of -filter criteria: - -- Use ``queryBy`` to obtain a current snapshot of data (for a given ``QueryCriteria``) -- Use ``trackBy`` to obtain both a current snapshot and a future stream of updates (for a given ``QueryCriteria``) - -.. note:: Streaming updates are only filtered based on contract type and state status (UNCONSUMED, CONSUMED, ALL). - They will not respect any other criteria that the initial query has been filtered by. - -Simple pagination (page number and size) and sorting (directional ordering using standard or custom property -attributes) is also specifiable. Defaults are defined for paging (pageNumber = 1, pageSize = 200) and sorting -(direction = ASC). - -The ``QueryCriteria`` interface provides a flexible mechanism for specifying different filtering criteria, including -and/or composition and a rich set of operators to include: - -* Binary logical (AND, OR) -* Comparison (LESS_THAN, LESS_THAN_OR_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL) -* Equality (EQUAL, NOT_EQUAL) -* Likeness (LIKE, NOT_LIKE) -* Nullability (IS_NULL, NOT_NULL) -* Collection based (IN, NOT_IN) -* Standard SQL-92 aggregate functions (SUM, AVG, MIN, MAX, COUNT) - -There are four implementations of this interface which can be chained together to define advanced filters. - -1. ``VaultQueryCriteria`` provides filterable criteria on attributes within the Vault states table: status (UNCONSUMED, - CONSUMED), state reference(s), contract state type(s), notaries, soft locked states, timestamps (RECORDED, CONSUMED), - state constraints (see :ref:`Constraint Types `), relevancy (ALL, RELEVANT, NON_RELEVANT), - participants (exact or any match). - - .. note:: Sensible defaults are defined for frequently used attributes (status = UNCONSUMED, always include soft - locked states). - -2. ``FungibleAssetQueryCriteria`` provides filterable criteria on attributes defined in the Corda Core - ``FungibleAsset`` contract state interface, used to represent assets that are fungible, countable and issued by a - specific party (eg. ``Cash.State`` and ``CommodityContract.State`` in the Corda finance module). Filterable - attributes include: participants (exact or any match), owner(s), quantity, issuer party(s) and issuer reference(s). - - .. note:: All contract states that extend the ``FungibleAsset`` now automatically persist that interfaces common - state attributes to the **vault_fungible_states** table. - -3. ``LinearStateQueryCriteria`` provides filterable criteria on attributes defined in the Corda Core ``LinearState`` - and ``DealState`` contract state interfaces, used to represent entities that continuously supersede themselves, all - of which share the same ``linearId`` (e.g. trade entity states such as the ``IRSState`` defined in the SIMM - valuation demo). Filterable attributes include: participants (exact or any match), linearId(s), uuid(s), and externalId(s). - - .. note:: All contract states that extend ``LinearState`` or ``DealState`` now automatically persist those - interfaces common state attributes to the **vault_linear_states** table. - -4. ``VaultCustomQueryCriteria`` provides the means to specify one or many arbitrary expressions on attributes defined - by a custom contract state that implements its own schema as described in the :doc:`Persistence ` - documentation and associated examples. Custom criteria expressions are expressed using one of several type-safe - ``CriteriaExpression``: BinaryLogical, Not, ColumnPredicateExpression, AggregateFunctionExpression. The - ``ColumnPredicateExpression`` allows for specification arbitrary criteria using the previously enumerated operator - types. The ``AggregateFunctionExpression`` allows for the specification of an aggregate function type (sum, avg, - max, min, count) with optional grouping and sorting. Furthermore, a rich DSL is provided to enable simple - construction of custom criteria using any combination of ``ColumnPredicate``. See the ``Builder`` object in - ``QueryCriteriaUtils`` for a complete specification of the DSL. - - .. note:: Custom contract schemas are automatically registered upon node startup for CorDapps. Please refer to - :doc:`Persistence ` for mechanisms of registering custom schemas for different testing - purposes. - -All ``QueryCriteria`` implementations are composable using ``and`` and ``or`` operators. - -All ``QueryCriteria`` implementations provide an explicitly specifiable set of common attributes: - -1. State status attribute (``Vault.StateStatus``), which defaults to filtering on UNCONSUMED states. - When chaining several criteria using AND / OR, the last value of this attribute will override any previous -2. Contract state types (``>``), which will contain at minimum one type (by default this - will be ``ContractState`` which resolves to all state types). When chaining several criteria using ``and`` and - ``or`` operators, all specified contract state types are combined into a single set - -An example of a custom query is illustrated here: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample20 - :end-before: DOCEND VaultQueryExample20 - :dedent: 12 - -.. note:: Custom contract states that implement the ``Queryable`` interface may now extend common schemas types - ``FungiblePersistentState`` or, ``LinearPersistentState``. Previously, all custom contracts extended the root - ``PersistentState`` class and defined repeated mappings of ``FungibleAsset`` and ``LinearState`` attributes. See - ``SampleCashSchemaV2`` and ``DummyLinearStateSchemaV2`` as examples. - -Examples of these ``QueryCriteria`` objects are presented below for Kotlin and Java. - -.. note:: When specifying the ``ContractType`` as a parameterised type to the ``QueryCriteria`` in Kotlin, queries now - include all concrete implementations of that type if this is an interface. Previously, it was only possible to query - on concrete types (or the universe of all ``ContractState``). - -The Vault Query API leverages the rich semantics of the underlying JPA Hibernate_ based -:doc:`Persistence ` framework adopted by Corda. - -.. _Hibernate: https://docs.jboss.org/hibernate/jpa/2.1/api/ - -.. note:: Permissioning at the database level will be enforced at a later date to ensure authenticated, role-based, - read-only access to underlying Corda tables. - -.. note:: API's now provide ease of use calling semantics from both Java and Kotlin. However, it should be noted that - Java custom queries are significantly more verbose due to the use of reflection fields to reference schema attribute - types. - -An example of a custom query in Java is illustrated here: - -.. literalinclude:: ../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java - :language: java - :start-after: DOCSTART VaultJavaQueryExample3 - :end-before: DOCEND VaultJavaQueryExample3 - :dedent: 16 - -.. note:: Queries by ``Party`` specify the ``AbstractParty`` which may be concrete or anonymous. In the later case, - where an anonymous party does not resolve to an X500 name via the ``IdentityService``, no query results will ever be - produced. For performance reasons, queries do not use ``PublicKey`` as search criteria. - -Custom queries can be either case sensitive or case insensitive. They are defined via a ``Boolean`` as one of the function parameters of each operator function. By default each operator is case sensitive. - -An example of a case sensitive custom query operator is illustrated here: - -.. container:: codeset - - .. sourcecode:: kotlin - - val currencyIndex = PersistentCashState::currency.equal(USD.currencyCode, true) - -.. note:: The ``Boolean`` input of ``true`` in this example could be removed since the function will default to ``true`` when not provided. - -An example of a case insensitive custom query operator is illustrated here: - -.. container:: codeset - - .. sourcecode:: kotlin - - val currencyIndex = PersistentCashState::currency.equal(USD.currencyCode, false) - -An example of a case sensitive custom query operator in Java is illustrated here: - -.. container:: codeset - - .. sourcecode:: java - - FieldInfo attributeCurrency = getField("currency", CashSchemaV1.PersistentCashState.class); - CriteriaExpression currencyIndex = Builder.equal(attributeCurrency, "USD", true); - -An example of a case insensitive custom query operator in Java is illustrated here: - -.. container:: codeset - - .. sourcecode:: java - - FieldInfo attributeCurrency = getField("currency", CashSchemaV1.PersistentCashState.class); - CriteriaExpression currencyIndex = Builder.equal(attributeCurrency, "USD", false); - -Pagination ----------- -The API provides support for paging where large numbers of results are expected (by default, a page size is set to 200 -results). Defining a sensible default page size enables efficient checkpointing within flows, and frees the developer -from worrying about pagination where result sets are expected to be constrained to 200 or fewer entries. Where large -result sets are expected (such as using the RPC API for reporting and/or UI display), it is strongly recommended to -define a ``PageSpecification`` to correctly process results with efficient memory utilisation. A fail-fast mode is in -place to alert API users to the need for pagination where a single query returns more than 200 results and no -``PageSpecification`` has been supplied. - -Here's a query that extracts every unconsumed ``ContractState`` from the vault in pages of size 200, starting from the -default page number (page one): - -.. container:: codeset - - .. sourcecode:: kotlin - - val vaultSnapshot = proxy.vaultQueryBy( - QueryCriteria.VaultQueryCriteria(Vault.StateStatus.UNCONSUMED), - PageSpecification(DEFAULT_PAGE_NUM, 200)) - -.. note:: A pages maximum size ``MAX_PAGE_SIZE`` is defined as ``Int.MAX_VALUE`` and should be used with extreme - caution as results returned may exceed your JVM's memory footprint. - -Example usage -------------- - -Kotlin -^^^^^^ - -**General snapshot queries using** ``VaultQueryCriteria``: - -Query for all unconsumed states (simplest query possible): - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample1 - :end-before: DOCEND VaultQueryExample1 - :dedent: 12 - -Query for unconsumed states for some state references: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample2 - :end-before: DOCEND VaultQueryExample2 - :dedent: 12 - -Query for unconsumed states for several contract state types: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample3 - :end-before: DOCEND VaultQueryExample3 - :dedent: 12 - -Query for unconsumed states for specified contract state constraint types and sorted in ascending alphabetical order: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample30 - :end-before: DOCEND VaultQueryExample30 - :dedent: 12 - -Query for unconsumed states for specified contract state constraints (type and data): - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample31 - :end-before: DOCEND VaultQueryExample31 - :dedent: 12 - -Query for unconsumed states for a given notary: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample4 - :end-before: DOCEND VaultQueryExample4 - :dedent: 12 - -Query for unconsumed states for a given set of participants (matches any state that contains at least one of the specified participants): - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample5 - :end-before: DOCEND VaultQueryExample5 - :dedent: 12 - -Query for unconsumed states for a given set of participants (exactly matches only states that contain all specified participants): - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample51 - :end-before: DOCEND VaultQueryExample51 - :dedent: 12 - -Query for unconsumed states recorded between two time intervals: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample6 - :end-before: DOCEND VaultQueryExample6 - :dedent: 12 - -.. note:: This example illustrates usage of a ``Between`` ``ColumnPredicate``. - -Query for all states with pagination specification (10 results per page): - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample7 - :end-before: DOCEND VaultQueryExample7 - :dedent: 12 - -.. note:: The result set metadata field `totalStatesAvailable` allows you to further paginate accordingly as - demonstrated in the following example. - -Query for all states using a pagination specification and iterate using the `totalStatesAvailable` field until no further -pages available: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample24 - :end-before: DOCEND VaultQueryExample24 - :dedent: 8 - -Query for only relevant states in the vault: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample25 - :end-before: DOCEND VaultQueryExample25 - :dedent: 8 - -**LinearState and DealState queries using** ``LinearStateQueryCriteria``: - -Query for unconsumed linear states for given linear ids: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample8 - :end-before: DOCEND VaultQueryExample8 - :dedent: 12 - -Query for all linear states associated with a linear id: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample9 - :end-before: DOCEND VaultQueryExample9 - :dedent: 12 - -Query for unconsumed deal states with deals references: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample10 - :end-before: DOCEND VaultQueryExample10 - :dedent: 12 - -Query for unconsumed deal states with deals parties (any match): - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample11 - :end-before: DOCEND VaultQueryExample11 - :dedent: 12 - -Query for unconsumed deal states with deals parties (exact match): - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample52 - :end-before: DOCEND VaultQueryExample52 - :dedent: 12 - -Query for only relevant linear states in the vault: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample26 - :end-before: DOCEND VaultQueryExample26 - :dedent: 8 - -**FungibleAsset and DealState queries using** ``FungibleAssetQueryCriteria``: - -Query for fungible assets for a given currency: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample12 - :end-before: DOCEND VaultQueryExample12 - :dedent: 12 - -Query for fungible assets for a minimum quantity: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample13 - :end-before: DOCEND VaultQueryExample13 - :dedent: 12 - -.. note:: This example uses the builder DSL. - -Query for fungible assets for a specific issuer party: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample14 - :end-before: DOCEND VaultQueryExample14 - :dedent: 12 - -Query for only relevant fungible states in the vault: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample27 - :end-before: DOCEND VaultQueryExample27 - :dedent: 12 - -**Aggregate Function queries using** ``VaultCustomQueryCriteria``: - -.. note:: Query results for aggregate functions are contained in the ``otherResults`` attribute of a results Page. - -Aggregations on cash using various functions: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample21 - :end-before: DOCEND VaultQueryExample21 - :dedent: 12 - -.. note:: ``otherResults`` will contain 5 items, one per calculated aggregate function. - -Aggregations on cash grouped by currency for various functions: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample22 - :end-before: DOCEND VaultQueryExample22 - :dedent: 12 - -.. note:: ``otherResults`` will contain 24 items, one result per calculated aggregate function per currency (the - grouping attribute - currency in this case - is returned per aggregate result). - -Sum aggregation on cash grouped by issuer party and currency and sorted by sum: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample23 - :end-before: DOCEND VaultQueryExample23 - :dedent: 12 - -.. note:: ``otherResults`` will contain 12 items sorted from largest summed cash amount to smallest, one result per - calculated aggregate function per issuer party and currency (grouping attributes are returned per aggregate result). - -Dynamic queries (also using ``VaultQueryCriteria``) are an extension to the snapshot queries by returning an -additional ``QueryResults`` return type in the form of an ``Observable``. Refer to -`ReactiveX Observable `_ for a detailed understanding and usage of -this type. - -Track unconsumed cash states: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample15 - :end-before: DOCEND VaultQueryExample15 - :dedent: 12 - -Track unconsumed linear states: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample16 - :end-before: DOCEND VaultQueryExample16 - :dedent: 12 - -.. note:: This will return both ``DealState`` and ``LinearState`` states. - -Track unconsumed deal states: - -.. literalinclude:: ../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt - :language: kotlin - :start-after: DOCSTART VaultQueryExample17 - :end-before: DOCEND VaultQueryExample17 - :dedent: 12 - -.. note:: This will return only ``DealState`` states. - -Java examples -^^^^^^^^^^^^^ - -Query for all unconsumed linear states: - -.. literalinclude:: ../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java - :language: java - :start-after: DOCSTART VaultJavaQueryExample0 - :end-before: DOCEND VaultJavaQueryExample0 - :dedent: 12 - -Query for all consumed cash states: - -.. literalinclude:: ../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java - :language: java - :start-after: DOCSTART VaultJavaQueryExample1 - :end-before: DOCEND VaultJavaQueryExample1 - :dedent: 12 - -Query for consumed deal states or linear ids, specify a paging specification and sort by unique identifier: - -.. literalinclude:: ../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java - :language: java - :start-after: DOCSTART VaultJavaQueryExample2 - :end-before: DOCEND VaultJavaQueryExample2 - :dedent: 12 - -Query for all states using a pagination specification and iterate using the `totalStatesAvailable` field until no further pages available: - -.. literalinclude:: ../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java - :language: java - :start-after: DOCSTART VaultQueryExample24 - :end-before: DOCEND VaultQueryExample24 - :dedent: 8 - -**Aggregate Function queries using** ``VaultCustomQueryCriteria``: - -Aggregations on cash using various functions: - -.. literalinclude:: ../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java - :language: java - :start-after: DOCSTART VaultJavaQueryExample21 - :end-before: DOCEND VaultJavaQueryExample21 - :dedent: 16 - -Aggregations on cash grouped by currency for various functions: - -.. literalinclude:: ../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java - :language: java - :start-after: DOCSTART VaultJavaQueryExample22 - :end-before: DOCEND VaultJavaQueryExample22 - :dedent: 16 - -Sum aggregation on cash grouped by issuer party and currency and sorted by sum: - -.. literalinclude:: ../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java - :language: java - :start-after: DOCSTART VaultJavaQueryExample23 - :end-before: DOCEND VaultJavaQueryExample23 - :dedent: 16 - -Track unconsumed cash states: - -.. literalinclude:: ../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java - :language: java - :start-after: DOCSTART VaultJavaQueryExample4 - :end-before: DOCEND VaultJavaQueryExample4 - :dedent: 12 - -Track unconsumed deal states or linear states (with snapshot including specification of paging and sorting by unique -identifier): - -.. literalinclude:: ../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java - :language: java - :start-after: DOCSTART VaultJavaQueryExample5 - :end-before: DOCEND VaultJavaQueryExample5 - :dedent: 12 - -Troubleshooting ---------------- -If the results your were expecting do not match actual returned query results we recommend you add an entry to your -``log4j2.xml`` configuration file to enable display of executed SQL statements:: - - 
 - 
 - - -Behavioural notes ------------------ -1. ``TrackBy`` updates do not take into account the full criteria specification due to different and more restrictive - syntax in `observables `_ filtering (vs full SQL-92 JDBC filtering as used - in snapshot views). Specifically, dynamic updates are filtered by ``contractStateType`` and ``stateType`` - (UNCONSUMED, CONSUMED, ALL) only -2. ``QueryBy`` and ``TrackBy`` snapshot views using pagination may return different result sets as each paging request - is a separate SQL query on the underlying database, and it is entirely conceivable that state modifications are - taking place in between and/or in parallel to paging requests. When using pagination, always check the value of the - ``totalStatesAvailable`` (from the ``Vault.Page`` result) and adjust further paging requests appropriately. - -Other use case scenarios ------------------------- - -For advanced use cases that require sophisticated pagination, sorting, grouping, and aggregation functions, it is -recommended that the CorDapp developer utilise one of the many proven frameworks that ship with this capability out of -the box. Namely, implementations of JPQL (JPA Query Language) such as Hibernate for advanced SQL access, and -Spring Data for advanced pagination and ordering constructs. - -The Corda Tutorials provide examples satisfying these additional Use Cases: - - 1. Example CorDapp service using Vault API Custom Query to access attributes of IOU State - 2. Example CorDapp service query extension executing Named Queries via JPQL_ - 3. `Advanced pagination `_ queries using Spring Data JPA_ - - .. _JPQL: http://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#hql - .. _JPA: https://docs.spring.io/spring-data/jpa/docs/current/reference/html - -Mapping owning keys to external IDs ------------------------------------ - -When creating new public keys via the ``KeyManagementService``, it is possible to create an association between the newly created public -key and an external ID. This, in effect, allows CorDapp developers to group state ownership/participation keys by an account ID. - -.. note:: This only works with freshly generated public keys and *not* the node's legal identity key. If you require that the freshly - generated keys be for the node's identity then use ``PersistentKeyManagementService.freshKeyAndCert`` instead of ``freshKey``. - Currently, the generation of keys for other identities is not supported. - -The code snippet below show how keys can be associated with an external ID by using the exposed JPA functionality: - -.. container:: codeset - - .. sourcecode:: java - - public AnonymousParty freshKeyForExternalId(UUID externalId, ServiceHub services) { - // Create a fresh key pair and return the public key. - AnonymousParty anonymousParty = freshKey(); - // Associate the fresh key to an external ID. - services.withEntityManager(entityManager -> { - PersistentKeyManagementService.PublicKeyHashToExternalId mapping = PersistentKeyManagementService.PublicKeyHashToExternalId(externalId, anonymousParty.owningKey); - entityManager.persist(mapping); - return null; - }); - return anonymousParty; - } - - .. sourcecode:: kotlin - - fun freshKeyForExternalId(externalId: UUID, services: ServiceHub): AnonymousParty { - // Create a fresh key pair and return the public key. - val anonymousParty = freshKey() - // Associate the fresh key to an external ID. - services.withEntityManager { - val mapping = PersistentKeyManagementService.PublicKeyHashToExternalId(externalId, anonymousParty.owningKey) - persist(mapping) - } - return anonymousParty - } - -As can be seen in the code snippet above, the ``PublicKeyHashToExternalId`` entity has been added to ``PersistentKeyManagementService``, -which allows you to associate your public keys with external IDs. So far, so good. - -.. note:: Here, it is worth noting that we must map **owning keys** to external IDs, as opposed to **state objects**. This is because it - might be the case that a ``LinearState`` is owned by two public keys generated by the same node. - -The intuition here is that when these public keys are used to own or participate in a state object, it is trivial to then associate those -states with a particular external ID. Behind the scenes, when states are persisted to the vault, the owning keys for each state are -persisted to a ``PersistentParty`` table. The ``PersistentParty`` table can be joined with the ``PublicKeyHashToExternalId`` table to create -a view which maps each state to one or more external IDs. The entity relationship diagram below helps to explain how this works. - -.. image:: resources/state-to-external-id.png - -When performing a vault query, it is now possible to query for states by external ID using the ``externalIds`` parameter in -``VaultQueryCriteria``. \ No newline at end of file diff --git a/docs/source/app-upgrade-notes.rst b/docs/source/app-upgrade-notes.rst deleted file mode 100644 index f8ec30dea0..0000000000 --- a/docs/source/app-upgrade-notes.rst +++ /dev/null @@ -1,600 +0,0 @@ -.. highlight:: kotlin -.. raw:: html - - - - -Upgrading CorDapps to newer Platform Versions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -These notes provide instructions for upgrading your CorDapps from previous versions. Corda provides backwards compatibility for public, -non-experimental APIs that have been committed to. A list can be found in the :doc:`api-stability-guarantees` page. - -This means that you can upgrade your node across versions *without recompiling or adjusting your CorDapps*. You just have to upgrade -your node and restart. - -However, there are usually new features and other opt-in changes that may improve the security, performance or usability of your -application that are worth considering for any actively maintained software. This guide shows you how to upgrade your app to benefit -from the new features in the latest release. - -.. warning:: The sample apps found in the Corda repository and the Corda samples repository are not intended to be used in production. - If you are using them you should re-namespace them to a package namespace you control, and sign/version them yourself. - -.. contents:: - :depth: 3 - -Upgrading apps to Platform Version 5 -==================================== - -This section provides instructions for upgrading your CorDapps from previous versions to take advantage of features and enhancements introduced -in platform version 5. - -.. note:: If you are upgrading from a platform version older than 4, then the upgrade notes for upgrading to Corda 4 (below) also apply. - -Step 1. Handle any source compatibility breaks (if using Kotlin) ----------------------------------------------------------------- - -The following code, which compiled in Platform Version 4, will not compile in Platform Version 5: - -.. container:: codeset - - .. sourcecode:: kotlin - - data class Obligation(val amount: Amount, val lender: AbstractParty, val borrower: AbstractParty) - - val (lenderId, borrowerId) = if (anonymous) { - val anonymousIdentitiesResult = subFlow(SwapIdentitiesFlow(lenderSession)) - Pair(anonymousIdentitiesResult[lenderSession.counterparty]!!, anonymousIdentitiesResult[ourIdentity]!!) - } else { - Pair(lender, ourIdentity) - } - - val obligation = Obligation(100.dollars, lenderId, borrowerId) - -Compiling this code against Platform Version 5 will result in the following error: - -``Type mismatch: inferred type is Any but AbstractParty was expected`` - -The issue here is that a new ``Destination`` interface introduced in Platform Version 5 can cause type inference failures when a variable is -used as an ``AbstractParty`` but has an actual value that is one of ``Party`` or ``AnonymousParty``. These subclasses -implement ``Destination``, while the superclass does not. Kotlin must pick a type for the variable, and so chooses the most specific -ancestor of both ``AbstractParty`` and ``Destination``. This is ``Any``, which is not a valid type for use as an ``AbstractParty`` later. -(For more information on ``Destination``, see the :doc:`changelog` for Platform Version 5, or the KDocs for the interface -`here `__) - -Note that this is a Kotlin-specific issue. Java can instead choose ``? extends AbstractParty & Destination`` here, which can later be used -as ``AbstractParty``. - -To fix this, an explicit type hint must be provided to the compiler: - -.. container:: codeset - - .. sourcecode:: kotlin - - data class Obligation(val amount: Amount, val lender: AbstractParty, val borrower: AbstractParty) - - val (lenderId, borrowerId) = if (anonymous) { - val anonymousIdentitiesResult = subFlow(SwapIdentitiesFlow(lenderSession)) - Pair(anonymousIdentitiesResult[lenderSession.counterparty]!!, anonymousIdentitiesResult[ourIdentity]!!) - } else { - // This Pair now provides a type hint to the compiler - Pair(lender, ourIdentity) - } - - val obligation = Obligation(100.dollars, lenderId, borrowerId) - -This stops type inference from occurring and forces the variable to be of type ``AbstractParty``. - -.. _platform_version_5_gradle_changes: - -Step 2. Update Gradle version and associated dependencies ---------------------------------------------------------- - -Platform Version 5 requires Gradle 5.4 to build. If you use the Gradle wrapper, you can upgrade by running: - - .. code:: shell - - ./gradlew wrapper --gradle-version 5.4.1 - -Otherwise, upgrade your installed copy in the usual manner for your operating system. - -Additionally, you'll need to add https://repo.gradle.org/gradle/libs-releases as a repository to your project, in order to pick up the -`gradle-api-tooling` dependency. You can do this by adding the following to the repositories in your Gradle file: - -.. code-block:: groovy - - maven { url 'https://repo.gradle.org/gradle/libs-releases' } - -Upgrading apps to Platform Version 4 -==================================== - -This section provides instructions for upgrading your CorDapps from previous versions to platform version 4. - -Step 1. Switch any RPC clients to use the new RPC library ---------------------------------------------------------- - -Although the RPC API is backwards compatible with Corda 3, the RPC wire protocol isn't. Therefore RPC clients like web servers need to be -updated in lockstep with the node to use the new version of the RPC library. Corda 4 delivers RPC wire stability and therefore in future you -will be able to update the node and apps without updating RPC clients. - -.. _cordapp_upgrade_version_numbers_ref: - -Step 2. Adjust the version numbers in your Gradle build files -------------------------------------------------------------- - -Alter the versions you depend on in your Gradle file like so: - -.. code-block:: groovy - - ext.corda_release_version = '|corda_version|' - ext.corda_gradle_plugins_version = '|gradle_plugins_version|' - ext.kotlin_version = '|kotlin_version|' - ext.quasar_version = '|quasar_version|' - -.. note:: You may wish to update your kotlinOptions to use language level 1.2, to benefit from the new features. Apps targeting Corda 4 - may not at this time use Kotlin 1.3, as it was released too late in the development cycle - for us to risk an upgrade. Sorry! Future work on app isolation will make it easier for apps to use newer Kotlin versions than - the node itself uses. - -You should also ensure you're using Gradle 4.10 (but not 5). If you use the Gradle wrapper, run: - -.. code:: shell - - ./gradlew wrapper --gradle-version 4.10.3 - -Otherwise just upgrade your installed copy in the usual manner for your operating system. - -.. note:: Platform Version 5 requires a different version of Gradle, so if you're intending to upgrade past Platform Version 4 you may wish - to skip updating Gradle here and upgrade directly to the version required by Platform Version 5. You'll still need to alter the version - numbers in your Gradle file as shown in this section. See :ref:`platform_version_5_gradle_changes` - -Step 3. Update your Gradle build file -------------------------------------- - -There are several adjustments that are beneficial to make to your Gradle build file, beyond simply incrementing the versions -as described in step 1. - -**Provide app metadata.** This is used by the Corda Gradle build plugin to populate your app JAR with useful information. -It should look like this: - -.. code-block:: groovy - - cordapp { - targetPlatformVersion 4 - minimumPlatformVersion 4 - contract { - name "MegaApp Contracts" - vendor "MegaCorp" - licence "A liberal, open source licence" - versionId 1 - } - workflow { - name "MegaApp flows" - vendor "MegaCorp" - licence "A really expensive proprietary licence" - versionId 1 - } - } - -.. important:: Watch out for the UK spelling of the word licence (with a c). - -Name, vendor and licence can be set to any string you like, they don't have to be Corda identities. - -Target versioning is a new concept introduced in Corda 4. Learn more by reading :doc:`versioning`. -Setting a target version of 4 opts in to changes that might not be 100% backwards compatible, such as -API semantics changes or disabling workarounds for bugs that may be in your apps, so by doing this you -are promising that you have thoroughly tested your app on the new version. Using a high target version is -a good idea because some features and improvements are only available to apps that opt in. - -The minimum platform version is the platform version of the node that you require, so if you -start using new APIs and features in Corda 4, you should set this to 4. Unfortunately Corda 3 and below -do not know about this metadata and don't check it, so your app will still be loaded in such nodes and -may exhibit undefined behaviour at runtime. However it's good to get in the habit of setting this -properly for future releases. - -.. note:: Whilst it's currently a convention that Corda releases have the platform version number as their - major version i.e. Corda 3.3 implements platform version 3, this is not actually required and may in - future not hold true. You should know the platform version of the node releases you want to target. - -The new ``versionId`` number is a version code for **your** app, and is unrelated to Corda's own versions. -It is currently used for informative purposes only. - -**Split your app into contract and workflow JARs.** The duplication between ``contract`` and ``workflow`` blocks exists because you should split your app into -two separate JARs/modules, one that contains on-ledger validation code like states and contracts, and one -for the rest (called by convention the "workflows" module although it can contain a lot more than just flows: -services would also go here, for instance). For simplicity, here we use one JAR for both, but this is in -general an anti-pattern and can result in your flow logic code being sent over the network to arbitrary -third party peers, even though they don't need it. - -In future, the version ID attached to the workflow JAR will also be used to help implement smoother upgrade -and migration features. You may directly reference the gradle version number of your app when setting the -CorDapp specific versionId identifiers if this follows the convention of always being a whole number -starting from 1. - -If you use the finance demo app, you should adjust your dependencies so you depend on the finance-contracts -and finance-workflows artifacts from your own contract and workflow JAR respectively. - -Step 4. Remove any custom configuration from the node.conf ----------------------------------------------------------- - -CorDapps can no longer access custom configuration items in the ``node.conf`` file. Any custom CorDapp configuration should be added to a -CorDapp configuration file. The Node's configuration will not be accessible. CorDapp configuration files should be placed in the -`config` subdirectory of the Node's `cordapps` folder. The name of the file should match the name of the JAR of the CorDapp (eg; if your -CorDapp is called ``hello-0.1.jar`` the configuration file needed would be ``cordapps/config/hello-0.1.conf``). - -If you are using the ``extraConfig`` of a ``node`` in the ``deployNodes`` Gradle task to populate custom configuration for testing, you will need -to make the following change so that: - -.. sourcecode:: groovy - - task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { - node { - name "O=Bank A,L=London,C=GB"c - ... - extraConfig = [ 'some.extra.config' : '12345' ] - } - } - -Would become: - -.. sourcecode:: groovy - - task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { - node { - name "O=Bank A,L=London,C=GB"c - ... - projectCordapp { - config "some.extra.config=12345" - } - } - } - -See :ref:`cordapp_configuration_files_ref` for more information. - -.. _cordapp_upgrade_finality_flow_ref: - -Step 5. Security: Upgrade your use of FinalityFlow --------------------------------------------------- - -The previous ``FinalityFlow`` API is insecure. It doesn't have a receive flow, so requires counterparty nodes to accept any and -all signed transactions that are sent to it, without checks. It is **highly** recommended that existing CorDapps migrate -away to the new API, as otherwise things like business network membership checks won't be reliably enforced. - -The flows that make use of ``FinalityFlow`` in a CorDapp can be classified in the following 2 basic categories: - -* **non-initiating flows**: these are flows that finalise a transaction without the involvement of a counterpart flow at all. -* **initiating flows**: these are flows that initiate a counterpart (responder) flow. - -There is a main difference between these 2 different categories, which is relevant to how the CorDapp can be upgraded. -The second category of flows can be upgraded to use the new ``FinalityFlow`` in a backwards compatible way, which means the upgraded CorDapp can be deployed at the various nodes using a *rolling deployment*. -On the other hand, the first category of flows cannot be upgraded to the new ``FinalityFlow`` in a backwards compatible way, so the changes to these flows need to be deployed simultaneously at all the nodes, using a *lockstep deployment*. - -.. note:: A *lockstep deployment* is one, where all the involved nodes are stopped, upgraded to the new version of the CorDapp and then re-started. - As a result, there can't be any nodes running different versions of the CorDapp at any time. - A *rolling deployment* is one, where every node can be stopped, upgraded to the new version of the CorDapp and re-started independently and on its own pace. - As a result, there can be nodes running different versions of the CorDapp and transact with each other successfully. - -The upgrade is a three step process: - -1. Change the flow that calls ``FinalityFlow``. -2. Change or create the flow that will receive the finalised transaction. -3. Make sure your application's minimum and target version numbers are both set to 4 (see :ref:`cordapp_upgrade_version_numbers_ref`). - -Upgrading a non-initiating flow -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -As an example, let's take a very simple flow that finalises a transaction without the involvement of a counterpart flow: - -.. container:: codeset - - .. literalinclude:: example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt - :language: kotlin - :start-after: DOCSTART SimpleFlowUsingOldApi - :end-before: DOCEND SimpleFlowUsingOldApi - - .. literalinclude:: example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java - :language: java - :start-after: DOCSTART SimpleFlowUsingOldApi - :end-before: DOCEND SimpleFlowUsingOldApi - :dedent: 4 - -To use the new API, this flow needs to be annotated with ``InitiatingFlow`` and a ``FlowSession`` to the participant(s) of the transaction must be -passed to ``FinalityFlow`` : - -.. container:: codeset - - .. literalinclude:: example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt - :language: kotlin - :start-after: DOCSTART SimpleFlowUsingNewApi - :end-before: DOCEND SimpleFlowUsingNewApi - - .. literalinclude:: example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java - :language: java - :start-after: DOCSTART SimpleFlowUsingNewApi - :end-before: DOCEND SimpleFlowUsingNewApi - :dedent: 4 - -If there are more than one transaction participants then a session to each one must be initiated, excluding the local party -and the notary. - -A responder flow has to be introduced, which will automatically run on the other participants' nodes, which will call ``ReceiveFinalityFlow`` -to record the finalised transaction: - -.. container:: codeset - - .. literalinclude:: example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt - :language: kotlin - :start-after: DOCSTART SimpleNewResponderFlow - :end-before: DOCEND SimpleNewResponderFlow - - .. literalinclude:: example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java - :language: java - :start-after: DOCSTART SimpleNewResponderFlow - :end-before: DOCEND SimpleNewResponderFlow - :dedent: 4 - -.. note:: As described above, all the nodes in your business network will need the new CorDapp, otherwise they won't know how to receive the transaction. **This - includes nodes which previously didn't have the old CorDapp.** If a node is sent a transaction and it doesn't have the new CorDapp loaded - then simply restart it with the CorDapp and the transaction will be recorded. - -Upgrading an initiating flow -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For flows which are already initiating counterpart flows then it's a matter of using the existing flow session. -Note however, the new ``FinalityFlow`` is inlined and so the sequence of sends and receives between the two flows will -change and will be incompatible with your current flows. You can use the flow version API to write your flows in a -backwards compatible manner. - -Here's what an upgraded initiating flow may look like: - -.. container:: codeset - - .. literalinclude:: example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt - :language: kotlin - :start-after: DOCSTART ExistingInitiatingFlow - :end-before: DOCEND ExistingInitiatingFlow - - .. literalinclude:: example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java - :language: java - :start-after: DOCSTART ExistingInitiatingFlow - :end-before: DOCEND ExistingInitiatingFlow - :dedent: 4 - -For the responder flow, insert a call to ``ReceiveFinalityFlow`` at the location where it's expecting to receive the -finalised transaction. If the initiator is written in a backwards compatible way then so must the responder. - -.. container:: codeset - - .. literalinclude:: example-code/src/main/kotlin/net/corda/docs/kotlin/FinalityFlowMigration.kt - :language: kotlin - :start-after: DOCSTART ExistingResponderFlow - :end-before: DOCEND ExistingResponderFlow - :dedent: 8 - - .. literalinclude:: example-code/src/main/java/net/corda/docs/java/FinalityFlowMigration.java - :language: java - :start-after: DOCSTART ExistingResponderFlow - :end-before: DOCEND ExistingResponderFlow - :dedent: 12 - -You may already be using ``waitForLedgerCommit`` in your responder flow for the finalised transaction to appear in the local node's vault. -Now that it's calling ``ReceiveFinalityFlow``, which effectively does the same thing, this is no longer necessary. The call to -``waitForLedgerCommit`` should be removed. - -Step 6. Security: Upgrade your use of SwapIdentitiesFlow --------------------------------------------------------- - -The :ref:`confidential_identities_ref` API is experimental in Corda 3 and remains so in Corda 4. In this release, the ``SwapIdentitiesFlow`` -has been adjusted in the same way as ``FinalityFlow`` above, to close problems with confidential identities being injectable into a node -outside of other flow context. Old code will still work, but it is recommended to adjust your call sites so a session is passed into -the ``SwapIdentitiesFlow``. - -Step 7. Possibly, adjust test code ----------------------------------- - -``MockNodeParameters`` and functions creating it no longer use a lambda expecting a ``NodeConfiguration`` object. -Use a ``MockNetworkConfigOverrides`` object instead. This is an API change we regret, but unfortunately in Corda 3 we accidentally exposed -large amounts of the node internal code through this one API entry point. We have now insulated the test API from node internals and -reduced the exposure. - -If you are constructing a MockServices for testing contracts, and your contract uses the Cash contract from the finance app, you -now need to explicitly add ``net.corda.finance.contracts`` to the list of ``cordappPackages``. This is a part of the work to disentangle -the finance app (which is really a demo app) from the Corda internals. Example: - -.. container:: codeset - - .. sourcecode:: kotlin - - val ledgerServices = MockServices( - listOf("net.corda.examples.obligation", "net.corda.testing.contracts"), - initialIdentity = TestIdentity(CordaX500Name("TestIdentity", "", "GB")), - identityService = makeTestIdentityService() - ) - - .. sourcecode:: java - - MockServices ledgerServices = new MockServices( - Arrays.asList("net.corda.examples.obligation", "net.corda.testing.contracts"), - new TestIdentity(new CordaX500Name("TestIdentity", "", "GB")), - makeTestIdentityService() - ); - -becomes: - -.. container:: codeset - - .. sourcecode:: kotlin - - val ledgerServices = MockServices( - listOf("net.corda.examples.obligation", "net.corda.testing.contracts", "net.corda.finance.contracts"), - initialIdentity = TestIdentity(CordaX500Name("TestIdentity", "", "GB")), - identityService = makeTestIdentityService() - ) - - .. sourcecode:: java - - MockServices ledgerServices = new MockServices( - Arrays.asList("net.corda.examples.obligation", "net.corda.testing.contracts", "net.corda.finance.contracts"), - new TestIdentity(new CordaX500Name("TestIdentity", "", "GB")), - makeTestIdentityService() - ); - -You may need to use the new ``TestCordapp`` API when testing with the node driver or mock network, especially if you decide to stick with the -pre-Corda 4 ``FinalityFlow`` API. The previous way of pulling in CorDapps into your tests (i.e. via using the ``cordappPackages`` parameter) does not honour CorDapp versioning. -The new API ``TestCordapp.findCordapp()`` discovers the CorDapps that contain the provided packages scanning the classpath, so you have to ensure that the classpath the tests are running under contains either the CorDapp ``.jar`` or (if using Gradle) the relevant Gradle sub-project. -In the first case, the versioning information in the CorDapp ``.jar`` file will be maintained. In the second case, the versioning information will be retrieved from the Gradle ``cordapp`` task. -For example, if you are using ``MockNetwork`` for your tests, the following code: - -.. container:: codeset - - .. sourcecode:: kotlin - - val mockNetwork = MockNetwork( - cordappPackages = listOf("net.corda.examples.obligation", "net.corda.finance.contracts"), - notarySpecs = listOf(MockNetworkNotarySpec(notary)) - ) - - .. sourcecode:: java - - MockNetwork mockNetwork = new MockNetwork( - Arrays.asList("net.corda.examples.obligation", "net.corda.finance.contracts"), - new MockNetworkParameters().withNotarySpecs(Arrays.asList(new MockNetworkNotarySpec(notary))) - ); - -would need to be transformed into: - -.. container:: codeset - - .. sourcecode:: kotlin - - val mockNetwork = MockNetwork( - MockNetworkParameters( - cordappsForAllNodes = listOf( - TestCordapp.findCordapp("net.corda.examples.obligation.contracts"), - TestCordapp.findCordapp("net.corda.examples.obligation.flows") - ), - notarySpecs = listOf(MockNetworkNotarySpec(notary)) - ) - ) - - .. sourcecode:: java - - MockNetwork mockNetwork = new MockNetwork( - new MockNetworkParameters( - Arrays.asList( - TestCordapp.findCordapp("net.corda.examples.obligation.contracts"), - TestCordapp.findCordapp("net.corda.examples.obligation.flows") - ) - ).withNotarySpecs(Arrays.asList(new MockNetworkNotarySpec(notary))) - ); - -Note that every package should exist in only one CorDapp, otherwise the discovery process won't be able to determine which one to use and you will most probably see an exception telling you ``There is more than one CorDapp containing the package``. -For instance, if you have 2 CorDapps containing the packages ``net.corda.examples.obligation.contracts`` and ``net.corda.examples.obligation.flows``, you will get this error if you specify the package ``net.corda.examples.obligation``. - - -.. note:: If you have any CorDapp code (e.g. flows/contracts/states) that is only used by the tests and located in the same test module, it won't be discovered now. - You will need to move them in the main module of one of your CorDapps or create a new, separate CorDapp for them, in case you don't want this code to live inside your production CorDapps. - -Step 8. Security: Add BelongsToContract annotations ---------------------------------------------------- - -In versions of the platform prior to v4, it was the responsibility of contract and flow logic to ensure that ``TransactionState`` objects -contained the correct class name of the expected contract class. If these checks were omitted, it would be possible for a malicious counterparty -to construct a transaction containing e.g. a cash state governed by a commercial paper contract. The contract would see that there were no -commercial paper states in a transaction and do nothing, i.e. accept. - -In Corda 4 the platform takes over this responsibility from the app, if the app has a target version of 4 or higher. A state is expected -to be governed by a contract that is either: - -1. The outer class of the state class, if the state is an inner class of a contract. This is a common design pattern. -2. Annotated with ``@BelongsToContract`` which specifies the contract class explicitly. - -Learn more by reading :ref:`contract_state_agreement`. If an app targets Corda 3 or lower (i.e. does not specify a target version), -states that point to contracts outside their package will trigger a log warning but validation will proceed. - -Step 9. Learn about signature constraints and JAR signing ---------------------------------------------------------- - -:ref:`signature_constraints` are a new data model feature introduced in Corda 4. They make it much easier to -deploy application upgrades smoothly and in a decentralised manner. Signature constraints are the new default mode for CorDapps, and -the act of upgrading your app to use the version 4 Gradle plugins will result in your app being automatically signed, and new states -automatically using new signature constraints selected automatically based on these signing keys. - -You can read more about signature constraints and what they do in :doc:`api-contract-constraints`. The ``TransactionBuilder`` class will -automatically use them if your application JAR is signed. **We recommend all JARs are signed**. To learn how to sign your JAR files, read -:ref:`cordapp_build_system_signing_cordapp_jar_ref`. In dev mode, all JARs are signed by developer certificates. If a JAR that was signed -with developer certificates is deployed to a production node, the node will refuse to start. Therefore to deploy apps built for Corda 4 -to production you will need to generate signing keys and integrate them with the build process. - -.. note:: Please read the :doc:`cordapp-constraint-migration` guide to understand how to upgrade CorDapps to use Corda 4 signature constraints and consume - existing states on ledger issued with older constraint types (e.g. Corda 3.x states issued with **hash** or **CZ whitelisted** constraints). - -Step 10. Security: Package namespace handling ---------------------------------------------- - -Almost no apps will be affected by these changes, but they're important to know about. - -There are two improvements to how Java package protection is handled in Corda 4: - -1. Package sealing -2. Package namespace ownership - -**Sealing.** App isolation has been improved. Version 4 of the finance CorDapps (*corda-finance-contracts.jar*, *corda-finance-workflows.jar*) is now built as a set of sealed and -signed JAR files. This means classes in your own CorDapps cannot be placed under the following package namespace: ``net.corda.finance`` - -In the unlikely event that you were injecting code into ``net.corda.finance.*`` package namespaces from your own apps, you will need to move them -into a new package, e.g. ``net/corda/finance/flows/MyClass.java`` can be moved to ``com/company/corda/finance/flows/MyClass.java``. -As a consequence your classes are no longer able to access non-public members of finance CorDapp classes. - -When signing your JARs for Corda 4, your own apps will also become sealed, meaning other JARs cannot place classes into your own packages. -This is a security upgrade that ensures package-private visibility in Java code works correctly. If other apps could define classes in your own -packages, they could call package-private methods, which may not be expected by the developers. - -**Namespace ownership.** This part is only relevant if you are joining a production compatibility zone. You may wish to contact your zone operator -and request ownership of your root package namespaces (e.g. ``com.megacorp.*``), with the signing keys you will be using to sign your app JARs. -The zone operator can then add your signing key to the network parameters, and prevent attackers defining types in your own package namespaces. -Whilst this feature is optional and not strictly required, it may be helpful to block attacks at the boundaries of a Corda based application -where type names may be taken "as read". - -Step 11. Consider adding extension points to your flows -------------------------------------------------------- - -In Corda 4 it is possible for flows in one app to subclass and take over flows from another. This allows you to create generic, shared -flow logic that individual users can customise at pre-agreed points (protected methods). For example, a site-specific app could be developed -that causes transaction details to be converted to a PDF and sent to a particular printer. This would be an inappropriate feature to put -into shared business logic, but it makes perfect sense to put into a user-specific app they developed themselves. - -If your flows could benefit from being extended in this way, read ":doc:`flow-overriding`" to learn more. - -Step 12. Possibly update vault state queries --------------------------------------------- - -In Corda 4 queries made on a node's vault can filter by the relevancy of those states to the node. As this functionality does not exist in -Corda 3, apps will continue to receive all states in any vault queries. However, it may make sense to migrate queries expecting just those states relevant -to the node in question to query for only relevant states. See :doc:`api-vault-query` for more details on how to do this. Not doing this -may result in queries returning more states than expected if the node is using observer functionality (see ":doc:`tutorial-observer-nodes`"). - -Step 13. Explore other new features that may be useful ------------------------------------------------------- - -Corda 4 adds several new APIs that help you build applications. Why not explore: - -* The `new withEntityManager API `_ for using JPA inside your flows and services. -* :ref:`reference_states`, that let you use an input state without consuming it. -* :ref:`state_pointers`, that make it easier to 'point' to one state from another and follow the latest version of a linear state. - -Please also read the :doc:`CorDapp Upgradeability Guarantees ` associated with CorDapp upgrading. - -Step 14. Possibly update your checked in quasar.jar ---------------------------------------------------- - -If your project is based on one of the official cordapp templates, it is likely you have a ``lib/quasar.jar`` checked in. It is worth noting -that you only use this if you use the JUnit runner in IntelliJ. In the latest release of the cordapp templates, this directory has -been removed. - -You have some choices here: - -* Upgrade your ``quasar.jar`` to ``|quasar_version|`` -* Delete your ``lib`` directory and switch to using the Gradle test runner - -Instructions for both options can be found in :ref:`Running tests in Intellij `. diff --git a/docs/source/aws-vm-explore.rst b/docs/source/aws-vm-explore.rst deleted file mode 100644 index c9b5f7e75a..0000000000 --- a/docs/source/aws-vm-explore.rst +++ /dev/null @@ -1,122 +0,0 @@ -Deploying Corda to Corda Testnet from an AWS Cloud Platform VM -============================================================== - -.. contents:: - -This document explains how to deploy a Corda node to AWS that can connect directly to the Corda Testnet. -A self service download link can be obtained from https://marketplace.r3.com/network/testnet. This -document will describe how to set up a virtual machine on the AWS -Cloud Platform to deploy your pre-configured Corda node and automatically connnect -to Testnet. - -Pre-requisites --------------- -* Ensure you have a registered Amazon AWS account which can create virtual machines and you are logged on to the AWS console: https://console.aws.amazon.com. - - -Deploy Corda node ------------------ - -Browse to https://console.aws.amazon.com and log in with your AWS account. - - -**STEP 1: Launch a new virtual machine** - -Click on Launch a virtual machine with EC2. - -.. image:: resources/aws-launch.png - -In the quick start wizard scroll down and select the most recent Ubuntu machine image as the Amazon Machine Image (AMI). - -.. image:: resources/aws_select_ubuntu.png - -Select the instance type (for example t2.xlarge). - -.. image:: resources/aws-instance-type.png - -Configure a couple of other settings before we review and launch - -Under the storage tab (Step 4) increase the storage to 40GB: - -.. image:: resources/aws-storage.png - -Configure the security group (Step 6) to open the firewall ports which Corda uses. - -.. image:: resources/aws-firewall.png - -Add a firewall rule for port range 10002-10003 and allow connection from Anywhere. Add another rule for the webserver on port 8080. - -Click on the Review and Launch button then if everything looks ok click Launch. - -You will be prompted to set up keys to securely access the VM remotely over ssh. Select "Create a new key pair" from the drop down and enter a name for the key file. Click download to get the keys and keep them safe on your local machine. - -.. note:: These keys are just for connecting to your VM and are separate from the keys Corda will use to sign transactions. These keys will be generated as part of the download bundle. - -.. image:: resources/aws-keys.png - -Click "Launch Instances". - -Click on the link to go to the Instances pages in the AWS console where after a few minutes you will be able to see your instance running. - -.. image:: resources/aws-instances.png - -**STEP 2: Set up static IP address** - -On AWS a permanent IP address is called an Elastic IP. Click on the -"Elastic IP" link in the navigation panel on the left hand side of the console and then click on "Allocate new address": - -.. image:: resources/aws-elastic.png - -Follow the form then once the address is allocated click on "Actions" -then "Associate address": - -.. image:: resources/aws-elastic-actions.png - -Then select the instance you created for your Corda node to attach the -IP address to. - -**STEP 3: Connect to your VM and set up the environment** - -In the instances console click on "Connect" and follow the instructions to connect to your instance using ssh. - -.. image:: resources/aws-instances-connect.png - -.. image:: resources/aws-connect.png - - -**STEP 4: Download and set up your Corda node** - -Now your AWS environment is configured you can switch back to the Testnet -web application and click on the copy to clipboard button to get a one -time installation script. - -.. note:: If you have not already set up your account on Testnet then please visit https://marketplace.r3.com/network/testnet and sign up. - -.. image:: resources/testnet-platform.png - -You can generate as many Testnet identites as you like by refreshing -this page to generate a new one time link. - -In the terminal of your cloud instance paste the command you just copied to install and run -your unique Corda instance on that instance: - -.. code:: bash - - sudo ONE_TIME_DOWNLOAD_KEY=YOUR_UNIQUE_DOWNLOAD_KEY_HERE bash -c "$(curl -L https://onboarder.prod.ws.r3.com/api/user/node/TESTNET/install.sh)" - -.. warning:: This command will execute the install script as ROOT on your cloud instance. You may wish to examine the script prior to executing it on your machine. - -You can follow the progress of the installation by typing the following command in your terminal: - -.. code:: bash - - tail -f /opt/corda/logs/node-.log - - -Testing your deployment ------------------------ - -To test your deployment is working correctly follow the instructions in :doc:`testnet-explorer-corda` to set up the Finance CorDapp and issue cash to a counterparty. - -This will also demonstrate how to install a custom CorDapp. - diff --git a/docs/source/aws-vm.rst b/docs/source/aws-vm.rst deleted file mode 100644 index 742411f170..0000000000 --- a/docs/source/aws-vm.rst +++ /dev/null @@ -1,72 +0,0 @@ -AWS Marketplace -=============== - -To help you design, build and test applications on Corda, called CorDapps, a Corda network AMI can be deployed from the `AWS Marketplace `__. Instructions on running Corda nodes can be found `here `_. - -This Corda network offering builds a pre-configured network of Corda nodes as Ubuntu virtual machines (VM). The network consists of a Notary node and three Corda nodes using version 1 of Corda. The following guide will also show you how to load one of four `Corda Sample apps `_ which demonstrates the basic principles of Corda. When you are ready to go further with developing on Corda and start making contributions to the project head over to the `Corda.net `_. - -Pre-requisites --------------- -* Ensure you have a registered AWS account which can create virtual machines under your subscription(s) and you are logged on to the `AWS portal `_ -* It is recommended you generate a private-public SSH key pair (see `here `__) - - -Deploying a Corda Network -------------------------- - -Browse to the `AWS Marketplace `__ and search for Corda. - -Follow the instructions to deploy the AMI to an instance of EC2 which is in a region near to your location. - -Build and Run a Sample CorDapp ------------------------------- -Once the instance is running ssh into the instance using your keypair - -.. sourcecode:: shell - - cd ~/dev - -There are 4 sample apps available by default - -.. sourcecode:: shell - - ubuntu@ip-xxx-xxx-xxx-xxx:~/dev$ ls -la - total 24 - drwxrwxr-x 6 ubuntu ubuntu 4096 Nov 13 21:48 . - drwxr-xr-x 8 ubuntu ubuntu 4096 Nov 21 16:34 .. - drwxrwxr-x 11 ubuntu ubuntu 4096 Oct 31 19:02 cordapp-example - drwxrwxr-x 9 ubuntu ubuntu 4096 Nov 13 21:48 obligation-cordapp - drwxrwxr-x 11 ubuntu ubuntu 4096 Nov 13 21:48 oracle-example - drwxrwxr-x 8 ubuntu ubuntu 4096 Nov 13 21:48 yo-cordapp - -cd into the Corda sample you would like to run. For example: - -.. sourcecode:: shell - - cd cordapp-example/ - -Follow instructions for the specific sample at https://www.corda.net/samples to build and run the Corda sample -For example: with cordapp-example (IOU app) the following commands would be run: - -.. sourcecode:: shell - - ./gradlew deployNodes - ./kotlin-source/build/nodes/runnodes - -Then start the Corda test webserver - -.. sourcecode:: shell - - find ~/dev/cordapp-example/kotlin-source/ -name corda-testserver.jar -execdir sh -c 'java -jar {} &' \; - -You can now interact with your running CorDapp. See the instructions `here `__. - -Next Steps ----------- -Now you have built a Corda network and used a basic Corda Cordapp do go and visit the `dedicated Corda website `_ - -Additional support is available on `Stack Overflow `_ and the `Corda Slack channel `_. - -You can build and run any other `Corda samples `_ or your own custom CorDapp here. - -Or to join the growing Corda community and get straight into the Corda open source codebase, head over to the `Github Corda repo `_ diff --git a/docs/source/azure-vm-explore.rst b/docs/source/azure-vm-explore.rst deleted file mode 100644 index 13c61caaf7..0000000000 --- a/docs/source/azure-vm-explore.rst +++ /dev/null @@ -1,139 +0,0 @@ -Deploying Corda to Corda Testnet from an Azure Cloud Platform VM -================================================================ - -.. contents:: - -This document will describe how to set up a virtual machine on the Azure Cloud Platform to deploy your pre-configured -Corda node and automatically connnect to Testnet. A self-service download link can be obtained from -https://marketplace.r3.com/network/testnet. - -Pre-requisites --------------- -* Ensure you have a registered Microsoft Azure account which can create virtual machines. - -Deploy Corda node ------------------ - -Browse to https://portal.azure.com and log in with your Microsoft account. - -STEP 1: Create a Resource Group -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Click on the "Resource groups" link in the side nav in the Azure Portal and then click "Add": - -.. image:: resources/azure-rg.png - -Fill in the form and click "Create": - -.. image:: resources/azure-rg-2.png - -STEP 2: Launch the VM -~~~~~~~~~~~~~~~~~~~~~ - -At the top of the left sidenav click on the button with the green cross "Create a resource". - -In this example we are going to use an Ubuntu server so select the latest Ubuntu Server option: - -.. image:: resources/azure-select-ubuntu.png - -Fill in the form: - -* Add a username (to log into the VM) and choose and enter a password -* Choose the resource group we created earlier from the "Use existing" dropdown -* Select a cloud region geographically near to your location to host your VM - -Click on "OK": - -.. image:: resources/azure-vm-form.png - -Choose a size ("D4S_V3 Standard" is recommended if available) and click "Select": - -.. image:: resources/azure-instance-type.png - -Click on "Public IP address" to open the "Settings" panel - -.. image:: resources/azure-vm-settings.png - -Set the IP address to "Static" under "Assignment" and click "OK": - -.. note:: This is so the IP address for your node does not change frequently in the global network map. - -.. image:: resources/azure-set-static-ip.png - -Next toggle "Network Security Group" to advanced and click on "Network security group (firewall)": - -.. image:: resources/azure-nsg.png - -Add the following inbound rules for ports 8080 (webserver), and 10002-10003 for the P2P and RPC ports used by the Corda -node respectively: - -.. code:: bash - - Destination port ranges: 10002, Priority: 1041 Name: Port_10002 - Destination port ranges: 10003, Priority: 1042 Name: Port_10003 - Destination port ranges: 8080, Priority: 1043 Name: Port_8080 - Destination port ranges: 22, Priority: 1044 Name: Port_22 - -.. note:: The priority has to be unique number in the range 900 (highest) and 4096 (lowest) priority. Make sure each - rule has a unique priority or there will be a validation failure and error message. - -.. image:: resources/azure-nsg-2.png - -Click "OK" and "OK" again on the "Settings" panel: - -.. image:: resources/azure-settings-ok.png - -Click "Create" and wait a few minutes for your instance to be provisioned and start running: - -.. image:: resources/azure-create-vm.png - -STEP 3: Connect to your VM and set up the environment -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Once your instance is running click on the "Connect" button and copy the ssh command: - -.. image:: resources/azure-ssh.png - -Enter the ssh command into your terminal. At the prompt, type "yes" to continue connecting and then enter the password -you configured earlier to log into the remote VM: - -.. image:: resources/azure-shell.png - -STEP 4: Download and set up your Corda node -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Now that your Azure environment is configured you can switch to the -`Testnet dashboard `_ and click "Copy" to get a one-time installation -script. - -.. note:: If you have not already set up your account on Testnet, please visit https://marketplace.r3.com/network/testnet and sign - up. - -.. note:: You can generate as many Testnet identites as you like by clicking "Generate new node" to generate a new one-time - link. - -.. image:: resources/testnet-platform.png - -In the terminal of your cloud instance, paste the command you just copied to install and run your Corda node: - -.. code:: bash - - sudo ONE_TIME_DOWNLOAD_KEY=YOUR_UNIQUE_DOWNLOAD_KEY_HERE bash -c "$(curl -L https://onboarder.prod.ws.r3.com/api/user/node/TESTNET/install.sh)" - -.. warning:: This command will execute the install script as ROOT on your cloud instance. You may wish to examine the - script prior to executing it on your machine. - -You can follow the progress of the installation by typing the following command in your terminal: - -.. code:: bash - - tail -f /opt/corda/logs/node-.log - - -Testing your deployment ------------------------ - -To test that your deployment is working correctly, follow the instructions in :doc:`testnet-explorer-corda` to set up -the Finance CorDapp and issue cash to a counterparty. - -This will also demonstrate how to install a custom CorDapp. \ No newline at end of file diff --git a/docs/source/azure-vm.rst b/docs/source/azure-vm.rst deleted file mode 100644 index 0624492f76..0000000000 --- a/docs/source/azure-vm.rst +++ /dev/null @@ -1,193 +0,0 @@ -Azure Marketplace -================= - -To help you design, build and test applications on Corda, called CorDapps, a Corda network can be deployed on the `Microsoft Azure Marketplace `_ - -This Corda network offering builds a pre-configured network of Corda nodes as Ubuntu virtual machines (VM). The network comprises of a Notary node and up to nine Corda nodes using a version of Corda of your choosing. The following guide will also show you how to load a simple Yo! CorDapp which demonstrates the basic principles of Corda. When you are ready to go further with developing on Corda and start making contributions to the project head over to the `Corda.net `_. - -Pre-requisites --------------- -* Ensure you have a registered Microsoft Azure account which can create virtual machines under your subscription(s) and you are logged on to the Azure portal (portal.azure.com) -* It is recommended you generate a private-public SSH key pair (see `here `__) - - -Deploying the Corda Network ---------------------------- - -Browse to portal.azure.com, login and search the Azure Marketplace for Corda and select 'Corda Single Ledger Network'. - -Click the 'Create' button. - -STEP 1: Basics - -Define the basic parameters which will be used to pre-configure your Corda nodes. - -* **Resource prefix**: Choose an appropriate descriptive name for your Corda nodes. This name will prefix the node hostnames -* **VM user name**: This is the user login name on the Ubuntu VMs. Leave it as azureuser or define your own -* **Authentication type**: Select 'SSH public key', then paste the contents of your SSH public key file (see pre-requisites, above) into the box. Alternatively select 'Password' to use a password of your choice to administer the VM -* **Restrict access by IP address**: Leave this as 'No' to allow access from any internet host, or provide an IP address or a range of IP addresses to limit access -* **Subscription**: Select which of your Azure subscriptions you want to use -* **Resource group**: Choose to 'Create new' and provide a useful name of your choice -* **Location**: Select the geographical location physically closest to you - -.. image:: resources/azure_multi_node_step1.png - :width: 300px - -Click 'OK' - -STEP 2: Network Size and Performance - -Define the number of Corda nodes in your network and the size of VM. - -* **Number of Network Map nodes**: There can only be one Network Map node in this network. Leave as '1' -* **Number of Notary nodes**: There can only be one Notary node in this network. Leave as '1' -* **Number of participant nodes**: This is the number of Corda nodes in your network. At least 2 nodes in your network is recommended (so you can send transactions between them). You can specific 1 participant node and use the Notary node as a second node. There is an upper limit of 9 -* **Storage performance**: Leave as 'Standard' -* **Virtual machine size**: The size of the VM is automatically adjusted to suit the number of participant nodes selected. It is recommended to use the suggested values - -.. image:: resources/azure_multi_node_step2.png - :width: 300px - -Click 'OK' - -STEP 3: Corda Specific Options - -Define the version of Corda you want on your nodes and the type of notary. - -* **Corda version (as seen in Maven Central)**: Select the version of Corda you want your nodes to use from the drop down list. The version numbers can be seen in `Maven Central `_, for example 0.11.0 -* **Notary type**: Select either 'Non Validating' (notary only checks whether a state has been previously used and marked as historic) or 'Validating' (notary performs transaction verification by seeing input and output states, attachments and other transaction information). More information on notaries can be found `here `_ - -.. image:: resources/azure_multi_node_step3.png - :width: 300px - -Click 'OK' - -STEP 4: Summary - -A summary of your selections is shown. - -.. image:: resources/azure_multi_node_step4.png - :width: 300px - -Click 'OK' for your selection to be validated. If everything is ok you will see the message 'Validation passed' - -Click 'OK' - -STEP 5: Buy - -Review the Azure Terms of Use and Privacy Policy and click 'Purchase' to buy the Azure VMs which will host your Corda nodes. - -The deployment process will start and typically takes 8-10 minutes to complete. - -Once deployed click 'Resources Groups', select the resource group you defined in Step 1 above and click 'Overview' to see the virtual machine details. The names of your VMs will be pre-fixed with the resource prefix value you defined in Step 1 above. - -The Network Map Service node is suffixed nm0. The Notary node is suffixed not0. Your Corda participant nodes are suffixed node0, node1, node2 etc. Note down the **Public IP address** for your Corda nodes. You will need these to connect to UI screens via your web browser: - -.. image:: resources/azure_ip.png - :width: 300px - -Using the Yo! CorDapp ---------------------- -Loading the Yo! CordDapp on your Corda nodes lets you send simple Yo! messages to other Corda nodes on the network. A Yo! message is a very simple transaction. The Yo! CorDapp demonstrates: - -- how transactions are only sent between Corda nodes which they are intended for and are not shared across the entire network by using the network map -- uses a pre-defined flow to orchestrate the ledger update automatically -- the contract imposes rules on the ledger updates - - -* **Loading the Yo! CorDapp onto your nodes** - -The nodes you will use to send and receive Yo messages require the Yo! CorDapp jar file to be saved to their cordapps directory. - -Connect to one of your Corda nodes (make sure this is not the Notary node) using an SSH client of your choice (e.g. Putty) and log into the virtual machine using the public IP address and your SSH key or username / password combination you defined in Step 1 of the Azure build process. Type the following command: - -Build the yo cordapp sample which you can find here: |os_samples_branch|/yo-cordapp and install it in the cordapp directory. - -Now restart Corda and the Corda test webserver using the following commands or restart your Corda VM from the Azure portal: - -.. sourcecode:: shell - - sudo systemctl restart corda - sudo systemctl restart corda-webserver - -Repeat these steps on other Corda nodes on your network which you want to send or receive Yo messages. - -* **Verify the Yo! CorDapp is running** - -Open a browser tab and browse to the following URL: - -.. sourcecode:: shell - - http://(public IP address):(port)/web/yo - -where (public IP address) is the public IP address of one of your Corda nodes on the Azure Corda network and (port) is the web server port number for your Corda node, 10004 by default - -You will now see the Yo! CordDapp web interface: - -.. image:: resources/Yo_web_ui.png - :width: 300px - -* **Sending a Yo message via the web interface** - -In the browser window type the following URL to send a Yo message to a target node on your Corda network: - -.. sourcecode:: shell - - http://(public IP address):(port)/api/yo/yo?target=(legalname of target node) - -where (public IP address) is the public IP address of one of your Corda nodes on the Azure Corda network and (port) is the web server port number for your Corda node, 10004 by default and (legalname of target node) is the Legal Name for the target node as defined in the node.conf file, for example: - -.. sourcecode:: shell - - http://40.69.40.42:10004/api/yo/yo?target=Corda 0.10.1 Node 1 in tstyo2 - -An easy way to see the Legal Names of Corda nodes on the network is to use the peers screen: - -.. sourcecode:: shell - - http://(public IP address):(port)/api/yo/peers - -.. image:: resources/yo_peers2.png - :width: 300px - -* **Viewing Yo messages** - -To see Yo! messages sent to a particular node open a browser window and browse to the following URL: - -.. sourcecode:: shell - - http://(public IP address):(port)/api/yo/yos - -.. image:: resources/azure_yos.png - :width: 300px - -Viewing logs ------------- -Users may wish to view the raw logs generated by each node, which contain more information about the operations performed by each node. - -You can access these using an SSH client of your choice (e.g. Putty) and logging into the virtual machine using the public IP address. -Once logged in, navigate to the following directory for Corda logs (node-xxxxxx): - -.. sourcecode:: shell - - /opt/corda/logs - -And navigate to the following directory for system logs (syslog): - -.. sourcecode:: shell - - /var/log - -You can open log files with any text editor. - -.. image:: resources/azure_vm_10_49.png - :width: 300px - -.. image:: resources/azure_syslog.png - :width: 300px - -Next Steps ----------- -Now you have built a Corda network and used a basic Corda CorDapp do go and visit the `dedicated Corda website `_ - -Or to join the growing Corda community and get straight into the Corda open source codebase, head over to the `Github Corda repo `_ diff --git a/docs/source/blob-inspector.rst b/docs/source/blob-inspector.rst deleted file mode 100644 index 4701913f87..0000000000 --- a/docs/source/blob-inspector.rst +++ /dev/null @@ -1,129 +0,0 @@ -Blob Inspector -============== - -There are many benefits to having a custom binary serialisation format (see :doc:`serialization` for details) but one -disadvantage is the inability to view the contents in a human-friendly manner. The Corda Blob Inspector tool alleviates -this issue by allowing the contents of a binary blob file (or URL end-point) to be output in either YAML or JSON. It -uses ``JacksonSupport`` to do this (see :doc:`json`). - -The tool can be downloaded from `here `_. - -To run simply pass in the file or URL as the first parameter:: - - java -jar blob-inspector.jar - -Use the ``--help`` flag for a full list of command line options. - -When inspecting your custom data structures, there's no need to include the jars containing the class definitions for them -in the classpath. The blob inspector (or rather the serialization framework) is able to synthesize any classes found in the -blob that aren't on the classpath. - -Supported formats -~~~~~~~~~~~~~~~~~ - -The inspector can read **input data** in three formats: raw binary, hex encoded text and base64 encoded text. For instance -if you have retrieved your binary data and it looks like this:: - - 636f7264610100000080c562000000000001d0000030720000000300a3226e65742e636f7264613a38674f537471464b414a5055... - -then you have hex encoded data. If it looks like this it's base64 encoded:: - - Y29yZGEBAAAAgMViAAAAAAAB0AAAMHIAAAADAKMibmV0LmNvcmRhOjhnT1N0cUZLQUpQVWVvY2Z2M1NlU1E9PdAAACc1AAAAAgCjIm5l... - -And if it looks like something vomited over your screen it's raw binary. You don't normally need to care about these -differences because the tool will try every format until it works. - -Something that's useful to know about Corda's format is that it always starts with the word "corda" in binary. Try -hex decoding 636f726461 using the `online hex decoder tool here `_ -to see for yourself. - -**Output data** can be in either a slightly extended form of YaML or JSON. YaML (Yet another markup language) is a bit -easier to read for humans and is the default. JSON can of course be parsed by any JSON library in any language. - -.. note:: One thing to note is that the binary blob may contain embedded ``SerializedBytes`` objects. Rather than printing these - out as a Base64 string, the blob inspector will first materialise them into Java objects and then output those. You will - see this when dealing with classes such as ``SignedData`` or other structures that attach a signature, such as the - ``nodeInfo-*`` files or the ``network-parameters`` file in the node's directory. - - -Example -~~~~~~~ - -Here's what a node-info file from the node's data directory may look like: - -* YAML: - -.. sourcecode:: none - - net.corda.nodeapi.internal.SignedNodeInfo - --- - raw: - class: "net.corda.core.node.NodeInfo" - deserialized: - addresses: - - "localhost:10005" - legalIdentitiesAndCerts: - - "O=BankOfCorda, L=London, C=GB" - platformVersion: 4 - serial: 1527851068715 - signatures: - - !!binary |- - VFRy4frbgRDbCpK1Vo88PyUoj01vbRnMR3ROR2abTFk7yJ14901aeScX/CiEP+CDGiMRsdw01cXt\nhKSobAY7Dw== - -* JSON: - -.. sourcecode:: none - - net.corda.nodeapi.internal.SignedNodeInfo - { - "raw" : { - "class" : "net.corda.core.node.NodeInfo", - "deserialized" : { - "addresses" : [ "localhost:10005" ], - "legalIdentitiesAndCerts" : [ "O=BankOfCorda, L=London, C=GB" ], - "platformVersion" : 4, - "serial" : 1527851068715 - } - }, - "signatures" : [ "VFRy4frbgRDbCpK1Vo88PyUoj01vbRnMR3ROR2abTFk7yJ14901aeScX/CiEP+CDGiMRsdw01cXthKSobAY7Dw==" ] - } - -Notice the file is actually a serialised ``SignedNodeInfo`` object, which has a ``raw`` property of type ``SerializedBytes``. -This property is materialised into a ``NodeInfo`` and is output under the ``deserialized`` field. - - -Classpath -~~~~~~~~~ - -If you run the blob inspector without any JAR files on the classpath, then it will deserialize objects using the Class Carpenter (see :doc:`serialization` for details). -The reason for this is that the types are not available, so the serialization framework has to synthesise them. - -.. note:: This mechanism works fine in most situations, but there is one known issue when the serialized blob contains an ``enum``. - In this case you will get this exception ``java.lang.NoClassDefFoundError: Could not initialize class _YourEnum_``. - To solve this problem, you must add the JAR file that contains the ``enum`` to the classpath of the blob inspector. - -Command-line options -~~~~~~~~~~~~~~~~~~~~ - -The blob inspector can be started with the following command-line options: - -.. code-block:: shell - - blob-inspector [-hvV] [--full-parties] [--schema] [--format=type] - [--input-format=type] [--logging-level=] SOURCE - [COMMAND] - -* ``--format=type``: Output format. Possible values: [YAML, JSON]. Default: YAML. -* ``--input-format=type``: Input format. If the file can't be decoded with the given value it's auto-detected, so you should - never normally need to specify this. Possible values [BINARY, HEX, BASE64]. Default: BINARY. -* ``--full-parties``: Display the owningKey and certPath properties of Party and PartyAndReference objects respectively. -* ``--schema``: Print the blob's schema first. -* ``--verbose``, ``--log-to-console``, ``-v``: If set, prints logging to the console as well as to a file. -* ``--logging-level=``: Enable logging at this level and higher. Possible values: ERROR, WARN, INFO, DEBUG, TRACE. Default: INFO. -* ``--help``, ``-h``: Show this help message and exit. -* ``--version``, ``-V``: Print version information and exit. - -Sub-commands -^^^^^^^^^^^^ - -``install-shell-extensions``: Install ``blob-inspector`` alias and auto completion for bash and zsh. See :doc:`cli-application-shell-extensions` for more info. \ No newline at end of file diff --git a/docs/source/building-a-cordapp-index.rst b/docs/source/building-a-cordapp-index.rst deleted file mode 100644 index 1ed1ccc988..0000000000 --- a/docs/source/building-a-cordapp-index.rst +++ /dev/null @@ -1,17 +0,0 @@ -CorDapps -======== - -.. toctree:: - :maxdepth: 1 - - cordapp-overview - getting-set-up - tutorial-cordapp - building-a-cordapp-samples - writing-a-cordapp - cordapp-build-systems - building-against-master - debugging-a-cordapp - secure-coding-guidelines - flow-overriding - flow-cookbook diff --git a/docs/source/building-a-cordapp-samples.rst b/docs/source/building-a-cordapp-samples.rst deleted file mode 100644 index 40affe1a26..0000000000 --- a/docs/source/building-a-cordapp-samples.rst +++ /dev/null @@ -1,21 +0,0 @@ -CorDapp samples -=============== - -There are two distinct sets of samples provided with Corda, one introducing new developers to how to write CorDapps, and -more complex worked examples of how solutions to a number of common designs could be implemented in a CorDapp. -The former can be found on `the Corda website `_. In particular, new developers -should start with the :doc:`example CorDapp `. - -The advanced samples are contained within the `samples/` folder of the Corda repository. The most generally useful of -these samples are: - -1. The `trader-demo`, which shows a delivery-vs-payment atomic swap of commercial paper for cash -2. The `attachment-demo`, which demonstrates uploading attachments to nodes -3. The `bank-of-corda-demo`, which shows a node acting as an issuer of assets (the Bank of Corda) while remote client - applications request issuance of some cash on behalf of a node called Big Corporation - -Documentation on running the samples can be found inside the sample directories themselves, in the `README.md` file. - -.. note:: If you would like to see flow activity on the nodes type in the node terminal ``flow watch``. - -Please report any bugs with the samples on `GitHub `_. diff --git a/docs/source/building-against-non-release.rst b/docs/source/building-against-non-release.rst deleted file mode 100644 index fb73283025..0000000000 --- a/docs/source/building-against-non-release.rst +++ /dev/null @@ -1,41 +0,0 @@ -Building CorDapps against a non-release branch -============================================== - -It is advisable to develop CorDapps against the most recent Corda stable release. However, you may need to build a CorDapp -against an unstable non-release branch if your CorDapp uses a very recent feature, or you are using the CorDapp to test a PR -on the main codebase. - -To work against a non-release branch, proceed as follows: - -1. Clone the `Corda repository `_ - -2. Check out the branch or commit of the Corda repository you want to work against - -3. Make a note of the ``gradlePluginsVersion`` in the root ``constants.properties`` file of the Corda repository - -4. Clone the `Corda Gradle Plugins repository `_ - -5. Check out the tag of the Corda Gradle Plugins repository corresponding to the ``gradlePluginsVersion`` - -6. Follow the instructions in the readme of the Corda Gradle Plugins repository to install this version of the Corda Gradle plugins locally - -7. Open a terminal window in the folder where you cloned the Corda repository - -8. Publish Corda to your local Maven repository using the following commands: - - * Unix/Mac OSX: ``./gradlew install`` - * Windows: ``gradlew.bat install`` - - .. warning:: If you do modify your local Corda repository after having published it to Maven local, then you must - re-publish it to Maven local for the local installation to reflect the changes you have made. - - .. warning:: As the Corda repository evolves on a daily basis, two clones of an unstable branch at different points in - time may differ. If you are using an unstable release and need help debugging an error, then please let us know the - **commit** you are working from. This will help us ascertain the issue. - -9. Make a note of the ``corda_release_version`` in the root ``build.gradle`` file of the Corda repository - -10. In your CorDapp's root ``build.gradle`` file: - - * Update ``ext.corda_release_version`` to the ``corda_release_version`` noted down earlier - * Update ``corda_gradle_plugins_version`` to the ``gradlePluginsVersion`` noted down earlier diff --git a/docs/source/building-corda.rst b/docs/source/building-corda.rst deleted file mode 100644 index fd3c8e57f8..0000000000 --- a/docs/source/building-corda.rst +++ /dev/null @@ -1,56 +0,0 @@ -Building Corda -============== - -These instructions are for downloading and building the Corda code locally. If you only wish to develop CorDapps for -use on Corda, you don't need to do this, follow the instructions at :doc:`getting-set-up` and use the precompiled binaries. - -Windows -------- - -Java -~~~~ -1. Visit http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html -2. Scroll down to "Java SE Development Kit 8uXXX" (where "XXX" is the latest minor version number) -3. Toggle "Accept License Agreement" -4. Click the download link for jdk-8uXXX-windows-x64.exe (where "XXX" is the latest minor version number) -5. Download and run the executable to install Java (use the default settings) -6. Add Java to the PATH environment variable by following the instructions at https://docs.oracle.com/javase/7/docs/webnotes/install/windows/jdk-installation-windows.html#path -7. Open a new command prompt and run ``java -version`` to test that Java is installed correctly - -Git -~~~ - -1. Visit https://git-scm.com/download/win -2. Click the "64-bit Git for Windows Setup" download link. -3. Download and run the executable to install Git (use the default installation values) and make a note of the installation directory. -4. Open a new command prompt and type ``git --version`` to test that Git is installed correctly - -Building Corda -~~~~~~~~~~~~~~ - -1. Open a command prompt -2. Run ``git clone https://github.com/corda/corda.git`` -3. Run ``gradlew build`` - - -Debian/Ubuntu Linux -------------------- - -These instructions were tested on Ubuntu Server 18.04 LTS. This distribution includes ``git`` and ``python`` so only the following steps are required: - -Java -~~~~ -1. Run ``sudo add-apt-repository ppa:webupd8team/java`` from the terminal. Press ENTER when prompted. -2. Run ``sudo apt-get update`` -3. Then run ``sudo apt-get install oracle-java8-installer``. Press Y when prompted and agree to the licence terms. -4. Run ``java --version`` to verify that java is installed correctly - - -Building Corda -~~~~~~~~~~~~~~ - -1. Open the terminal -2. Run ``git clone https://github.com/corda/corda.git`` -3. Run ``./gradlew build`` - - diff --git a/docs/source/building-the-docs.rst b/docs/source/building-the-docs.rst deleted file mode 100644 index 85673f6c3a..0000000000 --- a/docs/source/building-the-docs.rst +++ /dev/null @@ -1,146 +0,0 @@ -Building the documentation -========================== - -The documentation is under the ``docs`` folder, and is written in reStructuredText format. Documentation in HTML format -is pre-generated, as well as code documentation, and this can be done automatically via a provided script. - -Building Using the Docker Image -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This is the method used during the build. If you run: - -.. code-block:: shell - - ./gradlew makeDocs - -This will download a docker image from docker hub and run the build locally inside that by mounting quite a bit of the docs directory at -various places inside the image. - -This image is pre-built with the dependencies that were in requirements.txt at the time of the docker build. - -Changing requirements ---------------------- - -If you want to upgrade, say, the version of sphinx that we're using, you must: - -* Upgrade the version number in requirements.txt -* Build a new docker image: ``cd docs && docker build -t corda/docs-builder:latest -f docs_builder/Dockerfile .`` - - * post doing this the build will run using your image locally - * you can also push this to the docker registry if you have the corda keys - * you can run ``docker run -it corda/docs-builder /bin/bash`` to interactively look in the build docker image (e.g. to see what is in the - requirements.txt file) - -Building from the Command Line (non-docker) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Requirements ------------- - -In order to build the documentation you will need a development environment set up as described under :doc:`building-corda`. - -You will also need additional dependencies based on your O/S which are detailed below. - -Windows -------- - -Git, bash and make -~~~~~~~~~~~~~~~~~~ - -In order to build the documentation for Corda you need a ``bash`` emulator with ``make`` installed and accessible from the command prompt. Git for -Windows ships with a version of MinGW that contains a ``bash`` emulator, to which you can download and add a Windows port of -``make``, instructions for which are provided below. Alternatively you can install a full version of MinGW from `here `_. - -1. Go to `ezwinports `_ and click the download for ``make-4.2.1-without-guile-w32-bin.zip`` -2. Navigate to the Git installation directory (by default ``C:\Program Files\Git``), open ``mingw64`` -3. Unzip the downloaded file into this directory, but do NOT overwrite/replace any existing files -4. Add the Git ``bin`` directory to your system PATH environment variable (by default ``C:\Program Files\Git\bin``) -5. Open a new command prompt and run ``bash`` to test that you can access the Git bash emulator -6. Type ``make`` to make sure it has been installed successfully (you should get an error - like ``make: *** No targets specified and no makefile found. Stop.``) - - -Python, Pip and VirtualEnv -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. Visit https://www.python.org/downloads -2. Scroll down to the most recent v2 release (tested with v.2.7.15) and click the download link -3. Download the "Windows x86-64 MSI installer" -4. Run the installation, making a note of the Python installation directory (defaults to ``c:\Python27``) -5. Add the Python installation directory (e.g. ``c:\Python27``) to your system PATH environment variable -6. Add the Python scripts sub-directory (e.g. ``c:\Python27\scripts``) to your system PATH environment variable -7. Open a new command prompt and check you can run Python by running ``python --version`` -8. Check you can run pip by running ``pip --version`` -9. Install ``virtualenv`` by running ``pip install virtualenv`` from the commandline -10. Check you can run ``virualenv`` by running ``virtualenv --version`` from the commandline. - -LaTeX -~~~~~ - -Corda requires LaTeX to be available for building the documentation. The instructions below are for installing TeX Live -but other distributions are available. - -1. Visit https://tug.org/texlive/ -2. Click download -3. Download and run ``install-tl-windows.exe`` -4. Keep the default options (simple installation is fine) -5. Open a new command prompt and check you can run ``pdflatex`` by running ``pdflatex --version`` - - -Debian/Ubuntu Linux -------------------- - -These instructions were tested on Ubuntu Server 18.04 LTS. This distribution includes ``git`` and ``python`` so only the following steps are required: - -Pip/VirtualEnv -~~~~~~~~~~~~~~ - -1. Run ``sudo apt-get install python-pip`` -2. Run ``pip install virtualenv`` -3. Run ``pip --version`` to verify that pip is installed correctly -4. Run ``virtualenv --version`` to verify that virtualenv is installed correctly - -LaTeX -~~~~~ - -Corda requires LaTeX to be available for building the documentation. The instructions below are for installing TeX Live -but other distributions are available. - -1. Run ``sudo apt-get install texlive-full`` - - -Build ------ - -Once the requirements are installed, you can automatically build the HTML format user documentation, PDF, and -the API documentation by running the following script: - -.. sourcecode:: shell - - // On Windows - gradlew buildDocs - - // On Mac and Linux - ./gradlew buildDocs - -Alternatively you can build non-HTML formats from the ``docs`` folder. - -However, running ``make`` from the command line requires further dependencies to be installed. When building in Gradle they -are installed in a `python virtualenv `_, so they will need explicitly installing -by running: - -.. sourcecode:: shell - - pip install -r requirements.txt - -Change directory to the ``docs`` folder and then run the following to see a list of all available formats: - -.. sourcecode:: shell - - make - -For example to produce the documentation in HTML format run: - -.. sourcecode:: shell - - make html diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst deleted file mode 100644 index 9b5e62fa89..0000000000 --- a/docs/source/changelog.rst +++ /dev/null @@ -1,467 +0,0 @@ -Changelog -========= - -Here's a summary of what's changed in each Corda release. For guidance on how to upgrade code from the previous -release, see :doc:`app-upgrade-notes`. - -Unreleased ----------- - -* Added ability for ``CordaService`` to register for receiving node lifecycle events to perform initialisation and clean-up actions. - -* Custom serializer classes implementing ``SerializationCustomSerializer`` should ideally be packaged in the same CorDapp as the - contract classes. Corda 4 could therefore fail to verify transactions created with Corda 3 if their custom serializer classes - had been packaged somewhere else. Add a "fallback mechanism" to Corda's transaction verification logic which will attempt to - include any missing custom serializers from other CorDapps within ``AttachmentStorage``. -* ``AppServiceHub`` been extended to provide access to ``database`` which will enable the Service class to perform DB transactions - from the threads managed by the custom Service. - -* Moved and renamed the testing web server to the ``testing`` subproject. Also renamed the published artifact to ``corda-testserver.jar``. - -* New Vault Query criteria to specify exact matches for specified participants. - -* Support for Java 11 (compatibility mode). Please read https://github.com/corda/corda/pull/5356. - -* Updating FinalityFlow with functionality to indicate the appropriate StatesToRecord. This allows the initiating party to record states - from transactions which they are proposing, but are not necessarily participants of. - -* Removed the RPC exception privacy feature. Previously, in production mode, the exceptions thrown on the node were stripped of all content - when rethrown on the RPC client. - -* Introduced a new parameter ``externalIds: List`` to ``VaultQueryCriteria`` which allows CorDapp developers to constrain queries - to a specified set of external IDs. This feature should be used when querying states for a particular "account" (see accounts CorDapp for - further information). - -* Introduced a new API on ``IdentityService`` called ``RegisterKey`` which maps a ``PublicKey`` to a specified ``CordaX500Name`` and to an - optional ``UUID`` (external Id). - -* Introduced a new API on ``IdentityService`` called ``publicKeyToExternalId` which facilitates lookups of ``PublicKey`` s to - ``externalId`` s (Account IDs). - -* Introduced a new API on ``IdentityService`` called ``publicKeysForExternalId`` which returns all the ``PublicKey`` s associated with a - particular external ID. - -* ``StatePointer`` has been marked as ```@DoNotImplement``, which was an omission in the original release. - -* Introduced a new low level flow diagnostics tool: checkpoint agent (that can be used standalone or in conjunction with the ``checkpoints dump`` shell command). - See :doc:`checkpoint-tooling` for more information. - -* ``NotaryFlow.Client`` now performs transaction verification by default to prevent accidentally sending an invalid transaction to a - non-validating notary. The behaviour can be controlled by passing a constructor parameter flag ``skipVerification``. - Note: this only affects flows that invoke ``NotaryFlow.Client`` directly – no behavioural change if using ``FinalityFlow``. - -* The MockNet now supports setting a custom Notary class name, as was already supported by normal node config. See :doc:`tutorial-custom-notary`. - -* Introduced a new ``Destination`` abstraction for communicating with non-Party destinations using the new ``FlowLogic.initateFlow(Destination)`` - method. ``Party`` and ``AnonymousParty`` have been retrofitted to implement ``Destination``. Initiating a flow to an ``AnonymousParty`` - means resolving to the well-known identity ``Party`` and then communicating with that. - -* Removed ``finance-workflows`` dependency on jackson library. The functions that used jackson (e.g. ``FinanceJSONSupport``) have been moved - into IRS Demo. -* The introductory and technical white papers have been refreshed. They have new content and a clearer organisation. - -* Information about checkpointed flows can be retrieved from the shell. Calling ``checkpoints dump`` will create a zip file inside the node's - ``log`` directory. This zip will contain a JSON representation of each checkpointed flow. This information can then be used to determine the - state of stuck flows or flows that experienced internal errors and were kept in the node for manual intervention. - -* It is now possible to re-record transactions if a node wishes to record as an observer a transaction it has participated in. If this is - done, then the node may record new output states that are not relevant to the node. - - .. warning:: Nodes may re-record transactions if they have previously recorded them as a participant and wish to record them as an observer. - However, the node cannot resolve the forward chain of transactions if this is done. This means that if you wish to re-record a chain of - transactions and get the new output states to be correctly marked as consumed, the full chain must be sent to the node *in order*. - -* Added ``nodeDiagnosticInfo`` to the RPC API. The new RPC is also available as the ``run nodeDiagnosticInfo`` command executable from - the Corda shell. It retrieves version information about the Corda platform and the CorDapps installed on the node. - -* ``CordaRPCClient.start`` has a new ``gracefulReconnect`` parameter. The class ``GracefulReconnect`` takes two lambdas - one for callbacks - on disconnect, and one for callbacks on reconnection. When provided (ie. the ``gracefulReconnect`` parameter is not null) the RPC client - will to try to automatically reconnect to the node on disconnect. Further any ``Observable`` s previously created will continue to vend new - events on reconnect. - - .. note:: This is only best-effort and there are no guarantees of reliability. - -* Contract attachments are now automatically whitelisted by the node if another contract attachment is present with the same contract classes, - signed by the same public keys, and uploaded by a trusted uploader. This allows the node to resolve transactions that use earlier versions - of a contract without having to manually install that version, provided a newer version is installed. Similarly, non-contract attachments - are whitelisted if another attachment is present on the node that is signed by the same public key. - -* Package namespace ownership configurations can be now be set as described in - :ref:`node_package_namespace_ownership`, when using the Cordformation plugin version 4.0.43. - -* Wildcards can now be used when specifying RPC permissions, for example ``StartFlow.foo.bar.*`` will allow users to start any flow in the - ``foo.bar`` package. See :ref:`rpcUsers ` for more information. - -* ``-XX:+HeapDumpOnOutOfMemoryError`` and ``-XX:+CrashOnOutOfMemoryError`` have been added to the default JVM options of the node. - A node which is running out of memory is now expected to stop immediately to preserve ledger consistency and avoid flaws in operations. - Note that it's a responsibility of a client application to handle RPC reconnection in case this happens. - See :ref:`setting_jvm_args` and :ref:`memory_usage_and_tuning` for further details. - -* :doc:`design/data-model-upgrades/package-namespace-ownership` configurations can be now be set as described in - :ref:`node_package_namespace_ownership`, when using the Cordformation plugin version 4.0.43. - -* Environment variables and system properties can now be provided with underscore separators instead of dots. Neither are case sensitive. - See :ref:`overriding config values ` for more information. - -* SSH server in the :doc:`shell` has been updated to remove outdated weak ciphers and algorithms. - -* Removed support for external SSH connections to the standalone shell. As a result, ``--sshd-port`` and ``--sshd-hostkey-directory`` - options, as well as ``extensions.sshd`` configuration entry, have been removed from the standalone shell. - Available alternatives are either to use the standalone shell directly, or connect to the node embedded shell via SSH. - -* Added new node configuration option to exclude packages from Quasar instrumentation. - -* Fixed the operator used by the ``notEqual`` predicate - -.. _changelog_v4.1: - -Version 4.1 ------------ - -* Fix a bug in Corda 4.0 that combined commands in ``TransactionBuilder`` if they only differed by the signers list. The behaviour is now consistent with prior Corda releases. - -* Disabled the default loading of ``hibernate-validator`` as a plugin by hibernate when a CorDapp depends on it. This change will in turn fix the - (https://github.com/corda/corda/issues/4444) issue, because nodes will no longer need to add ``hibernate-validator`` to the ``\libs`` folder. - For nodes that already did that, it can be safely removed when the latest Corda is installed. - One thing to keep in mind is that if any CorDapp relied on hibernate-validator to validate Querayable JPA Entities via annotations, that will no longer happen. - That was a bad practice anyway, because the ``ContractState`` should be validated in the Contract verify method. - -.. _changelog_v4.0: - -Version 4.0 ------------ - -* Fixed race condition between ``NodeVaultService.trackBy`` and ``NodeVaultService.notifyAll``, where there could be states that were not reflected - in the data feed returned from ``trackBy`` (either in the query's result snapshot or the observable). - -* TimedFlows (only used by the notary client flow) will never give up trying to reach the notary, as this would leave the states - in the notarisation request in an undefined state (unknown whether the spend has been notarised, i.e. has happened, or not). Also, - retries have been disabled for single node notaries since in this case they offer no potential benefits, unlike for a notary cluster with - several members who might have different availability. - -* New configuration property ``database.initialiseAppSchema`` with values ``UPDATE``, ``VALIDATE`` and ``NONE``. - The property controls the behavior of the Hibernate DDL generation. ``UPDATE`` performs an update of CorDapp schemas, while - ``VALIDATE`` only verifies their integrity. The property does not affect the node-specific DDL handling and - complements ``database.initialiseSchema`` to disable DDL handling altogether. - -* ``JacksonSupport.createInMemoryMapper`` was incorrectly marked as deprecated and is no longer so. - -* Standardised CorDapp version identifiers in jar manifests (aligned with associated cordapp Gradle plugin changes). - Updated all samples to reflect new conventions. - -* Introduction of unique CorDapp version identifiers in jar manifests for contract and flows/services CorDapps. - Updated all sample CorDapps to reflect new conventions. - See :ref:`CorDapp separation ` for further information. - -* Automatic Constraints propagation for hash-constrained states to signature-constrained states. - This allows Corda 4 signed CorDapps using signature constraints to consume existing hash constrained states generated - by unsigned CorDapps in previous versions of Corda. - -* You can now load different CorDapps for different nodes in the node-driver and mock-network. This previously wasn't possible with the - ``DriverParameters.extraCordappPackagesToScan`` and ``MockNetwork.cordappPackages`` parameters as all the nodes would get the same CorDapps. - See ``TestCordapp``, ``NodeParameters.additionalCordapps`` and ``MockNodeParameters.additionalCordapps``. - -* ``DriverParameters.extraCordappPackagesToScan`` and ``MockNetwork.cordappPackages`` have been deprecated as they do not support the new - CorDapp versioning and MANIFEST metadata support that has been added. They create artificial CorDapp jars which do not preserve these - settings and thus may produce incorrect results when testing. It is recommended ``DriverParameters.cordappsForAllNodes`` and - ``MockNetworkParameters.cordappsForAllNodes`` be used instead. - -* Fixed a problem with IRS demo not being able to simulate future dates as expected (https://github.com/corda/corda/issues/3851). - -* Fixed a problem that was preventing ``Cash.generateSpend`` to be used more than once per transaction (https://github.com/corda/corda/issues/4110). - -* Fixed a bug resulting in poor vault query performance and incorrect results when sorting. - -* Improved exception thrown by ``AttachmentsClassLoader`` when an attachment cannot be used because its uploader is not trusted. - -* Fixed deadlocks generated by starting flow from within CordaServices. - -* Marked the ``Attachment`` interface as ``@DoNotImplement`` because it is not meant to be extended by CorDapp developers. If you have already - done so, please get in contact on the usual communication channels. - -* Added auto-acceptance of network parameters for network updates. This behaviour is available for a subset of the network parameters - and is configurable via the node config. See :doc:`network-map` for more information. - -* Deprecated ``SerializationContext.withAttachmentsClassLoader``. This functionality has always been disabled by flags - and there is no reason for a CorDapp developer to use it. It is just an internal implementation detail of Corda. - -* Deprecated all means to directly create a ``LedgerTransaction`` instance, as client code is only meant to get hold of a ``LedgerTransaction`` - via ``WireTransaction.toLedgerTransaction``. - -* Introduced new optional network bootstrapper command line options (--register-package-owner, --unregister-package-owner) - to register/unregister a java package namespace with an associated owner in the network parameter packageOwnership whitelist. - -* BFT-Smart and Raft notary implementations have been moved to the ``net.corda.notary.experimental`` package to emphasise - their experimental nature. Note that it is not possible to preserve the state for both types of notaries when upgrading from V3 or an earlier Corda version. - -* New "validate-configuration" sub-command to ``corda.jar``, allowing to validate the actual node configuration without starting the node. - -* CorDapps now have the ability to specify a minimum platform version in their MANIFEST.MF to prevent old nodes from loading them. - -* CorDapps have the ability to specify a target platform version in their MANIFEST.MF as a means of indicating to the node - the app was designed and tested on that version. - -* Nodes will no longer automatically reject flow initiation requests for flows they don't know about. Instead the request will remain - un-acknowledged in the message broker. This enables the recovery scenerio whereby any missing CorDapp can be installed and retried on node - restart. As a consequence the initiating flow will be blocked until the receiving node has resolved the issue. - -* ``FinalityFlow`` is now an inlined flow and requires ``FlowSession`` s to each party intended to receive the transaction. This is to fix the - security problem with the old API that required every node to accept any transaction it received without any checks. Existing CorDapp - binaries relying on this old behaviour will continue to function as previously. However, it is strongly recommended CorDapps switch to - this new API. See :doc:`app-upgrade-notes` for further details. - -* For similar reasons, ``SwapIdentitiesFlow``, from confidential-identities, is also now an inlined flow. The old API has been preserved but - it is strongly recommended CorDapps switch to this new API. See :doc:`app-upgrade-notes` for further details. - -* Introduced new optional network bootstrapper command line option (--minimum-platform-version) to set as a network parameter - -* Vault storage of contract state constraints metadata and associated vault query functions to retrieve and sort by constraint type. - -* New overload for ``CordaRPCClient.start()`` method allowing to specify target legal identity to use for RPC call. - -* Case insensitive vault queries can be specified via a boolean on applicable SQL criteria builder operators. By default - queries will be case sensitive. - -* Getter added to ``CordaRPCOps`` for the node's network parameters. - -* The RPC client library now checks at startup whether the server is of the client libraries major version or higher. - Therefore to connect to a Corda 4 node you must use version 4 or lower of the library. This behaviour can be overridden - by specifying a lower number in the ``CordaRPCClientConfiguration`` class. - -* Removed experimental feature ``CordformDefinition`` - -* Added new overload of ``StartedMockNode.registerInitiatedFlow`` which allows registering custom initiating-responder flow pairs, which - can be useful for testing error cases. - -* "app", "rpc", "p2p" and "unknown" are no longer allowed as uploader values when importing attachments. These are used - internally in security sensitive code. - -* Change type of the ``checkpoint_value`` column. Please check the upgrade-notes on how to update your database. - -* Removed buggy :serverNameTablePrefix: configuration. - -* ``freeLocalHostAndPort``, ``freePort``, and ``getFreeLocalPorts`` from ``TestUtils`` have been deprecated as they - don't provide any guarantee the returned port will be available which can result in flaky tests. Use ``PortAllocation.Incremental`` - instead. - -* Docs for IdentityService. assertOwnership updated to correctly state that an UnknownAnonymousPartyException is thrown - rather than IllegalStateException. - -* The Corda JPA entities no longer implement java.io.Serializable, as this was causing persistence errors in obscure cases. - Java serialization is disabled globally in the node, but in the unlikely event you were relying on these types being Java - serializable please contact us. - -* Remove all references to the out-of-process transaction verification. - -* The class carpenter has a "lenient" mode where it will, during deserialisation, happily synthesis classes that implement - interfaces that will have unimplemented methods. This is useful, for example, for object viewers. This can be turned on - with ``SerializationContext.withLenientCarpenter``. - -* Added a ``FlowMonitor`` to log information about flows that have been waiting for IO more than a configurable threshold. - -* H2 database changes: - * The node's H2 database now listens on ``localhost`` by default. - * The database server address must also be enabled in the node configuration. - * A new ``h2Settings`` configuration block supersedes the ``h2Port`` option. - -* Improved documentation PDF quality. Building the documentation now requires ``LaTex`` to be installed on the OS. - -* Add ``devModeOptions.allowCompatibilityZone`` to re-enable the use of a compatibility zone and ``devMode`` - -* Fixed an issue where ``trackBy`` was returning ``ContractStates`` from a transaction that were not being tracked. The - unrelated ``ContractStates`` will now be filtered out from the returned ``Vault.Update``. - -* Introducing the flow hospital - a component of the node that manages flows that have errored and whether they should - be retried from their previous checkpoints or have their errors propagate. Currently it will respond to any error that - occurs during the resolution of a received transaction as part of ``FinalityFlow``. In such a scenario the receiving - flow will be parked and retried on node restart. This is to allow the node operator to rectify the situation as otherwise - the node will have an incomplete view of the ledger. - -* Fixed an issue preventing out of process nodes started by the ``Driver`` from logging to file. - -* Fixed an issue with ``CashException`` not being able to deserialize after the introduction of AMQP for RPC. - -* Removed -Xmx VM argument from Explorer's Capsule setup. This helps avoiding out of memory errors. - -* New ``killFlow`` RPC for killing stuck flows. - -* Shell now kills an ongoing flow when CTRL+C is pressed in the terminal. - -* Add check at startup that all persisted Checkpoints are compatible with the current version of the code. - -* ``ServiceHub`` and ``CordaRPCOps`` can now safely be used from multiple threads without incurring in database transaction problems. - -* Doorman and NetworkMap url's can now be configured individually rather than being assumed to be - the same server. Current ``compatibilityZoneURL`` configurations remain valid. See both :doc:`corda-configuration-file` - and :doc:`permissioning` for details. - -* Improved audit trail for ``FinalityFlow`` and related sub-flows. - -* Notary client flow retry logic was improved to handle validating flows better. Instead of re-sending flow messages the - entire flow is now restarted after a timeout. The relevant node configuration section was renamed from ``p2pMessagingRetry``, - to ``flowTimeout`` to reflect the behaviour change. - -* The node's configuration is only printed on startup if ``devMode`` is ``true``, avoiding the risk of printing passwords - in a production setup. - -* ``NodeStartup`` will now only print node's configuration if ``devMode`` is ``true``, avoiding the risk of printing passwords - in a production setup. - -* SLF4J's MDC will now only be printed to the console if not empty. No more log lines ending with "{}". - -* ``WireTransaction.Companion.createComponentGroups`` has been marked as ``@CordaInternal``. It was never intended to be - public and was already internal for Kotlin code. - -* RPC server will now mask internal errors to RPC clients if not in devMode. ``Throwable``s implementing ``ClientRelevantError`` - will continue to be propagated to clients. - -* RPC Framework moved from Kryo to the Corda AMQP implementation [Corda-847]. This completes the removal - of ``Kryo`` from general use within Corda, remaining only for use in flow checkpointing. - -* Set co.paralleluniverse.fibers.verifyInstrumentation=true in devMode. - -* Node will now gracefully fail to start if one of the required ports is already in use. - -* Node will now gracefully fail to start if ``devMode`` is true and ``compatibilityZoneURL`` is specified. - -* Added smart detection logic for the development mode setting and an option to override it from the command line. - -* Changes to the JSON/YAML serialisation format from ``JacksonSupport``, which also applies to the node shell: - - * ``WireTransaction`` now nicely outputs into its components: ``id``, ``notary``, ``inputs``, ``attachments``, ``outputs``, - ``commands``, ``timeWindow`` and ``privacySalt``. This can be deserialized back. - * ``SignedTransaction`` is serialised into ``wire`` (i.e. currently only ``WireTransaction`` tested) and ``signatures``, - and can be deserialized back. - -* The Vault Criteria API has been extended to take a more precise specification of which class contains a field. This - primarily impacts Java users; Kotlin users need take no action. The old methods have been deprecated but still work - - the new methods avoid bugs that can occur when JPA schemas inherit from each other. - -* Due to ongoing work the experimental interfaces for defining custom notary services have been moved to the internal package. - CorDapps implementing custom notary services will need to be updated, see ``samples/notary-demo`` for an example. - Further changes may be required in the future. - -* Configuration file changes: - - * Added program line argument ``on-unknown-config-keys`` to allow specifying behaviour on unknown node configuration property keys. - Values are: [FAIL, IGNORE], default to FAIL if unspecified. - * Introduced a placeholder for custom properties within ``node.conf``; the property key is "custom". - * The deprecated web server now has its own ``web-server.conf`` file, separate from ``node.conf``. - * Property keys with double quotes (e.g. "key") in ``node.conf`` are no longer allowed, for rationale refer to :doc:`corda-configuration-file`. - * The ``issuableCurrencies`` property is no longer valid for ``node.conf``. Instead, it has been moved to the finance workflows CorDapp configuration. - -* Added public support for creating ``CordaRPCClient`` using SSL. For this to work the node needs to provide client applications - a certificate to be added to a truststore. See :doc:`tutorial-clientrpc-api` - -* The node RPC broker opens 2 endpoints that are configured with ``address`` and ``adminAddress``. RPC Clients would connect - to the address, while the node will connect to the adminAddress. Previously if ssl was enabled for RPC the ``adminAddress`` - was equal to ``address``. - -* Upgraded H2 to v1.4.197 - -* Shell (embedded available only in dev mode or via SSH) connects to the node via RPC instead of using the ``CordaRPCOps`` - object directly. To enable RPC connectivity ensure node’s ``rpcSettings.address`` and ``rpcSettings.adminAddress`` settings - are present. - -* Changes to the network bootstrapper: - - * The whitelist.txt file is no longer needed. The existing network parameters file is used to update the current contracts - whitelist. - * The CorDapp jars are also copied to each nodes' ``cordapps`` directory. - -* Errors thrown by a Corda node will now reported to a calling RPC client with attention to serialization and obfuscation - of internal data. - -* Serializing an inner class (non-static nested class in Java, inner class in Kotlin) will be rejected explicitly by the serialization - framework. Prior to this change it didn't work, but the error thrown was opaque (complaining about too few arguments - to a constructor). Whilst this was possible in the older Kryo implementation (Kryo passing null as the synthesised - reference to the outer class) as per the Java documentation `here `_ - we are disallowing this as the paradigm in general makes little sense for contract states. - -* Node can be shut down abruptly by ``shutdown`` function in ``CordaRPCOps`` or gracefully (draining flows first) through - ``gracefulShutdown`` command from shell. - -* API change: ``net.corda.core.schemas.PersistentStateRef`` fields (index and txId) are now non-nullable. - The fields were always effectively non-nullable - values were set from non-nullable fields of other objects. - The class is used as database Primary Key columns of other entities and databases already impose those columns as non-nullable - (even if JPA annotation nullable=false was absent). - In case your Cordapps use this entity class to persist data in own custom tables as non Primary Key columns refer to - :doc:`app-upgrade-notes` for upgrade instructions. - -* Adding a public method to check if a public key satisfies Corda recommended algorithm specs, ``Crypto.validatePublicKey(java.security.PublicKey)``. - For instance, this method will check if an ECC key lies on a valid curve or if an RSA key is >= 2048bits. This might - be required for extra key validation checks, e.g., for Doorman to check that a CSR key meets the minimum security requirements. - -* Table name with a typo changed from ``NODE_ATTCHMENTS_CONTRACTS`` to ``NODE_ATTACHMENTS_CONTRACTS``. - -* Node logs a warning for any ``MappedSchema`` containing a JPA entity referencing another JPA entity from a different ``MappedSchema``. - The log entry starts with "Cross-reference between MappedSchemas". - API: Persistence documentation no longer suggests mapping between different schemas. - -* Upgraded Artemis to v2.6.2. - -* Introduced the concept of "reference input states". A reference input state is a ``ContractState`` which can be referred - to in a transaction by the contracts of input and output states but whose contract is not executed as part of the - transaction verification process and is not consumed when the transaction is committed to the ledger but is checked - for "current-ness". In other words, the contract logic isn't run for the referencing transaction only. It's still a - normal state when it occurs in an input or output position. *This feature is only available on Corda networks running - with a minimum platform version of 4.* - -* A new wrapper class over ``StateRef`` is introduced, called ``ReferenceStateRef``. Although "reference input states" are stored as - ``StateRef`` objects in ``WireTransaction``, we needed a way to distinguish between "input states" and "reference input states" when - required to filter by object type. Thus, when one wants to filter-in all "reference input states" in a ``FilteredTransaction`` - then he/she should check if it is of type ``ReferenceStateRef``. - -* Removed type parameter ``U`` from ``tryLockFungibleStatesForSpending`` to allow the function to be used with ``FungibleState`` - as well as ``FungibleAsset``. This _might_ cause a compile failure in some obscure cases due to the removal of the type - parameter from the method. If your CorDapp does specify types explicitly when using this method then updating the types - will allow your app to compile successfully. However, those using type inference (e.g. using Kotlin) should not experience - any changes. Old CorDapp JARs will still work regardless. - -* ``issuer_ref`` column in ``FungibleStateSchema`` was updated to be nullable to support the introduction of the - ``FungibleState`` interface. The ``vault_fungible_states`` table can hold both ``FungibleAssets`` and ``FungibleStates``. - -* CorDapps built by ``corda-gradle-plugins`` are now signed and sealed JAR files. - Signing can be configured or disabled, and it defaults to using the Corda development certificate. - -* Finance CorDapps are now built as sealed and signed JAR files. - Custom classes can no longer be placed in the packages defined in either finance Cordapp or access it's non-public members. - -* Finance CorDapp was split into two separate apps: ``corda-finance-contracts`` and ``corda-finance-workflows``. There is - no longer a single cordapp which provides both. You need to have both JARs installed in the node simultaneously for the - app to work however. - -* All sample CorDapps were split into separate apps: workflows and contracts to reflect new convention. It is recommended to structure your CorDapps - this way, see :doc:`app-upgrade-notes` on upgrading your CorDapp. - -* The format of the shell commands' output can now be customized via the node shell, using the ``output-format`` command. - -* The ``node_transaction_mapping`` database table has been folded into the ``node_transactions`` database table as an additional column. - -* Logging for P2P and RPC has been separated, to make it easier to enable all P2P or RPC logging without hand-picking loggers for individual classes. - -* Vault Query Criteria have been enhanced to allow filtering by state relevancy. Queries can request all states, just relevant ones, or just non relevant ones. The default is to return all states, to maintain backwards compatibility. - Note that this means apps running on nodes using Observer node functionality should update their queries to request only relevant states if they are only expecting to see states in which they participate. - -* Postgres dependency was updated to version 42.2.5 - -* Test ``CordaService`` s can be installed on mock nodes using ``UnstartedMockNode.installCordaService``. - -* The finance-contracts demo CorDapp has been slimmed down to contain only that which is relevant for contract verification. Everything else - has been moved to the finance-workflows CorDapp: - - * The cash selection logic. ``AbstractCashSelection`` is now in net.corda.finance.contracts.asset so any custom implementations must now be - defined in ``META-INF/services/net.corda.finance.workflows.asset.selection.AbstractCashSelection``. - - * The jackson annotations on ``Expression`` have been removed. You will need to use ``FinanceJSONSupport.registerFinanceJSONMappers`` if - you wish to preserve the JSON format for this class. - - * The various utility methods defined in ``Cash`` for creating cash transactions have been moved to ``net.corda.finance.workflows.asset.CashUtils``. - Similarly with ``CommercialPaperUtils`` and ``ObligationUtils``. - - * Various other utilities such as ``GetBalances`` and the test calendar data. - - The only exception to this is ``Interpolator`` and related classes. These are now in the `IRS demo workflows CorDapp `_. - -* Vault states are migrated when moving from V3 to V4: the relevancy column is correctly filled, and the state party table is populated. - Note: This means Corda can be slow to start up for the first time after upgrading from V3 to V4. diff --git a/docs/source/cheat-sheet.rst b/docs/source/cheat-sheet.rst deleted file mode 100644 index 991a55a70d..0000000000 --- a/docs/source/cheat-sheet.rst +++ /dev/null @@ -1,9 +0,0 @@ -Cheat sheet -=========== - -A "cheat sheet" summarizing the key Corda types. A PDF version is downloadable `here`_. - -.. image:: resources/cheatsheet.jpg - :width: 700px - -.. _`here`: _static/corda-cheat-sheet.pdf \ No newline at end of file diff --git a/docs/source/checkpoint-tooling.rst b/docs/source/checkpoint-tooling.rst deleted file mode 100644 index 63f06bc4a0..0000000000 --- a/docs/source/checkpoint-tooling.rst +++ /dev/null @@ -1,559 +0,0 @@ -Checkpoint Tooling -================== - -This page contains information about checkpoint tooling. These tools can be used to debug the causes of stuck flows. - -Before reading this page, please ensure you understand the mechanics and principles of Corda Flows by reading :doc:`key-concepts-flows` and :doc:`flow-state-machines`. -It is also recommended that you understand the purpose and behaviour of the :doc:`node-flow-hospital` in relation to *checkpoints* and flow recovery. -An advanced explanation of :ref:`*checkpoints* ` within the flow state machine can be found here: :doc:`contributing-flow-internals`. - -.. note:: As a recap, - - A flow *checkpoint* is a serialised snapshot of the flow's stack frames and any objects reachable from the stack. Checkpoints are saved to - the database automatically when a flow suspends or resumes, which typically happens when sending or receiving messages. A flow may be replayed - from the last checkpoint if the node restarts. Automatic checkpointing is an unusual feature of Corda and significantly helps developers write - reliable code that can survive node restarts and crashes. It also assists with scaling up, as flows that are waiting for a response can be flushed - from memory. - -The checkpoint tools available are: - -- :ref:`Checkpoint dumper ` -- :ref:`Checkpoint agent ` - -.. _checkpoint_dumper: - -Checkpoint dumper -~~~~~~~~~~~~~~~~~ - -The checkpoint dumper outputs information about flows running on a node. This is useful for diagnosing the causes of stuck flows. Using the generated output, -corrective actions can be taken to resolve the issues flows are facing. One possible solution, is ending a flow using the ``flow kill`` command. - -.. warning:: Deleting checkpoints manually or via ``flow kill``/``killFlow`` can lead to an inconsistent ledger among transacting parties. Great care - and coordination with a flow's counterparties must be taken to ensure that a initiating flow and flows responding to it are correctly - removed. This experience will be improved in the future. Making it easier to kill flows while notifying their counterparties. - -To retrieve this information, execute ``checkpoints dump`` in the node's shell. The command creates a zip and generates a JSON file for each flow. - -- Each file follows the naming format ``-.json`` (for example, ``CashIssueAndPaymentFlow-90613d6f-be78-41bd-98e1-33a756c28808.json``). -- The zip is placed into the ``logs`` directory of the node and is named ``checkpoints_dump-.zip`` (for example, ``checkpoints_dump-20190812-153847``). - -Below are some of the more important fields included in the output: - -- ``flowId``: The id of the flow -- ``topLevelFlowClass``: The name of the original flow that was invoked (by RPC or a service) -- ``topLevelFlowLogic``: Detailed view of the top level flow -- ``flowCallStackSummary``: A summarised list of the current stack of sub flows along with any progress tracker information -- ``suspendedOn``: The command that the flow is suspended on (e.g. ``SuspendAndReceive``) which includes the ``suspendedTimestamp`` -- ``flowCallStack`` A detailed view of the of the current stack of sub flows - -.. _checkpoint_dumper_sample_output: - -Sample output -------------- - -Below is an example of the JSON output: - -.. sourcecode:: json - - { - "flowId" : "90613d6f-be78-41bd-98e1-33a756c28808", - "topLevelFlowClass" : "net.corda.finance.flows.CashIssueAndPaymentFlow", - "topLevelFlowLogic" : { - "amount" : "10.00 USD", - "issueRef" : "MTIzNA==", - "recipient" : "O=BigCorporation, L=New York, C=US", - "anonymous" : true, - "notary" : "O=Notary, L=London, C=GB" - }, - "flowCallStackSummary" : [ - { - "flowClass" : "net.corda.finance.flows.CashIssueAndPaymentFlow", - "progressStep" : "Paying recipient" - }, - { - "flowClass" : "net.corda.finance.flows.CashPaymentFlow", - "progressStep" : "Generating anonymous identities" - }, - { - "flowClass" : "net.corda.confidential.SwapIdentitiesFlow", - "progressStep" : "Awaiting counterparty's anonymous identity" - } - ], - "suspendedOn" : { - "sendAndReceive" : [ - { - "session" : { - "peer" : "O=BigCorporation, L=New York, C=US", - "ourSessionId" : -5024519991106064492 - }, - "sentPayloadType" : "net.corda.confidential.SwapIdentitiesFlow$IdentityWithSignature", - "sentPayload" : { - "identity" : { - "class" : "net.corda.core.identity.PartyAndCertificate", - "deserialized" : "O=BankOfCorda, L=London, C=GB" - }, - "signature" : "M5DN180OeE4M8jJ3mFohjgeqNYOWXzR6a2PIclJaWyit2uLnmJcZatySoSC12b6e4rQYKIICNFUXRzJnoQTQCg==" - } - } - ], - "suspendedTimestamp" : "2019-08-12T15:38:39Z", - "secondsSpentWaiting" : 7 - }, - "flowCallStack" : [ - { - "flowClass" : "net.corda.finance.flows.CashIssueAndPaymentFlow", - "progressStep" : "Paying recipient", - "flowLogic" : { - "amount" : "10.00 USD", - "issueRef" : "MTIzNA==", - "recipient" : "O=BigCorporation, L=New York, C=US", - "anonymous" : true, - "notary" : "O=Notary, L=London, C=GB" - } - }, - { - "flowClass" : "net.corda.finance.flows.CashPaymentFlow", - "progressStep" : "Generating anonymous identities", - "flowLogic" : { - "amount" : "10.00 USD", - "recipient" : "O=BigCorporation, L=New York, C=US", - "anonymous" : true, - "issuerConstraint" : [ ], - "notary" : "O=Notary, L=London, C=GB" - } - }, - { - "flowClass" : "net.corda.confidential.SwapIdentitiesFlow", - "progressStep" : "Awaiting counterparty's anonymous identity", - "flowLogic" : { - "otherSideSession" : { - "peer" : "O=BigCorporation, L=New York, C=US", - "ourSessionId" : -5024519991106064492 - }, - "otherParty" : null - } - } - ], - "origin" : { - "rpc" : "bankUser" - }, - "ourIdentity" : "O=BankOfCorda, L=London, C=GB", - "activeSessions" : [ ], - "errored" : null - } - -.. _checkpoint_agent: - -Checkpoint Agent -~~~~~~~~~~~~~~~~ - -The Checkpoint Agent is a very low level diagnostics tool that can be used to output the type, size and content of flow *checkpoints* at node runtime. -It is primarily targeted at users developing and testing code that may exhibit flow mis-behaviour (preferably before going into production). - -For a given flow *checkpoint*, the agent outputs: - - 1. Information about the checkpoint such as its ``id`` (also called a ``flow id``) that can be used to correlate with that flows lifecycle details in the main Corda logs. - 2. A nested hierarchical view of its reachable objects (indented and tagged with depth and size) and their associated sizes, including the state - of any flows held within the checkpoint. - -Diagnostics information is written to standard log files (eg. log4j2 configured logger). - -This tool is particularly useful when used in conjunction with the ``checkpoints dump`` CRaSH shell command to troubleshoot and identify potential -problems associated with checkpoints for flows that appear to not be completing. - -The checkpoint agent can be downloaded from `here `_. - -To run simply pass in the following jar to the JVM used to start a Corda node: ``-Dcapsule.jvm.args=-javaagent:/checkpoint-agent.jar[=arg=value,...]`` - -.. note:: As above also ensure to use the jar when using corda gradle plugin configuration tasks: e.g. ``cordformation deployNodes`` task. - See https://docs.corda.net/head/generating-a-node.html#the-cordform-task - -.. warning:: This tool requires additional memory footprint and we recommended a minimal heap size of at least 1Gb. - -The agent can be customised with a number of optional parameters described below. - -Configuration -------------- - -The checkpoint agent can be started with the following optional parameters: - -.. code-block:: shell - - checkpoint-agent.jar=[instrumentType=],[instrumentClassname=],[minimumSize=],[maximumSize=, [graphDepth=], [printOnce=] - -* ``instrumentType``: whether to output checkpoints on read or write. Possible values: [read, write]. Default: read. -* ``instrumentClassname``: specify the base type of objects to log. The default setting is to process all *Flow* object types. Default: net.corda.node.services.statemachine.FlowStateMachineImpl. -* ``minimumSize``: specifies the minimum size (in bytes) of objects to log. Default: 8192 bytes (8K) -* ``maximumSize``: specifies the maximum size (in bytes) of objects to log. Default: 20000000 bytes (20Mb) -* ``graphDepth``: specifies how many levels deep to display the graph output. Default: unlimited -* ``printOnce``: if true, will display a full object reference (and its sub-graph) only once. Otherwise an object will be displayed repeatedly as referenced. Default: true - -These arguments are passed to the JVM along with the agent specification. For example: - -.. code-block:: shell - - -javaagent:/checkpoint-agent.jar=instrumentClassname=net.corda.vega.flows.SimmFlow,instrumentType=read,minimumSize=10240,maximumSize=512000,graphDepth=6,printOnce=false - -.. note:: Arguments may be passed into the agent in any order and should **not** contain spaces between them. - -Checkpoint Dump support ------------------------ - -When used in combination with the ``checkpoints dump`` shell command (see :ref:`Checkpoint Dumper `), -the checkpoint agent will automatically output additional diagnostic information for all checkpoints dumped by the aforementioned tool. - -You should therefore see two different output files upon invoking the checkpoint dumper command: - -* ``\logs\checkpoints_dump-.zip`` contains zipped JSON representation of checkpoints (from ``checkpoints dump`` shell command) -* ``\logs\checkpoints_agent-.log`` contains output from this agent tool (types and sizes of a checkpoint stack) - -.. note:: You will only see a separate `checkpoints_agent-.log` file if you configure a separate log4j logger as described below. - Otherwise all diagnostics logging will be routed to the standard Corda node log file: ``node-.log``. - -If you **only** wish to log checkpoint data for failing flows, start the checkpoint agent with the following arguments: - -.. code-block:: shell - - checkpoint-agent.jar=instrumentType=read,instrumentClassname=NONE - -and use the ``checkpoints dump`` shell command to trigger diagnostics collection. - -.. warning:: The checkpoint agent JAR file must be called "checkpoint-agent.jar" as the checkpoint dump support code uses Java reflection to - determine whether the VM has been instrumented or not at runtime. - -Logging configuration ---------------------- - -The agent will log output to a log4j2 configured logger. - -It is recommended to configure a separate log file to capture this information by configuring an appender as follows: - -.. sourcecode:: xml - - - - - -.. warning:: You must specify "CheckpointAgent" as the logger name. - -In this instance we are specifying a Rolling File appender with archival rotation as follows: - -.. sourcecode:: xml - - - - - - - - - - - - - - - - - - - - - - - -The *log4j2.xml* containing the above configuration must now be be passed to the Corda node JVM along with the agent specification: - -.. code-block:: shell - - -Dlog4j.configurationFile=/log4j2.xml - -Sample output -------------- - -Using the *log4j2* configuration described above, the following output is generated to a file called ``checkpoints_agent-.log`` under -the Corda node ``logs`` directory for a single flow execution (in this case): - -.. sourcecode:: none - - [INFO ] 2019-07-11T18:25:15,723Z [Node thread-1] CheckpointAgent. - [WRITE] Fiber@10000004:[43c7d5c8-aa66-4a98-beed-dc91354d0353][task: co.paralleluniverse.fibers.RunnableFiberTask@4dc8eaf(Fiber@10000004), target: null, scheduler: co.paralleluniverse.fibers.FiberExecutorScheduler@4e468018] - 000:net.corda.node.services.statemachine.FlowStateMachineImpl 21,149 - - [INFO ] 2019-07-11T18:19:51,115Z [FiberDeserializationChecker] CheckpointAgent. - [READ] class net.corda.node.services.statemachine.FlowStateMachineImpl - 000:net.corda.node.services.statemachine.FlowStateMachineImpl 21,151 - 001: net.corda.node.services.statemachine.FlowStateMachineImpl 21,149 - 002: java.lang.String 107 - 003: [C 77 - 002: co.paralleluniverse.fibers.Stack 20,932 - 003: [J 278 - 003: [Ljava.lang.Object; 20,054 - 004: net.corda.finance.flows.CashIssueAndPaymentFlow 7,229 - 005: net.corda.core.utilities.ProgressTracker 5,664 - etc ... - - [INFO ] 2019-07-11T18:35:03,198Z [rpc-server-handler-pool-2] CheckpointAgent. - [READ] class net.corda.node.services.statemachine.ErrorState$Clean - Checkpoint id: 15f16740-4ea2-4e48-bcb3-fd9051d5ba59 - 000:net.corda.node.services.statemachine.FlowStateMachineImpl 21,151 - 001: [C 77 - 001: [J 278 - 001: [Ljava.lang.Object; 20,054 - 002: java.util.ArrayList 1,658 - 003: net.corda.core.utilities.ProgressTracker$STARTING 0 - etc ... - -Note, - -* on WRITE (eg. a checkpoint is being serialized to disk), we have complete information of the checkpoint object including the Fiber it is - running on and its checkpoint id (43c7d5c8-aa66-4a98-beed-dc91354d0353) - -* on READ (eg. a checkpoint is being deserialized from disk), we only have information about the stack class hierarchy. - Additionally, if we are using the CRaSH shell ``checkpoints dump`` command, we also see a flows checkpoint id. - -Flow diagnostic process -~~~~~~~~~~~~~~~~~~~~~~~ - -Lets assume a scenario where we have triggered a flow in a node (eg. node acting as a flow initiator) but the flow does not appear to complete. - -For example, you may see the following using the CRaSH shell ``flow watch`` command: - -.. sourcecode:: none - - Id Flow name Initiator Status - ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 15f16740-4ea2-4e48-bcb3-fd9051d5b Cash Issue And Payment bankUser In progress - 1c6c3e59-26aa-4b93-8435-4e34e265e Cash Issue And Payment bankUser In progress - 90613d6f-be78-41bd-98e1-33a756c28 Cash Issue And Payment bankUser In progress - 43c7d5c8-aa66-4a98-beed-dc91354d0 Cash Issue And Payment bankUser In progress - Waiting for completion or Ctrl-C ... - -Note that "In progress" indicates the flows above have not completed (and will have been checkpointed). - - -1. Check the main corda node log file for *hospitalisation* and/or *flow retry* messages: ``\logs\node-.log`` - -.. sourcecode:: none - - [INFO ] 2019-07-11T17:56:43,227Z [pool-12-thread-1] statemachine.FlowMonitor. - Flow with id 90613d6f-be78-41bd-98e1-33a756c28808 has been waiting for 97904 seconds to receive messages from parties [O=BigCorporation, L=New York, C=US]. - -.. note:: Always search for the flow id, in this case **90613d6f-be78-41bd-98e1-33a756c28808** - -2. From the CRaSH shell run the ``checkpoints dump`` command to trigger diagnostics information. - -.. sourcecode:: none - - Welcome to the Corda interactive shell. - Useful commands include 'help' to see what is available, and 'bye' to shut down the node. - - Thu Jul 11 18:56:48 BST 2019>>> checkpoints dump - -You will now see an addition line in the main corda node log file as follows: - -.. sourcecode:: none - - [INFO ] 2019-07-11T18:02:47,610Z [rpc-server-handler-pool-0] rpc.CheckpointDumper. - Checkpoint agent processing checkpointId: [90613d6f-be78-41bd-98e1-33a756c28808] - -And two additional files will appear in the nodes logs directory: - -* ``\logs\checkpoints_dump-20190711-180247.zip`` -* ``\logs\checkpoints_agent-20190711-185424.log`` - -3. Unzip the ``\logs\checkpoints_dump-.zip`` file, and you should see a file with a matching flow id as above: - **CashIssueAndPaymentFlow-90613d6f-be78-41bd-98e1-33a756c28808.json** - - Its contents will contain the following diagnostics information: - - .. sourcecode:: json - - { - "flowId" : "90613d6f-be78-41bd-98e1-33a756c28808", - "topLevelFlowClass" : "net.corda.finance.flows.CashIssueAndPaymentFlow", - "topLevelFlowLogic" : { - "amount" : "10.00 USD", - "issueRef" : "MTIzNA==", - "recipient" : "O=BigCorporation, L=New York, C=US", - "anonymous" : true, - "notary" : "O=Notary, L=London, C=GB" - }, - "flowCallStackSummary" : [ - { - "flowClass" : "net.corda.finance.flows.CashIssueAndPaymentFlow", - "progressStep" : "Paying recipient" - }, - { - "flowClass" : "net.corda.finance.flows.CashPaymentFlow", - "progressStep" : "Generating anonymous identities" - }, - { - "flowClass" : "net.corda.confidential.SwapIdentitiesFlow", - "progressStep" : "Awaiting counterparty's anonymous identity" - } - ], - "suspendedOn" : { - "sendAndReceive" : [ - { - "session" : { - "peer" : "O=BigCorporation, L=New York, C=US", - "ourSessionId" : -5024519991106064492 - }, - "sentPayloadType" : "net.corda.confidential.SwapIdentitiesFlow$IdentityWithSignature", - "sentPayload" : { - "identity" : { - "class" : "net.corda.core.identity.PartyAndCertificate", - "deserialized" : "O=BankOfCorda, L=London, C=GB" - }, - "signature" : "M5DN180OeE4M8jJ3mFohjgeqNYOWXzR6a2PIclJaWyit2uLnmJcZatySoSC12b6e4rQYKIICNFUXRzJnoQTQCg==" - } - } - ], - "suspendedTimestamp" : "2019-08-12T15:38:39Z", - "secondsSpentWaiting" : 7 - }, - "flowCallStack" : [ - { - "flowClass" : "net.corda.finance.flows.CashIssueAndPaymentFlow", - "progressStep" : "Paying recipient", - "flowLogic" : { - "amount" : "10.00 USD", - "issueRef" : "MTIzNA==", - "recipient" : "O=BigCorporation, L=New York, C=US", - "anonymous" : true, - "notary" : "O=Notary, L=London, C=GB" - } - }, - { - "flowClass" : "net.corda.finance.flows.CashPaymentFlow", - "progressStep" : "Generating anonymous identities", - "flowLogic" : { - "amount" : "10.00 USD", - "recipient" : "O=BigCorporation, L=New York, C=US", - "anonymous" : true, - "issuerConstraint" : [ ], - "notary" : "O=Notary, L=London, C=GB" - } - }, - { - "flowClass" : "net.corda.confidential.SwapIdentitiesFlow", - "progressStep" : "Awaiting counterparty's anonymous identity", - "flowLogic" : { - "otherSideSession" : { - "peer" : "O=BigCorporation, L=New York, C=US", - "ourSessionId" : -5024519991106064492 - }, - "otherParty" : null - } - } - ], - "origin" : { - "rpc" : "bankUser" - }, - "ourIdentity" : "O=BankOfCorda, L=London, C=GB", - "activeSessions" : [ ], - "errored" : null - } - -4. View the contents of the node agent diagnostics file: - -.. sourcecode:: none - - [INFO ] 2019-07-11T18:02:47,615Z [rpc-server-handler-pool-0] CheckpointAgent. - [READ] class net.corda.node.services.statemachine.Checkpoint - Checkpoint id: 90613d6f-be78-41bd-98e1-33a756c28808 - 000:net.corda.node.services.statemachine.Checkpoint 29,200 - 001: net.corda.node.services.statemachine.ErrorState$Clean 0 - 001: net.corda.node.services.statemachine.FlowState$Started 26,061 - 002: net.corda.core.internal.FlowIORequest$SendAndReceive 4,666 - 003: java.util.Collections$SingletonMap 4,536 - 004: net.corda.node.services.statemachine.FlowSessionImpl 500 - 005: net.corda.core.identity.Party 360 - 005: net.corda.node.services.statemachine.SessionId 28 - 004: net.corda.core.serialization.SerializedBytes 3,979 - 002: net.corda.core.serialization.SerializedBytes 21,222 - 001: net.corda.core.context.InvocationContext 905 - 002: net.corda.core.context.Actor 259 - 002: net.corda.core.context.InvocationOrigin$RPC 13 - 002: net.corda.core.context.Trace 398 - 001: net.corda.core.identity.Party 156 - 002: net.i2p.crypto.eddsa.EdDSAPublicKey 45 - 002: net.corda.core.identity.CordaX500Name 92 - 001: java.util.LinkedHashMap 327 - 002: net.corda.node.services.statemachine.SessionState$Initiating 214 - 001: java.util.ArrayList 1,214 - 002: net.corda.node.services.statemachine.SubFlow$Inlined 525 - 003: java.lang.Class 47 - 003: net.corda.node.services.statemachine.SubFlowVersion$CorDappFlow 328 - 004: net.corda.core.crypto.SecureHash$SHA256 118 - 005: [B 33 - 002: net.corda.node.services.statemachine.SubFlow$Initiating 322 - 003: java.lang.Class 39 - 003: net.corda.core.flows.FlowInfo 124 - 003: net.corda.node.services.statemachine.SubFlowVersion$CorDappFlow 11 - 002: net.corda.node.services.statemachine.SubFlow$Initiating 250 - 003: java.lang.Class 41 - 003: net.corda.core.flows.FlowInfo 99 - 004: java.lang.String 91 - 005: [C 85 - 003: net.corda.node.services.statemachine.SubFlowVersion$CoreFlow 28 - -5. Take relevant recovery action, which may include: - -* killing and retrying the flow: - -.. sourcecode:: none - - Welcome to the Corda interactive shell. - Useful commands include 'help' to see what is available, and 'bye' to shut down the node. - - Thu Jul 11 20:24:11 BST 2019>>> flow kill 90613d6f-be78-41bd-98e1-33a756c28808 - [ERROR] 20:24:18+0100 [Node thread-1] corda.flow. - Flow interrupted while waiting for events, aborting immediately {actor_id=bankUser, actor_owning_identity=O=BankOfCorda, L=London, C=GB, actor_store_id=NODE_CONFIG, fiber-id=10000003, flow-id=15f16740-4ea2-4e48-bcb3-fd9051d5ba59, invocation_id=45622dc7-c4cf-4d11-85ad-1c45e0943455, invocation_timestamp=2019-07-11T18:19:40.519Z, origin=bankUser, session_id=02010e15-8e7a-46f7-976b-5e0626451c54, session_timestamp=2019-07-11T18:19:32.285Z, thread-id=176} - Killed flow [90613d6f-be78-41bd-98e1-33a756c28808] - - Thu Jul 11 20:26:45 BST 2019>>> flow start CashIssueAndPaymentFlow amount: $1000, issueRef: 0x01, recipient: "Bank B", anonymous: false, notary: "Notary Service" - -* attempting to perform a graceful shutdown (draining all outstanding flows and preventing others from starting) and re-start of the node: - -.. sourcecode:: none - - Welcome to the Corda interactive shell. - Useful commands include 'help' to see what is available, and 'bye' to shut down the node. - - Thu Jul 11 19:52:56 BST 2019>>> gracefulShutdown - -Upon re-start ensure you disable flow draining mode to allow the node to continue to receive requests: - -.. sourcecode:: none - - Welcome to the Corda interactive shell. - Useful commands include 'help' to see what is available, and 'bye' to shut down the node. - - Thu Jul 11 19:52:56 BST 2019>>> run setFlowsDrainingModeEnabled enabled: false - -See also :ref:`Flow draining mode `. - -* contacting other participants in the network where their nodes are not responding to an initiated flow. - The checkpoint dump gives good diagnostics on the reason a flow may be suspended (including the destination peer participant node that is not responding): - -.. sourcecode:: json - - { - "suspendedOn" : { - "sendAndReceive" : [ - { - "session" : { - "peer" : "O=BigCorporation, L=New York, C=US", - "ourSessionId" : -5024519991106064492 - }, - "sentPayloadType" : "net.corda.confidential.SwapIdentitiesFlow$IdentityWithSignature", - "sentPayload" : { - "identity" : { - "class" : "net.corda.core.identity.PartyAndCertificate", - "deserialized" : "O=BankOfCorda, L=London, C=GB" - }, - "signature" : "M5DN180OeE4M8jJ3mFohjgeqNYOWXzR6a2PIclJaWyit2uLnmJcZatySoSC12b6e4rQYKIICNFUXRzJnoQTQCg==" - } - } - ], - "suspendedTimestamp" : "2019-08-12T15:38:39Z", - "secondsSpentWaiting" : 7 - } - } \ No newline at end of file diff --git a/docs/source/cipher-suites.rst b/docs/source/cipher-suites.rst deleted file mode 100644 index 25e4c99664..0000000000 --- a/docs/source/cipher-suites.rst +++ /dev/null @@ -1,106 +0,0 @@ -Cipher suites supported by Corda -================================ - -.. contents:: - -The set of signature schemes supported forms a part of the consensus rules for a Corda DLT network. -Thus, it is important that implementations do not support pluggability of any crypto algorithms and do take measures -to prevent algorithms supported by any underlying cryptography library from becoming accidentally accessible. -Signing a transaction with an algorithm that is not a part of the base specification would result in a transaction -being considered invalid by peer nodes and thus a loss of consensus occurring. The introduction of new algorithms -over time will require a global upgrade of all nodes. - -Corda has been designed to be cryptographically agile, in the sense that the available set of signature schemes is -carefully selected based on various factors, such as provided security-level and cryptographic strength, compatibility -with various HSM vendors, algorithm standardisation, variety of cryptographic primitives, business demand, option for -post-quantum resistance, side channel security, efficiency and rigorous testing. - -Before we present the pool of supported schemes it is useful to be familiar with :doc:`permissioning` -and :doc:`api-identity`. An important design decision in Corda is its shared hierarchy between the -TLS and Node Identity certificates. - -Certificate hierarchy ---------------------- - -A Corda network has 8 types of keys and a regular node requires 4 of them: - -**Network Keys** - -* The **root network CA** key -* The **doorman CA** key -* The **network map** key -* The **service identity** key(s) (per service, such as a notary cluster; it can be a Composite key) - -**Node Keys** - -* The **node CA** key(s) (one per node) -* The **legal identity** key(s) (one per node) -* The **tls** key(s) (per node) -* The **confidential identity** key(s) (per node) - -We can visualise the certificate structure as follows (for a detailed description of cert-hierarchy, -see :doc:`permissioning`): - -.. image:: resources/certificate_structure.png - :scale: 55% - :align: center - -Supported cipher suites ------------------------ -Due to the shared certificate hierarchy, the following 4 key/certificate types: **root network CA**, **doorman CA**, -**node CA** and **tls** should be compatible with the standard TLS 1.2 protocol. The latter is a requirement from the -TLS certificate-path validator. It is highlighted that the rest of the keys can be any of the 5 supported cipher suites. -For instance, **network map** is ECDSA NIST P-256 (secp256r1) in the Corda Network (CN) as it is well-supported by the -underlying HSM device, but the default for dev-mode is Pure EdDSA (ed25519). - -The following table presents the 5 signature schemes currently supported by Corda. The TLS column shows which of them -are compatible with TLS 1.2, while the default scheme per key type is also shown in the last column. - -+-------------------------+---------------------------------------------------------------+-----+-------------------------+ -| Cipher suite | Description | TLS | Default for | -+=========================+===============================================================+=====+=========================+ -| | Pure EdDSA using the | | EdDSA represents the current state of the art in mainstream | NO | - node identity | -| | ed25519 curve | | cryptography. It implements elliptic curve cryptography | | - confidential identity | -| | and SHA-512 | | with deterministic signatures a fast implementation, | | - network map (dev) | -| | | explained constants, side channel resistance and many other | | | -| | | desirable characteristics. However, it is relatively new | | | -| | | and not widely supported, for example, you can't use it in | | | -| | | TLS yet (a draft RFC exists but is not standardised yet). | | | -+-------------------------+---------------------------------------------------------------+-----+-------------------------+ -| | ECDSA using the | | This is the default choice for most systems that support | YES | - root network CA | -| | NIST P-256 curve | | elliptic curve cryptography today and is recommended by | | - doorman CA | -| | (secp256r1) | | NIST. It is also supported by the majority of the HSM | | - node CA | -| | and SHA-256 | | vendors. | | - tls | -| | | | - network map (CN) | -+-------------------------+---------------------------------------------------------------+-----+-------------------------+ -| | ECDSA using the | | secp256k1 is the curve adopted by Bitcoin and as such there | NO | | -| | Koblitz k1 curve | | is a wealth of infrastructure, code and advanced algorithms | | | -| | (secp256k1) | | designed for use with it. This curve is standardised by | | | -| | and SHA-256 | | NIST as part of the "Suite B" cryptographic algorithms and | | | -| | | as such is more widely supported than ed25519. By | | | -| | | supporting it we gain access to the ecosystem of advanced | | | -| | | cryptographic techniques and devices pioneered by the | | | -| | | Bitcoin community. | | | -+-------------------------+---------------------------------------------------------------+-----+-------------------------+ -| | RSA (3072bit) PKCS#1 | | RSA is well supported by any sort of hardware or software | YES | | -| | and SHA-256 | | as a signature algorithm no matter how old, for example, | | | -| | | legacy HSMs will support this along with obsolete operating | | | -| | | systems. RSA is using bigger keys than ECDSA and thus it is | | | -| | | recommended for inclusion only for its backwards | | | -| | | compatibility properties, and only for usage where legacy | | | -| | | constraints or government regulation forbids the usage of | | | -| | | more modern approaches. | | | -+-------------------------+---------------------------------------------------------------+-----+-------------------------+ -| | SPHINCS-256 | | SPHINCS-256 is a post-quantum secure algorithm that relies | NO | | -| | and SHA-512 | | only on hash functions. It is included as a hedge against | | | -| | (experimental) | | the possibility of a malicious adversary obtaining a | | | -| | | quantum computer capable of running Shor's algorithm in | | | -| | | future. SPHINCS is based ultimately on a clever usage of | | | -| | | Merkle hash trees. Hash functions are a very heavily | | | -| | | studied and well understood area of cryptography. Thus, it | | | -| | | is assumed that there is a much lower chance of | | | -| | | breakthrough attacks on the underlying mathematical | | | -| | | problems. However, SPHINCS uses relatively big public keys, | | | -| | | it is slower and outputs bigger signatures than EdDSA, | | | -| | | ECDSA and RSA algorithms. | | | -+-------------------------+---------------------------------------------------------------+-----+-------------------------+ diff --git a/docs/source/cli-application-shell-extensions.rst b/docs/source/cli-application-shell-extensions.rst deleted file mode 100644 index ea38827818..0000000000 --- a/docs/source/cli-application-shell-extensions.rst +++ /dev/null @@ -1,72 +0,0 @@ -Shell extensions for CLI Applications -===================================== - -.. _installing-shell-extensions: - -Installing shell extensions -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Users of ``bash`` or ``zsh`` can install an alias and auto-completion for Corda applications that contain a command line interface. Run: - -.. code-block:: shell - - java -jar .jar install-shell-extensions - -Then, either restart your shell, or for ``bash`` users run: - -.. code-block:: shell - - . ~/.bashrc - -Or, for ``zsh`` run: - -.. code-block:: shell - - . ~/.zshrc - -You will now be able to run the command line application from anywhere by running the following: - -.. code-block:: shell - - --