diff --git a/.gitignore b/.gitignore index 5bee9ce6..6c808ad0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ *.swp .gradletasknamecache .classpath -/bin/ +**/bin/ /build/ build/* @@ -36,4 +36,10 @@ nbdist/ .nb-gradle/ local-config.yaml -gradle.properties \ No newline at end of file +gradle.properties +.vscode/ + +# The local repos for the chaincode + +fabric-chaincode-example-sacc/repository +fabric-chaincode-example-sbe/repository \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index bb3a9e93..f9c2b09d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,66 @@ +## v1.4.8 +Wed 4 Nov 2020 14:28:37 GMT + +* [7aefaa9](https://github.com/hyperledger/fabric-chaincode-java/commit/7aefaa9) [FABCJ-295](https://jira.hyperledger.org/browse/FABCJ-295) Clean sdkman cache +* [3c1d0fa](https://github.com/hyperledger/fabric-chaincode-java/commit/3c1d0fa) [FABCJ-290](https://jira.hyperledger.org/browse/FABCJ-290) Add release guide +* [a2707b1](https://github.com/hyperledger/fabric-chaincode-java/commit/a2707b1) Bump version to 1.4.8 + +## v1.4.7 +Thu 8 Oct 2020 10:21:26 BST + + [27141a0](https://github.com/hyperledger/fabric-chaincode-java/commit/27141a0) [FABCJ-293](https://jira.hyperledger.org/browse/FABCJ-293) Remove gradle from javaenv, defer to gradle wrapper + +## v1.4.6 +Wed 4 Mar 10:21:28 GMT 2020 + +* [b54d8bb](https://github.com/hyperledger/fabric-chaincode-java/commit/b54d8bb) [FABCJ-280](https://jira.hyperledger.org/browse/FABCJ-280) Copy chaincode into temporary directory before building +* [dac90d2](https://github.com/hyperledger/fabric-chaincode-java/commit/dac90d2) [FAB-6415](https://jira.hyperledger.org/browse/FAB-6415) Replace org.reflections with classgraph +* [f109d19](https://github.com/hyperledger/fabric-chaincode-java/commit/f109d19) [FAB-6415](https://jira.hyperledger.org/browse/FAB-6415) Add javax.xml.bind dependency for Java 11 +* [540b9ca](https://github.com/hyperledger/fabric-chaincode-java/commit/540b9ca) [FAB-6415](https://jira.hyperledger.org/browse/FAB-6415) Add javax.annotation dependency for Java 11 +* [88e2da2](https://github.com/hyperledger/fabric-chaincode-java/commit/88e2da2) [FABCJ-270](https://jira.hyperledger.org/browse/FABCJ-270) Prepare release 1.4.6 + +## v1.4.5 +Thu 16 Jan 16:16:48 GMT 2020 + +* [bc99f73](https://github.com/hyperledger/fabric-chaincode-java/commit/bc99f73) [FABCJ-259](https://jira.hyperledger.org/browse/FABCJ-259) Pagination Fix +* [8fc5763](https://github.com/hyperledger/fabric-chaincode-java/commit/8fc5763) Maven build in batch mode +* [4f03935](https://github.com/hyperledger/fabric-chaincode-java/commit/4f03935) [FAB-17100](https://jira.hyperledger.org/browse/FAB-17100) Default Thread Pool not set correctly +* [5ff847e](https://github.com/hyperledger/fabric-chaincode-java/commit/5ff847e) [FAB-17078](https://jira.hyperledger.org/browse/FAB-17078) Update version number + +## v1.4.4 +Mon 11 Nov 15:57:05 GMT 2019 + +* [5ce56df](https://github.com/hyperledger/fabric-chaincode-java/commit/5ce56df) [FAB-16712](https://jira.hyperledger.org/browse/FAB-16712) Update contributing guide +* [baaaef8](https://github.com/hyperledger/fabric-chaincode-java/commit/baaaef8) [FAB-16315](https://jira.hyperledger.org/browse/FAB-16315) Improved Load Ability +* [c7efeb4](https://github.com/hyperledger/fabric-chaincode-java/commit/c7efeb4) [FAB-16871](https://jira.hyperledger.org/browse/FAB-16871) Deprecate Logger interface +* [a4938e8](https://github.com/hyperledger/fabric-chaincode-java/commit/a4938e8) [FAB-16845](https://jira.hyperledger.org/browse/FAB-16845) Correct Logging +* [f0a1784](https://github.com/hyperledger/fabric-chaincode-java/commit/f0a1784) [FAB-16817](https://jira.hyperledger.org/browse/FAB-16817) manifest classpath +* [f6c007a](https://github.com/hyperledger/fabric-chaincode-java/commit/f6c007a) fabric-chaincode-java update to baseimage 0.4.16 +* [5f6d88d](https://github.com/hyperledger/fabric-chaincode-java/commit/5f6d88d) [FAB-16711](https://jira.hyperledger.org/browse/FAB-16711) azure pipelines +* [388802e](https://github.com/hyperledger/fabric-chaincode-java/commit/388802e) [FAB-16745](https://jira.hyperledger.org/browse/FAB-16745) Remove SDK from integration tests +* [b58f11d](https://github.com/hyperledger/fabric-chaincode-java/commit/b58f11d) [FAB-16680](https://jira.hyperledger.org/browse/FAB-16680) Fix cloudflare error on jitpack.io +* [8cca4bb](https://github.com/hyperledger/fabric-chaincode-java/commit/8cca4bb) [FAB-16315](https://jira.hyperledger.org/browse/FAB-16315) Unrequired lock +* [bd59b34](https://github.com/hyperledger/fabric-chaincode-java/commit/bd59b34) [FAB-16217](https://jira.hyperledger.org/browse/FAB-16217) Do not load JSON Schema schema from network +* [55c29f9](https://github.com/hyperledger/fabric-chaincode-java/commit/55c29f9) [FAB-15895](https://jira.hyperledger.org/browse/FAB-15895) Added client identity to context + +## v1.4.3 +Wed 31 Jul 11:20:26 BST 2019 + +* [3461258](https://github.com/hyperledger/fabric-chaincode-java/commit/3461258) [FAB-16136](https://jira.hyperledger.org/browse/FAB-16136) Do not run tests in chaincode container +* [8ae8b6f](https://github.com/hyperledger/fabric-chaincode-java/commit/8ae8b6f) Prepare for next release 1.4.3-SNAPSHOT +* [601eade](https://github.com/hyperledger/fabric-chaincode-java/commit/601eade) [FAB-16091](https://jira.hyperledger.org/browse/FAB-16091) Handle invalid contract name +* [614b14b](https://github.com/hyperledger/fabric-chaincode-java/commit/614b14b) [FAB-15929](https://jira.hyperledger.org/browse/FAB-15929) Add getPrivateDataHash support + +## v1.4.2 +Thu 18 Jul 11:06:09 BST 2019 + +* [beed2e6](https://github.com/hyperledger/fabric-chaincode-java/commit/beed2e6) [FAB-16003](https://jira.hyperledger.org/browse/FAB-16003) 1.4.2 Java Release +* [7f1e772](https://github.com/hyperledger/fabric-chaincode-java/commit/7f1e772) [FAB-15213](https://jira.hyperledger.org/browse/FAB-15213) In-repo examples, readme update +* [ea32146](https://github.com/hyperledger/fabric-chaincode-java/commit/ea32146) [FAB-15883](https://jira.hyperledger.org/browse/FAB-15883) Removed swagger annotations +* [605bebe](https://github.com/hyperledger/fabric-chaincode-java/commit/605bebe) [FAB-13753](https://jira.hyperledger.org/browse/FAB-13753) Contract Support +* [1c688a3](https://github.com/hyperledger/fabric-chaincode-java/commit/1c688a3) [FAB-15136](https://jira.hyperledger.org/browse/FAB-15136) Update javaenv mutiarch publish script +* [3597863](https://github.com/hyperledger/fabric-chaincode-java/commit/3597863) [FAB-14973](https://jira.hyperledger.org/browse/FAB-14973)Prepare for next relaase 1.4.2 + ## v1.4.1 Fri Apr 5 21:29:04 IDT 2019 diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..6eb5f87e --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Fabric Chaincode Java Maintainers +* @hyperledger/fabric-chaincode-java-maintainers diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 2f1f0e36..279bbf76 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,8 +1,7 @@ Code of Conduct Guidelines ========================== -Please review the Hyperledger [Code of -Conduct](https://wiki.hyperledger.org/community/hyperledger-project-code-of-conduct) +Please review the Hyperledger [Code of Conduct](https://wiki.hyperledger.org/community/hyperledger-project-code-of-conduct) before participating. It is important that we keep things civil. Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md new file mode 100644 index 00000000..c964b775 --- /dev/null +++ b/COMPATIBILITY.md @@ -0,0 +1,53 @@ +# Support and Compatibility for fabric-chaincode-java + +Github is used for code base management, issues should reported in the [FABCJ](https://jira.hyperledger.org/projects/FABCJ/issues/) component in JIRA. + + +## Summary of Compatibility + +This table shows the summary of the compatibility of the Java libraries at versions 1.4 and 2.1, together with the JVM version they require and the Fabric Peer versions they can communicate with. + +| | Fabric Peer v1.4 connectivity | Java 8 VM | Fabric Peer v2.1 Connectivity | Java 11 VM | +| ----------------------- | ----------------------------- | --------- | ----------------------------- | ---------- | +| Java libraries **v1.4** | Yes | Yes | Yes | Yes | +| Java libraries **v2.1** | Yes | No | Yes | Yes | + +Testing is performed with + - Java v8: Openjdk version 1.8.0_222 + - Java v11: Openjdk version 11.04_11 + +By default a Fabric Peer v1.4 will create a Java 8 VM, and a Fabric Peer v2.1 will create a Java 11 VM. Whilst is the default, the docker image used to host the chaincode and contracts can be altered. Set the environment variable `CORE_CHAINCODE_JAVA_RUNTIME` on the peer to the name of the docker image. For example `CORE_CHAINCODE_JAVA_RUNTIME=example/customJavaRuntime:latest` + +The Java Libraries will connect to the peer whilst running; this is referred to as 'Fabric Peer Connectivity' in the table. For example, whilst the Fabric Peer v1.4 will create a Java 8 environment, if a Java 11 environment was configured, the Java Libraries at v2.1.0 still function when connecting to the Fabric Peer v1.4. + +## Compatibility + +The key elements are :  + +- the version of the Fabric Contract Java libraries used +- the version of the JVM used to run the code +- When starting a chaincode container to run a Smart Contract the version of the runtime that is used is determined by these factors: + +Fabric v1.4.2, and Fabric v2.1.0 will, by default, start up docker image to host the chaincode and contracts. The version of the docker image used is defined by the version of Fabric in use. + +With Fabric v2.1.0, the chaincode container can be configured to be started by other means, and not the Peer. In this case, the environment used is not in the control of Fabric. + +The Java libraries are produced are `group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim'` + +### Supported JVMs + +v1.4.x and v2.1.0 Java Libraries are supported running in Java 11 with the x86_64 architecture. Later Java 11 versions are supported but are not tested. + +v1.4.x Java Libraries are supported running in Java 8 with the  x86_64 architecture. Later Java 8 versions are supported but are not tested. + +Architecture Support: all docker images, JVMs, tools are tested under x86_64 ONLY + +### Default Peer Runtime selection + +When using Fabric 2.1.0, the default docker image that is used to run the Java chaincode is *openjdk11:jdk-11.04_11-alpine* + +With the default docker image used by Fabric 2.1.0. should the packaged Java code contain a Maven or Gradle build script, it will be built using Gradle 5.6.2, or Maven 3.6.2 (if both Gradle and Maven files are present Gradle is used. Gradle build files can be groovy, or kotlin. If the Gradle wrapper is present, this will used in preference to the installed version of Gradle; note that the version of Gradle in the docker image is a copy of the Gradle Wrapper, not the full Gradle install. Therefore if there is limited Internet acccess in your production environment, do not use Gradle). Alternatively it is recommended to package prebuilt jar files, including the contract and all dependencies, in which case no build or Internet access is required when installing Java chaincode. + +### Supported Runtime communication with the Peer +  +Subject to a suitable runtime environment, the 1.4.4 and 2.1.0 Java Libraries can used to communicate with a Fabric 2.1.0 or 1.4.4 Peer - with the level of functionality that is implied by the Fabric version in use.  \ No newline at end of file diff --git a/CONTRACT_TUTORIAL.md b/CONTRACT_TUTORIAL.md new file mode 100644 index 00000000..f3aeb5e3 --- /dev/null +++ b/CONTRACT_TUTORIAL.md @@ -0,0 +1,98 @@ +## Contract tutorials + +This tutorial will teach you how to write Java based Hyperledger Fabric Contract; the code examples have been created using the IBM Blockchain Platform VSCode extension. + +## Writing your own contract + +Either gradle or maven can be used for building your code; here the example is shown with gradle. + +### Create Gradle project +You can use `fabric-contract-example/gradle` as staring point. Make sure that your project build creates a runnable jar that contains all dependencies named `chaincode.jar` as result. + +The main class is very important for Contracts and must be set to `org.hyperledger.fabric.contract.ContractRouter`. All these are set correctly in the examples but for reference the important parts are + +``` +plugins { + id 'com.github.johnrengelman.shadow' version '2.0.3' +} +... + +... +shadowJar { + baseName = 'chaincode' + version = null + classifier = null + + manifest { + attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter' + } +} +``` + +### Writing the contract + +Typically a Contract will be working with one or more 'assets', so in this example we are using a `MyAssestContract` class. Within a given chaincode container, + (the docker container that starts when chaincode is instantiated), you can have one or more contract classes. Each contract class has one or more + 'transaction functions' these can be executed from the SDK or from other contracts. + +With the VSCode extension you can create a starter project, or you can use the same Yeoman generator from the command line. + +``` +# if you don't have Yeoman already +npm install -g yo + +npm install -g generator-fabric +``` + +You can then run the generator to create a sample Java Contract project that uses Gradle 4.6 +This is an example output of running the generator + +``` + yo fabric:contract +? Please specify the contract language: Java +? Please specify the contract name: MyJavaContract +? Please specify the contract version: 0.0.1 +? Please specify the contract description: My first Java contract +? Please specify the contract author: ANOther +? Please specify the contract license: Apache-2.0 +? Please specify the asset type: MyAsset +``` + +### Code overview + +As well as the gradle project files, a `org.example.MyAsset.java` and a `org.example.MyAssetContract.java` are +created. + +All contract classes like `MyAssetContract` must implement the `ContractInterface` and have a `@Contract` annotation +to mark this as a Contract. The annotation allows you to specify meta information, such as version, author +and description. Refer to the JavaDoc for the full specificaiton. + +The `@Default` annotation is useful, as it marks the class as a the default contract - when referring to the +transaction function from the client SDK it permits a shorthand to be used. + +It is recommened to have a no-argument constructor in the contract. + +Each method you wish to be a transaction function must be marked by a `@Transaction()` annotation. +The first parameter to each of these must accept a `org.hyperledger.fabric.contract.Context` object. This +object is the 'transactional context' and provides information about the current transaction being executed +and also provides access to the APIs to check and update the ledger state. + +Transaciton functions can have as many other parameters as they wish. + +Standard Java primitives and strings can be passed; any other Java Object IS NOT supported, eg passing a HashMap. +More complex types can be defined if they are suitably defined. Arrays are supported types are permitted. + +The `MyAsset` class is an example of the more a complex datatype that can be passed. Such a class is +marked used the `@DataType` annotation, with each property within the object marked by a `@Property` annotation. + +Richer constraints on datatype and parameters can be applied; see the JavaDoc for details. + +#### Building contract + +Run build command. + +```bash +gradle clean build shadowJar +``` +Assuming there are no build errors, you can proceed to chaincode testing. + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6432cb62..ecbb46ff 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,44 @@ -## Contributing +# Contributing to fabric-chaincode-java -We welcome contributions to the Hyperledger Fabric Project in many forms, and -there's always plenty to do! +We welcome contributions to the [Hyperledger Fabric](https://hyperledger-fabric.readthedocs.io) Project. There's always plenty to do! -Please visit the -[contributors guide](http://hyperledger-fabric.readthedocs.io/en/latest/CONTRIBUTING.html) in the -docs to learn how to make contributions to this exciting project. +If you have any questions about the project or how to contribute, you can find us in the [fabric-java-chaincode](https://chat.hyperledger.org/channel/fabric-java-chaincode) Hyperledger Rocket.Chat channel. + +Here are a few guidelines to help you contribute successfully... + +## Issues + +We currently track bug reports using the [Hyperledger JIRA](https://jira.hyperledger.org/issues/?jql=project+%3D+FAB+AND+component+%3D+fabric-chaincode-java) tool. + +If you find a bug which we don't already know about, you can help us by creating a new issue describing the problem. Please include as much detail as possible to help us track down the cause. + +> **Note:** Please use Rocket.Chat instead of JIRA to ask questions. + +## Fixes + +If you want to begin contributing code, looking through our open issues is a good way to start. Try looking for recent issues with detailed descriptions first, or ask us on Rocket.Chat if you're unsure which issue to choose. + +## Enhancements + +Make sure you have the support of the Hyperledger Fabric community before investing a lot of effort in project enhancements. For example, discuss your proposal on Rocket.Chat or open a JIRA issue for feedback before starting work. + +> **Note:** A more formal RFC process is under development for Hyperledger Fabric enhancement requests. + +## Pull Requests + +We use our own forks and [Github Flow](https://guides.github.com/introduction/flow/index.html) to deliver changes to the code. Follow these steps to deliver your first pull request: + +1. [Fork the repository](https://guides.github.com/activities/forking/#fork) and create a new branch from `master`. +2. If you've added code that should be tested, add tests! +3. If you've added any new features or made breaking changes, update the documentation. +4. Ensure all the tests pass. +5. Include the JIRA issue number, a descriptive message, and the [Developer Certificate of Origin (DCO) sign-off](https://github.com/probot/dco#how-it-works) on all commit messages. +6. [Issue a pull request](https://guides.github.com/activities/forking/#making-a-pull-request)! +7. [Azure DevOps](https://dev.azure.com/Hyperledger/Fabric-Chaincode-Java) builds must succeed before the pull request can be reviewed and merged. + +## Coding Style + +Please to try to be consistent with the rest of the code and conform to checkstyle rules where they are provided. ## Code of Conduct Guidelines @@ -15,4 +48,12 @@ See our [Code of Conduct Guidelines](../blob/master/CODE_OF_CONDUCT.md). Should you have any questions or concerns, please reach out to one of the project's [Maintainers](../blob/master/MAINTAINERS.md). -Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. +## Hyperledger Fabric + +See the +[Hyperledger Fabric contributors guide](http://hyperledger-fabric.readthedocs.io/en/latest/CONTRIBUTING.html) for more details, including other Hyperledger Fabric projects you may wish to contribute to. + +--- + +[![Creative Commons License](https://i.creativecommons.org/l/by/4.0/88x31.png)](http://creativecommons.org/licenses/by/4.0/) +This work is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/) diff --git a/FAQ.md b/FAQ.md deleted file mode 100644 index 12916dff..00000000 --- a/FAQ.md +++ /dev/null @@ -1,40 +0,0 @@ -# Frequently Asked Questions - Hyperledger Fabric Shim for Java chaincode - -### Q. How to build latest master code? - -#### Install prerequisites - -Make sure you installed all [fabric prerequisites](https://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html) - -Install java shim specific prerequisites: -* Java 8 -* gradle 4.4 - -#### Build shim - -Clone the fabric shim for java chaincode repo. - -``` -git clone https://github.com/hyperledger/fabric-chaincode-java.git -``` - -Build java shim jars (proto and shim jars) and install them to local maven repository. -``` -cd fabric-chaincode-java -gradle clean build install -``` - -Build javaenv docker image, to have it locally. -``` -gradle buildImage -``` - -#### Update your chaincode dependencies - -Make your chanincode depend on java shim master version and not on version from maven central - -``` -dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.2-SNAPSHOT' -} -``` \ No newline at end of file diff --git a/MAINTAINERS.md b/MAINTAINERS.md index a2baee6f..82dc3ce6 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -7,6 +7,7 @@ Maintainers | Gari Singh | mastersingh24 | mastersingh24 | garisingh | gari.r.singh@gmail.com | | Artem Barger | c0rwin | c0rwin | c0rwin | bartem@il.ibm.com | | Gennady Laventman | gennadyl | gennadylaventman | gennadyl | gennady@il.ibm.com | +| Matthew B White | mbwhite | mbwhite | mbwhite | whitemat@uk.ibm.com | Retired Maintainers diff --git a/README.md b/README.md index b3299590..08346fb2 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,75 @@ -# Hyperledger Fabric Shim for Java chaincode +# Hyperledger Fabric Chaincode Java -This is a Java based implementation of Hyprledger Fabric chaincode shim APIs, which enables development of chaincodes using Java language. +[![Build Status](https://dev.azure.com/Hyperledger/Fabric-Chaincode-Java/_apis/build/status/Fabric-Chaincode-Java?branchName=release-1.4)](https://dev.azure.com/Hyperledger/Fabric-Chaincode-Java/_build/latest?definitionId=39&branchName=release-1.4) +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.hyperledger.fabric-chaincode-java/fabric-chaincode-shim/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.hyperledger.fabric-chaincode-java/fabric-chaincode-shim) +[![Rocket.Chat](https://chat.hyperledger.org/images/join-chat.svg)](https://chat.hyperledger.org/channel/fabric-java-chaincode) -Application developers interested in developing smart contracts (what we call chaincode) for Hyperledger Fabric should -read the tutorial in TUTORIAL.md file and visit -`Chaincode for developers `__. - -Contributors or early adopters who need to be able to build and test recent Java chaincode shim, should reference [FAQ.md](FAQ.md) file. +This is a Java based implementation of Hyprledger Fabric chaincode shim APIs, which enables development of smart contracts using the Java language. This project creates `fabric-chaincode-protos` and `fabric-chaincode-shim` jar -files for developers consumption and the `hyperledger/fabric-javaenv` docker image +files for developers' consumption and the `hyperledger/fabric-javaenv` docker image to run Java chaincode. -## Folder structure +## Getting Started + +Application developers interested in developing Java smart contracts for Hyperledger Fabric should read the [JavaDoc](https://hyperledger.github.io/fabric-chaincode-java/) which inludes download information, and links to documentation and samples. + +## Project structure + +### fabric-chaincode-protos + +Contains the protobuf definition files used by Java shim to communicate with Fabric peers. + +### fabric-chaincode-shim + +Contains the java shim classes that define Java chaincode API and way to communicate with Fabric peers. + +### fabric-chaincode-docker + +Contains instructions to build the `hyperledger/fabric-javaenv` docker image. + +### fabric-chaincode-integration-test + +Contains higher level tests for Java chaincode. + +> **Note:** in the future these should be replaced with a separate suite of [Cucumber](https://cucumber.io) tests which run against all chaincode implementations. + +### fabric-chaincode-example-gradle + +Contains an example java chaincode gradle project that includes sample chaincode and basic gradle build instructions. + +## Building and testing + +Make sure you have the following prereqs installed: + +- [Docker](https://www.docker.com/get-docker) +- [Docker Compose](https://docs.docker.com/compose/install/) +- [Java 8](https://www.java.com) + +> **Note:** Java can be installed using [sdkman](https://sdkman.io/). + +Clone the repository if you haven't already. + +``` +git clone https://github.com/hyperledger/fabric-chaincode-java.git +``` + +Build java shim jars (proto and shim jars) and install them to local maven repository. + +``` +cd fabric-chaincode-java +./gradlew clean build install +``` + +> **Note:** `./gradlew clean build classes` can be used instead to reduce the binaries that are built. This should be sufficient for using the local repository. -The "fabric-chaincode-protos" folder contains the protobuf definition files used by -Java shim to communicate with Fabric peer. +Build javaenv docker image, to have it locally. -The "fabric-chaincode-shim" folder contains the java shim classes that define Java -chaincode API and way to communicate with Fabric peer. +``` +./gradlew buildImage +``` -The "fabric-chaincode-docker" folder contains instructions to the build -`hyperledger/fabric-javaenv` docker image. +--- -The "fabric-chaincode-example-gradle" contains an example java chaincode gradle -project that includes sample chaincode and basic gradle build instructions. \ No newline at end of file +[![Creative Commons License](https://i.creativecommons.org/l/by/4.0/88x31.png)](http://creativecommons.org/licenses/by/4.0/) +This work is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/) diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 00000000..c0b8a107 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,59 @@ +# Releasing + +The following artifacts are created as a result of releasing Fabric Chaincode Java: + +- docker images + - [fabric-javaenv](https://hub.docker.com/r/hyperledger/fabric-javaenv) +- Java libraries + - [fabric-chaincode-shim](https://search.maven.org/search?q=a:fabric-chaincode-shim) + - [fabric-chaincode-protos](https://search.maven.org/search?q=a:fabric-chaincode-protos) + +**Note:** A docker image with a matching V.R version is required before releasing a new version of Fabric. + +## Before releasing + +It's useful to create an issue to keep track of each release, for example [Release 1.4.6 Java Chaincode](https://jira.hyperledger.org/browse/FABCJ-281). + +The following tasks are required before releasing: + +- Update version numbers in `build.gradle` files to the required version +- Update test, sample, and docs files to match the new version +- Create a new release notes file +- Update the `CHANGELOG.md` file + + The `changelog.sh` script in `scripts` will prepopulate the changelog but you must check and edit the file manually afterwards as required + +See the [Prepare 1.4.7 release](https://github.com/hyperledger/fabric-chaincode-java/pull/139) pull request for an example, although be careful to search for all versions in the codebase as they're easy to miss and things change! + +## Create release + +Creating a GitHub release on the [releases page](https://github.com/hyperledger/fabric-chaincode-java/releases) will trigger the build to publish the new release. + +When drafting the release, create a new tag for the new version (with a `v` prefix), e.g. `v1.4.6` + +See previous releases for examples of the title and description. + +## Publish Java libraries + +Log on to the [nexus repository manager](https://oss.sonatype.org/#welcome) to manually publish the JARs which were pushed by the release build. + +Find the results of the release build under _Build Promotion > Staging Repositories_ and perform the following steps: + +1. Close + + You should see a series of close activities (see note) + +2. Release using the automatically drop option + + You should see a series of release activities (see note) + +Note: you may need to refresh to update the activities view. + +When the release has completed and the _Staging Repositories_ list is empty, the Java chaincode libraries should appear in the maven repository. They can take some time to appear in the UI but they should exist in the repository sooner. + +## After releasing + +- Update version numbers in `build.gradle` files to the next version +- Update test, sample, and docs files to match the new version + +See the [[FABCJ-281] Set to the next version 1.4.7](https://github.com/hyperledger/fabric-chaincode-java/pull/90) pull request for an example. It should include almost all the files changed to prepare for the release, except for the release notes and changelog which do not need updating. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..91509aa0 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,12 @@ +# Hyperledger Security Policy + +## Reporting a Security Bug + +If you think you have discovered a security issue in any of the Hyperledger projects, we'd love to hear from you. We will take all security bugs seriously and if confirmed upon investigation we will patch it within a reasonable amount of time and release a public security bulletin discussing the impact and credit the discoverer. + +There are two ways to report a security bug. The easiest is to email a description of the flaw and any related information (e.g. reproduction steps, version) to [security at hyperledger dot org](mailto:security@hyperledger.org). + +The other way is to file a confidential security bug in our [JIRA bug tracking system](https://jira.hyperledger.org). Be sure to set the “Security Level” to “Security issue”. + +The process by which the Hyperledger Security Team handles security bugs is documented further in our [Defect Response page](https://wiki.hyperledger.org/display/HYP/Defect+Response) on our [wiki](https://wiki.hyperledger.org). + diff --git a/TUTORIAL.md b/TUTORIAL.md deleted file mode 100644 index 16c3f226..00000000 --- a/TUTORIAL.md +++ /dev/null @@ -1,370 +0,0 @@ -## Chaincode tutorials -This tutorial will teach you how to write Java based Hyperledger Fabric chaincode. -For general explanation about chaincode, how to write and operate it, please visit [Chaincode Tutorials](https://hyperledger-fabric.readthedocs.io/en/latest/chaincode.html) - -## Writing your own chaincode -Writing your own chaincode requires understanding Fabric platform, Java and Gradle. - -### Create Gradle project -You can use `fabric-chaincode-example-gradle` as staring point. Make sure that -your project build creates a runnable jar that contains all dependencies named `chaincode.jar` as result. - -``` -plugins { - id 'com.github.johnrengelman.shadow' version '2.0.3' -} -... - -... -shadowJar { - baseName = 'chaincode' - version = null - classifier = null - - manifest { - attributes 'Main-Class': 'your.chaincode.class.name' - } -} -``` - -### Writing chaincode -We will use the Java version of [Simple Asset Chaincode](https://hyperledger-fabric.readthedocs.io/en/latest/chaincode4ade.html#simple-asset-chaincode) as an example. -This chaincode is a Go to Java translation of Simple Asset Chaincode, which we will explain. - -Using a chaincode class of `org.hyperledger.fabric.example.SimpleAsset`, -create the Java file -`src/main/java/org/hyperledger/fabric/example/SimpleAsset.java` inside your -Gradle project. - -#### Housekeeping -Your chaincode should implement the `Chaincode` interface (or extend -`ChaincodeBase` abstract class) in order to use the `ChaincodeStub` API to -access proposal and ledger data. - -`ChaincodeBase` class is abstract class which inherits form `Chaincode` which -contains the `start` method used to start chaincode. Therefore, we will create -our chaincode by extending `ChaincodeBase` instead of implementing `Chaincode`. - -```java -package org.hyperledger.fabric.example; - -import org.hyperledger.fabric.shim.ChaincodeBase; -import org.hyperledger.fabric.shim.ChaincodeStub; - -import java.util.List; - -/** - * SimpleAsset implements a simple chaincode to manage an asset - */ -public class SimpleAsset extends ChaincodeBase { - @Override - public Response init(ChaincodeStub stub) { - return newSuccessResponse(); - } - - @Override - public Response invoke(ChaincodeStub stub) { - return newSuccessResponse(); - } - -} - -``` - -#### Initializing the Chaincode - -Chaincode initialization is done inside the -` Response init(ChaincodeStub stub)` method. First, retrieve arguments using -`ChaincodeStub.getStringArgs()` method. -```java - /** - * Init is called during chaincode instantiation to initialize any - * data. Note that chaincode upgrade also calls this function to reset - * or to migrate data. - * - * @param stub {@link ChaincodeStub} to operate proposal and ledger - * @return response - */ - @Override - public Response init(ChaincodeStub stub) { - // Get the args from the transaction proposal - List args = stub.getStringArgs(); - if (args.size() != 2) { - newErrorResponse("Incorrect arguments. Expecting a key and a value"); - } - return newSuccessResponse(); - } -``` - -After that, store state to ledger using using -`ChaincodeStub.putStringState(key, value)` method. -```java - /** - * Init is called during chaincode instantiation to initialize any - * data. Note that chaincode upgrade also calls this function to reset - * or to migrate data. - * - * @param stub {@link ChaincodeStub} to operate proposal and ledger - * @return response - */ - @Override - public Response init(ChaincodeStub stub) { - try { - // Get the args from the transaction proposal - List args = stub.getStringArgs(); - if (args.size() != 2) { - newErrorResponse("Incorrect arguments. Expecting a key and a value"); - } - // Set up any variables or assets here by calling stub.putState() - // We store the key and the value on the ledger - stub.putStringState(args.get(0), args.get(1)); - return newSuccessResponse(); - } catch (Throwable e) { - return newErrorResponse("Failed to create asset"); - } - } -``` - -#### Invoking the Chaincode - -Chaincode invokation is done inside the `Response invoke(ChaincodeStub stub)` -method. -```java - /** - * Invoke is called per transaction on the chaincode. Each transaction is - * either a 'get' or a 'set' on the asset created by Init function. The Set - * method may create a new asset by specifying a new key-value pair. - * - * @param stub {@link ChaincodeStub} to operate proposal and ledger - * @return response - */ - @Override - public Response invoke(ChaincodeStub stub) { - return newSuccessResponse(); - } -``` - -Extract the function name and arguments using `ChaincodeStub.getFunction()` and -`ChaincodeStub.getParameters()` methods. Validate function name and invoke -corresponding chaincode methods. The value received by the chaincode methods should be returned as -a success response payload. In case of an exception or incorrect function value, -return an error response. - -```java - public Response invoke(ChaincodeStub stub) { - try { - // Extract the function and args from the transaction proposal - String func = stub.getFunction(); - List params = stub.getParameters(); - if (func.equals("set")) { - // Return result as success payload - return newSuccessResponse(set(stub, params)); - } else if (func.equals("get")) { - // Return result as success payload - return newSuccessResponse(get(stub, params)); - } - return newErrorResponse("Invalid invoke function name. Expecting one of: [\"set\", \"get\""); - } catch (Throwable e) { - return newErrorResponse(e.getMessage()); - } - } - -``` - -#### Implementing the Chaincode methods - -Implement methods `set()` and `get()` using -`ChaincodeStub.putStringState(key, value)` and -`ChaincodeStub.getStringState(key)`. - -```java - /** - * get returns the value of the specified asset key - * - * @param stub {@link ChaincodeStub} to operate proposal and ledger - * @param args key - * @return value - */ - private String get(ChaincodeStub stub, List args) { - if (args.size() != 2) { - throw new RuntimeException("Incorrect arguments. Expecting a key"); - } - - String value = stub.getStringState(args.get(0)); - if (value == null || value.isEmpty()) { - throw new RuntimeException("Asset not found: " + args.get(0)); - } - return value; - } - - /** - * set stores the asset (both key and value) on the ledger. If the key exists, - * it will override the value with the new one - * - * @param stub {@link ChaincodeStub} to operate proposal and ledger - * @param args key and value - * @return value - */ - private String set(ChaincodeStub stub, List args) { - if (args.size() != 2) { - throw new RuntimeException("Incorrect arguments. Expecting a key and a value"); - } - stub.putStringState(args.get(0), args.get(1)); - return args.get(1); - } - -``` - -#### Putting it All Together - -Finally, add `main()` method to start chaincode. - -```java -package org.hyperledger.fabric.example; - -import org.hyperledger.fabric.shim.ChaincodeBase; -import org.hyperledger.fabric.shim.ChaincodeStub; - -import java.util.List; - -/** - * SimpleAsset implements a simple chaincode to manage an asset - */ -public class SimpleAsset extends ChaincodeBase { - - /** - * Init is called during chaincode instantiation to initialize any - * data. Note that chaincode upgrade also calls this function to reset - * or to migrate data. - * - * @param stub {@link ChaincodeStub} to operate proposal and ledger - * @return response - */ - @Override - public Response init(ChaincodeStub stub) { - try { - // Get the args from the transaction proposal - List args = stub.getStringArgs(); - if (args.size() != 2) { - newErrorResponse("Incorrect arguments. Expecting a key and a value"); - } - // Set up any variables or assets here by calling stub.putState() - // We store the key and the value on the ledger - stub.putStringState(args.get(0), args.get(1)); - return newSuccessResponse(); - } catch (Throwable e) { - return newErrorResponse("Failed to create asset"); - } - } - - /** - * Invoke is called per transaction on the chaincode. Each transaction is - * either a 'get' or a 'set' on the asset created by Init function. The Set - * method may create a new asset by specifying a new key-value pair. - * - * @param stub {@link ChaincodeStub} to operate proposal and ledger - * @return response - */ - @Override - public Response invoke(ChaincodeStub stub) { - try { - // Extract the function and args from the transaction proposal - String func = stub.getFunction(); - List params = stub.getParameters(); - if (func.equals("set")) { - // Return result as success payload - return newSuccessResponse(set(stub, params)); - } else if (func.equals("get")) { - // Return result as success payload - return newSuccessResponse(get(stub, params)); - } - return newErrorResponse("Invalid invoke function name. Expecting one of: [\"set\", \"get\""); - } catch (Throwable e) { - return newErrorResponse(e.getMessage()); - } - } - - /** - * get returns the value of the specified asset key - * - * @param stub {@link ChaincodeStub} to operate proposal and ledger - * @param args key - * @return value - */ - private String get(ChaincodeStub stub, List args) { - if (args.size() != 2) { - throw new RuntimeException("Incorrect arguments. Expecting a key"); - } - - String value = stub.getStringState(args.get(0)); - if (value == null || value.isEmpty()) { - throw new RuntimeException("Asset not found: " + args.get(0)); - } - return value; - } - - /** - * set stores the asset (both key and value) on the ledger. If the key exists, - * it will override the value with the new one - * - * @param stub {@link ChaincodeStub} to operate proposal and ledger - * @param args key and value - * @return value - */ - private String set(ChaincodeStub stub, List args) { - if (args.size() != 2) { - throw new RuntimeException("Incorrect arguments. Expecting a key and a value"); - } - stub.putStringState(args.get(0), args.get(1)); - return args.get(1); - } - - public static void main(String[] args) { - new SimpleAsset().start(args); - } - -} -``` - -#### Building chaincode - -Run build command. - -```bash -gradle clean build shadowJar -``` -Assuming there are no build errors, you can proceed to chaincode testing. - -#### Testing chaincode - -First, install the chaincode. The peer CLI will package the Java chaincode source -(src folder) and Gradle build scripts and send them to the peer to install. If -you have previously installed a chaincode called by the same name and version, -you can delete it from the peer by removing the file -`/var/hyperledger/production/chaincodes/.`. -``` -CORE_LOGGING_PEER=debug ./build/bin/peer chaincode install -l java -n mycc -v v0 -p -``` - -Upon successful response, instantiate the chaincode on the "test" channel -created above: -``` -CORE_LOGGING_PEER=debug ./build/bin/peer chaincode instantiate -o localhost:7050 -C mychannel -l java -n mycc -v v0 -c '{"Args":["init"]}' -P 'OR ("Org1MSP.member")' -``` - -This will take a while to complete as the peer must perform "docker pull" to download -java specific image in order to build and launch the chaincode. When successfully -completed, you should see in the peer's log a message confirming the committing -of a new block. This new block contains the transaction to instantiate the -chaincode `mycc:v0`. - -To further inspect the result of the chaincode instantiate command, run -`docker images` and you will see a new image listed at the top of the list with -the name starting with `dev-`. You can inspect the content of this image by -running the following command: -``` -docker run -it dev-jdoe-mycc-v0 bash -root@c188ae089ee5:/# ls /root/chaincode-java/chaincode -chaincode.jar -root@c188ae089ee5:/# -``` diff --git a/build.gradle b/build.gradle index 9e462690..91956a12 100644 --- a/build.gradle +++ b/build.gradle @@ -6,12 +6,25 @@ apply plugin: 'idea' apply plugin: 'eclipse-wtp' +apply plugin: 'com.dorongold.task-tree' +version = '1.4.8' +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "gradle.plugin.com.dorongold.plugins:task-tree:1.4" + } +} allprojects { repositories { + mavenCentral() mavenLocal() jcenter() - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } + maven { url "https://www.jitpack.io" } } } @@ -20,7 +33,7 @@ subprojects { apply plugin: 'maven' group = 'org.hyperledger.fabric-chaincode-java' - version = '1.4.2-SNAPSHOT' + version = rootProject.version sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -28,11 +41,29 @@ subprojects { dependencies { compile 'commons-cli:commons-cli:1.4' compile 'commons-logging:commons-logging:1.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1' - testCompile 'junit:junit:4.12' testCompile 'org.hamcrest:hamcrest-library:1.3' testCompile 'org.mockito:mockito-core:2.23.0' testCompile 'com.github.stefanbirkner:system-rules:1.17.0' + + testCompileOnly 'junit:junit:4.12' + testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.3.1' + testCompile 'org.assertj:assertj-core:3.9.1' + } + + + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" + } + + test { + useJUnitPlatform() } + } +task printVersionName() { + println rootProject.version +} diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml new file mode 100644 index 00000000..09af5a79 --- /dev/null +++ b/ci/azure-pipelines.yml @@ -0,0 +1,170 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +# fabric-chaincode-java azure pipeline configuration. +# +# Daily build for final quality +# cf https://crontab.guru/#0_23_*_*_* +schedules: + - cron: "0 23 * * *" + displayName: 'Chaincode 1.4 Java Nightly Driver' + branches: + include: + - release-1.4 + always: true + + + +trigger: + branches: + include: + - 'release-1.4' + tags: + include: + - '*' + +# These are custom defined variables, the pipeline one is currently used for the build scripts +# to know to produce tests results in XML format for Azure to consume, for developers +# this isn't set so command line output is given +# +variables: + - group: Chaincode_Java_Creds + - group: Github-PackageRegistry-Credentials + - group: JARSigningPublish + - name: component + value: fabric-chaincode-java + - name: pipeline + value: ci + - name: PUSH_VERSION + value: stable + +pool: + vmImage: 'ubuntu-latest' + +# +# The stages and jobs, potential for rationalization and optimization +# Keeping it simple and explict whilst we gain experience +stages: + - stage: Build_and_test + jobs: + - job: main + steps: + - script: | + env | sort + java -version + VERSION=$(cat build.gradle | sed -n "s/version =.*'\(.*\)\(-SNAPSHOT\)\?'/\1/p") + VERSION=${VERSION// } + echo Current version in code is :${VERSION}: + echo "##vso[task.setvariable variable=PACKAGE_VERSION;isOutput=true]${VERSION}" + name: builddata + - task: Gradle@2 + inputs: + workingDirectory: '' + gradleWrapperFile: 'gradlew' + gradleOptions: '-Xmx3072m' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.8' + jdkArchitectureOption: 'x64' + options: '-x javadoc' + publishJUnitResults: true + testResultsFiles: '$(System.DefaultWorkingDirectory)/**/TEST-*.xml' + tasks: 'build' + - task: PublishCodeCoverageResults@1 + inputs: + summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/fabric-chaincode-shim/build/reports/jacoco/test/jacocoTestReport.xml' + - task: PublishCodeCoverageResults@1 + inputs: + summaryFileLocation: "$(System.DefaultWorkingDirectory)/**/fabric-chaincode-shim/build/reports/jacoco/test/jacocoTestReport.xml" + # Copy the built artifacts to the staging directory, tgz, and the docker image + - script: | + set -ev + ./gradlew publishToMavenLocal + tar -zcvf localmaven.tgz ${HOME}/.m2/repository/org/hyperledger + docker image save hyperledger/fabric-javaenv | gzip > $(Build.ArtifactStagingDirectory)/fabric-javaenv.tar.gz + displayName: 'Package tgz and docker image' + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: localmaven.tgz + artifactName: java-tgz + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: $(Build.ArtifactStagingDirectory)/fabric-javaenv.tar.gz + artifactName: javaenv-docker-image + + - job: javadoc + steps: + - script: ./gradlew javadoc + displayName: 'Build JavaDoc' + - script: | + git fetch origin + git checkout -b gh-pages origin/gh-pages + mkdir -p $(Build.SourceBranchName)/api + rm -rf $(Build.SourceBranchName)/api/* + cp -r fabric-chaincode-shim/build/docs/javadoc/* $(Build.SourceBranchName)/api + displayName: 'Update gh-pages branch' + - script: | + git config --global user.email "hlfdev.azp@gmail.com" + git config --global user.name "Hyperledger Bot" + git add -A + git commit -m "Publishing GitHub Pages" + git push https://$(GITHUB-PAT)@github.com/hyperledger/fabric-chaincode-java.git gh-pages + displayName: 'Commit gh-pages changes' + condition: and(succeeded(),eq(variables['Build.Reason'], 'IndividualCI')) + + # As the next script is more complex and uses loops, run this descretely in a sh file + # Publishing step for git tags + - stage: Publish_tag + condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags')) + jobs: + - job: publish_release + steps: + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: javaenv-docker-image + path: $(Build.SourcesDirectory)/build + - task: DownloadSecureFile@1 + name: keyring + inputs: + secureFile: secring.gpg + - script: | + wget -qO "$PWD/manifest-tool" https://github.com/estesp/manifest-tool/releases/download/v1.0.0/manifest-tool-linux-amd64 + chmod +x ./manifest-tool + + # temporarily use this approach instead of the gittag + VERSION=$(cat build.gradle | sed -n "s/version =.*'\(.*\)\(-SNAPSHOT\)\?'/\1/p") + VERSION=${VERSION// } + echo Version is :${VERSION}: + + + docker image load --input build/fabric-javaenv.tar.gz + docker images + docker login ${DOCKER_REGISTRY_URL} --username=${DOCKER_REGISTRY_USERNAME} --password=${DOCKER_REGISTRY_PASSWORD} + echo "Logged in to docker registry" + + # tag javaenv image + docker tag hyperledger/fabric-javaenv fabric-javaenv:amd64-${VERSION} + + # push javaenv to repository + docker push hyperledger/fabric-javaenv:amd64-${VERSION} + ./manifest-tool push from-args --platforms linux/amd64 --template "hyperledger/fabric-javaenv:amd64-${VERSION}" --target "hyperledger/fabric-javaenv:${VERSION}" + ./manifest-tool push from-args --platforms linux/amd64 --template "hyperledger/fabric-javaenv:amd64-${VERSION}" --target "hyperledger/fabric-javaenv:1.4" + env: + DOCKER_REGISTRY_USERNAME: $(DockerHub-Username) + DOCKER_REGISTRY_PASSWORD: $(DockerHub-Password) + - script: | + env | sort + + # temporarily use this approach instead of the gittag + VERSION=$(cat build.gradle | sed -n "s/version =.*'\(.*\)\(-SNAPSHOT\)\?'/\1/p") + VERSION=${VERSION// } + echo Version is :${VERSION}: + + ./gradlew -Psigning.keyId=${SIGNING_ID} -Psigning.password=${SIGNING_PASSWORD} -Psigning.secretKeyRingFile=${KEYRING_FILE} -PossrhUsername=${OSSRH_USER} -PossrhPassword=${OSSRH_PASSWORD} uploadArchives + env: + SIGNING_ID: $(JAR-Signing-Id) + SIGNING_PASSWORD: $(JAR-Signing-Password) + KEYRING_FILE: $(keyring.secureFilePath) + OSSRH_USER: $(OSSRH-User) + OSSRH_PASSWORD: $(OSSRH-Password) diff --git a/fabric-chaincode-docker/.gitignore b/fabric-chaincode-docker/.gitignore new file mode 100644 index 00000000..ae3c1726 --- /dev/null +++ b/fabric-chaincode-docker/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index befc80d7..2c65614d 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -1,4 +1,4 @@ -FROM hyperledger/fabric-baseimage:amd64-0.4.15 +FROM hyperledger/fabric-baseimage:amd64-0.4.16 as dependencies RUN apt-get update RUN apt-get install zip -y RUN curl -s "https://get.sdkman.io" | bash @@ -28,14 +28,20 @@ RUN source /root/.sdkman/bin/sdkman-init.sh; gradle clean # Building protobuf jar and installing it to maven local and gradle cache WORKDIR /root/chaincode-java/shim-src/fabric-chaincode-protos -RUN source /root/.sdkman/bin/sdkman-init.sh; gradle clean build install publishToMavenLocal +RUN source /root/.sdkman/bin/sdkman-init.sh; gradle clean build install publishToMavenLocal \ + -x javadoc \ + -x test + # Installing all jar dependencies to maven local WORKDIR /root/chaincode-java/shim-src/fabric-chaincode-protos/build/publications/protosJar/ RUN source /root/.sdkman/bin/sdkman-init.sh; mvn -f pom-default.xml compile # Building shim jar and installing it to maven local and gradle cache WORKDIR /root/chaincode-java/shim-src/fabric-chaincode-shim -RUN source /root/.sdkman/bin/sdkman-init.sh; gradle clean build install publishToMavenLocal +RUN source /root/.sdkman/bin/sdkman-init.sh; gradle clean build install publishToMavenLocal \ + -x javadoc \ + -x test + # Installing all jar dependencies to maven local WORKDIR /root/chaincode-java/shim-src/fabric-chaincode-shim/build/publications/shimJar/ RUN source /root/.sdkman/bin/sdkman-init.sh; mvn -f pom-default.xml compile @@ -48,10 +54,10 @@ RUN source /root/.sdkman/bin/sdkman-init.sh; mvn compile package # Adding shim 1.3.0 jar WORKDIR /tmp -RUN wget https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric-chaincode-java/fabric-chaincode-shim/1.3.0/fabric-chaincode-shim-1.3.0.pom -RUN wget https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric-chaincode-java/fabric-chaincode-shim/1.3.0/fabric-chaincode-shim-1.3.0.jar -RUN wget https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric-chaincode-java/fabric-chaincode-protos/1.3.0/fabric-chaincode-protos-1.3.0.pom -RUN wget https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric-chaincode-java/fabric-chaincode-protos/1.3.0/fabric-chaincode-protos-1.3.0.jar +RUN wget https://hyperledger.jfrog.io/hyperledger/fabric-maven/fabric-chaincode-shim/fabric-chaincode-shim/1.3.0/fabric-chaincode-shim-1.3.0.pom +RUN wget https://hyperledger.jfrog.io/hyperledger/fabric-maven/fabric-chaincode-shim/fabric-chaincode-shim/1.3.0/fabric-chaincode-shim-1.3.0.jar +RUN wget https://hyperledger.jfrog.io/hyperledger/fabric-maven/fabric-chaincode-protos/fabric-chaincode-protos/1.3.0/fabric-chaincode-protos-1.3.0.pom +RUN wget https://hyperledger.jfrog.io/hyperledger/fabric-maven/fabric-chaincode-protos/fabric-chaincode-protos/1.3.0/fabric-chaincode-protos-1.3.0.jar RUN source /root/.sdkman/bin/sdkman-init.sh; mvn install::install-file -Dfile=fabric-chaincode-protos-1.3.0.jar -DpomFile=fabric-chaincode-protos-1.3.0.pom RUN source /root/.sdkman/bin/sdkman-init.sh; mvn install::install-file -Dfile=fabric-chaincode-shim-1.3.0.jar -DpomFile=fabric-chaincode-shim-1.3.0.pom @@ -59,3 +65,26 @@ RUN source /root/.sdkman/bin/sdkman-init.sh; mvn install::install-file -Dfile=fa WORKDIR /root/chaincode-java RUN rm -rf example-src/* RUN rm -rf shim-src + +RUN source /root/.sdkman/bin/sdkman-init.sh; gradle wrapper --gradle-version 4.6 +RUN source /root/.sdkman/bin/sdkman-init.sh; sdk uninstall gradle 4.6 + +# Creating final javaenv image which will include all required +# dependencies to build and compile java chaincode +FROM adoptopenjdk/openjdk8 +RUN apt-get update && apt-get upgrade -y + +COPY --from=dependencies /root/chaincode-java/gradle /root/chaincode-java/ +COPY --from=dependencies /root/chaincode-java/gradlew /root/chaincode-java/gradlew +COPY --from=dependencies /root/.sdkman/candidates/maven/current /usr/bin/maven +COPY --from=dependencies /root/.sdkman/ /root/.sdkman/ +SHELL ["/bin/bash", "-c"] +ENV PATH="/usr/bin/maven/bin:/usr/bin/maven/:${PATH}" + +COPY --from=dependencies /root/chaincode-java /root/chaincode-java +COPY --from=dependencies /root/.m2 /root/.m2 + +RUN mkdir -p /chaincode/input +RUN mkdir -p /chaincode/output + +WORKDIR /root/chaincode-java diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index 82b6f6c6..5fd963c3 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -6,7 +6,9 @@ buildscript { repositories { + mavenLocal() jcenter() + maven { url "https://www.jitpack.io" } mavenCentral() } dependencies { @@ -78,6 +80,6 @@ task copyAllDeps(type: Copy) { task buildImage(type: DockerBuildImage) { dependsOn copyAllDeps inputDir = project.file('Dockerfile').parentFile - tags = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:amd64-1.4.2', 'hyperledger/fabric-javaenv:amd64-latest'] + tags = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:amd64-1.4.8', 'hyperledger/fabric-javaenv:amd64-latest'] } diff --git a/fabric-chaincode-docker/build.sh b/fabric-chaincode-docker/build.sh index 67f8a745..589d4de6 100644 --- a/fabric-chaincode-docker/build.sh +++ b/fabric-chaincode-docker/build.sh @@ -1,9 +1,19 @@ #!/bin/bash +TMP_DIR=$(mktemp -d) + buildGradle() { - cd "$1" > /dev/null + echo "Copying from $1 to ${TMP_DIR}" + cd $1 + tar cf - . | (cd ${TMP_DIR}; tar xf -) + cd ${TMP_DIR} echo "Gradle build" - gradle build shadowJar + if [ -f ./gradlew ]; then + chmod +x ./gradlew + ./gradlew build shadowJar -x test + else + /root/chaincode-java/gradlew build shadowJar -x test + fi retval=$? if [ $retval -ne 0 ]; then exit $retval @@ -17,9 +27,12 @@ buildGradle() { } buildMaven() { - cd "$1" > /dev/null + echo "Copying from $1 to ${TMP_DIR}" + cd $1 + tar cf - . | (cd ${TMP_DIR}; tar xf -) + cd ${TMP_DIR} echo "Maven build" - mvn compile package + mvn -B compile package -DskipTests -Dmaven.test.skip=true retval=$? if [ $retval -ne 0 ]; then exit $retval @@ -73,6 +86,18 @@ fi if [ -f "/chaincode/input/src/build.gradle" ] then buildGradle /chaincode/input/src/ /chaincode/output/ -else +elif [ -f "/chaincode/input/build.gradle" ] +then + buildGradle /chaincode/input/ /chaincode/output/ +elif [ -f "/chaincode/input/src/pom.xml" ] +then buildMaven /chaincode/input/src/ /chaincode/output/ +elif [ -f "/chaincode/input/pom.xml" ] +then + buildMaven /chaincode/input/ /chaincode/output/ +else + >&2 echo "Not build.gralde nor pom.xml found in chaincode source, don't know how to build chaincode" + >&2 echo "Project folder content:" + >&2 find /chaincode/input/src/ -name "*" -exec ls -ld '{}' \; + exit 255 fi diff --git a/fabric-chaincode-example-gradle/build.gradle b/fabric-chaincode-example-gradle/build.gradle index 388bb35d..6ef6ee23 100644 --- a/fabric-chaincode-example-gradle/build.gradle +++ b/fabric-chaincode-example-gradle/build.gradle @@ -11,10 +11,11 @@ sourceCompatibility = 1.8 repositories { mavenLocal() mavenCentral() + maven { url "https://www.jitpack.io" } } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.2-SNAPSHOT' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.8' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-example-maven/pom.xml b/fabric-chaincode-example-maven/pom.xml index 9e6016f3..66ac3c65 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.2-SNAPSHOT + 1.4.8 1.0.13 @@ -22,6 +22,17 @@ 4.11 + + + + jitpack.io + https://www.jitpack.io + + + artifactory + https://hyperledger.jfrog.io/hyperledger/fabric-maven + + diff --git a/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-example-sacc/build.gradle index ebf9947f..b3f08af2 100644 --- a/fabric-chaincode-example-sacc/build.gradle +++ b/fabric-chaincode-example-sacc/build.gradle @@ -11,10 +11,11 @@ sourceCompatibility = 1.8 repositories { mavenLocal() mavenCentral() + maven { url "https://www.jitpack.io" } } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.2-SNAPSHOT' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.8' testCompile group: 'junit', name: 'junit', version: '4.12' } @@ -24,6 +25,6 @@ shadowJar { classifier = null manifest { - attributes 'Main-Class': 'org.hyperledger.fabric.example.SimpleAsset' + attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter' } } diff --git a/fabric-chaincode-example-sacc/src/main/java/org/hyperledger/fabric/example/SimpleAsset.java b/fabric-chaincode-example-sacc/src/main/java/org/hyperledger/fabric/example/SimpleAsset.java index 862e13c0..a386e4f0 100644 --- a/fabric-chaincode-example-sacc/src/main/java/org/hyperledger/fabric/example/SimpleAsset.java +++ b/fabric-chaincode-example-sacc/src/main/java/org/hyperledger/fabric/example/SimpleAsset.java @@ -24,14 +24,15 @@ public Response init(ChaincodeStub stub) { // Get the args from the transaction proposal List args = stub.getParameters(); if (args.size() != 2) { - newErrorResponse("Incorrect arguments. Expecting a key and a value"); + return newErrorResponse("Incorrect arguments. Expecting a key and a value"); } + // Set up any variables or assets here by calling stub.putState() // We store the key and the value on the ledger stub.putStringState(args.get(0), args.get(1)); return newSuccessResponse(); } catch (Throwable e) { - return newErrorResponse("Failed to create asset"); + return newErrorResponse("Failed to create asset "+e.getMessage()); } } diff --git a/fabric-chaincode-example-sbe/build.gradle b/fabric-chaincode-example-sbe/build.gradle index f55eadf4..b18cbfe1 100644 --- a/fabric-chaincode-example-sbe/build.gradle +++ b/fabric-chaincode-example-sbe/build.gradle @@ -4,17 +4,18 @@ plugins { } group 'org.hyperledger.fabric-chaincode-java' -version '1.0-SNAPSHOT' +version '1.0' sourceCompatibility = 1.8 repositories { mavenLocal() mavenCentral() + maven { url "https://www.jitpack.io" } } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.2-SNAPSHOT' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.8' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-example-sbe/src/main/java/org/hyperledger/fabric/example/EndorsementCC.java b/fabric-chaincode-example-sbe/src/main/java/org/hyperledger/fabric/example/EndorsementCC.java index 95c19a19..03964e45 100644 --- a/fabric-chaincode-example-sbe/src/main/java/org/hyperledger/fabric/example/EndorsementCC.java +++ b/fabric-chaincode-example-sbe/src/main/java/org/hyperledger/fabric/example/EndorsementCC.java @@ -32,6 +32,7 @@ public class EndorsementCC extends ChaincodeBase { functions.put("getval", EndorsementCC.class.getMethod("getVal", ChaincodeStub.class)); functions.put("cc2cc", EndorsementCC.class.getMethod("invokeCC", ChaincodeStub.class)); } catch (NoSuchMethodException e) { + e.printStackTrace(); _logger.error(e); } } @@ -44,6 +45,7 @@ public Response init(ChaincodeStub stub) { _logger.info("Init done"); return newSuccessResponse(); } catch (Throwable e) { + e.printStackTrace(); return newErrorResponse(e); } } @@ -59,6 +61,7 @@ public Response invoke(ChaincodeStub stub) { } return newErrorResponse("Unknown function " + funcName); } catch (Throwable e) { + e.printStackTrace(); return newErrorResponse(e); } } @@ -189,13 +192,16 @@ public Response setVal(ChaincodeStub stub) { if ("pub".equals(parameters.get(0))) { stub.putStringState("pub", parameters.get(1)); + _logger.info("Put state "+parameters.get(1)); } else if ("priv".equals(parameters.get(0))) { stub.putPrivateData("col", "priv", parameters.get(1)); + _logger.info("Put Private "+parameters.get(1)); } else { return newErrorResponse("Unknown key specified"); } return newSuccessResponse(new byte[]{}); } catch (Throwable e) { + e.printStackTrace(); return newErrorResponse(e); } } @@ -209,13 +215,18 @@ public Response getVal(ChaincodeStub stub) { } if ("pub".equals(parameters.get(0))) { - return newSuccessResponse(stub.getState("pub")); + _logger.info(stub.getState("pub")); + return newSuccessResponse((byte[])stub.getState("pub")); } else if ("priv".equals(parameters.get(0))) { - return newSuccessResponse(stub.getPrivateData("col", "priv")); + byte[] d = stub.getPrivateData("col", "priv"); + _logger.info("get privateData" + new String(d,UTF_8)); + + return newSuccessResponse((byte[])d); } else { return newErrorResponse("Unknown key specified"); } } catch (Throwable e) { + e.printStackTrace(); return newErrorResponse(e); } } diff --git a/fabric-chaincode-integration-test/build.gradle b/fabric-chaincode-integration-test/build.gradle index a0a16cca..5c9f5234 100644 --- a/fabric-chaincode-integration-test/build.gradle +++ b/fabric-chaincode-integration-test/build.gradle @@ -1,9 +1,24 @@ dependencies { compile project(':fabric-chaincode-docker') testCompile 'org.testcontainers:testcontainers:1.7.1' - testCompile 'org.hyperledger.fabric-sdk-java:fabric-sdk-java:1.4.1' + testCompile 'org.hyperledger.fabric-sdk-java:fabric-sdk-java:1.4.8' compile project(':fabric-chaincode-shim') + implementation group: 'org.json', name: 'json', version: '20180813' } build.dependsOn project(':fabric-chaincode-docker').buildImage + test { + // Always run tests, even when nothing changed. + dependsOn 'cleanTest' + + // Show test results. + testLogging { + events "passed", "skipped", "failed" + showExceptions true + showCauses true + showStandardStreams true + exceptionFormat "full" + + } + } diff --git a/fabric-chaincode-integration-test/getDockerImages.sh b/fabric-chaincode-integration-test/getDockerImages.sh new file mode 100755 index 00000000..92836464 --- /dev/null +++ b/fabric-chaincode-integration-test/getDockerImages.sh @@ -0,0 +1,43 @@ +#!/bin/bash -e +set -o pipefail + +echo "======== PULL DOCKER IMAGES ========" + +########################################################## +# Pull and Tag the fabric and fabric-ca images from Artifactory +########################################################## +echo "Fetching images from Artifactory" +ARTIFACTORY_URL=hyperledger-fabric.jfrog.io +ORG_NAME="fabric" + +VERSION=2.0.0 +ARCH="amd64" +: ${STABLE_VERSION:=$VERSION-stable} +STABLE_TAG=$ARCH-$STABLE_VERSION +MASTER_TAG=$ARCH-master + +echo "---------> STABLE_VERSION:" $STABLE_VERSION + +dockerTag() { + for IMAGE in peer orderer ca tools orderer ccenv; do + echo "Images: $IMAGE" + echo + docker pull $ARTIFACTORY_URL/fabric-$IMAGE:$STABLE_TAG + if [ $? != 0 ]; then + echo "FAILED: Docker Pull Failed on $IMAGES" + exit 1 + fi + docker tag $ARTIFACTORY_URL/fabric-$IMAGE:$STABLE_TAG fabric-$IMAGE + docker tag $ARTIFACTORY_URL/fabric-$IMAGE:$STABLE_TAG fabric-$IMAGE:$MASTER_TAG + docker tag $ARTIFACTORY_URL/fabric-$IMAGE:$STABLE_TAG fabric-$IMAGE:$VERSION + echo "$ORG_NAME-$IMAGE:$MASTER_TAG" + echo "Deleting Artifactory docker images: $IMAGE" + docker rmi -f $ARTIFACTORY_URL/fabric-$IMAGE:$STABLE_TAG + done +} + +dockerTag + +echo +docker images | grep "hyperledger*" +echo diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/build.gradle new file mode 100644 index 00000000..b3f08af2 --- /dev/null +++ b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/build.gradle @@ -0,0 +1,30 @@ +plugins { + id 'com.github.johnrengelman.shadow' version '2.0.3' + id 'java' +} + +group 'org.hyperledger.fabric-chaincode-java' +version '1.0-SNAPSHOT' + +sourceCompatibility = 1.8 + +repositories { + mavenLocal() + mavenCentral() + maven { url "https://www.jitpack.io" } +} + +dependencies { + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.8' + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +shadowJar { + baseName = 'chaincode' + version = null + classifier = null + + manifest { + attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter' + } +} diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/settings.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/settings.gradle new file mode 100644 index 00000000..a60de0b8 --- /dev/null +++ b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'fabric-chaincode-example-sacc' + diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/src/main/java/org/hyperledger/fabric/example/AllAPI.java b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/src/main/java/org/hyperledger/fabric/example/AllAPI.java new file mode 100644 index 00000000..a19b8fa5 --- /dev/null +++ b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/src/main/java/org/hyperledger/fabric/example/AllAPI.java @@ -0,0 +1,99 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ +package org.example; + +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.annotation.*; + + +import org.hyperledger.fabric.shim.ledger.*; +import org.hyperledger.fabric.shim.*; +import java.util.*; +import static java.nio.charset.StandardCharsets.UTF_8; + +@Contract(name = "AllAPI", + info = @Info(title = "AllAPI contract", + description = "Contract but using all the APIs", + version = "0.0.1", + license = + @License(name = "SPDX-License-Identifier: Apache-2.0", + url = ""), + contact = @Contact(email = "fred@example.com", + name = "fred", + url = "http://fred.example.com"))) +@Default +public class AllAPI implements ContractInterface { + public AllAPI() { + + } + + @Transaction() + public void putBulkStates(Context ctx){ + for (int x=100; x<200; x++){ + String key = "key"+x; + String value = "value:"+x; + + putState(ctx,key,value); + } + } + + @Transaction() + public void putState(Context ctx, String key, String payload){ + ChaincodeStub stub = ctx.getStub(); + stub.putState(key,payload.getBytes(UTF_8)); + } + + @Transaction() + public void putStateComposite(Context ctx, String key[], String payload){ + String composite = new CompositeKey("composite",key).toString(); + this.putState(ctx,composite,payload); + } + + @Transaction() + public void getState(Context ctx, String key, String payload){ + ChaincodeStub stub = ctx.getStub(); + String result = stub.getStringState(key); + if (!result.equals(payload)){ + String msg = "GetState::["+key+"] Expected "+payload+" got "+result; + System.out.println(msg); + throw new RuntimeException(msg); + } + } + + @Transaction() + public int getByRange(Context ctx, String start, String end){ + ChaincodeStub stub = ctx.getStub(); + System.out.println("getByRange>>"); + QueryResultsIterator qri = stub.getStateByRange(start,end); + int count=0; + for (KeyValue kv : qri){ + kv.getKey(); + kv.getStringValue(); + count++; + System.out.println("["+kv.getKey()+"] "+kv.getStringValue()); + } + System.out.println("getByRange<<"); + return count; + } + + @Transaction() + public String getByRangePaged(Context ctx, String start, String end, int pageSize, String bookmark){ + ChaincodeStub stub = ctx.getStub(); + System.out.println("getByRangePaged>>"); + QueryResultsIteratorWithMetadata qri = stub.getStateByRangeWithPagination(start,end,pageSize,bookmark); + for (KeyValue kv : qri){ + kv.getKey(); + kv.getStringValue(); + System.out.println("["+kv.getKey()+"] "+kv.getStringValue()); + } + String newbookmark = qri.getMetadata().getBookmark(); + int records = qri.getMetadata().getFetchedRecordsCount(); + System.out.println(newbookmark+" @ "+records); + + System.out.println("getByRangePaged<<"); + return newbookmark; + } + +} \ No newline at end of file diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/build.gradle new file mode 100644 index 00000000..37eed64f --- /dev/null +++ b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/build.gradle @@ -0,0 +1,30 @@ +plugins { + id 'com.github.johnrengelman.shadow' version '4.0.3' + id 'java' +} + +group 'org.hyperledger.fabric-chaincode-java' +version '1.0' + +sourceCompatibility = 1.8 + +repositories { + mavenLocal() + mavenCentral() + maven { url "https://www.jitpack.io" } +} + +dependencies { + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.8' + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +shadowJar { + baseName = 'chaincode' + version = null + classifier = null + + manifest { + attributes 'Main-Class': 'org.hyperledger.fabric.example.EndorsementCC' + } +} diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradle/wrapper/gradle-wrapper.jar b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..5c2d1cf0 Binary files /dev/null and b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradle/wrapper/gradle-wrapper.jar differ diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradle/wrapper/gradle-wrapper.properties b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..7c4388a9 --- /dev/null +++ b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradlew b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradlew new file mode 100755 index 00000000..8e25e6c1 --- /dev/null +++ b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradlew @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradlew.bat b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradlew.bat new file mode 100644 index 00000000..24467a14 --- /dev/null +++ b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/settings.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/settings.gradle new file mode 100644 index 00000000..fe0f3ce3 --- /dev/null +++ b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'fabric-chaincode-example-sbe' + diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/src/main/java/org/hyperledger/fabric/example/EndorsementCC.java b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/src/main/java/org/hyperledger/fabric/example/EndorsementCC.java new file mode 100644 index 00000000..03964e45 --- /dev/null +++ b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/src/main/java/org/hyperledger/fabric/example/EndorsementCC.java @@ -0,0 +1,256 @@ +package org.hyperledger.fabric.example; + +import com.google.gson.JsonArray; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hyperledger.fabric.shim.ChaincodeBase; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement; +import org.hyperledger.fabric.shim.ext.sbe.impl.StateBasedEndorsementFactory; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class EndorsementCC extends ChaincodeBase { + + private static Log _logger = LogFactory.getLog(EndorsementCC.class); + + private static Map functions; + + static { + functions = new HashMap<>(); + try { + functions.put("addorgs", EndorsementCC.class.getMethod("addOrgs", ChaincodeStub.class)); + functions.put("delorgs", EndorsementCC.class.getMethod("delOrgs", ChaincodeStub.class)); + functions.put("listorgs", EndorsementCC.class.getMethod("listOrgs", ChaincodeStub.class)); + functions.put("delep", EndorsementCC.class.getMethod("delEP", ChaincodeStub.class)); + functions.put("setval", EndorsementCC.class.getMethod("setVal", ChaincodeStub.class)); + functions.put("getval", EndorsementCC.class.getMethod("getVal", ChaincodeStub.class)); + functions.put("cc2cc", EndorsementCC.class.getMethod("invokeCC", ChaincodeStub.class)); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + _logger.error(e); + } + } + + @Override + public Response init(ChaincodeStub stub) { + try { + _logger.info("Init java EndorsementCC"); + stub.putStringState("pub", "foo"); + _logger.info("Init done"); + return newSuccessResponse(); + } catch (Throwable e) { + e.printStackTrace(); + return newErrorResponse(e); + } + } + + @Override + public Response invoke(ChaincodeStub stub) { + try { + _logger.info("Invoking java EndorsementCC"); + String funcName = stub.getFunction(); + + if (functions.containsKey(funcName)) { + return (Response) functions.get(funcName).invoke(this, stub); + } + return newErrorResponse("Unknown function " + funcName); + } catch (Throwable e) { + e.printStackTrace(); + return newErrorResponse(e); + } + } + + public Response addOrgs(ChaincodeStub stub) { + try { + _logger.info("Invoking addOrgs"); + List parameters = stub.getParameters(); + if (parameters.size() < 2) { + return newErrorResponse("No orgs to add specified"); + } + + byte[] epBytes; + if ("pub".equals(parameters.get(0))) { + epBytes = stub.getStateValidationParameter("pub"); + } else if ("priv".equals(parameters.get(0))) { + epBytes = stub.getPrivateDataValidationParameter("col", "priv"); + } else { + return newErrorResponse("Unknown key specified"); + } + + StateBasedEndorsement ep = StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(epBytes); + ep.addOrgs(StateBasedEndorsement.RoleType.RoleTypePeer, parameters.subList(1, parameters.size()).toArray(new String[]{})); + epBytes = ep.policy(); + if ("pub".equals(parameters.get(0))) { + stub.setStateValidationParameter("pub", epBytes); + } else { + stub.setPrivateDataValidationParameter("col", "priv", epBytes); + } + + return newSuccessResponse(new byte[]{}); + + } catch (Throwable e) { + return newErrorResponse(e); + } + } + + public Response delOrgs(ChaincodeStub stub) { + try { + _logger.info("Invoking delOrgs"); + List parameters = stub.getParameters(); + if (parameters.size() < 2) { + return newErrorResponse("No orgs to delete specified"); + } + + byte[] epBytes; + if ("pub".equals(parameters.get(0))) { + epBytes = stub.getStateValidationParameter("pub"); + } else if ("priv".equals(parameters.get(0))) { + epBytes = stub.getPrivateDataValidationParameter("col", "priv"); + } else { + return newErrorResponse("Unknown key specified"); + } + + StateBasedEndorsement ep = StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(epBytes); + // delete organizations from the endorsement policy of that key + ep.delOrgs(parameters.subList(1, parameters.size()).toArray(new String[]{})); + epBytes = ep.policy(); + if ("pub".equals(parameters.get(0))) { + stub.setStateValidationParameter("pub", epBytes); + } else { + stub.setPrivateDataValidationParameter("col", "priv", epBytes); + } + + stub.setStateValidationParameter("endorsed_state", epBytes); + + return newSuccessResponse(new byte[]{}); + } catch (Throwable e) { + return newErrorResponse(e); + } + } + + public Response listOrgs(ChaincodeStub stub) { + try { + _logger.info("Invoking listOrgs"); + List parameters = stub.getParameters(); + if (parameters.size() < 1) { + return newErrorResponse("No key specified"); + } + + byte[] epBytes; + if ("pub".equals(parameters.get(0))) { + epBytes = stub.getStateValidationParameter("pub"); + } else if ("priv".equals(parameters.get(0))) { + epBytes = stub.getPrivateDataValidationParameter("col", "priv"); + } else { + return newErrorResponse("Unknown key specified"); + } + StateBasedEndorsement ep = StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(epBytes); + + List orgs = ep.listOrgs(); + JsonArray orgsList = new JsonArray(); + orgs.forEach(org -> orgsList.add(org)); + return newSuccessResponse(orgsList.toString().getBytes()); + } catch (Throwable e) { + return newErrorResponse(e); + } + } + + public Response delEP(ChaincodeStub stub) { + try { + _logger.info("Invoking delEP"); + List parameters = stub.getParameters(); + if (parameters.size() < 1) { + return newErrorResponse("No key specified"); + } + + if ("pub".equals(parameters.get(0))) { + stub.setStateValidationParameter("pub", null); + } else if ("priv".equals(parameters.get(0))) { + stub.setPrivateDataValidationParameter("col", "priv", null); + } else { + return newErrorResponse("Unknown key specified"); + } + return newSuccessResponse(new byte[]{}); + } catch (Throwable e) { + return newErrorResponse(e); + } + } + + public Response setVal(ChaincodeStub stub) { + try { + _logger.info("Invoking setVal"); + List parameters = stub.getParameters(); + if (parameters.size() != 2) { + return newErrorResponse("setval expects two arguments"); + } + + if ("pub".equals(parameters.get(0))) { + stub.putStringState("pub", parameters.get(1)); + _logger.info("Put state "+parameters.get(1)); + } else if ("priv".equals(parameters.get(0))) { + stub.putPrivateData("col", "priv", parameters.get(1)); + _logger.info("Put Private "+parameters.get(1)); + } else { + return newErrorResponse("Unknown key specified"); + } + return newSuccessResponse(new byte[]{}); + } catch (Throwable e) { + e.printStackTrace(); + return newErrorResponse(e); + } + } + + public Response getVal(ChaincodeStub stub) { + try { + _logger.info("Invoking getVal"); + List parameters = stub.getParameters(); + if (parameters.size() != 1) { + return newErrorResponse("setval expects one argument"); + } + + if ("pub".equals(parameters.get(0))) { + _logger.info(stub.getState("pub")); + return newSuccessResponse((byte[])stub.getState("pub")); + } else if ("priv".equals(parameters.get(0))) { + byte[] d = stub.getPrivateData("col", "priv"); + _logger.info("get privateData" + new String(d,UTF_8)); + + return newSuccessResponse((byte[])d); + } else { + return newErrorResponse("Unknown key specified"); + } + } catch (Throwable e) { + e.printStackTrace(); + return newErrorResponse(e); + } + } + + public Response invokeCC(ChaincodeStub stub) { + try { + _logger.info("Invoking invokeCC"); + List args = stub.getArgs(); + if (args.size() < 3) { + return newErrorResponse("cc2cc expects at least two arguments (channel and chaincode)"); + } + String channel = new String(args.get(1), UTF_8); + String cc = new String(args.get(2), UTF_8); + + List nargs = args.subList(3, args.size()); + + return stub.invokeChaincode(cc, nargs, channel); + } catch (Throwable e) { + return newErrorResponse(e); + } + } + + public static void main(String[] args) { + new EndorsementCC().start(args); + } + +} diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Command.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Command.java new file mode 100644 index 00000000..7f52fb41 --- /dev/null +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Command.java @@ -0,0 +1,119 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperleder.fabric.shim.integration; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +public class Command { + + protected List cmd; + protected Map env; + + Command(List cmd) { + this.cmd = cmd; + this.env = new HashMap<>(); + + } + + class Result { + ArrayList stdout; + ArrayList stderr; + int exitcode; + } + + /** + * Run but don't suppress the output being printed directly + */ + public Result run() { + return this.run(false); + } + + /** + * Run the command, and process the output to arrays for later parsing and checking + * + * @param quiet true if the output should NOT be printed directly to System.out/System.err + */ + public Result run(boolean quiet) { + + ProcessBuilder processBuilder = new ProcessBuilder(cmd); + processBuilder.environment().putAll(env); + final Result result = new Result(); + + System.out.println("Running:" + this.toString()); + try { + Process process = processBuilder.start(); + + CompletableFuture> soutFut = readOutStream(process.getInputStream(),quiet?null:System.out); + CompletableFuture> serrFut = readOutStream(process.getErrorStream(),quiet?null:System.err); + + CompletableFuture resultFut = soutFut.thenCombine(serrFut, (stdout, stderr) -> { + // print to current stderr the stderr of process and return the stdout + result.stderr = stderr; + result.stdout = stdout; + return result; + }); + + result.exitcode = process.waitFor(); + // get stdout once ready, blocking + resultFut.get(); + + } catch (IOException | InterruptedException | ExecutionException e) { + e.printStackTrace(); + result.exitcode = -1; + } + + return result; + } + + /** + * Collect the information from the executed process and add them to a result object + * + * @param is + * @param stream + * @return Completable Future with the array list of the stdout/sstderr + */ + CompletableFuture> readOutStream(InputStream is, PrintStream stream) { + return CompletableFuture.supplyAsync(() -> { + try (InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr);) { + ArrayList res = new ArrayList(); + String inputLine; + while ((inputLine = br.readLine()) != null) { + if (stream!=null) stream.println(inputLine); + res.add(inputLine); + } + return res; + } catch (Throwable e) { + throw new RuntimeException("problem with executing program", e); + } + }); + } + + public String toString() { + return "[" + String.join(" ", cmd) + "]"; + } + + static public class Builder implements Cloneable { + public Builder duplicate() { + try { + return (Builder) this.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + return null; + } + } + } +} diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/CommandSingleton.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/CommandSingleton.java new file mode 100644 index 00000000..c4706121 --- /dev/null +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/CommandSingleton.java @@ -0,0 +1,58 @@ +/* +Copyright 2020 IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperleder.fabric.shim.integration; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.Semaphore; + +import org.hyperleder.fabric.shim.integration.Docker.DockerBuilder; +import org.hyperleder.fabric.shim.integration.DockerCompose.DockerComposeBuilder; + +/** Utility class to run the setup script once */ +public class CommandSingleton { + + private static boolean done = false; + + private static Semaphore flag = new Semaphore(1); + + public static void setup(){ + + try { + // things have not been setup up yet + flag.acquire(); + if (done){ + flag.release(); + return; + } + // get current working directory for debug and reference purposes only + Path currentRelativePath = Paths.get(""); + String s = currentRelativePath.toAbsolutePath().toString(); + System.out.println("Current relative path is: " + s); + + // create the docker-compose command + DockerComposeBuilder composebuilder = DockerCompose.newBuilder() + .file("src/test/resources/first-network/docker-compose-cli.yaml"); + + // close down anything running... + composebuilder.duplicate().down().build().run(); + + // ...and bring up + DockerCompose compose = composebuilder.up().detach().build(); + compose.run(); + + // the cli container contains a script that does the channel create, joing + // and chaincode install/instantiate + DockerBuilder dockerBuilder = new Docker.DockerBuilder(); + Docker docker = dockerBuilder.exec().container("cli").script("./scripts/script.sh").build(); + docker.run(); + done=true; + flag.release(); + } catch (InterruptedException e){ + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Docker.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Docker.java new file mode 100644 index 00000000..cedc0573 --- /dev/null +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Docker.java @@ -0,0 +1,77 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperleder.fabric.shim.integration; +import java.util.ArrayList; +import java.util.List; + +/** Represents the 'peer' cli command + * + * + * + */ +public class Docker extends Command { + + public static DockerBuilder newBuilder(){ + return new DockerBuilder(); + } + + static public class DockerBuilder implements Cloneable { + boolean exec; + String container; + String script; + + public DockerBuilder duplicate() { + try { + return (DockerBuilder) this.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + return null; + } + } + + public DockerBuilder script(String script){ + this.script = script; + return this; + } + + public DockerBuilder container(String container){ + this.container = container; + return this; + } + + public DockerBuilder exec(){ + this.exec = true; + return this; + } + public Docker build(){ + + ArrayList list = new ArrayList<>(); + list.add("docker"); + if(exec){ + list.add("exec"); + + } + + if (container == null || container.isEmpty()){ + throw new RuntimeException("container should be set"); + } + list.add(container); + + if (script == null || script.isEmpty()){ + throw new RuntimeException("script should be set"); + } + list.add(script); + + + return new Docker(list); + } + } + + Docker(List cmd) { + super(cmd); + } + +} \ No newline at end of file diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/DockerCompose.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/DockerCompose.java new file mode 100644 index 00000000..09a2515d --- /dev/null +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/DockerCompose.java @@ -0,0 +1,74 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperleder.fabric.shim.integration; +import java.util.ArrayList; +import java.util.List; + +/** Represents the 'peer' cli command + * + * + * + */ +public class DockerCompose extends Command { + + public static DockerComposeBuilder newBuilder(){ + return new DockerComposeBuilder(); + } + + static public class DockerComposeBuilder extends Command.Builder{ + String composeFile; + + boolean up = true; + boolean detach = false; + + public DockerComposeBuilder file(String composeFile){ + this.composeFile = composeFile; + return this; + } + + public DockerComposeBuilder duplicate() { + return (DockerComposeBuilder) super.duplicate(); + } + + public DockerComposeBuilder up(){ + this.up = true; + return this; + } + + public DockerComposeBuilder detach(){ + this.detach = true; + return this; + } + + public DockerComposeBuilder down(){ + this.up = false; + return this; + } + + public DockerCompose build(){ + + ArrayList list = new ArrayList<>(); + list.add("docker-compose"); + if (composeFile!=null && !composeFile.isEmpty()) { + list.add("-f"); + list.add(composeFile); + } + list.add(up?"up":"down"); + if (detach){ + list.add("-d"); + } + + + return new DockerCompose(list); + } + } + + DockerCompose(List cmd) { + super(cmd); + super.env.put("COMPOSE_PROJECT_NAME","first-network"); + } + +} \ No newline at end of file diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Peer.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Peer.java new file mode 100644 index 00000000..481f5e5f --- /dev/null +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Peer.java @@ -0,0 +1,169 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperleder.fabric.shim.integration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONObject; + +/** Represents the 'peer' cli command + * + * + * + */ +public class Peer extends Command { + + public static PeerBuilder newBuilder(){ + return new PeerBuilder(); + } + + static public class PeerBuilder extends Command.Builder { + String tlsArgs; + String orderer; + String channel; + String ccname; + boolean evaluate = false; + int waitForEventTimeout; + List args = new ArrayList(); + Map transientData; + + public PeerBuilder duplicate() { + try { + return (PeerBuilder) this.clone(); + } catch (CloneNotSupportedException e) { + + e.printStackTrace(); + return null; + } + } + + public PeerBuilder tlsArgs(String tlsArgs){ + this.tlsArgs = tlsArgs; + return this; + } + + public PeerBuilder orderer(String orderer){ + this.orderer = orderer; + return this; + } + + public PeerBuilder channel(String channel){ + this.channel = channel; + return this; + } + + public PeerBuilder ccname(String ccname){ + this.ccname = ccname; + return this; + } + + public PeerBuilder evaluate(){ + this.evaluate = true; + return this; + } + + public PeerBuilder invoke(){ + this.evaluate = false; + return this; + } + + public PeerBuilder argsTx(List args){ + this.args = args; + return this; + } + + public PeerBuilder argsTx(String argsArray[]){ + this.args = Arrays.asList(argsArray); + return this; + } + + public PeerBuilder transientData(Map transientData){ + this.transientData = transientData; + return this; + } + + public PeerBuilder waitForEvent(int seconds){ + this.waitForEventTimeout = seconds; + return this; + } + + public PeerBuilder waitForEvent(){ + this.waitForEvent(0); + return this; + } + + private String transientToString() { + JSONObject json = new JSONObject(this.transientData); + return "'"+json.toString()+"'"; + } + + private String argsToString() { + JSONArray array = new JSONArray(this.args); + JSONObject json = new JSONObject(); + json.put("Args", array); + return json.toString(); + } + + public Peer build(){ + + ArrayList list = new ArrayList<>(); + list.add("docker"); + list.add("exec"); + list.add("cli"); + list.add("peer"); + list.add("chaincode"); + list.add(evaluate?"query":"invoke"); + if (tlsArgs != null && !tlsArgs.isEmpty()) { + list.add(tlsArgs); + } + + if (channel == null || channel.isEmpty()){ + throw new RuntimeException("Channel should be set"); + } + list.add("-C"); + list.add(channel); + + if (ccname == null || ccname.isEmpty()){ + throw new RuntimeException("Chaincode name should be set"); + } + list.add("-n"); + list.add(ccname); + + if (args == null || args.isEmpty()){ + throw new RuntimeException("Args should be set"); + } + list.add("-c"); + list.add(argsToString()); + + if (transientData != null && !transientData.isEmpty()){ + list.add("--transient"); + list.add(transientToString()); + } + + if (waitForEventTimeout>0){ + list.add("--waitForEvent --waitForEventTimeout"); + list.add(waitForEventTimeout+"s"); + } else if (waitForEventTimeout == 0 ){ + list.add("--waitForEvent"); + } + + list.add("--peerAddresses"); + list.add("peer0.org1.example.com:7051"); + list.add("--peerAddresses"); + list.add("peer0.org2.example.com:7051"); + + return new Peer(list); + } + } + + + Peer(List cmd) { + super(cmd); + } +} \ No newline at end of file diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/SACCIntegrationTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/SACCIntegrationTest.java index e9d2de3c..fdf7c294 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/SACCIntegrationTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/SACCIntegrationTest.java @@ -4,87 +4,65 @@ SPDX-License-Identifier: Apache-2.0 */ package org.hyperleder.fabric.shim.integration; +import java.util.ArrayList; +import java.util.Arrays; +import static org.junit.Assert.assertThat; +import static org.hamcrest.core.StringContains.containsString; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Collectors; -import org.hamcrest.Matchers; -import org.hyperledger.fabric.sdk.*; -import org.hyperledger.fabric.sdk.exception.ChaincodeCollectionConfigurationException; -import org.hyperledger.fabric.sdk.exception.ChaincodeEndorsementPolicyParseException; -import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; -import org.hyperledger.fabric.sdk.security.CryptoSuite; +import org.hyperleder.fabric.shim.integration.Command.Result; +import org.hyperleder.fabric.shim.integration.Docker.DockerBuilder; +import org.hyperleder.fabric.shim.integration.DockerCompose.DockerComposeBuilder; +import org.hyperleder.fabric.shim.integration.Peer.PeerBuilder; import org.junit.BeforeClass; -import org.junit.ClassRule; import org.junit.Test; -import org.testcontainers.containers.DockerComposeContainer; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; - +/** + * Basic Java Chaincode Test + * + */ public class SACCIntegrationTest { - @ClassRule - public static DockerComposeContainer env = new DockerComposeContainer( - new File("src/test/resources/first-network/docker-compose-cli.yaml") - ) - .withLocalCompose(false) - .withPull(true); @BeforeClass - public static void setUp() throws Exception { - Utils.setUp(); + public static void setUp() { + CommandSingleton.setup(); } - @Test - public void TestSACCChaincodeInstallInstantiateInvokeQuery() throws Exception { - - final CryptoSuite crypto = CryptoSuite.Factory.getCryptoSuite(); - - // Create client and set default crypto suite - System.out.println("Creating client"); - final HFClient client = HFClient.createNewInstance(); - client.setCryptoSuite(crypto); - - client.setUserContext(Utils.getAdminUserOrg1TLS()); - - Channel myChannel = Utils.getMyChannelFirstNetwork(client); - List peers = myChannel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org1") != -1).collect(Collectors.toList()); - - InstallProposalRequest installProposalRequest = generateSACCInstallRequest(client); - Utils.sendInstallProposals(client, installProposalRequest, peers); - - // Instantiating chaincode - InstantiateProposalRequest instantiateProposalRequest = generateSACCInstantiateRequest(client); - Utils.sendInstantiateProposal("javacc", instantiateProposalRequest, myChannel, peers, myChannel.getOrderers()); - - client.setUserContext(Utils.getUser1Org1TLS()); - - final TransactionProposalRequest proposalRequest = generateSACCInvokeRequest(client, "b", "200"); - Utils.sendTransactionProposalInvoke(proposalRequest, myChannel, peers, myChannel.getOrderers()); - - // Creating proposal for query - final TransactionProposalRequest queryAProposalRequest = generateSACCQueryRequest(client, "a"); - Utils.sendTransactionProposalQuery(queryAProposalRequest, myChannel, peers, Matchers.is(200), Matchers.is("100"), null); - - // Creating proposal for query - final TransactionProposalRequest queryBProposalRequest = generateSACCQueryRequest(client, "b"); - Utils.sendTransactionProposalQuery(queryBProposalRequest, myChannel, peers, Matchers.is(200), Matchers.is("200"), null); + private String invoke(String... args){ + PeerBuilder coreBuilder = Peer.newBuilder().ccname("javacc").channel("mychannel"); + Result r = coreBuilder.argsTx(args).build().run(); + System.out.println(r.stderr); + String text = r.stderr.stream() + .filter(line -> line.matches(".*chaincodeInvokeOrQuery.*")) + .collect(Collectors.joining(System.lineSeparator())) + .trim(); + + if (!text.contains("result: status:200")){ + throw new RuntimeException(text); + } + + int payloadIndex = text.indexOf("payload:"); + if (payloadIndex>1){ + return text.substring(payloadIndex+9,text.length()-1); + } + return "status:200"; } - static public InstallProposalRequest generateSACCInstallRequest(HFClient client) throws IOException, InvalidArgumentException { - return Utils.generateInstallRequest(client, "javacc", "1.0", "../fabric-chaincode-example-sacc"); - } + @Test + public void TestQuery(){ - static public InstantiateProposalRequest generateSACCInstantiateRequest(HFClient client) throws InvalidArgumentException, IOException, ChaincodeEndorsementPolicyParseException, ChaincodeCollectionConfigurationException { - return Utils.generateInstantiateRequest(client, "javacc", "1.0", "src/test/resources/chaincodeendorsementpolicy.yaml", null, "init", "a", "100"); - } + String text = invoke(new String[]{"putBulkStates"}); + assertThat(text, containsString("status:200")); + + text = invoke(new String[]{"getByRange","key120","key170"}); + assertThat(text, containsString("50")); - static public TransactionProposalRequest generateSACCInvokeRequest(HFClient client, String key, String value) { - return Utils.generateTransactionRequest(client, "javacc", "1.0", "set", key, value); - } + text = invoke(new String[]{"getByRangePaged","key120","key170","10",""}); + System.out.println(text); + assertThat(text, containsString("key130")); - static public TransactionProposalRequest generateSACCQueryRequest(HFClient client, String key) { - return Utils.generateTransactionRequest(client, "javacc", "1.0", "get", key); } } diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/SBECCIntegrationTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/SBECCIntegrationTest.java index 6461e613..ed940675 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/SBECCIntegrationTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/SBECCIntegrationTest.java @@ -5,140 +5,173 @@ */ package org.hyperleder.fabric.shim.integration; -import com.google.protobuf.ByteString; -import org.hamcrest.Matchers; -import org.hyperledger.fabric.sdk.*; -import org.hyperledger.fabric.sdk.exception.*; -import org.hyperledger.fabric.sdk.security.CryptoSuite; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.testcontainers.containers.DockerComposeContainer; +import static org.hamcrest.core.StringContains.containsString; +import static org.junit.Assert.assertThat; -import java.io.File; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.spec.InvalidKeySpecException; +import java.util.List; import java.util.stream.Collectors; -public class SBECCIntegrationTest { +import org.hyperleder.fabric.shim.integration.Command.Result; +import org.hyperleder.fabric.shim.integration.Docker.DockerBuilder; +import org.hyperleder.fabric.shim.integration.Peer.PeerBuilder; +import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; +import org.hyperledger.fabric.sdk.exception.ProposalException; +import org.junit.BeforeClass; +import org.junit.Test; - @ClassRule - public static DockerComposeContainer env = new DockerComposeContainer( - new File("src/test/resources/first-network/docker-compose-cli.yaml") - ) - .withLocalCompose(false) - .withPull(true); +public class SBECCIntegrationTest { @BeforeClass public static void setUp() throws Exception { - Utils.setUp(); + + CommandSingleton.setup(); + } + + private String filter(List lines){ + String text = lines.stream() + .filter(line -> line.matches(".*chaincodeInvokeOrQuery.*")) + .collect(Collectors.joining(System.lineSeparator())); + + System.out.println(text); + return text; } @Test - public void testSBECCFirstNetwork() throws IllegalAccessException, InvocationTargetException, InvalidArgumentException, InstantiationException, NoSuchMethodException, CryptoException, ClassNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, IOException, TransactionException, ProposalException, ChaincodeEndorsementPolicyParseException, ChaincodeCollectionConfigurationException { - final CryptoSuite crypto = CryptoSuite.Factory.getCryptoSuite(); + public void RunSBE_pub_setget() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, IOException, ProposalException, InvalidArgumentException { + String mode = "pub"; + // Need to send a number of 'peer chaincode invoke' commands + // Setup the core buider command and then duplicate per test + PeerBuilder coreBuilder = Peer.newBuilder().ccname("sbecc").channel("mychannel"); + Result r; + + String text; + + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "foo" }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); - // Create client and set default crypto suite - System.out.println("Creating client"); - final HFClient client = HFClient.createNewInstance(); - client.setCryptoSuite(crypto); + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); - client.setUserContext(Utils.getAdminUserOrg1TLS()); + r = coreBuilder.duplicate().argsTx(new String[] { "addorgs", mode, "Org1MSP" }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); - Channel myChannel = Utils.getMyChannelFirstNetwork(client); + r = coreBuilder.duplicate().argsTx(new String[] { "listorgs", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); - System.out.println("Installing chaincode fabric-chaincode-example-sacc, packaged as gzip stream"); - InstallProposalRequest installProposalRequest = generateSBECCInstallRequest(client); - Utils.sendInstallProposals(client, installProposalRequest, myChannel.getPeers().stream().filter(peer -> peer.getName().indexOf("org1") != -1).collect(Collectors.toList())); + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val1" }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); - client.setUserContext(Utils.getAdminUserOrg2TLS()); - installProposalRequest = generateSBECCInstallRequest(client); - Utils.sendInstallProposals(client, installProposalRequest, myChannel.getPeers().stream().filter(peer -> peer.getName().indexOf("org2") != -1).collect(Collectors.toList())); + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); - InstantiateProposalRequest instantiateProposal = generateSBECCInstantiateRequest(client); - Utils.sendInstantiateProposal("sbecc", instantiateProposal, myChannel, myChannel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org2") != -1).collect(Collectors.toList()), myChannel.getOrderers()); + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val2" }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); - RunSBE(client, myChannel, "pub"); - RunSBE(client, myChannel, "priv"); + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); + + r = coreBuilder.duplicate().argsTx(new String[] { "addorgs", mode, "Org2MSP" }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); + + r = coreBuilder.duplicate().argsTx(new String[] { "listorgs", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); + + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val3" }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); + + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); + + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val4" }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); + + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); + + r = coreBuilder.duplicate().argsTx(new String[] { "delorgs", mode, "Org1MSP" }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); + + r = coreBuilder.duplicate().argsTx(new String[] { "listorgs", mode }).build().run(true); + text = filter(r.stderr); + assertThat(filter(r.stderr), containsString("result: status:200")); } - void RunSBE(HFClient client, Channel channel, String mode) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, IOException, ProposalException, InvalidArgumentException { - client.setUserContext(Utils.getUser1Org1TLS()); - TransactionProposalRequest proposal = generateSBECCTransactionRequest(client, "setval", mode, "foo"); - Utils.sendTransactionProposalInvoke(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org1") != -1).collect(Collectors.toList()), channel.getOrderers()); - proposal = generateSBECCTransactionRequest(client, "getval", mode); - Utils.sendTransactionProposalQuery(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org1") != -1).collect(Collectors.toList()), Matchers.is(200), Matchers.anything(), Matchers.is(ByteString.copyFrom("foo", StandardCharsets.UTF_8))); + @Test + public void RunSBE_priv() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, IOException, ProposalException, InvalidArgumentException { + String mode = "priv"; - proposal = generateSBECCTransactionRequest(client, "addorgs", mode, "Org1MSP"); - Utils.sendTransactionProposalInvoke(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org1") != -1).collect(Collectors.toList()), channel.getOrderers()); + // Need to send a number of 'peer chaincode invoke' commands + // Setup the core buider command and then duplicate per test + PeerBuilder coreBuilder = Peer.newBuilder().ccname("sbecc").channel("mychannel"); + Result r; + String text; - proposal = generateSBECCTransactionRequest(client, "listorgs", mode); - Utils.sendTransactionProposalQuery(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org1") != -1).collect(Collectors.toList()), Matchers.is(200), Matchers.anything(), Matchers.is(ByteString.copyFrom("[\"Org1MSP\"]", StandardCharsets.UTF_8))); + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "foo" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - proposal = generateSBECCTransactionRequest(client, "setval", mode, "val1"); - Utils.sendTransactionProposalInvoke(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org1") != -1).collect(Collectors.toList()), channel.getOrderers()); + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - proposal = generateSBECCTransactionRequest(client, "getval", mode); - Utils.sendTransactionProposalQuery(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org1") != -1).collect(Collectors.toList()), Matchers.is(200), Matchers.anything(), Matchers.is(ByteString.copyFrom("val1", StandardCharsets.UTF_8))); + r = coreBuilder.duplicate().argsTx(new String[] { "addorgs", mode, "Org1MSP" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - client.setUserContext(Utils.getUser1Org2TLS()); - proposal = generateSBECCTransactionRequest(client, "setval", mode, "val2"); - Utils.sendTransactionProposalInvoke(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org2") != -1).collect(Collectors.toList()), channel.getOrderers(), true); + r = coreBuilder.duplicate().argsTx(new String[] { "listorgs", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200 payload:\"[\\\"Org1MSP\\\"]\"")); - proposal = generateSBECCTransactionRequest(client, "getval", mode); - Utils.sendTransactionProposalQuery(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org2") != -1).collect(Collectors.toList()), Matchers.is(200), Matchers.anything(), Matchers.is(ByteString.copyFrom("val1", StandardCharsets.UTF_8))); + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val1" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - client.setUserContext(Utils.getUser1Org1TLS()); - proposal = generateSBECCTransactionRequest(client, "addorgs", mode, "Org2MSP"); - Utils.sendTransactionProposalInvoke(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org1") != -1).collect(Collectors.toList()), channel.getOrderers()); + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200 payload:\"val1\"")); - proposal = generateSBECCTransactionRequest(client, "listorgs", mode); - Utils.sendTransactionProposalQuery(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org1") != -1).collect(Collectors.toList()), Matchers.is(200), Matchers.anything(), Matchers.anyOf(Matchers.is(ByteString.copyFrom("[\"Org1MSP\",\"Org2MSP\"]", StandardCharsets.UTF_8)),Matchers.is(ByteString.copyFrom("[\"Org2MSP\",\"Org1MSP\"]", StandardCharsets.UTF_8)))); + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val2" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - client.setUserContext(Utils.getUser1Org2TLS()); - proposal = generateSBECCTransactionRequest(client, "setval", mode, "val3"); - Utils.sendTransactionProposalInvoke(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org2") != -1).collect(Collectors.toList()), channel.getOrderers(), true); + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200 payload:\"val2\"")); - proposal = generateSBECCTransactionRequest(client, "getval", mode); - Utils.sendTransactionProposalQuery(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org2") != -1).collect(Collectors.toList()), Matchers.is(200), Matchers.anything(), Matchers.is(ByteString.copyFrom("val1", StandardCharsets.UTF_8))); + r = coreBuilder.duplicate().argsTx(new String[] { "addorgs", mode, "Org2MSP" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - proposal = generateSBECCTransactionRequest(client, "setval", mode, "val4"); - Utils.sendTransactionProposalInvoke(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0") != -1).collect(Collectors.toList()), channel.getOrderers()); + r = coreBuilder.duplicate().argsTx(new String[] { "listorgs", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200 payload:\"[\\\"Org2MSP\\\",\\\"Org1MSP\\\"]\"")); - client.setUserContext(Utils.getUser1Org1TLS()); - proposal = generateSBECCTransactionRequest(client, "getval", mode); - Utils.sendTransactionProposalQuery(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org1") != -1).collect(Collectors.toList()), Matchers.is(200), Matchers.anything(), Matchers.is(ByteString.copyFrom("val4", StandardCharsets.UTF_8))); - client.setUserContext(Utils.getUser1Org2TLS()); - proposal = generateSBECCTransactionRequest(client, "delorgs", mode, "Org1MSP"); - Utils.sendTransactionProposalInvoke(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org2") != -1).collect(Collectors.toList()), channel.getOrderers(), true); + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val3" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - proposal = generateSBECCTransactionRequest(client, "listorgs", mode); - Utils.sendTransactionProposalQuery(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org2") != -1).collect(Collectors.toList()), Matchers.is(200), Matchers.anything(), Matchers.anyOf(Matchers.is(ByteString.copyFrom("[\"Org1MSP\",\"Org2MSP\"]", StandardCharsets.UTF_8)),Matchers.is(ByteString.copyFrom("[\"Org2MSP\",\"Org1MSP\"]", StandardCharsets.UTF_8)))); + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200 payload:\"val3\"")); - proposal = generateSBECCTransactionRequest(client, "delorgs", mode, "Org1MSP"); - Utils.sendTransactionProposalInvoke(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0") != -1).collect(Collectors.toList()), channel.getOrderers()); + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val4" }).build().run(true); + assertThat(filter(r.stderr),text, containsString("result: status:200")); - proposal = generateSBECCTransactionRequest(client, "listorgs", mode); - Utils.sendTransactionProposalQuery(proposal, channel, channel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org2") != -1).collect(Collectors.toList()), Matchers.is(200), Matchers.anything(), Matchers.is(ByteString.copyFrom("[\"Org2MSP\"]", StandardCharsets.UTF_8))); + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200 payload:\"val4\"")); - } + r = coreBuilder.duplicate().argsTx(new String[] { "delorgs", mode, "Org1MSP" }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200")); - private InstallProposalRequest generateSBECCInstallRequest(HFClient client) throws IOException, InvalidArgumentException { - return Utils.generateInstallRequest(client, "sbecc", "1.0", "../fabric-chaincode-example-sbe"); - } + r = coreBuilder.duplicate().argsTx(new String[] { "listorgs", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200 payload:\"[\\\"Org2MSP\\\"]\"")); - static public InstantiateProposalRequest generateSBECCInstantiateRequest(HFClient client) throws InvalidArgumentException, IOException, ChaincodeEndorsementPolicyParseException, ChaincodeCollectionConfigurationException { - return Utils.generateInstantiateRequest(client, "sbecc", "1.0", "src/test/resources/chaincodeendorsementpolicy_2orgs.yaml", "src/test/resources/collection_config.yaml", "init", new String[]{}); } - static public TransactionProposalRequest generateSBECCTransactionRequest(HFClient client, String func, String... args) { - return Utils.generateTransactionRequest(client, "sbecc", "1.0", func, args); - } } diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Utils.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Utils.java deleted file mode 100644 index fea47893..00000000 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Utils.java +++ /dev/null @@ -1,577 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ -package org.hyperleder.fabric.shim.integration; - -import com.github.dockerjava.api.model.Container; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.tar.TarArchiveEntry; -import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; -import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; -import org.hamcrest.Matcher; -import org.hamcrest.Matchers; -import org.hyperledger.fabric.sdk.*; -import org.hyperledger.fabric.sdk.exception.*; -import org.testcontainers.DockerClientFactory; - -import java.io.*; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.Security; -import java.security.spec.InvalidKeySpecException; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -public class Utils { - - static public User getUser(String name, String mspId, File privateKeyFile, File certificateFile) - throws IOException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException { - - try { - - final String certificate = new String(IOUtils.toByteArray(new FileInputStream(certificateFile)), "UTF-8"); - - final PrivateKey privateKey = getPrivateKeyFromBytes(IOUtils.toByteArray(new FileInputStream(privateKeyFile))); - - User user = new User() { - - @Override - public String getName() { - return name; - } - - @Override - public Set getRoles() { - return null; - } - - @Override - public String getAccount() { - return null; - } - - @Override - public String getAffiliation() { - return null; - } - - @Override - public Enrollment getEnrollment() { - return new Enrollment() { - - @Override - public PrivateKey getKey() { - return privateKey; - } - - @Override - public String getCert() { - return certificate; - } - }; - } - - @Override - public String getMspId() { - return mspId; - } - - }; - - return user; - } catch (IOException e) { - e.printStackTrace(); - throw e; - - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - throw e; - } catch (NoSuchProviderException e) { - e.printStackTrace(); - throw e; - } catch (InvalidKeySpecException e) { - e.printStackTrace(); - throw e; - } catch (ClassCastException e) { - e.printStackTrace(); - throw e; - } - - } - - static PrivateKey getPrivateKeyFromBytes(byte[] data) - throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException { - final Reader pemReader = new StringReader(new String(data)); - - final PrivateKeyInfo pemPair; - try (PEMParser pemParser = new PEMParser(pemReader)) { - pemPair = (PrivateKeyInfo) pemParser.readObject(); - } - - PrivateKey privateKey = new JcaPEMKeyConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME) - .getPrivateKey(pemPair); - - return privateKey; - } - - public static InputStream generateTarGzInputStream(File src, String pathPrefix) throws IOException { - File sourceDirectory = src; - - ByteArrayOutputStream bos = new ByteArrayOutputStream(500000); - - String sourcePath = sourceDirectory.getAbsolutePath(); - - TarArchiveOutputStream archiveOutputStream = new TarArchiveOutputStream(new GzipCompressorOutputStream(new BufferedOutputStream(bos))); - archiveOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); - - try { - Collection childrenFiles = org.apache.commons.io.FileUtils.listFiles(sourceDirectory, null, true); - - ArchiveEntry archiveEntry; - FileInputStream fileInputStream; - for (File childFile : childrenFiles) { - String childPath = childFile.getAbsolutePath(); - String relativePath = childPath.substring((sourcePath.length() + 1), childPath.length()); - - if (pathPrefix != null) { - relativePath = org.hyperledger.fabric.sdk.helper.Utils.combinePaths(pathPrefix, relativePath); - } - - relativePath = FilenameUtils.separatorsToUnix(relativePath); - - archiveEntry = new TarArchiveEntry(childFile, relativePath); - fileInputStream = new FileInputStream(childFile); - archiveOutputStream.putArchiveEntry(archiveEntry); - - try { - IOUtils.copy(fileInputStream, archiveOutputStream); - } finally { - IOUtils.closeQuietly(fileInputStream); - archiveOutputStream.closeArchiveEntry(); - } - } - } finally { - IOUtils.closeQuietly(archiveOutputStream); - } - - return new ByteArrayInputStream(bos.toByteArray()); - } - - public static void runWithTimeout(Runnable callable, long timeout, TimeUnit timeUnit) throws Exception { - final ExecutorService executor = Executors.newSingleThreadExecutor(); - final CountDownLatch latch = new CountDownLatch(1); - Thread t = new Thread(() -> { - try { - callable.run(); - } finally { - latch.countDown(); - } - }); - try { - executor.execute(t); - if (!latch.await(timeout, timeUnit)) { - throw new TimeoutException(); - } - } finally { - executor.shutdown(); - t.interrupt(); - } - } - - - static public void waitForCliContainerExecution() throws InterruptedException { - for (int i = 0; i < 20; i++) { - AtomicBoolean foundCliContainer = new AtomicBoolean(false); - List containers = DockerClientFactory.instance().client().listContainersCmd().withShowAll(true).exec(); - containers.forEach(container -> { - for (String name : container.getNames()) { - if (name.indexOf("cli") != -1) { - if (container.getStatus().indexOf("Exited (0)") != -1) { - foundCliContainer.getAndSet(true); - break; - } - } - } - }); - if (foundCliContainer.get()) { - return; - } - TimeUnit.SECONDS.sleep(10); - } - } - - static public User getAdminUser() throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException, IOException { - // Loading admin user - System.out.println("Loading org1 admin from disk"); - - File userPrivateKeyFile = new File("src/test/resources/basic-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/276795ccedceb1d7923668307dcd9e124289c98b6e0a9731e71ba8d2193a7cce_sk"); - File userCertificateFile = new File("src/test/resources/basic-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"); - return getUser("peeradmin", "Org1MSP", userPrivateKeyFile, userCertificateFile); - } - - static public User getUser1() throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException, IOException { - // Loading admin user - System.out.println("Loading org1 admin from disk"); - - File userPrivateKeyFile = new File("src/test/resources/basic-network/crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/0cd56151db5d102e209b295f16b562dd2fba7a41988341cd4a783a9f0520855f_sk"); - File userCertificateFile = new File("src/test/resources/basic-network/crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/User1@org1.example.com-cert.pem"); - return getUser("peeruser1", "Org1MSP", userPrivateKeyFile, userCertificateFile); - } - - static public Channel getMyChannelBasicNetwork(HFClient client) throws InvalidArgumentException, TransactionException { - // Accessing channel, should already exist - System.out.println("Accessing channel"); - Channel myChannel = client.newChannel("mychannel"); - - System.out.println("Setting channel configuration"); - final List peers = new LinkedList<>(); - peers.add(client.newPeer("peer0.org1.example.com", "grpc://localhost:7051")); - - final List orderers = new LinkedList<>(); - orderers.add(client.newOrderer("orderer.example.com", "grpc://localhost:7050")); - - myChannel.addEventHub(client.newEventHub("peer0.org1.example.com", "grpc://localhost:7053")); - - for (Orderer orderer : orderers) { - myChannel.addOrderer(orderer); - } - - for (Peer peer : peers) { - myChannel.addPeer(peer); - } - myChannel.initialize(); - - return myChannel; - } - - public static void setUp() throws Exception { - try { - runWithTimeout(new Thread(() -> { - try { - waitForCliContainerExecution(); - } catch (InterruptedException e) { - - } - return; - } - ), 300, TimeUnit.SECONDS); - } catch (TimeoutException e) { - fail("Got timeout, while waiting for cli execution"); - } - - Security.addProvider(new BouncyCastleProvider()); - } - - - static public InstantiateProposalRequest generateInstantiateRequest(HFClient client, String chaincode, String version, String policyLocation, String collectionLocation, String function, String... args) throws InvalidArgumentException, IOException, ChaincodeEndorsementPolicyParseException, ChaincodeCollectionConfigurationException { - System.out.println("Instantiating chaincode: " + function + "(" + String.join(", ", args) + ")"); - final ChaincodeID chaincodeID = ChaincodeID.newBuilder() - .setName(chaincode) - .setVersion(version) - .build(); - - // Building proposal - System.out.println("Building instantiate proposal"); - InstantiateProposalRequest instantiateProposalRequest = client.newInstantiationProposalRequest(); - instantiateProposalRequest.setProposalWaitTime(120000); - instantiateProposalRequest.setChaincodeID(chaincodeID); - instantiateProposalRequest.setFcn(function); - instantiateProposalRequest.setChaincodeLanguage(TransactionRequest.Type.JAVA); - instantiateProposalRequest.setArgs(args); - if (collectionLocation != null) { - instantiateProposalRequest.setChaincodeCollectionConfiguration(ChaincodeCollectionConfiguration.fromYamlFile(new File(collectionLocation))); - } - Map tm = new HashMap<>(); - tm.put("HyperLedgerFabric", "InstantiateProposalRequest:JavaSDK".getBytes(UTF_8)); - tm.put("method", "InstantiateProposalRequest".getBytes(UTF_8)); - instantiateProposalRequest.setTransientMap(tm); - - ChaincodeEndorsementPolicy chaincodeEndorsementPolicy = new ChaincodeEndorsementPolicy(); - chaincodeEndorsementPolicy.fromYamlFile(new File(policyLocation)); - instantiateProposalRequest.setChaincodeEndorsementPolicy(chaincodeEndorsementPolicy); - - return instantiateProposalRequest; - } - - static public InstallProposalRequest generateInstallRequest(HFClient client, String chaincode, String version, String chaincodeLocation) throws IOException, InvalidArgumentException { - System.out.println("Creating install proposal for " + chaincode + " located at: " + chaincodeLocation); - final InstallProposalRequest installProposalRequest = client.newInstallProposalRequest(); - final ChaincodeID chaincodeID = ChaincodeID.newBuilder() - .setName(chaincode) - .setVersion(version) - .build(); - - installProposalRequest.setChaincodeID(chaincodeID); - installProposalRequest.setChaincodeLanguage(TransactionRequest.Type.JAVA); - installProposalRequest.setChaincodeInputStream(generateTarGzInputStream(new File(chaincodeLocation), "src")); - installProposalRequest.setChaincodeVersion(version); - - return installProposalRequest; - } - - static public TransactionProposalRequest generateTransactionRequest(HFClient client, String chaincode, String version, String function, String... args) { - System.out.println("Creating proposal for " + function + "(" + String.join(", ", args) + ")"); - final TransactionProposalRequest proposalRequest = client.newTransactionProposalRequest(); - - final ChaincodeID chaincodeID = ChaincodeID.newBuilder() - .setName(chaincode) - .setVersion(version) - .build(); - - proposalRequest.setChaincodeID(chaincodeID); - proposalRequest.setFcn(function); - proposalRequest.setProposalWaitTime(TimeUnit.SECONDS.toMillis(60)); - proposalRequest.setArgs(args); - - return proposalRequest; - } - - static public void sendInstallProposals(HFClient client, InstallProposalRequest installProposalRequest, Collection peers) throws InvalidArgumentException, ProposalException { - System.out.println("Sending install to peers: " + String.join(", ", peers.stream().map(p -> p.getName()).collect(Collectors.toList()))); - Collection installResponces = client.sendInstallProposal(installProposalRequest, peers); - - for (ProposalResponse response : installResponces) { - if (response.getStatus() != ProposalResponse.Status.SUCCESS) { - System.out.println("We have a problem, chaicode not installed: " + response.getMessage()); - fail("We have a problem, chaicode not installed: " + response.getMessage()); - } - } - - } - - static public void sendInstantiateProposal(String chaincode, InstantiateProposalRequest proposal, Channel channel, Collection peers, Collection orderers) throws ProposalException, InvalidArgumentException { - // Sending proposal - System.out.println("Sending instantiate to peers: " + String.join(", ", peers.stream().map(p -> p.getName()).collect(Collectors.toList()))); - Collection instantiationResponces = channel.sendInstantiationProposal(proposal, peers); - if (instantiationResponces == null || instantiationResponces.isEmpty()) { - System.out.println("We have a problem, no responses to instantiate request"); - fail("We have a problem, no responses to instantiate request"); - } - for (ProposalResponse response : instantiationResponces) { - if (response.getStatus() != ProposalResponse.Status.SUCCESS) { - System.out.println("We have a problem, chaicode not instantiated: " + response.getMessage()); - fail("We have a problem, chaicode not instantiated: " + response.getMessage()); - } - } - - // Sending result transaction to orderers - System.out.println("Sending instantiate transaction to orderers"); - - Channel.NOfEvents nofEvents = Channel.NOfEvents.createNofEvents(); - if (!peers.stream().filter(peer -> channel.getPeersOptions(peer).getPeerRoles().contains(Peer.PeerRole.EVENT_SOURCE)).collect(Collectors.toList()).isEmpty()) { - nofEvents.addPeers(peers.stream().filter(peer -> channel.getPeersOptions(peer).getPeerRoles().contains(Peer.PeerRole.EVENT_SOURCE)).collect(Collectors.toList())); - } - - CompletableFuture instantiateFuture = channel.sendTransaction(instantiationResponces, - Channel.TransactionOptions.createTransactionOptions() - .orderers(orderers) - .shuffleOrders(false) - .nOfEvents(nofEvents)); - try { - instantiateFuture.get(240000, TimeUnit.MILLISECONDS); - } catch (Exception e) { - System.out.println("We have problem waiting for transaction"); - fail("We have problem waiting for transaction send to orderers"); - } - - peers.forEach(peer -> { - try { - assertThat("Peer " + peer.getName() + " doesn't have chaincode javacc installed and instantiated", channel.queryInstantiatedChaincodes(peer).stream().map(ccInfo -> ccInfo.getName()).collect(Collectors.toList()), Matchers.contains(chaincode)); - } catch (Exception e) { - fail("Accessing instantiate chaincodes on peer " + peer.getName() + " resulted in exception " + e); - } - }); - } - - static public void sendTransactionProposalInvoke(TransactionProposalRequest proposal, Channel channel, Collection peers, Collection orderers) throws InvalidArgumentException, ProposalException { - sendTransactionProposalInvoke(proposal, channel, peers, orderers, false); - } - - static public void sendTransactionProposalInvoke(TransactionProposalRequest proposal, Channel channel, Collection peers, Collection orderers, boolean ignoreFailure) throws InvalidArgumentException, ProposalException { - // Send proposal and wait for responses - System.out.println("Sending proposal for " + proposal.getFcn() + "(" + String.join(", ", proposal.getArgs()) + ") to peers: " + String.join(", ", peers.stream().map(p -> p.getName()).collect(Collectors.toList()))); - final Collection responses = channel.sendTransactionProposal(proposal, peers); - - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - // Sending transaction to orderers - System.out.println("Sending transaction to orderes"); - - Channel.NOfEvents nofEvents = Channel.NOfEvents.createNofEvents(); - if (!peers.stream().filter(peer -> channel.getPeersOptions(peer).getPeerRoles().contains(Peer.PeerRole.EVENT_SOURCE)).collect(Collectors.toList()).isEmpty()) { - nofEvents.addPeers(peers.stream().filter(peer -> channel.getPeersOptions(peer).getPeerRoles().contains(Peer.PeerRole.EVENT_SOURCE)).collect(Collectors.toList())); - } - - CompletableFuture txFuture = channel.sendTransaction(responses, - Channel.TransactionOptions.createTransactionOptions() - .orderers(orderers) - .shuffleOrders(false) - .nOfEvents(nofEvents)); - - BlockEvent.TransactionEvent event = null; - try { - event = txFuture.get(50000, TimeUnit.MILLISECONDS); - } catch (Exception e) { - System.out.println("Exception " + e + " during wait"); - e.printStackTrace(); - if (!ignoreFailure) { - fail("Exception " + e + " during wait"); - } - } - - if (event == null) { - System.out.println("Something wrong, event is null"); - if (!ignoreFailure) { - fail("Something wrong, event is null"); - } - } - } - - static public void sendTransactionProposalQuery(TransactionProposalRequest proposal, Channel channel, Collection peers, Matcher statusMatcher, Matcher messageMatcher, Matcher payloadMatcher) throws InvalidArgumentException, ProposalException { - // Send proposal and wait for responses - System.out.println("Sending proposal for " + proposal.getFcn() + "(" + String.join(", ", proposal.getArgs()) + ") to peers: " + String.join(", ", peers.stream().map(p -> p.getName()).collect(Collectors.toList()))); - final Collection queryAResponses = channel.sendTransactionProposal(proposal,peers); - - for (ProposalResponse resp : queryAResponses) { - System.out.println("Response from peer " + resp.getPeer().getName() + " is: " + resp.getProposalResponse().getResponse().getStatus() + ": " + resp.getProposalResponse().getResponse().getMessage() + ": " + resp.getProposalResponse().getResponse().getPayload().toStringUtf8()); - if (statusMatcher != null) { - assertThat(resp.getProposalResponse().getResponse().getStatus(), statusMatcher); - // Matchers.is(200) - } - if (messageMatcher != null) { - assertThat(resp.getProposalResponse().getResponse().getMessage(), messageMatcher); - // Matchers.is("100") - } - - if (payloadMatcher != null) { - assertThat(resp.getProposalResponse().getResponse().getPayload(), payloadMatcher); - } - } - - } - - - - static public User getAdminUserOrg1TLS() throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException, IOException { - // Loading admin user - System.out.println("Loading org1 admin from disk"); - - File userPrivateKeyFile = new File("src/test/resources/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/23acbdca52b60346fb189be8846f5799b379fcd582bdde8230641ff2eb2ae883_sk"); - File userCertificateFile = new File("src/test/resources/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"); - return getUser("org1admin", "Org1MSP", userPrivateKeyFile, userCertificateFile); - } - - static public User getAdminUserOrg2TLS() throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException, IOException { - // Loading admin user - System.out.println("Loading org2 admin from disk"); - - File userPrivateKeyFile = new File("src/test/resources/first-network/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/73b84d0e0bb0c31d6eb40d6054811b2c7764059e95831bb0ed160f79f3a3794e_sk"); - File userCertificateFile = new File("src/test/resources/first-network/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts/Admin@org2.example.com-cert.pem"); - return getUser("org2admin", "Org2MSP", userPrivateKeyFile, userCertificateFile); - } - - static public User getUser1Org1TLS() throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException, IOException { - // Loading admin user - System.out.println("Loading org1 user1 from disk"); - - File userPrivateKeyFile = new File("src/test/resources/first-network/crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/06598da2a5c8268d5e09ff090136c411392fe5af949354b05a5bd8041ec1f8a5_sk"); - File userCertificateFile = new File("src/test/resources/first-network/crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/User1@org1.example.com-cert.pem"); - return getUser("org1user1", "Org1MSP", userPrivateKeyFile, userCertificateFile); - } - - static public User getUser1Org2TLS() throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException, IOException { - // Loading admin user - System.out.println("Loading org1 user1 from disk"); - - File userPrivateKeyFile = new File("src/test/resources/first-network/crypto-config/peerOrganizations/org2.example.com/users/User1@org2.example.com/msp/keystore/f0cbbe6fb24330132e15fd0f56296d497f9a450341b3d39a42d1d86ba3e285c4_sk"); - File userCertificateFile = new File("src/test/resources/first-network/crypto-config/peerOrganizations/org2.example.com/users/User1@org2.example.com/msp/signcerts/User1@org2.example.com-cert.pem"); - return getUser("org2user1", "Org2MSP", userPrivateKeyFile, userCertificateFile); - } - - static public Channel getMyChannelFirstNetwork(HFClient client) throws InvalidArgumentException, TransactionException, IOException { - // Accessing channel, should already exist - System.out.println("Accessing channel"); - Channel myChannel = client.newChannel("mychannel"); - - System.out.println("Setting channel configuration"); - final List peers = new LinkedList<>(); - Properties peer01Properties = new Properties(); - peer01Properties.setProperty("pemFile", getPEMCertFromFile("src/test/resources/first-network/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt")); - peer01Properties.setProperty("hostnameOverride", "peer0.org1.example.com"); - peer01Properties.setProperty("sslProvider", "openSSL"); - peer01Properties.setProperty("negotiationType", "TLS"); - peers.add(client.newPeer("peer0.org1.example.com", "grpcs://localhost:7051", peer01Properties)); - - Properties peer11Properties = new Properties(); - peer11Properties.setProperty("pemFile", getPEMCertFromFile("src/test/resources/first-network/crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/server.crt")); - peer11Properties.setProperty("hostnameOverride", "peer1.org1.example.com"); - peer11Properties.setProperty("sslProvider", "openSSL"); - peer11Properties.setProperty("negotiationType", "TLS"); - peers.add(client.newPeer("peer1.org1.example.com", "grpcs://localhost:8051", peer11Properties)); - - Properties peer02Properties = new Properties(); - peer02Properties.setProperty("pemFile", getPEMCertFromFile("src/test/resources/first-network/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.crt")); - peer02Properties.setProperty("hostnameOverride", "peer0.org2.example.com"); - peer02Properties.setProperty("sslProvider", "openSSL"); - peer02Properties.setProperty("negotiationType", "TLS"); - peers.add(client.newPeer("peer0.org2.example.com", "grpcs://localhost:9051", peer02Properties)); - - Properties peer12Properties = new Properties(); - peer12Properties.setProperty("pemFile", getPEMCertFromFile("src/test/resources/first-network/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/server.crt")); - peer12Properties.setProperty("hostnameOverride", "peer1.org2.example.com"); - peer12Properties.setProperty("sslProvider", "openSSL"); - peer12Properties.setProperty("negotiationType", "TLS"); - peers.add(client.newPeer("peer1.org2.example.com", "grpcs://localhost:10051", peer12Properties)); - - final List orderers = new LinkedList<>(); - Properties ordererProperties = new Properties(); - ordererProperties.setProperty("pemFile", getPEMCertFromFile("src/test/resources/first-network/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt")); - ordererProperties.setProperty("hostnameOverride", "orderer.example.com"); - ordererProperties.setProperty("sslProvider", "openSSL"); - ordererProperties.setProperty("negotiationType", "TLS"); - orderers.add(client.newOrderer("orderer.example.com", "grpcs://localhost:7050", ordererProperties)); - - for (Orderer orderer : orderers) { - myChannel.addOrderer(orderer); - } - - for (Peer peer : peers) { - myChannel.addPeer(peer); - } - myChannel.initialize(); - - return myChannel; - } - - private static String getPEMCertFromFile(String location) throws IOException { - File f = new File(location); - if (!f.exists()) { - f = new File(Utils.class.getClassLoader().getResource(location).getFile()); - if (!f.exists()) { - fail(); - } - } - - return f.getCanonicalPath(); - } - -} diff --git a/fabric-chaincode-integration-test/src/test/resources/first-network/base/docker-compose-base.yaml b/fabric-chaincode-integration-test/src/test/resources/first-network/base/docker-compose-base.yaml index 55cf94b7..92b58a50 100644 --- a/fabric-chaincode-integration-test/src/test/resources/first-network/base/docker-compose-base.yaml +++ b/fabric-chaincode-integration-test/src/test/resources/first-network/base/docker-compose-base.yaml @@ -9,7 +9,7 @@ services: orderer.example.com: container_name: orderer.example.com - image: hyperledger/fabric-orderer:latest + image: hyperledger/fabric-orderer:1.4.8 environment: - ORDERER_GENERAL_LOGLEVEL=INFO - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 @@ -18,7 +18,7 @@ services: - ORDERER_GENERAL_LOCALMSPID=OrdererMSP - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp # enabled TLS - - ORDERER_GENERAL_TLS_ENABLED=true + - ORDERER_GENERAL_TLS_ENABLED=false - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] diff --git a/fabric-chaincode-integration-test/src/test/resources/first-network/base/peer-base.yaml b/fabric-chaincode-integration-test/src/test/resources/first-network/base/peer-base.yaml index 29956f41..27a33687 100644 --- a/fabric-chaincode-integration-test/src/test/resources/first-network/base/peer-base.yaml +++ b/fabric-chaincode-integration-test/src/test/resources/first-network/base/peer-base.yaml @@ -7,22 +7,22 @@ version: '2' services: peer-base: - image: hyperledger/fabric-peer:latest + image: hyperledger/fabric-peer:1.4.8 environment: - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock # the following setting starts chaincode containers on the same # bridge network as the peers # https://docs.docker.com/compose/networking/ - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_byfn - - CORE_LOGGING_LEVEL=INFO - #- CORE_LOGGING_LEVEL=DEBUG - - CORE_PEER_TLS_ENABLED=true + - FABRIC_LOGGING_SPEC=INFO + - CORE_PEER_TLS_ENABLED=false - CORE_PEER_GOSSIP_USELEADERELECTION=true - CORE_PEER_GOSSIP_ORGLEADER=false - CORE_PEER_PROFILE_ENABLED=true - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt - - CORE_CHAINCODE_JAVA_RUNTIME=hyperledger/fabric-javaenv:amd64-1.4.2 + - CORE_CHAINCODE_JAVA_RUNTIME=hyperledger/fabric-javaenv:amd64-latest + - CORE_CHAINCODE_EXECUTETIMEOUT=300s working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: peer node start diff --git a/fabric-chaincode-integration-test/src/test/resources/first-network/docker-compose-cli.yaml b/fabric-chaincode-integration-test/src/test/resources/first-network/docker-compose-cli.yaml index cef9d109..398a4d22 100644 --- a/fabric-chaincode-integration-test/src/test/resources/first-network/docker-compose-cli.yaml +++ b/fabric-chaincode-integration-test/src/test/resources/first-network/docker-compose-cli.yaml @@ -59,29 +59,30 @@ services: cli: container_name: cli - image: hyperledger/fabric-tools:latest + image: hyperledger/fabric-tools:amd64-1.4.8 tty: true stdin_open: true environment: - GOPATH=/opt/gopath - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock - #- CORE_LOGGING_LEVEL=DEBUG - - CORE_LOGGING_LEVEL=INFO + - FABRIC_LOGGING_SPEC=INFO - CORE_PEER_ID=cli - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 - CORE_PEER_LOCALMSPID=Org1MSP - - CORE_PEER_TLS_ENABLED=true + - CORE_PEER_TLS_ENABLED=false - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer - command: scripts/script.sh + command: /bin/bash volumes: - /var/run/:/host/var/run/ - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/ - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts + - ./../../../contracts/fabric-chaincode-example-sacc:/opt/gopath/src/github.com/hyperledger/fabric/peer/chaincodes/sacc + - ./../../../contracts/fabric-chaincode-example-sbe:/opt/gopath/src/github.com/hyperledger/fabric/peer/chaincodes/sbe depends_on: - orderer.example.com - peer0.org1.example.com diff --git a/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/collection_config.json b/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/collection_config.json new file mode 100644 index 00000000..ef1971d3 --- /dev/null +++ b/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/collection_config.json @@ -0,0 +1,9 @@ +[ +{ + "name": "col", + "policy": "OR( OR('Org1MSP.member','Org1MSP.admin') , OR('Org2MSP.member','Org2MSP.admin') )", + "blockToLive": 100000, + "maxPeerCount": 2, + "requiredPeerCount": 2 +} +] diff --git a/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/script-sbe.sh b/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/script-sbe.sh new file mode 100755 index 00000000..2a83ac23 --- /dev/null +++ b/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/script-sbe.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +echo +echo "Install Instantiate the SBE Chaincode" +echo +CHANNEL_NAME="$1" +DELAY="$2" +LANGUAGE="$3" +TIMEOUT="$4" +VERBOSE="$5" +: ${CHANNEL_NAME:="mychannel"} +: ${DELAY:="10"} +: ${LANGUAGE:="java"} +: ${TIMEOUT:="10"} +: ${VERBOSE:="false"} +LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]` +COUNTER=1 +MAX_RETRY=10 +echo "Channel name : "$CHANNEL_NAME + +# import utils +. scripts/utils.sh + +CC_SRC_PATH="/opt/gopath/src/github.com/hyperledger/fabric/peer/chaincodes/sbe" +CC_NAME="sbecc" +COLLECTIONS_CFG=$(realpath scripts/collection_config.json) + +echo "Installing chaincode on peer 0, org 1" +installChaincode 0 1 +echo "Installing chaincode on peer 0, org 2" +installChaincode 0 2 + +echo "Instantiating chaincode on peer 0, org 1" +instantiateChaincodeSBE 0 1 + + +# exit 0 diff --git a/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/script.sh b/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/script.sh index 26b11896..6a5eaf2c 100755 --- a/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/script.sh +++ b/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/script.sh @@ -15,23 +15,13 @@ LANGUAGE="$3" TIMEOUT="$4" VERBOSE="$5" : ${CHANNEL_NAME:="mychannel"} -: ${DELAY:="3"} -: ${LANGUAGE:="golang"} +: ${DELAY:="10"} +: ${LANGUAGE:="java"} : ${TIMEOUT:="10"} : ${VERBOSE:="false"} LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]` COUNTER=1 MAX_RETRY=10 - -CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/" -if [ "$LANGUAGE" = "node" ]; then - CC_SRC_PATH="/opt/gopath/src/github.com/chaincode/chaincode_example02/node/" -fi - -if [ "$LANGUAGE" = "java" ]; then - CC_SRC_PATH="/opt/gopath/src/github.com/chaincode/chaincode_example02/java/" -fi - echo "Channel name : "$CHANNEL_NAME # import utils @@ -82,4 +72,29 @@ updateAnchorPeers 0 1 echo "Updating anchor peers for org2..." updateAnchorPeers 0 2 -exit 0 +CC_SRC_PATH="/opt/gopath/src/github.com/hyperledger/fabric/peer/chaincodes/sacc" +CC_NAME="javacc" + +echo "Installing chaincode ${CC_NAME} on peer 0, org 1" +installChaincode 0 1 +echo "Installing chaincode ${CC_NAME} on peer 0, org 2" +installChaincode 0 2 + +echo "Instantiating chaincode ${CC_NAME} on peer 0, org 1" +instantiateChaincode 0 1 + + + +CC_SRC_PATH="/opt/gopath/src/github.com/hyperledger/fabric/peer/chaincodes/sbe" +CC_NAME="sbecc" +COLLECTIONS_CFG=$(realpath scripts/collection_config.json) + +echo "Installing chaincode ${CC_NAME} on peer 0, org 1" +installChaincode 0 1 +echo "Installing chaincode ${CC_NAME} on peer 0, org 2" +installChaincode 0 2 + +echo "Instantiating chaincode ${CC_NAME} on peer 0, org 1" +instantiateChaincodeSBE 0 1 + +# exit 0 diff --git a/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/utils.sh b/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/utils.sh index 3b3820f1..f6670cd4 100755 --- a/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/utils.sh +++ b/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/utils.sh @@ -119,7 +119,7 @@ installChaincode() { setGlobals $PEER $ORG VERSION=${3:-1.0} set -x - peer chaincode install -n mycc -v ${VERSION} -l ${LANGUAGE} -p ${CC_SRC_PATH} >&log.txt + peer chaincode install -n ${CC_NAME} -v ${VERSION} -l ${LANGUAGE} -p ${CC_SRC_PATH} >&log.txt res=$? set +x cat log.txt @@ -128,7 +128,7 @@ installChaincode() { echo } -instantiateChaincode() { +instantiateChaincodeSBE() { PEER=$1 ORG=$2 setGlobals $PEER $ORG @@ -139,17 +139,60 @@ instantiateChaincode() { # the "-o" option if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then set -x - peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v ${VERSION} -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt + peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n ${CC_NAME} -l ${LANGUAGE} -v ${VERSION} -c '{"Args":["init"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')" --collections-config ${COLLECTIONS_CFG} >&log.txt res=$? set +x else set -x - peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt + peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n ${CC_NAME} -l ${LANGUAGE} -v 1.0 -c '{"Args":["init"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')" --collections-config ${COLLECTIONS_CFG} >&log.txt res=$? set +x fi cat log.txt verifyResult $res "Chaincode instantiation on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' failed" + sleep $DELAY + echo "===================== Chaincode is instantiated on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' ===================== " + echo +} + + +instantiateChaincode() { + PEER=$1 + ORG=$2 + setGlobals $PEER $ORG + VERSION=${3:-1.0} + + # while 'peer chaincode' command can get the orderer endpoint from the peer + # (if join was successful), let's supply it directly as we know it using + # the "-o" option + if [ -z "$COLLECTIONS_CFG" ]; then + if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then + set -x + peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n ${CC_NAME} -l ${LANGUAGE} -v ${VERSION} -c '{"Args":[]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt + res=$? + set +x + else + set -x + peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n javacc -l ${LANGUAGE} -v ${VERSION} -c '{"Args":[]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt + res=$? + set +x + fi + else + if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then + set -x + peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n ${CC_NAME} -l ${LANGUAGE} -v ${VERSION} -c '{"Args":[]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" --collections-config ${COLLECTIONS_CFG} >&log.txt + res=$? + set +x + else + set -x + peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n javacc -l ${LANGUAGE} -v ${VERSION} -c '{"Args":[]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" --collections-config ${COLLECTIONS_CFG} >&log.txt + res=$? + set +x + fi + fi + cat log.txt + verifyResult $res "Chaincode instantiation on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' failed" + sleep $DELAY echo "===================== Chaincode is instantiated on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' ===================== " echo } @@ -304,7 +347,7 @@ chaincodeInvoke() { # it using the "-o" option if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then set -x - peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc $PEER_CONN_PARMS -c '{"Args":["invoke","a","b","10"]}' >&log.txt + peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc $PEER_CONN_PARMS -c '{"Args":["set","a","10"]}' >&log.txt res=$? set +x else diff --git a/fabric-chaincode-protos/build.gradle b/fabric-chaincode-protos/build.gradle index 3f2f98e9..6183f1c7 100644 --- a/fabric-chaincode-protos/build.gradle +++ b/fabric-chaincode-protos/build.gradle @@ -17,7 +17,7 @@ repositories { } // Fabric branch to download proto files from -def fabricBranch = 'master' +def fabricBranch = 'release-1.4' // Fabric Github repository link def fabricRepo = 'https://raw.githubusercontent.com/hyperledger/fabric' def protosDir = 'src/main/protos' @@ -32,7 +32,9 @@ def protoFiles = ['protos/common/common.proto' : "$protosDir 'protos/msp/identities.proto' : "$protosDir/msp/identities.proto", 'protos/peer/transaction.proto' : "$protosDir/peer/transaction.proto", 'protos/msp/msp_principal.proto' : "$protosDir/msp/msp_principal.proto", - 'protos/common/policies.proto' : "$protosDir/common/policies.proto"] + 'protos/common/policies.proto' : "$protosDir/common/policies.proto", + 'protos/token/expectations.proto' : "$protosDir/token/expectations.proto", + 'protos/token/transaction.proto' : "$protosDir/token/transaction.proto"] buildscript { repositories { @@ -47,9 +49,11 @@ buildscript { dependencies { compile 'com.google.protobuf:protobuf-java:3.5.1' compile 'com.google.protobuf:protobuf-java-util:3.5.1' - compile 'io.grpc:grpc-netty:1.9.0' - compile 'io.grpc:grpc-protobuf:1.9.0' - compile 'io.grpc:grpc-stub:1.9.0' + compile 'io.grpc:grpc-netty:1.23.0' + compile 'io.grpc:grpc-protobuf:1.23.0' + compile 'io.grpc:grpc-stub:1.23.0' + // Required if using Java 11+ as no longer bundled in the core libraries + compile 'javax.annotation:javax.annotation-api:1.3.2' } protobuf { diff --git a/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/common/Common.java b/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/common/Common.java index 47624e1b..06c56a8a 100644 --- a/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/common/Common.java +++ b/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/common/Common.java @@ -454,12 +454,22 @@ public enum BlockMetadataIndex TRANSACTIONS_FILTER(2), /** *
-     * Block metadata array position to store operational metadata for orderers
+     * Block metadata array position to store operational metadata for orderers e.g. For Kafka,
+     *this is where we store the last offset written to the local ledger 
      * 
* * ORDERER = 3; */ ORDERER(3), + /** + *
+     * Block metadata array position to store the hash of TRANSACTIONS_FILTER, State Updates,
+     *and the COMMIT_HASH of the previous block 
+     * 
+ * + * COMMIT_HASH = 4; + */ + COMMIT_HASH(4), UNRECOGNIZED(-1), ; @@ -489,12 +499,22 @@ public enum BlockMetadataIndex public static final int TRANSACTIONS_FILTER_VALUE = 2; /** *
-     * Block metadata array position to store operational metadata for orderers
+     * Block metadata array position to store operational metadata for orderers e.g. For Kafka,
+     *this is where we store the last offset written to the local ledger 
      * 
* * ORDERER = 3; */ public static final int ORDERER_VALUE = 3; + /** + *
+     * Block metadata array position to store the hash of TRANSACTIONS_FILTER, State Updates,
+     *and the COMMIT_HASH of the previous block 
+     * 
+ * + * COMMIT_HASH = 4; + */ + public static final int COMMIT_HASH_VALUE = 4; public final int getNumber() { @@ -519,6 +539,7 @@ public static BlockMetadataIndex forNumber(int value) { case 1: return LAST_CONFIG; case 2: return TRANSACTIONS_FILTER; case 3: return ORDERER; + case 4: return COMMIT_HASH; default: return null; } } @@ -8786,6 +8807,640 @@ public org.hyperledger.fabric.protos.common.Common.BlockMetadata getDefaultInsta } + public interface OrdererBlockMetadataOrBuilder extends + // @@protoc_insertion_point(interface_extends:common.OrdererBlockMetadata) + com.google.protobuf.MessageOrBuilder { + + /** + * optional .common.LastConfig last_config = 1; + */ + boolean hasLastConfig(); + /** + * optional .common.LastConfig last_config = 1; + */ + org.hyperledger.fabric.protos.common.Common.LastConfig getLastConfig(); + /** + * optional .common.LastConfig last_config = 1; + */ + org.hyperledger.fabric.protos.common.Common.LastConfigOrBuilder getLastConfigOrBuilder(); + + /** + * optional bytes consenter_metadata = 2; + */ + com.google.protobuf.ByteString getConsenterMetadata(); + } + /** + *
+   * OrdererBlockMetadata defines metadata that is set by the ordering service.
+   * 
+ * + * Protobuf type {@code common.OrdererBlockMetadata} + */ + public static final class OrdererBlockMetadata extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:common.OrdererBlockMetadata) + OrdererBlockMetadataOrBuilder { + // Use OrdererBlockMetadata.newBuilder() to construct. + private OrdererBlockMetadata(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private OrdererBlockMetadata() { + consenterMetadata_ = com.google.protobuf.ByteString.EMPTY; + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private OrdererBlockMetadata( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + org.hyperledger.fabric.protos.common.Common.LastConfig.Builder subBuilder = null; + if (lastConfig_ != null) { + subBuilder = lastConfig_.toBuilder(); + } + lastConfig_ = input.readMessage(org.hyperledger.fabric.protos.common.Common.LastConfig.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(lastConfig_); + lastConfig_ = subBuilder.buildPartial(); + } + + break; + } + case 18: { + + consenterMetadata_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.common.Common.internal_static_common_OrdererBlockMetadata_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.common.Common.internal_static_common_OrdererBlockMetadata_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata.class, org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata.Builder.class); + } + + public static final int LAST_CONFIG_FIELD_NUMBER = 1; + private org.hyperledger.fabric.protos.common.Common.LastConfig lastConfig_; + /** + * optional .common.LastConfig last_config = 1; + */ + public boolean hasLastConfig() { + return lastConfig_ != null; + } + /** + * optional .common.LastConfig last_config = 1; + */ + public org.hyperledger.fabric.protos.common.Common.LastConfig getLastConfig() { + return lastConfig_ == null ? org.hyperledger.fabric.protos.common.Common.LastConfig.getDefaultInstance() : lastConfig_; + } + /** + * optional .common.LastConfig last_config = 1; + */ + public org.hyperledger.fabric.protos.common.Common.LastConfigOrBuilder getLastConfigOrBuilder() { + return getLastConfig(); + } + + public static final int CONSENTER_METADATA_FIELD_NUMBER = 2; + private com.google.protobuf.ByteString consenterMetadata_; + /** + * optional bytes consenter_metadata = 2; + */ + public com.google.protobuf.ByteString getConsenterMetadata() { + return consenterMetadata_; + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (lastConfig_ != null) { + output.writeMessage(1, getLastConfig()); + } + if (!consenterMetadata_.isEmpty()) { + output.writeBytes(2, consenterMetadata_); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (lastConfig_ != null) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, getLastConfig()); + } + if (!consenterMetadata_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, consenterMetadata_); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata other = (org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata) obj; + + boolean result = true; + result = result && (hasLastConfig() == other.hasLastConfig()); + if (hasLastConfig()) { + result = result && getLastConfig() + .equals(other.getLastConfig()); + } + result = result && getConsenterMetadata() + .equals(other.getConsenterMetadata()); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + if (hasLastConfig()) { + hash = (37 * hash) + LAST_CONFIG_FIELD_NUMBER; + hash = (53 * hash) + getLastConfig().hashCode(); + } + hash = (37 * hash) + CONSENTER_METADATA_FIELD_NUMBER; + hash = (53 * hash) + getConsenterMetadata().hashCode(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * OrdererBlockMetadata defines metadata that is set by the ordering service.
+     * 
+ * + * Protobuf type {@code common.OrdererBlockMetadata} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:common.OrdererBlockMetadata) + org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadataOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.common.Common.internal_static_common_OrdererBlockMetadata_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.common.Common.internal_static_common_OrdererBlockMetadata_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata.class, org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + public Builder clear() { + super.clear(); + if (lastConfigBuilder_ == null) { + lastConfig_ = null; + } else { + lastConfig_ = null; + lastConfigBuilder_ = null; + } + consenterMetadata_ = com.google.protobuf.ByteString.EMPTY; + + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.common.Common.internal_static_common_OrdererBlockMetadata_descriptor; + } + + public org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata build() { + org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata buildPartial() { + org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata result = new org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata(this); + if (lastConfigBuilder_ == null) { + result.lastConfig_ = lastConfig_; + } else { + result.lastConfig_ = lastConfigBuilder_.build(); + } + result.consenterMetadata_ = consenterMetadata_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata) { + return mergeFrom((org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata other) { + if (other == org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata.getDefaultInstance()) return this; + if (other.hasLastConfig()) { + mergeLastConfig(other.getLastConfig()); + } + if (other.getConsenterMetadata() != com.google.protobuf.ByteString.EMPTY) { + setConsenterMetadata(other.getConsenterMetadata()); + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private org.hyperledger.fabric.protos.common.Common.LastConfig lastConfig_ = null; + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.common.Common.LastConfig, org.hyperledger.fabric.protos.common.Common.LastConfig.Builder, org.hyperledger.fabric.protos.common.Common.LastConfigOrBuilder> lastConfigBuilder_; + /** + * optional .common.LastConfig last_config = 1; + */ + public boolean hasLastConfig() { + return lastConfigBuilder_ != null || lastConfig_ != null; + } + /** + * optional .common.LastConfig last_config = 1; + */ + public org.hyperledger.fabric.protos.common.Common.LastConfig getLastConfig() { + if (lastConfigBuilder_ == null) { + return lastConfig_ == null ? org.hyperledger.fabric.protos.common.Common.LastConfig.getDefaultInstance() : lastConfig_; + } else { + return lastConfigBuilder_.getMessage(); + } + } + /** + * optional .common.LastConfig last_config = 1; + */ + public Builder setLastConfig(org.hyperledger.fabric.protos.common.Common.LastConfig value) { + if (lastConfigBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + lastConfig_ = value; + onChanged(); + } else { + lastConfigBuilder_.setMessage(value); + } + + return this; + } + /** + * optional .common.LastConfig last_config = 1; + */ + public Builder setLastConfig( + org.hyperledger.fabric.protos.common.Common.LastConfig.Builder builderForValue) { + if (lastConfigBuilder_ == null) { + lastConfig_ = builderForValue.build(); + onChanged(); + } else { + lastConfigBuilder_.setMessage(builderForValue.build()); + } + + return this; + } + /** + * optional .common.LastConfig last_config = 1; + */ + public Builder mergeLastConfig(org.hyperledger.fabric.protos.common.Common.LastConfig value) { + if (lastConfigBuilder_ == null) { + if (lastConfig_ != null) { + lastConfig_ = + org.hyperledger.fabric.protos.common.Common.LastConfig.newBuilder(lastConfig_).mergeFrom(value).buildPartial(); + } else { + lastConfig_ = value; + } + onChanged(); + } else { + lastConfigBuilder_.mergeFrom(value); + } + + return this; + } + /** + * optional .common.LastConfig last_config = 1; + */ + public Builder clearLastConfig() { + if (lastConfigBuilder_ == null) { + lastConfig_ = null; + onChanged(); + } else { + lastConfig_ = null; + lastConfigBuilder_ = null; + } + + return this; + } + /** + * optional .common.LastConfig last_config = 1; + */ + public org.hyperledger.fabric.protos.common.Common.LastConfig.Builder getLastConfigBuilder() { + + onChanged(); + return getLastConfigFieldBuilder().getBuilder(); + } + /** + * optional .common.LastConfig last_config = 1; + */ + public org.hyperledger.fabric.protos.common.Common.LastConfigOrBuilder getLastConfigOrBuilder() { + if (lastConfigBuilder_ != null) { + return lastConfigBuilder_.getMessageOrBuilder(); + } else { + return lastConfig_ == null ? + org.hyperledger.fabric.protos.common.Common.LastConfig.getDefaultInstance() : lastConfig_; + } + } + /** + * optional .common.LastConfig last_config = 1; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.common.Common.LastConfig, org.hyperledger.fabric.protos.common.Common.LastConfig.Builder, org.hyperledger.fabric.protos.common.Common.LastConfigOrBuilder> + getLastConfigFieldBuilder() { + if (lastConfigBuilder_ == null) { + lastConfigBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.common.Common.LastConfig, org.hyperledger.fabric.protos.common.Common.LastConfig.Builder, org.hyperledger.fabric.protos.common.Common.LastConfigOrBuilder>( + getLastConfig(), + getParentForChildren(), + isClean()); + lastConfig_ = null; + } + return lastConfigBuilder_; + } + + private com.google.protobuf.ByteString consenterMetadata_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes consenter_metadata = 2; + */ + public com.google.protobuf.ByteString getConsenterMetadata() { + return consenterMetadata_; + } + /** + * optional bytes consenter_metadata = 2; + */ + public Builder setConsenterMetadata(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + + consenterMetadata_ = value; + onChanged(); + return this; + } + /** + * optional bytes consenter_metadata = 2; + */ + public Builder clearConsenterMetadata() { + + consenterMetadata_ = getDefaultInstance().getConsenterMetadata(); + onChanged(); + return this; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:common.OrdererBlockMetadata) + } + + // @@protoc_insertion_point(class_scope:common.OrdererBlockMetadata) + private static final org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata(); + } + + public static org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public OrdererBlockMetadata parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new OrdererBlockMetadata(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.common.Common.OrdererBlockMetadata getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + private static final com.google.protobuf.Descriptors.Descriptor internal_static_common_LastConfig_descriptor; private static final @@ -8846,6 +9501,11 @@ public org.hyperledger.fabric.protos.common.Common.BlockMetadata getDefaultInsta private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_common_BlockMetadata_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_common_OrdererBlockMetadata_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_common_OrdererBlockMetadata_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { @@ -8877,21 +9537,24 @@ public org.hyperledger.fabric.protos.common.Common.BlockMetadata getDefaultInsta "lockHeader\022\016\n\006number\030\001 \001(\004\022\025\n\rprevious_h", "ash\030\002 \001(\014\022\021\n\tdata_hash\030\003 \001(\014\"\031\n\tBlockDat" + "a\022\014\n\004data\030\001 \003(\014\"!\n\rBlockMetadata\022\020\n\010meta" + - "data\030\001 \003(\014*\300\001\n\006Status\022\013\n\007UNKNOWN\020\000\022\014\n\007SU" + - "CCESS\020\310\001\022\020\n\013BAD_REQUEST\020\220\003\022\016\n\tFORBIDDEN\020" + - "\223\003\022\016\n\tNOT_FOUND\020\224\003\022\035\n\030REQUEST_ENTITY_TOO" + - "_LARGE\020\235\003\022\032\n\025INTERNAL_SERVER_ERROR\020\364\003\022\024\n" + - "\017NOT_IMPLEMENTED\020\365\003\022\030\n\023SERVICE_UNAVAILAB" + - "LE\020\367\003*\312\001\n\nHeaderType\022\013\n\007MESSAGE\020\000\022\n\n\006CON" + - "FIG\020\001\022\021\n\rCONFIG_UPDATE\020\002\022\030\n\024ENDORSER_TRA" + - "NSACTION\020\003\022\027\n\023ORDERER_TRANSACTION\020\004\022\025\n\021D", - "ELIVER_SEEK_INFO\020\005\022\025\n\021CHAINCODE_PACKAGE\020" + - "\006\022\030\n\024PEER_ADMIN_OPERATION\020\010\022\025\n\021TOKEN_TRA" + - "NSACTION\020\t*[\n\022BlockMetadataIndex\022\016\n\nSIGN" + - "ATURES\020\000\022\017\n\013LAST_CONFIG\020\001\022\027\n\023TRANSACTION" + - "S_FILTER\020\002\022\013\n\007ORDERER\020\003BS\n$org.hyperledg" + - "er.fabric.protos.commonZ+github.com/hype" + - "rledger/fabric/protos/commonb\006proto3" + "data\030\001 \003(\014\"[\n\024OrdererBlockMetadata\022\'\n\013la" + + "st_config\030\001 \001(\0132\022.common.LastConfig\022\032\n\022c" + + "onsenter_metadata\030\002 \001(\014*\300\001\n\006Status\022\013\n\007UN" + + "KNOWN\020\000\022\014\n\007SUCCESS\020\310\001\022\020\n\013BAD_REQUEST\020\220\003\022" + + "\016\n\tFORBIDDEN\020\223\003\022\016\n\tNOT_FOUND\020\224\003\022\035\n\030REQUE" + + "ST_ENTITY_TOO_LARGE\020\235\003\022\032\n\025INTERNAL_SERVE" + + "R_ERROR\020\364\003\022\024\n\017NOT_IMPLEMENTED\020\365\003\022\030\n\023SERV" + + "ICE_UNAVAILABLE\020\367\003*\312\001\n\nHeaderType\022\013\n\007MES", + "SAGE\020\000\022\n\n\006CONFIG\020\001\022\021\n\rCONFIG_UPDATE\020\002\022\030\n" + + "\024ENDORSER_TRANSACTION\020\003\022\027\n\023ORDERER_TRANS" + + "ACTION\020\004\022\025\n\021DELIVER_SEEK_INFO\020\005\022\025\n\021CHAIN" + + "CODE_PACKAGE\020\006\022\030\n\024PEER_ADMIN_OPERATION\020\010" + + "\022\025\n\021TOKEN_TRANSACTION\020\t*l\n\022BlockMetadata" + + "Index\022\016\n\nSIGNATURES\020\000\022\017\n\013LAST_CONFIG\020\001\022\027" + + "\n\023TRANSACTIONS_FILTER\020\002\022\013\n\007ORDERER\020\003\022\017\n\013" + + "COMMIT_HASH\020\004BS\n$org.hyperledger.fabric." + + "protos.commonZ+github.com/hyperledger/fa" + + "bric/protos/commonb\006proto3" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { @@ -8978,6 +9641,12 @@ public com.google.protobuf.ExtensionRegistry assignDescriptors( com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_common_BlockMetadata_descriptor, new java.lang.String[] { "Metadata", }); + internal_static_common_OrdererBlockMetadata_descriptor = + getDescriptor().getMessageTypes().get(12); + internal_static_common_OrdererBlockMetadata_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_common_OrdererBlockMetadata_descriptor, + new java.lang.String[] { "LastConfig", "ConsenterMetadata", }); com.google.protobuf.TimestampProto.getDescriptor(); } diff --git a/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/peer/ChaincodeShim.java b/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/peer/ChaincodeShim.java index 9c9e4a23..be173eff 100644 --- a/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/peer/ChaincodeShim.java +++ b/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/peer/ChaincodeShim.java @@ -334,6 +334,10 @@ public enum Type * PUT_STATE_METADATA = 21; */ PUT_STATE_METADATA(21), + /** + * GET_PRIVATE_DATA_HASH = 22; + */ + GET_PRIVATE_DATA_HASH(22), UNRECOGNIZED(-1), ; @@ -421,6 +425,10 @@ public enum Type * PUT_STATE_METADATA = 21; */ public static final int PUT_STATE_METADATA_VALUE = 21; + /** + * GET_PRIVATE_DATA_HASH = 22; + */ + public static final int GET_PRIVATE_DATA_HASH_VALUE = 22; public final int getNumber() { @@ -462,6 +470,7 @@ public static Type forNumber(int value) { case 19: return GET_HISTORY_FOR_KEY; case 20: return GET_STATE_METADATA; case 21: return PUT_STATE_METADATA; + case 22: return GET_PRIVATE_DATA_HASH; default: return null; } } @@ -12400,14 +12409,14 @@ public org.hyperledger.fabric.protos.peer.ChaincodeShim.StateMetadataResult getD java.lang.String[] descriptorData = { "\n\031peer/chaincode_shim.proto\022\006protos\032\032pee" + "r/chaincode_event.proto\032\023peer/proposal.p" + - "roto\032\037google/protobuf/timestamp.proto\"\366\004" + + "roto\032\037google/protobuf/timestamp.proto\"\221\005" + "\n\020ChaincodeMessage\022+\n\004type\030\001 \001(\0162\035.proto" + "s.ChaincodeMessage.Type\022-\n\ttimestamp\030\002 \001" + "(\0132\032.google.protobuf.Timestamp\022\017\n\007payloa" + "d\030\003 \001(\014\022\014\n\004txid\030\004 \001(\t\022(\n\010proposal\030\005 \001(\0132" + "\026.protos.SignedProposal\022/\n\017chaincode_eve" + "nt\030\006 \001(\0132\026.protos.ChaincodeEvent\022\022\n\nchan" + - "nel_id\030\007 \001(\t\"\367\002\n\004Type\022\r\n\tUNDEFINED\020\000\022\014\n\010", + "nel_id\030\007 \001(\t\"\222\003\n\004Type\022\r\n\tUNDEFINED\020\000\022\014\n\010", "REGISTER\020\001\022\016\n\nREGISTERED\020\002\022\010\n\004INIT\020\003\022\t\n\005" + "READY\020\004\022\017\n\013TRANSACTION\020\005\022\r\n\tCOMPLETED\020\006\022" + "\t\n\005ERROR\020\007\022\r\n\tGET_STATE\020\010\022\r\n\tPUT_STATE\020\t" + @@ -12416,35 +12425,36 @@ public org.hyperledger.fabric.protos.peer.ChaincodeShim.StateMetadataResult getD "ET_QUERY_RESULT\020\017\022\024\n\020QUERY_STATE_NEXT\020\020\022" + "\025\n\021QUERY_STATE_CLOSE\020\021\022\r\n\tKEEPALIVE\020\022\022\027\n" + "\023GET_HISTORY_FOR_KEY\020\023\022\026\n\022GET_STATE_META" + - "DATA\020\024\022\026\n\022PUT_STATE_METADATA\020\025\"+\n\010GetSta" + - "te\022\013\n\003key\030\001 \001(\t\022\022\n\ncollection\030\002 \001(\t\"3\n\020G", - "etStateMetadata\022\013\n\003key\030\001 \001(\t\022\022\n\ncollecti" + - "on\030\002 \001(\t\":\n\010PutState\022\013\n\003key\030\001 \001(\t\022\r\n\005val" + - "ue\030\002 \001(\014\022\022\n\ncollection\030\003 \001(\t\"\\\n\020PutState" + - "Metadata\022\013\n\003key\030\001 \001(\t\022\022\n\ncollection\030\003 \001(" + - "\t\022\'\n\010metadata\030\004 \001(\0132\025.protos.StateMetada" + - "ta\"+\n\010DelState\022\013\n\003key\030\001 \001(\t\022\022\n\ncollectio" + - "n\030\002 \001(\t\"Y\n\017GetStateByRange\022\020\n\010startKey\030\001" + - " \001(\t\022\016\n\006endKey\030\002 \001(\t\022\022\n\ncollection\030\003 \001(\t" + - "\022\020\n\010metadata\030\004 \001(\014\"E\n\016GetQueryResult\022\r\n\005" + - "query\030\001 \001(\t\022\022\n\ncollection\030\002 \001(\t\022\020\n\010metad", - "ata\030\003 \001(\014\"3\n\rQueryMetadata\022\020\n\010pageSize\030\001" + - " \001(\005\022\020\n\010bookmark\030\002 \001(\t\"\037\n\020GetHistoryForK" + - "ey\022\013\n\003key\030\001 \001(\t\"\034\n\016QueryStateNext\022\n\n\002id\030" + - "\001 \001(\t\"\035\n\017QueryStateClose\022\n\n\002id\030\001 \001(\t\"\'\n\020" + - "QueryResultBytes\022\023\n\013resultBytes\030\001 \001(\014\"j\n" + - "\rQueryResponse\022)\n\007results\030\001 \003(\0132\030.protos" + - ".QueryResultBytes\022\020\n\010has_more\030\002 \001(\010\022\n\n\002i" + - "d\030\003 \001(\t\022\020\n\010metadata\030\004 \001(\014\"H\n\025QueryRespon" + - "seMetadata\022\035\n\025fetched_records_count\030\001 \001(" + - "\005\022\020\n\010bookmark\030\002 \001(\t\"/\n\rStateMetadata\022\017\n\007", - "metakey\030\001 \001(\t\022\r\n\005value\030\002 \001(\014\"=\n\023StateMet" + - "adataResult\022&\n\007entries\030\001 \003(\0132\025.protos.St" + - "ateMetadata2X\n\020ChaincodeSupport\022D\n\010Regis" + - "ter\022\030.protos.ChaincodeMessage\032\030.protos.C" + - "haincodeMessage\"\000(\0010\001BO\n\"org.hyperledger" + - ".fabric.protos.peerZ)github.com/hyperled" + - "ger/fabric/protos/peerb\006proto3" + "DATA\020\024\022\026\n\022PUT_STATE_METADATA\020\025\022\031\n\025GET_PR" + + "IVATE_DATA_HASH\020\026\"+\n\010GetState\022\013\n\003key\030\001 \001", + "(\t\022\022\n\ncollection\030\002 \001(\t\"3\n\020GetStateMetada" + + "ta\022\013\n\003key\030\001 \001(\t\022\022\n\ncollection\030\002 \001(\t\":\n\010P" + + "utState\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\014\022\022\n\nc" + + "ollection\030\003 \001(\t\"\\\n\020PutStateMetadata\022\013\n\003k" + + "ey\030\001 \001(\t\022\022\n\ncollection\030\003 \001(\t\022\'\n\010metadata" + + "\030\004 \001(\0132\025.protos.StateMetadata\"+\n\010DelStat" + + "e\022\013\n\003key\030\001 \001(\t\022\022\n\ncollection\030\002 \001(\t\"Y\n\017Ge" + + "tStateByRange\022\020\n\010startKey\030\001 \001(\t\022\016\n\006endKe" + + "y\030\002 \001(\t\022\022\n\ncollection\030\003 \001(\t\022\020\n\010metadata\030" + + "\004 \001(\014\"E\n\016GetQueryResult\022\r\n\005query\030\001 \001(\t\022\022", + "\n\ncollection\030\002 \001(\t\022\020\n\010metadata\030\003 \001(\014\"3\n\r" + + "QueryMetadata\022\020\n\010pageSize\030\001 \001(\005\022\020\n\010bookm" + + "ark\030\002 \001(\t\"\037\n\020GetHistoryForKey\022\013\n\003key\030\001 \001" + + "(\t\"\034\n\016QueryStateNext\022\n\n\002id\030\001 \001(\t\"\035\n\017Quer" + + "yStateClose\022\n\n\002id\030\001 \001(\t\"\'\n\020QueryResultBy" + + "tes\022\023\n\013resultBytes\030\001 \001(\014\"j\n\rQueryRespons" + + "e\022)\n\007results\030\001 \003(\0132\030.protos.QueryResultB" + + "ytes\022\020\n\010has_more\030\002 \001(\010\022\n\n\002id\030\003 \001(\t\022\020\n\010me" + + "tadata\030\004 \001(\014\"H\n\025QueryResponseMetadata\022\035\n" + + "\025fetched_records_count\030\001 \001(\005\022\020\n\010bookmark", + "\030\002 \001(\t\"/\n\rStateMetadata\022\017\n\007metakey\030\001 \001(\t" + + "\022\r\n\005value\030\002 \001(\014\"=\n\023StateMetadataResult\022&" + + "\n\007entries\030\001 \003(\0132\025.protos.StateMetadata2X" + + "\n\020ChaincodeSupport\022D\n\010Register\022\030.protos." + + "ChaincodeMessage\032\030.protos.ChaincodeMessa" + + "ge\"\000(\0010\001BO\n\"org.hyperledger.fabric.proto" + + "s.peerZ)github.com/hyperledger/fabric/pr" + + "otos/peerb\006proto3" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { diff --git a/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/peer/ProposalPackage.java b/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/peer/ProposalPackage.java index c0bad491..84ecefc7 100644 --- a/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/peer/ProposalPackage.java +++ b/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/peer/ProposalPackage.java @@ -3043,6 +3043,34 @@ public interface ChaincodeActionOrBuilder extends * optional .protos.ChaincodeID chaincode_id = 4; */ org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeIDOrBuilder getChaincodeIdOrBuilder(); + + /** + *
+     * This field contains the token expectation generated by the chaincode
+     * executing this invocation
+     * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + boolean hasTokenExpectation(); + /** + *
+     * This field contains the token expectation generated by the chaincode
+     * executing this invocation
+     * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation getTokenExpectation(); + /** + *
+     * This field contains the token expectation generated by the chaincode
+     * executing this invocation
+     * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + org.hyperledger.fabric.protos.token.Expectations.TokenExpectationOrBuilder getTokenExpectationOrBuilder(); } /** *
@@ -3124,6 +3152,19 @@ private ChaincodeAction(
                 chaincodeId_ = subBuilder.buildPartial();
               }
 
+              break;
+            }
+            case 42: {
+              org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.Builder subBuilder = null;
+              if (tokenExpectation_ != null) {
+                subBuilder = tokenExpectation_.toBuilder();
+              }
+              tokenExpectation_ = input.readMessage(org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.parser(), extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(tokenExpectation_);
+                tokenExpectation_ = subBuilder.buildPartial();
+              }
+
               break;
             }
           }
@@ -3255,6 +3296,42 @@ public org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeIDOrBuilder getChai
       return getChaincodeId();
     }
 
+    public static final int TOKEN_EXPECTATION_FIELD_NUMBER = 5;
+    private org.hyperledger.fabric.protos.token.Expectations.TokenExpectation tokenExpectation_;
+    /**
+     * 
+     * This field contains the token expectation generated by the chaincode
+     * executing this invocation
+     * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + public boolean hasTokenExpectation() { + return tokenExpectation_ != null; + } + /** + *
+     * This field contains the token expectation generated by the chaincode
+     * executing this invocation
+     * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + public org.hyperledger.fabric.protos.token.Expectations.TokenExpectation getTokenExpectation() { + return tokenExpectation_ == null ? org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.getDefaultInstance() : tokenExpectation_; + } + /** + *
+     * This field contains the token expectation generated by the chaincode
+     * executing this invocation
+     * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + public org.hyperledger.fabric.protos.token.Expectations.TokenExpectationOrBuilder getTokenExpectationOrBuilder() { + return getTokenExpectation(); + } + private byte memoizedIsInitialized = -1; public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; @@ -3279,6 +3356,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) if (chaincodeId_ != null) { output.writeMessage(4, getChaincodeId()); } + if (tokenExpectation_ != null) { + output.writeMessage(5, getTokenExpectation()); + } } public int getSerializedSize() { @@ -3302,6 +3382,10 @@ public int getSerializedSize() { size += com.google.protobuf.CodedOutputStream .computeMessageSize(4, getChaincodeId()); } + if (tokenExpectation_ != null) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, getTokenExpectation()); + } memoizedSize = size; return size; } @@ -3332,6 +3416,11 @@ public boolean equals(final java.lang.Object obj) { result = result && getChaincodeId() .equals(other.getChaincodeId()); } + result = result && (hasTokenExpectation() == other.hasTokenExpectation()); + if (hasTokenExpectation()) { + result = result && getTokenExpectation() + .equals(other.getTokenExpectation()); + } return result; } @@ -3354,6 +3443,10 @@ public int hashCode() { hash = (37 * hash) + CHAINCODE_ID_FIELD_NUMBER; hash = (53 * hash) + getChaincodeId().hashCode(); } + if (hasTokenExpectation()) { + hash = (37 * hash) + TOKEN_EXPECTATION_FIELD_NUMBER; + hash = (53 * hash) + getTokenExpectation().hashCode(); + } hash = (29 * hash) + unknownFields.hashCode(); memoizedHashCode = hash; return hash; @@ -3493,6 +3586,12 @@ public Builder clear() { chaincodeId_ = null; chaincodeIdBuilder_ = null; } + if (tokenExpectationBuilder_ == null) { + tokenExpectation_ = null; + } else { + tokenExpectation_ = null; + tokenExpectationBuilder_ = null; + } return this; } @@ -3527,6 +3626,11 @@ public org.hyperledger.fabric.protos.peer.ProposalPackage.ChaincodeAction buildP } else { result.chaincodeId_ = chaincodeIdBuilder_.build(); } + if (tokenExpectationBuilder_ == null) { + result.tokenExpectation_ = tokenExpectation_; + } else { + result.tokenExpectation_ = tokenExpectationBuilder_.build(); + } onBuilt(); return result; } @@ -3580,6 +3684,9 @@ public Builder mergeFrom(org.hyperledger.fabric.protos.peer.ProposalPackage.Chai if (other.hasChaincodeId()) { mergeChaincodeId(other.getChaincodeId()); } + if (other.hasTokenExpectation()) { + mergeTokenExpectation(other.getTokenExpectation()); + } onChanged(); return this; } @@ -4035,6 +4142,168 @@ public org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeIDOrBuilder getChai } return chaincodeIdBuilder_; } + + private org.hyperledger.fabric.protos.token.Expectations.TokenExpectation tokenExpectation_ = null; + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation, org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.Builder, org.hyperledger.fabric.protos.token.Expectations.TokenExpectationOrBuilder> tokenExpectationBuilder_; + /** + *
+       * This field contains the token expectation generated by the chaincode
+       * executing this invocation
+       * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + public boolean hasTokenExpectation() { + return tokenExpectationBuilder_ != null || tokenExpectation_ != null; + } + /** + *
+       * This field contains the token expectation generated by the chaincode
+       * executing this invocation
+       * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + public org.hyperledger.fabric.protos.token.Expectations.TokenExpectation getTokenExpectation() { + if (tokenExpectationBuilder_ == null) { + return tokenExpectation_ == null ? org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.getDefaultInstance() : tokenExpectation_; + } else { + return tokenExpectationBuilder_.getMessage(); + } + } + /** + *
+       * This field contains the token expectation generated by the chaincode
+       * executing this invocation
+       * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + public Builder setTokenExpectation(org.hyperledger.fabric.protos.token.Expectations.TokenExpectation value) { + if (tokenExpectationBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + tokenExpectation_ = value; + onChanged(); + } else { + tokenExpectationBuilder_.setMessage(value); + } + + return this; + } + /** + *
+       * This field contains the token expectation generated by the chaincode
+       * executing this invocation
+       * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + public Builder setTokenExpectation( + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.Builder builderForValue) { + if (tokenExpectationBuilder_ == null) { + tokenExpectation_ = builderForValue.build(); + onChanged(); + } else { + tokenExpectationBuilder_.setMessage(builderForValue.build()); + } + + return this; + } + /** + *
+       * This field contains the token expectation generated by the chaincode
+       * executing this invocation
+       * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + public Builder mergeTokenExpectation(org.hyperledger.fabric.protos.token.Expectations.TokenExpectation value) { + if (tokenExpectationBuilder_ == null) { + if (tokenExpectation_ != null) { + tokenExpectation_ = + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.newBuilder(tokenExpectation_).mergeFrom(value).buildPartial(); + } else { + tokenExpectation_ = value; + } + onChanged(); + } else { + tokenExpectationBuilder_.mergeFrom(value); + } + + return this; + } + /** + *
+       * This field contains the token expectation generated by the chaincode
+       * executing this invocation
+       * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + public Builder clearTokenExpectation() { + if (tokenExpectationBuilder_ == null) { + tokenExpectation_ = null; + onChanged(); + } else { + tokenExpectation_ = null; + tokenExpectationBuilder_ = null; + } + + return this; + } + /** + *
+       * This field contains the token expectation generated by the chaincode
+       * executing this invocation
+       * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + public org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.Builder getTokenExpectationBuilder() { + + onChanged(); + return getTokenExpectationFieldBuilder().getBuilder(); + } + /** + *
+       * This field contains the token expectation generated by the chaincode
+       * executing this invocation
+       * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + public org.hyperledger.fabric.protos.token.Expectations.TokenExpectationOrBuilder getTokenExpectationOrBuilder() { + if (tokenExpectationBuilder_ != null) { + return tokenExpectationBuilder_.getMessageOrBuilder(); + } else { + return tokenExpectation_ == null ? + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.getDefaultInstance() : tokenExpectation_; + } + } + /** + *
+       * This field contains the token expectation generated by the chaincode
+       * executing this invocation
+       * 
+ * + * optional .protos.TokenExpectation token_expectation = 5; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation, org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.Builder, org.hyperledger.fabric.protos.token.Expectations.TokenExpectationOrBuilder> + getTokenExpectationFieldBuilder() { + if (tokenExpectationBuilder_ == null) { + tokenExpectationBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation, org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.Builder, org.hyperledger.fabric.protos.token.Expectations.TokenExpectationOrBuilder>( + getTokenExpectation(), + getParentForChildren(), + isClean()); + tokenExpectation_ = null; + } + return tokenExpectationBuilder_; + } public final Builder setUnknownFields( final com.google.protobuf.UnknownFieldSet unknownFields) { return this; @@ -4125,22 +4394,24 @@ public org.hyperledger.fabric.protos.peer.ProposalPackage.ChaincodeAction getDef java.lang.String[] descriptorData = { "\n\023peer/proposal.proto\022\006protos\032\024peer/chai" + "ncode.proto\032\034peer/proposal_response.prot" + - "o\";\n\016SignedProposal\022\026\n\016proposal_bytes\030\001 " + - "\001(\014\022\021\n\tsignature\030\002 \001(\014\">\n\010Proposal\022\016\n\006he" + - "ader\030\001 \001(\014\022\017\n\007payload\030\002 \001(\014\022\021\n\textension" + - "\030\003 \001(\014\"a\n\030ChaincodeHeaderExtension\022\032\n\022pa" + - "yload_visibility\030\001 \001(\014\022)\n\014chaincode_id\030\002" + - " \001(\0132\023.protos.ChaincodeID\"\250\001\n\030ChaincodeP" + - "roposalPayload\022\r\n\005input\030\001 \001(\014\022H\n\014Transie" + - "ntMap\030\002 \003(\01322.protos.ChaincodeProposalPa", - "yload.TransientMapEntry\0323\n\021TransientMapE" + - "ntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\014:\0028\001\"\201\001\n" + - "\017ChaincodeAction\022\017\n\007results\030\001 \001(\014\022\016\n\006eve" + - "nts\030\002 \001(\014\022\"\n\010response\030\003 \001(\0132\020.protos.Res" + - "ponse\022)\n\014chaincode_id\030\004 \001(\0132\023.protos.Cha" + - "incodeIDB`\n\"org.hyperledger.fabric.proto" + - "s.peerB\017ProposalPackageZ)github.com/hype" + - "rledger/fabric/protos/peerb\006proto3" + "o\032\030token/expectations.proto\";\n\016SignedPro" + + "posal\022\026\n\016proposal_bytes\030\001 \001(\014\022\021\n\tsignatu" + + "re\030\002 \001(\014\">\n\010Proposal\022\016\n\006header\030\001 \001(\014\022\017\n\007" + + "payload\030\002 \001(\014\022\021\n\textension\030\003 \001(\014\"a\n\030Chai" + + "ncodeHeaderExtension\022\032\n\022payload_visibili" + + "ty\030\001 \001(\014\022)\n\014chaincode_id\030\002 \001(\0132\023.protos." + + "ChaincodeID\"\250\001\n\030ChaincodeProposalPayload" + + "\022\r\n\005input\030\001 \001(\014\022H\n\014TransientMap\030\002 \003(\01322.", + "protos.ChaincodeProposalPayload.Transien" + + "tMapEntry\0323\n\021TransientMapEntry\022\013\n\003key\030\001 " + + "\001(\t\022\r\n\005value\030\002 \001(\014:\0028\001\"\266\001\n\017ChaincodeActi" + + "on\022\017\n\007results\030\001 \001(\014\022\016\n\006events\030\002 \001(\014\022\"\n\010r" + + "esponse\030\003 \001(\0132\020.protos.Response\022)\n\014chain" + + "code_id\030\004 \001(\0132\023.protos.ChaincodeID\0223\n\021to" + + "ken_expectation\030\005 \001(\0132\030.protos.TokenExpe" + + "ctationB`\n\"org.hyperledger.fabric.protos" + + ".peerB\017ProposalPackageZ)github.com/hyper" + + "ledger/fabric/protos/peerb\006proto3" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { @@ -4155,6 +4426,7 @@ public com.google.protobuf.ExtensionRegistry assignDescriptors( new com.google.protobuf.Descriptors.FileDescriptor[] { org.hyperledger.fabric.protos.peer.Chaincode.getDescriptor(), org.hyperledger.fabric.protos.peer.ProposalResponsePackage.getDescriptor(), + org.hyperledger.fabric.protos.token.Expectations.getDescriptor(), }, assigner); internal_static_protos_SignedProposal_descriptor = getDescriptor().getMessageTypes().get(0); @@ -4191,9 +4463,10 @@ public com.google.protobuf.ExtensionRegistry assignDescriptors( internal_static_protos_ChaincodeAction_fieldAccessorTable = new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_protos_ChaincodeAction_descriptor, - new java.lang.String[] { "Results", "Events", "Response", "ChaincodeId", }); + new java.lang.String[] { "Results", "Events", "Response", "ChaincodeId", "TokenExpectation", }); org.hyperledger.fabric.protos.peer.Chaincode.getDescriptor(); org.hyperledger.fabric.protos.peer.ProposalResponsePackage.getDescriptor(); + org.hyperledger.fabric.protos.token.Expectations.getDescriptor(); } // @@protoc_insertion_point(outer_class_scope) diff --git a/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/token/Expectations.java b/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/token/Expectations.java new file mode 100644 index 00000000..a545b6fc --- /dev/null +++ b/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/token/Expectations.java @@ -0,0 +1,2584 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: token/expectations.proto + +package org.hyperledger.fabric.protos.token; + +public final class Expectations { + private Expectations() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + public interface TokenExpectationOrBuilder extends + // @@protoc_insertion_point(interface_extends:protos.TokenExpectation) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * PlainExpectation describes a plain token expectation
+     * 
+ * + * optional .protos.PlainExpectation plain_expectation = 1; + */ + org.hyperledger.fabric.protos.token.Expectations.PlainExpectation getPlainExpectation(); + /** + *
+     * PlainExpectation describes a plain token expectation
+     * 
+ * + * optional .protos.PlainExpectation plain_expectation = 1; + */ + org.hyperledger.fabric.protos.token.Expectations.PlainExpectationOrBuilder getPlainExpectationOrBuilder(); + + public org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.ExpectationCase getExpectationCase(); + } + /** + *
+   * TokenExpectation represent the belief that someone should achieve in terms of a token action
+   * 
+ * + * Protobuf type {@code protos.TokenExpectation} + */ + public static final class TokenExpectation extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:protos.TokenExpectation) + TokenExpectationOrBuilder { + // Use TokenExpectation.newBuilder() to construct. + private TokenExpectation(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private TokenExpectation() { + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private TokenExpectation( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.Builder subBuilder = null; + if (expectationCase_ == 1) { + subBuilder = ((org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) expectation_).toBuilder(); + } + expectation_ = + input.readMessage(org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom((org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) expectation_); + expectation_ = subBuilder.buildPartial(); + } + expectationCase_ = 1; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_TokenExpectation_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_TokenExpectation_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.class, org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.Builder.class); + } + + private int expectationCase_ = 0; + private java.lang.Object expectation_; + public enum ExpectationCase + implements com.google.protobuf.Internal.EnumLite { + PLAIN_EXPECTATION(1), + EXPECTATION_NOT_SET(0); + private final int value; + private ExpectationCase(int value) { + this.value = value; + } + /** + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static ExpectationCase valueOf(int value) { + return forNumber(value); + } + + public static ExpectationCase forNumber(int value) { + switch (value) { + case 1: return PLAIN_EXPECTATION; + case 0: return EXPECTATION_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public ExpectationCase + getExpectationCase() { + return ExpectationCase.forNumber( + expectationCase_); + } + + public static final int PLAIN_EXPECTATION_FIELD_NUMBER = 1; + /** + *
+     * PlainExpectation describes a plain token expectation
+     * 
+ * + * optional .protos.PlainExpectation plain_expectation = 1; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainExpectation getPlainExpectation() { + if (expectationCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) expectation_; + } + return org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.getDefaultInstance(); + } + /** + *
+     * PlainExpectation describes a plain token expectation
+     * 
+ * + * optional .protos.PlainExpectation plain_expectation = 1; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainExpectationOrBuilder getPlainExpectationOrBuilder() { + if (expectationCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) expectation_; + } + return org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (expectationCase_ == 1) { + output.writeMessage(1, (org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) expectation_); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (expectationCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) expectation_); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.token.Expectations.TokenExpectation)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation other = (org.hyperledger.fabric.protos.token.Expectations.TokenExpectation) obj; + + boolean result = true; + result = result && getExpectationCase().equals( + other.getExpectationCase()); + if (!result) return false; + switch (expectationCase_) { + case 1: + result = result && getPlainExpectation() + .equals(other.getPlainExpectation()); + break; + case 0: + default: + } + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + switch (expectationCase_) { + case 1: + hash = (37 * hash) + PLAIN_EXPECTATION_FIELD_NUMBER; + hash = (53 * hash) + getPlainExpectation().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.token.Expectations.TokenExpectation parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Expectations.TokenExpectation parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Expectations.TokenExpectation parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Expectations.TokenExpectation parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Expectations.TokenExpectation parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Expectations.TokenExpectation parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Expectations.TokenExpectation parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Expectations.TokenExpectation parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Expectations.TokenExpectation parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Expectations.TokenExpectation parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.token.Expectations.TokenExpectation prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * TokenExpectation represent the belief that someone should achieve in terms of a token action
+     * 
+ * + * Protobuf type {@code protos.TokenExpectation} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:protos.TokenExpectation) + org.hyperledger.fabric.protos.token.Expectations.TokenExpectationOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_TokenExpectation_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_TokenExpectation_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.class, org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + public Builder clear() { + super.clear(); + expectationCase_ = 0; + expectation_ = null; + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_TokenExpectation_descriptor; + } + + public org.hyperledger.fabric.protos.token.Expectations.TokenExpectation getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.token.Expectations.TokenExpectation build() { + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.token.Expectations.TokenExpectation buildPartial() { + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation result = new org.hyperledger.fabric.protos.token.Expectations.TokenExpectation(this); + if (expectationCase_ == 1) { + if (plainExpectationBuilder_ == null) { + result.expectation_ = expectation_; + } else { + result.expectation_ = plainExpectationBuilder_.build(); + } + } + result.expectationCase_ = expectationCase_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.token.Expectations.TokenExpectation) { + return mergeFrom((org.hyperledger.fabric.protos.token.Expectations.TokenExpectation)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.token.Expectations.TokenExpectation other) { + if (other == org.hyperledger.fabric.protos.token.Expectations.TokenExpectation.getDefaultInstance()) return this; + switch (other.getExpectationCase()) { + case PLAIN_EXPECTATION: { + mergePlainExpectation(other.getPlainExpectation()); + break; + } + case EXPECTATION_NOT_SET: { + break; + } + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.token.Expectations.TokenExpectation parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.token.Expectations.TokenExpectation) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int expectationCase_ = 0; + private java.lang.Object expectation_; + public ExpectationCase + getExpectationCase() { + return ExpectationCase.forNumber( + expectationCase_); + } + + public Builder clearExpectation() { + expectationCase_ = 0; + expectation_ = null; + onChanged(); + return this; + } + + + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Expectations.PlainExpectation, org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.Builder, org.hyperledger.fabric.protos.token.Expectations.PlainExpectationOrBuilder> plainExpectationBuilder_; + /** + *
+       * PlainExpectation describes a plain token expectation
+       * 
+ * + * optional .protos.PlainExpectation plain_expectation = 1; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainExpectation getPlainExpectation() { + if (plainExpectationBuilder_ == null) { + if (expectationCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) expectation_; + } + return org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.getDefaultInstance(); + } else { + if (expectationCase_ == 1) { + return plainExpectationBuilder_.getMessage(); + } + return org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.getDefaultInstance(); + } + } + /** + *
+       * PlainExpectation describes a plain token expectation
+       * 
+ * + * optional .protos.PlainExpectation plain_expectation = 1; + */ + public Builder setPlainExpectation(org.hyperledger.fabric.protos.token.Expectations.PlainExpectation value) { + if (plainExpectationBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + expectation_ = value; + onChanged(); + } else { + plainExpectationBuilder_.setMessage(value); + } + expectationCase_ = 1; + return this; + } + /** + *
+       * PlainExpectation describes a plain token expectation
+       * 
+ * + * optional .protos.PlainExpectation plain_expectation = 1; + */ + public Builder setPlainExpectation( + org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.Builder builderForValue) { + if (plainExpectationBuilder_ == null) { + expectation_ = builderForValue.build(); + onChanged(); + } else { + plainExpectationBuilder_.setMessage(builderForValue.build()); + } + expectationCase_ = 1; + return this; + } + /** + *
+       * PlainExpectation describes a plain token expectation
+       * 
+ * + * optional .protos.PlainExpectation plain_expectation = 1; + */ + public Builder mergePlainExpectation(org.hyperledger.fabric.protos.token.Expectations.PlainExpectation value) { + if (plainExpectationBuilder_ == null) { + if (expectationCase_ == 1 && + expectation_ != org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.getDefaultInstance()) { + expectation_ = org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.newBuilder((org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) expectation_) + .mergeFrom(value).buildPartial(); + } else { + expectation_ = value; + } + onChanged(); + } else { + if (expectationCase_ == 1) { + plainExpectationBuilder_.mergeFrom(value); + } + plainExpectationBuilder_.setMessage(value); + } + expectationCase_ = 1; + return this; + } + /** + *
+       * PlainExpectation describes a plain token expectation
+       * 
+ * + * optional .protos.PlainExpectation plain_expectation = 1; + */ + public Builder clearPlainExpectation() { + if (plainExpectationBuilder_ == null) { + if (expectationCase_ == 1) { + expectationCase_ = 0; + expectation_ = null; + onChanged(); + } + } else { + if (expectationCase_ == 1) { + expectationCase_ = 0; + expectation_ = null; + } + plainExpectationBuilder_.clear(); + } + return this; + } + /** + *
+       * PlainExpectation describes a plain token expectation
+       * 
+ * + * optional .protos.PlainExpectation plain_expectation = 1; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.Builder getPlainExpectationBuilder() { + return getPlainExpectationFieldBuilder().getBuilder(); + } + /** + *
+       * PlainExpectation describes a plain token expectation
+       * 
+ * + * optional .protos.PlainExpectation plain_expectation = 1; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainExpectationOrBuilder getPlainExpectationOrBuilder() { + if ((expectationCase_ == 1) && (plainExpectationBuilder_ != null)) { + return plainExpectationBuilder_.getMessageOrBuilder(); + } else { + if (expectationCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) expectation_; + } + return org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.getDefaultInstance(); + } + } + /** + *
+       * PlainExpectation describes a plain token expectation
+       * 
+ * + * optional .protos.PlainExpectation plain_expectation = 1; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Expectations.PlainExpectation, org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.Builder, org.hyperledger.fabric.protos.token.Expectations.PlainExpectationOrBuilder> + getPlainExpectationFieldBuilder() { + if (plainExpectationBuilder_ == null) { + if (!(expectationCase_ == 1)) { + expectation_ = org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.getDefaultInstance(); + } + plainExpectationBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Expectations.PlainExpectation, org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.Builder, org.hyperledger.fabric.protos.token.Expectations.PlainExpectationOrBuilder>( + (org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) expectation_, + getParentForChildren(), + isClean()); + expectation_ = null; + } + expectationCase_ = 1; + onChanged();; + return plainExpectationBuilder_; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:protos.TokenExpectation) + } + + // @@protoc_insertion_point(class_scope:protos.TokenExpectation) + private static final org.hyperledger.fabric.protos.token.Expectations.TokenExpectation DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.token.Expectations.TokenExpectation(); + } + + public static org.hyperledger.fabric.protos.token.Expectations.TokenExpectation getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public TokenExpectation parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new TokenExpectation(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.token.Expectations.TokenExpectation getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface PlainExpectationOrBuilder extends + // @@protoc_insertion_point(interface_extends:protos.PlainExpectation) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * ImportExpectation describes an token import expectation
+     * 
+ * + * optional .protos.PlainTokenExpectation import_expectation = 1; + */ + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation getImportExpectation(); + /** + *
+     * ImportExpectation describes an token import expectation
+     * 
+ * + * optional .protos.PlainTokenExpectation import_expectation = 1; + */ + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder getImportExpectationOrBuilder(); + + /** + *
+     * TransferExpectation describes a token transfer expectation
+     * 
+ * + * optional .protos.PlainTokenExpectation transfer_expectation = 2; + */ + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation getTransferExpectation(); + /** + *
+     * TransferExpectation describes a token transfer expectation
+     * 
+ * + * optional .protos.PlainTokenExpectation transfer_expectation = 2; + */ + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder getTransferExpectationOrBuilder(); + + public org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.PayloadCase getPayloadCase(); + } + /** + *
+   * PlainExpectation represent the plain expectation where no confidentiality is provided.
+   * 
+ * + * Protobuf type {@code protos.PlainExpectation} + */ + public static final class PlainExpectation extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:protos.PlainExpectation) + PlainExpectationOrBuilder { + // Use PlainExpectation.newBuilder() to construct. + private PlainExpectation(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private PlainExpectation() { + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private PlainExpectation( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder subBuilder = null; + if (payloadCase_ == 1) { + subBuilder = ((org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_).toBuilder(); + } + payload_ = + input.readMessage(org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom((org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_); + payload_ = subBuilder.buildPartial(); + } + payloadCase_ = 1; + break; + } + case 18: { + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder subBuilder = null; + if (payloadCase_ == 2) { + subBuilder = ((org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_).toBuilder(); + } + payload_ = + input.readMessage(org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom((org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_); + payload_ = subBuilder.buildPartial(); + } + payloadCase_ = 2; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_PlainExpectation_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_PlainExpectation_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.class, org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.Builder.class); + } + + private int payloadCase_ = 0; + private java.lang.Object payload_; + public enum PayloadCase + implements com.google.protobuf.Internal.EnumLite { + IMPORT_EXPECTATION(1), + TRANSFER_EXPECTATION(2), + PAYLOAD_NOT_SET(0); + private final int value; + private PayloadCase(int value) { + this.value = value; + } + /** + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static PayloadCase valueOf(int value) { + return forNumber(value); + } + + public static PayloadCase forNumber(int value) { + switch (value) { + case 1: return IMPORT_EXPECTATION; + case 2: return TRANSFER_EXPECTATION; + case 0: return PAYLOAD_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public PayloadCase + getPayloadCase() { + return PayloadCase.forNumber( + payloadCase_); + } + + public static final int IMPORT_EXPECTATION_FIELD_NUMBER = 1; + /** + *
+     * ImportExpectation describes an token import expectation
+     * 
+ * + * optional .protos.PlainTokenExpectation import_expectation = 1; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation getImportExpectation() { + if (payloadCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_; + } + return org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } + /** + *
+     * ImportExpectation describes an token import expectation
+     * 
+ * + * optional .protos.PlainTokenExpectation import_expectation = 1; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder getImportExpectationOrBuilder() { + if (payloadCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_; + } + return org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } + + public static final int TRANSFER_EXPECTATION_FIELD_NUMBER = 2; + /** + *
+     * TransferExpectation describes a token transfer expectation
+     * 
+ * + * optional .protos.PlainTokenExpectation transfer_expectation = 2; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation getTransferExpectation() { + if (payloadCase_ == 2) { + return (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_; + } + return org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } + /** + *
+     * TransferExpectation describes a token transfer expectation
+     * 
+ * + * optional .protos.PlainTokenExpectation transfer_expectation = 2; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder getTransferExpectationOrBuilder() { + if (payloadCase_ == 2) { + return (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_; + } + return org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (payloadCase_ == 1) { + output.writeMessage(1, (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_); + } + if (payloadCase_ == 2) { + output.writeMessage(2, (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (payloadCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_); + } + if (payloadCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.token.Expectations.PlainExpectation)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.token.Expectations.PlainExpectation other = (org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) obj; + + boolean result = true; + result = result && getPayloadCase().equals( + other.getPayloadCase()); + if (!result) return false; + switch (payloadCase_) { + case 1: + result = result && getImportExpectation() + .equals(other.getImportExpectation()); + break; + case 2: + result = result && getTransferExpectation() + .equals(other.getTransferExpectation()); + break; + case 0: + default: + } + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + switch (payloadCase_) { + case 1: + hash = (37 * hash) + IMPORT_EXPECTATION_FIELD_NUMBER; + hash = (53 * hash) + getImportExpectation().hashCode(); + break; + case 2: + hash = (37 * hash) + TRANSFER_EXPECTATION_FIELD_NUMBER; + hash = (53 * hash) + getTransferExpectation().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.token.Expectations.PlainExpectation parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainExpectation parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainExpectation parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainExpectation parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainExpectation parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainExpectation parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainExpectation parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainExpectation parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainExpectation parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainExpectation parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.token.Expectations.PlainExpectation prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * PlainExpectation represent the plain expectation where no confidentiality is provided.
+     * 
+ * + * Protobuf type {@code protos.PlainExpectation} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:protos.PlainExpectation) + org.hyperledger.fabric.protos.token.Expectations.PlainExpectationOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_PlainExpectation_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_PlainExpectation_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.class, org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + public Builder clear() { + super.clear(); + payloadCase_ = 0; + payload_ = null; + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_PlainExpectation_descriptor; + } + + public org.hyperledger.fabric.protos.token.Expectations.PlainExpectation getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.token.Expectations.PlainExpectation build() { + org.hyperledger.fabric.protos.token.Expectations.PlainExpectation result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.token.Expectations.PlainExpectation buildPartial() { + org.hyperledger.fabric.protos.token.Expectations.PlainExpectation result = new org.hyperledger.fabric.protos.token.Expectations.PlainExpectation(this); + if (payloadCase_ == 1) { + if (importExpectationBuilder_ == null) { + result.payload_ = payload_; + } else { + result.payload_ = importExpectationBuilder_.build(); + } + } + if (payloadCase_ == 2) { + if (transferExpectationBuilder_ == null) { + result.payload_ = payload_; + } else { + result.payload_ = transferExpectationBuilder_.build(); + } + } + result.payloadCase_ = payloadCase_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) { + return mergeFrom((org.hyperledger.fabric.protos.token.Expectations.PlainExpectation)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.token.Expectations.PlainExpectation other) { + if (other == org.hyperledger.fabric.protos.token.Expectations.PlainExpectation.getDefaultInstance()) return this; + switch (other.getPayloadCase()) { + case IMPORT_EXPECTATION: { + mergeImportExpectation(other.getImportExpectation()); + break; + } + case TRANSFER_EXPECTATION: { + mergeTransferExpectation(other.getTransferExpectation()); + break; + } + case PAYLOAD_NOT_SET: { + break; + } + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.token.Expectations.PlainExpectation parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.token.Expectations.PlainExpectation) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int payloadCase_ = 0; + private java.lang.Object payload_; + public PayloadCase + getPayloadCase() { + return PayloadCase.forNumber( + payloadCase_); + } + + public Builder clearPayload() { + payloadCase_ = 0; + payload_ = null; + onChanged(); + return this; + } + + + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder> importExpectationBuilder_; + /** + *
+       * ImportExpectation describes an token import expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation import_expectation = 1; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation getImportExpectation() { + if (importExpectationBuilder_ == null) { + if (payloadCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_; + } + return org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } else { + if (payloadCase_ == 1) { + return importExpectationBuilder_.getMessage(); + } + return org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } + } + /** + *
+       * ImportExpectation describes an token import expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation import_expectation = 1; + */ + public Builder setImportExpectation(org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation value) { + if (importExpectationBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + importExpectationBuilder_.setMessage(value); + } + payloadCase_ = 1; + return this; + } + /** + *
+       * ImportExpectation describes an token import expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation import_expectation = 1; + */ + public Builder setImportExpectation( + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder builderForValue) { + if (importExpectationBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + importExpectationBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 1; + return this; + } + /** + *
+       * ImportExpectation describes an token import expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation import_expectation = 1; + */ + public Builder mergeImportExpectation(org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation value) { + if (importExpectationBuilder_ == null) { + if (payloadCase_ == 1 && + payload_ != org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance()) { + payload_ = org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.newBuilder((org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 1) { + importExpectationBuilder_.mergeFrom(value); + } + importExpectationBuilder_.setMessage(value); + } + payloadCase_ = 1; + return this; + } + /** + *
+       * ImportExpectation describes an token import expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation import_expectation = 1; + */ + public Builder clearImportExpectation() { + if (importExpectationBuilder_ == null) { + if (payloadCase_ == 1) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 1) { + payloadCase_ = 0; + payload_ = null; + } + importExpectationBuilder_.clear(); + } + return this; + } + /** + *
+       * ImportExpectation describes an token import expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation import_expectation = 1; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder getImportExpectationBuilder() { + return getImportExpectationFieldBuilder().getBuilder(); + } + /** + *
+       * ImportExpectation describes an token import expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation import_expectation = 1; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder getImportExpectationOrBuilder() { + if ((payloadCase_ == 1) && (importExpectationBuilder_ != null)) { + return importExpectationBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_; + } + return org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } + } + /** + *
+       * ImportExpectation describes an token import expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation import_expectation = 1; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder> + getImportExpectationFieldBuilder() { + if (importExpectationBuilder_ == null) { + if (!(payloadCase_ == 1)) { + payload_ = org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } + importExpectationBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder>( + (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 1; + onChanged();; + return importExpectationBuilder_; + } + + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder> transferExpectationBuilder_; + /** + *
+       * TransferExpectation describes a token transfer expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation transfer_expectation = 2; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation getTransferExpectation() { + if (transferExpectationBuilder_ == null) { + if (payloadCase_ == 2) { + return (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_; + } + return org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } else { + if (payloadCase_ == 2) { + return transferExpectationBuilder_.getMessage(); + } + return org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } + } + /** + *
+       * TransferExpectation describes a token transfer expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation transfer_expectation = 2; + */ + public Builder setTransferExpectation(org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation value) { + if (transferExpectationBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + payload_ = value; + onChanged(); + } else { + transferExpectationBuilder_.setMessage(value); + } + payloadCase_ = 2; + return this; + } + /** + *
+       * TransferExpectation describes a token transfer expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation transfer_expectation = 2; + */ + public Builder setTransferExpectation( + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder builderForValue) { + if (transferExpectationBuilder_ == null) { + payload_ = builderForValue.build(); + onChanged(); + } else { + transferExpectationBuilder_.setMessage(builderForValue.build()); + } + payloadCase_ = 2; + return this; + } + /** + *
+       * TransferExpectation describes a token transfer expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation transfer_expectation = 2; + */ + public Builder mergeTransferExpectation(org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation value) { + if (transferExpectationBuilder_ == null) { + if (payloadCase_ == 2 && + payload_ != org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance()) { + payload_ = org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.newBuilder((org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_) + .mergeFrom(value).buildPartial(); + } else { + payload_ = value; + } + onChanged(); + } else { + if (payloadCase_ == 2) { + transferExpectationBuilder_.mergeFrom(value); + } + transferExpectationBuilder_.setMessage(value); + } + payloadCase_ = 2; + return this; + } + /** + *
+       * TransferExpectation describes a token transfer expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation transfer_expectation = 2; + */ + public Builder clearTransferExpectation() { + if (transferExpectationBuilder_ == null) { + if (payloadCase_ == 2) { + payloadCase_ = 0; + payload_ = null; + onChanged(); + } + } else { + if (payloadCase_ == 2) { + payloadCase_ = 0; + payload_ = null; + } + transferExpectationBuilder_.clear(); + } + return this; + } + /** + *
+       * TransferExpectation describes a token transfer expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation transfer_expectation = 2; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder getTransferExpectationBuilder() { + return getTransferExpectationFieldBuilder().getBuilder(); + } + /** + *
+       * TransferExpectation describes a token transfer expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation transfer_expectation = 2; + */ + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder getTransferExpectationOrBuilder() { + if ((payloadCase_ == 2) && (transferExpectationBuilder_ != null)) { + return transferExpectationBuilder_.getMessageOrBuilder(); + } else { + if (payloadCase_ == 2) { + return (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_; + } + return org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } + } + /** + *
+       * TransferExpectation describes a token transfer expectation
+       * 
+ * + * optional .protos.PlainTokenExpectation transfer_expectation = 2; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder> + getTransferExpectationFieldBuilder() { + if (transferExpectationBuilder_ == null) { + if (!(payloadCase_ == 2)) { + payload_ = org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } + transferExpectationBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder>( + (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) payload_, + getParentForChildren(), + isClean()); + payload_ = null; + } + payloadCase_ = 2; + onChanged();; + return transferExpectationBuilder_; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:protos.PlainExpectation) + } + + // @@protoc_insertion_point(class_scope:protos.PlainExpectation) + private static final org.hyperledger.fabric.protos.token.Expectations.PlainExpectation DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.token.Expectations.PlainExpectation(); + } + + public static org.hyperledger.fabric.protos.token.Expectations.PlainExpectation getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public PlainExpectation parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new PlainExpectation(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.token.Expectations.PlainExpectation getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface PlainTokenExpectationOrBuilder extends + // @@protoc_insertion_point(interface_extends:protos.PlainTokenExpectation) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * Outputs contains the expected outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + java.util.List + getOutputsList(); + /** + *
+     * Outputs contains the expected outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutputs(int index); + /** + *
+     * Outputs contains the expected outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + int getOutputsCount(); + /** + *
+     * Outputs contains the expected outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + java.util.List + getOutputsOrBuilderList(); + /** + *
+     * Outputs contains the expected outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputsOrBuilder( + int index); + } + /** + *
+   * PlainTokenExpectation represents the expecation that
+   * certain outputs will be matched
+   * 
+ * + * Protobuf type {@code protos.PlainTokenExpectation} + */ + public static final class PlainTokenExpectation extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:protos.PlainTokenExpectation) + PlainTokenExpectationOrBuilder { + // Use PlainTokenExpectation.newBuilder() to construct. + private PlainTokenExpectation(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private PlainTokenExpectation() { + outputs_ = java.util.Collections.emptyList(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private PlainTokenExpectation( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + outputs_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000001; + } + outputs_.add( + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainOutput.parser(), extensionRegistry)); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + outputs_ = java.util.Collections.unmodifiableList(outputs_); + } + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_PlainTokenExpectation_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_PlainTokenExpectation_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.class, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder.class); + } + + public static final int OUTPUTS_FIELD_NUMBER = 1; + private java.util.List outputs_; + /** + *
+     * Outputs contains the expected outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public java.util.List getOutputsList() { + return outputs_; + } + /** + *
+     * Outputs contains the expected outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public java.util.List + getOutputsOrBuilderList() { + return outputs_; + } + /** + *
+     * Outputs contains the expected outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public int getOutputsCount() { + return outputs_.size(); + } + /** + *
+     * Outputs contains the expected outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutputs(int index) { + return outputs_.get(index); + } + /** + *
+     * Outputs contains the expected outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputsOrBuilder( + int index) { + return outputs_.get(index); + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < outputs_.size(); i++) { + output.writeMessage(1, outputs_.get(i)); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < outputs_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, outputs_.get(i)); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation other = (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) obj; + + boolean result = true; + result = result && getOutputsList() + .equals(other.getOutputsList()); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + if (getOutputsCount() > 0) { + hash = (37 * hash) + OUTPUTS_FIELD_NUMBER; + hash = (53 * hash) + getOutputsList().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * PlainTokenExpectation represents the expecation that
+     * certain outputs will be matched
+     * 
+ * + * Protobuf type {@code protos.PlainTokenExpectation} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:protos.PlainTokenExpectation) + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectationOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_PlainTokenExpectation_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_PlainTokenExpectation_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.class, org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + getOutputsFieldBuilder(); + } + } + public Builder clear() { + super.clear(); + if (outputsBuilder_ == null) { + outputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + } else { + outputsBuilder_.clear(); + } + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.token.Expectations.internal_static_protos_PlainTokenExpectation_descriptor; + } + + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation build() { + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation buildPartial() { + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation result = new org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation(this); + int from_bitField0_ = bitField0_; + if (outputsBuilder_ == null) { + if (((bitField0_ & 0x00000001) == 0x00000001)) { + outputs_ = java.util.Collections.unmodifiableList(outputs_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.outputs_ = outputs_; + } else { + result.outputs_ = outputsBuilder_.build(); + } + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) { + return mergeFrom((org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation other) { + if (other == org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation.getDefaultInstance()) return this; + if (outputsBuilder_ == null) { + if (!other.outputs_.isEmpty()) { + if (outputs_.isEmpty()) { + outputs_ = other.outputs_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureOutputsIsMutable(); + outputs_.addAll(other.outputs_); + } + onChanged(); + } + } else { + if (!other.outputs_.isEmpty()) { + if (outputsBuilder_.isEmpty()) { + outputsBuilder_.dispose(); + outputsBuilder_ = null; + outputs_ = other.outputs_; + bitField0_ = (bitField0_ & ~0x00000001); + outputsBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getOutputsFieldBuilder() : null; + } else { + outputsBuilder_.addAllMessages(other.outputs_); + } + } + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.util.List outputs_ = + java.util.Collections.emptyList(); + private void ensureOutputsIsMutable() { + if (!((bitField0_ & 0x00000001) == 0x00000001)) { + outputs_ = new java.util.ArrayList(outputs_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder> outputsBuilder_; + + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public java.util.List getOutputsList() { + if (outputsBuilder_ == null) { + return java.util.Collections.unmodifiableList(outputs_); + } else { + return outputsBuilder_.getMessageList(); + } + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public int getOutputsCount() { + if (outputsBuilder_ == null) { + return outputs_.size(); + } else { + return outputsBuilder_.getCount(); + } + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutputs(int index) { + if (outputsBuilder_ == null) { + return outputs_.get(index); + } else { + return outputsBuilder_.getMessage(index); + } + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder setOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOutputsIsMutable(); + outputs_.set(index, value); + onChanged(); + } else { + outputsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder setOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.set(index, builderForValue.build()); + onChanged(); + } else { + outputsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder addOutputs(org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOutputsIsMutable(); + outputs_.add(value); + onChanged(); + } else { + outputsBuilder_.addMessage(value); + } + return this; + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder addOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOutputsIsMutable(); + outputs_.add(index, value); + onChanged(); + } else { + outputsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder addOutputs( + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.add(builderForValue.build()); + onChanged(); + } else { + outputsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder addOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.add(index, builderForValue.build()); + onChanged(); + } else { + outputsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder addAllOutputs( + java.lang.Iterable values) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, outputs_); + onChanged(); + } else { + outputsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder clearOutputs() { + if (outputsBuilder_ == null) { + outputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + outputsBuilder_.clear(); + } + return this; + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder removeOutputs(int index) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.remove(index); + onChanged(); + } else { + outputsBuilder_.remove(index); + } + return this; + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder getOutputsBuilder( + int index) { + return getOutputsFieldBuilder().getBuilder(index); + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputsOrBuilder( + int index) { + if (outputsBuilder_ == null) { + return outputs_.get(index); } else { + return outputsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public java.util.List + getOutputsOrBuilderList() { + if (outputsBuilder_ != null) { + return outputsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(outputs_); + } + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder addOutputsBuilder() { + return getOutputsFieldBuilder().addBuilder( + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance()); + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder addOutputsBuilder( + int index) { + return getOutputsFieldBuilder().addBuilder( + index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance()); + } + /** + *
+       * Outputs contains the expected outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public java.util.List + getOutputsBuilderList() { + return getOutputsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder> + getOutputsFieldBuilder() { + if (outputsBuilder_ == null) { + outputsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder>( + outputs_, + ((bitField0_ & 0x00000001) == 0x00000001), + getParentForChildren(), + isClean()); + outputs_ = null; + } + return outputsBuilder_; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:protos.PlainTokenExpectation) + } + + // @@protoc_insertion_point(class_scope:protos.PlainTokenExpectation) + private static final org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation(); + } + + public static org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public PlainTokenExpectation parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new PlainTokenExpectation(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.token.Expectations.PlainTokenExpectation getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_protos_TokenExpectation_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_protos_TokenExpectation_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_protos_PlainExpectation_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_protos_PlainExpectation_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_protos_PlainTokenExpectation_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_protos_PlainTokenExpectation_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\030token/expectations.proto\022\006protos\032\037goog" + + "le/protobuf/timestamp.proto\032\027token/trans" + + "action.proto\"X\n\020TokenExpectation\0225\n\021plai" + + "n_expectation\030\001 \001(\0132\030.protos.PlainExpect" + + "ationH\000B\r\n\013Expectation\"\231\001\n\020PlainExpectat" + + "ion\022;\n\022import_expectation\030\001 \001(\0132\035.protos" + + ".PlainTokenExpectationH\000\022=\n\024transfer_exp" + + "ectation\030\002 \001(\0132\035.protos.PlainTokenExpect" + + "ationH\000B\t\n\007payload\"6\n\025PlainTokenExpectat" + + "ion\022\035\n\007outputs\030\001 \003(\0132\014.PlainOutputBQ\n#or", + "g.hyperledger.fabric.protos.tokenZ*githu" + + "b.com/hyperledger/fabric/protos/tokenb\006p" + + "roto3" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + com.google.protobuf.TimestampProto.getDescriptor(), + org.hyperledger.fabric.protos.token.Transaction.getDescriptor(), + }, assigner); + internal_static_protos_TokenExpectation_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_protos_TokenExpectation_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_protos_TokenExpectation_descriptor, + new java.lang.String[] { "PlainExpectation", "Expectation", }); + internal_static_protos_PlainExpectation_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_protos_PlainExpectation_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_protos_PlainExpectation_descriptor, + new java.lang.String[] { "ImportExpectation", "TransferExpectation", "Payload", }); + internal_static_protos_PlainTokenExpectation_descriptor = + getDescriptor().getMessageTypes().get(2); + internal_static_protos_PlainTokenExpectation_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_protos_PlainTokenExpectation_descriptor, + new java.lang.String[] { "Outputs", }); + com.google.protobuf.TimestampProto.getDescriptor(); + org.hyperledger.fabric.protos.token.Transaction.getDescriptor(); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/token/Transaction.java b/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/token/Transaction.java new file mode 100644 index 00000000..13291dfb --- /dev/null +++ b/fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/token/Transaction.java @@ -0,0 +1,10167 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: token/transaction.proto + +package org.hyperledger.fabric.protos.token; + +public final class Transaction { + private Transaction() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + public interface TokenTransactionOrBuilder extends + // @@protoc_insertion_point(interface_extends:TokenTransaction) + com.google.protobuf.MessageOrBuilder { + + /** + * optional .PlainTokenAction plain_action = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction getPlainAction(); + /** + * optional .PlainTokenAction plain_action = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainTokenActionOrBuilder getPlainActionOrBuilder(); + + public org.hyperledger.fabric.protos.token.Transaction.TokenTransaction.ActionCase getActionCase(); + } + /** + *
+   * TokenTransaction governs the structure of Payload.data, when
+   * the transaction's envelope header indicates a transaction of type
+   * "Token"
+   * 
+ * + * Protobuf type {@code TokenTransaction} + */ + public static final class TokenTransaction extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:TokenTransaction) + TokenTransactionOrBuilder { + // Use TokenTransaction.newBuilder() to construct. + private TokenTransaction(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private TokenTransaction() { + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private TokenTransaction( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.Builder subBuilder = null; + if (actionCase_ == 1) { + subBuilder = ((org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) action_).toBuilder(); + } + action_ = + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) action_); + action_ = subBuilder.buildPartial(); + } + actionCase_ = 1; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_TokenTransaction_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_TokenTransaction_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.TokenTransaction.class, org.hyperledger.fabric.protos.token.Transaction.TokenTransaction.Builder.class); + } + + private int actionCase_ = 0; + private java.lang.Object action_; + public enum ActionCase + implements com.google.protobuf.Internal.EnumLite { + PLAIN_ACTION(1), + ACTION_NOT_SET(0); + private final int value; + private ActionCase(int value) { + this.value = value; + } + /** + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static ActionCase valueOf(int value) { + return forNumber(value); + } + + public static ActionCase forNumber(int value) { + switch (value) { + case 1: return PLAIN_ACTION; + case 0: return ACTION_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public ActionCase + getActionCase() { + return ActionCase.forNumber( + actionCase_); + } + + public static final int PLAIN_ACTION_FIELD_NUMBER = 1; + /** + * optional .PlainTokenAction plain_action = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction getPlainAction() { + if (actionCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) action_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.getDefaultInstance(); + } + /** + * optional .PlainTokenAction plain_action = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTokenActionOrBuilder getPlainActionOrBuilder() { + if (actionCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) action_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (actionCase_ == 1) { + output.writeMessage(1, (org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) action_); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (actionCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) action_); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.token.Transaction.TokenTransaction)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.token.Transaction.TokenTransaction other = (org.hyperledger.fabric.protos.token.Transaction.TokenTransaction) obj; + + boolean result = true; + result = result && getActionCase().equals( + other.getActionCase()); + if (!result) return false; + switch (actionCase_) { + case 1: + result = result && getPlainAction() + .equals(other.getPlainAction()); + break; + case 0: + default: + } + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + switch (actionCase_) { + case 1: + hash = (37 * hash) + PLAIN_ACTION_FIELD_NUMBER; + hash = (53 * hash) + getPlainAction().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.token.Transaction.TokenTransaction parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.TokenTransaction parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.TokenTransaction parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.TokenTransaction parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.TokenTransaction parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.TokenTransaction parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.TokenTransaction parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.TokenTransaction parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.TokenTransaction parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.TokenTransaction parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.token.Transaction.TokenTransaction prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * TokenTransaction governs the structure of Payload.data, when
+     * the transaction's envelope header indicates a transaction of type
+     * "Token"
+     * 
+ * + * Protobuf type {@code TokenTransaction} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:TokenTransaction) + org.hyperledger.fabric.protos.token.Transaction.TokenTransactionOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_TokenTransaction_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_TokenTransaction_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.TokenTransaction.class, org.hyperledger.fabric.protos.token.Transaction.TokenTransaction.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.token.Transaction.TokenTransaction.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + public Builder clear() { + super.clear(); + actionCase_ = 0; + action_ = null; + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_TokenTransaction_descriptor; + } + + public org.hyperledger.fabric.protos.token.Transaction.TokenTransaction getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.token.Transaction.TokenTransaction.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.token.Transaction.TokenTransaction build() { + org.hyperledger.fabric.protos.token.Transaction.TokenTransaction result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.token.Transaction.TokenTransaction buildPartial() { + org.hyperledger.fabric.protos.token.Transaction.TokenTransaction result = new org.hyperledger.fabric.protos.token.Transaction.TokenTransaction(this); + if (actionCase_ == 1) { + if (plainActionBuilder_ == null) { + result.action_ = action_; + } else { + result.action_ = plainActionBuilder_.build(); + } + } + result.actionCase_ = actionCase_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.token.Transaction.TokenTransaction) { + return mergeFrom((org.hyperledger.fabric.protos.token.Transaction.TokenTransaction)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.token.Transaction.TokenTransaction other) { + if (other == org.hyperledger.fabric.protos.token.Transaction.TokenTransaction.getDefaultInstance()) return this; + switch (other.getActionCase()) { + case PLAIN_ACTION: { + mergePlainAction(other.getPlainAction()); + break; + } + case ACTION_NOT_SET: { + break; + } + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.token.Transaction.TokenTransaction parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.token.Transaction.TokenTransaction) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int actionCase_ = 0; + private java.lang.Object action_; + public ActionCase + getActionCase() { + return ActionCase.forNumber( + actionCase_); + } + + public Builder clearAction() { + actionCase_ = 0; + action_ = null; + onChanged(); + return this; + } + + + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction, org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainTokenActionOrBuilder> plainActionBuilder_; + /** + * optional .PlainTokenAction plain_action = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction getPlainAction() { + if (plainActionBuilder_ == null) { + if (actionCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) action_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.getDefaultInstance(); + } else { + if (actionCase_ == 1) { + return plainActionBuilder_.getMessage(); + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.getDefaultInstance(); + } + } + /** + * optional .PlainTokenAction plain_action = 1; + */ + public Builder setPlainAction(org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction value) { + if (plainActionBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + action_ = value; + onChanged(); + } else { + plainActionBuilder_.setMessage(value); + } + actionCase_ = 1; + return this; + } + /** + * optional .PlainTokenAction plain_action = 1; + */ + public Builder setPlainAction( + org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.Builder builderForValue) { + if (plainActionBuilder_ == null) { + action_ = builderForValue.build(); + onChanged(); + } else { + plainActionBuilder_.setMessage(builderForValue.build()); + } + actionCase_ = 1; + return this; + } + /** + * optional .PlainTokenAction plain_action = 1; + */ + public Builder mergePlainAction(org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction value) { + if (plainActionBuilder_ == null) { + if (actionCase_ == 1 && + action_ != org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.getDefaultInstance()) { + action_ = org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.newBuilder((org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) action_) + .mergeFrom(value).buildPartial(); + } else { + action_ = value; + } + onChanged(); + } else { + if (actionCase_ == 1) { + plainActionBuilder_.mergeFrom(value); + } + plainActionBuilder_.setMessage(value); + } + actionCase_ = 1; + return this; + } + /** + * optional .PlainTokenAction plain_action = 1; + */ + public Builder clearPlainAction() { + if (plainActionBuilder_ == null) { + if (actionCase_ == 1) { + actionCase_ = 0; + action_ = null; + onChanged(); + } + } else { + if (actionCase_ == 1) { + actionCase_ = 0; + action_ = null; + } + plainActionBuilder_.clear(); + } + return this; + } + /** + * optional .PlainTokenAction plain_action = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.Builder getPlainActionBuilder() { + return getPlainActionFieldBuilder().getBuilder(); + } + /** + * optional .PlainTokenAction plain_action = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTokenActionOrBuilder getPlainActionOrBuilder() { + if ((actionCase_ == 1) && (plainActionBuilder_ != null)) { + return plainActionBuilder_.getMessageOrBuilder(); + } else { + if (actionCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) action_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.getDefaultInstance(); + } + } + /** + * optional .PlainTokenAction plain_action = 1; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction, org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainTokenActionOrBuilder> + getPlainActionFieldBuilder() { + if (plainActionBuilder_ == null) { + if (!(actionCase_ == 1)) { + action_ = org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.getDefaultInstance(); + } + plainActionBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction, org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainTokenActionOrBuilder>( + (org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) action_, + getParentForChildren(), + isClean()); + action_ = null; + } + actionCase_ = 1; + onChanged();; + return plainActionBuilder_; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:TokenTransaction) + } + + // @@protoc_insertion_point(class_scope:TokenTransaction) + private static final org.hyperledger.fabric.protos.token.Transaction.TokenTransaction DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.token.Transaction.TokenTransaction(); + } + + public static org.hyperledger.fabric.protos.token.Transaction.TokenTransaction getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public TokenTransaction parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new TokenTransaction(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.token.Transaction.TokenTransaction getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface PlainTokenActionOrBuilder extends + // @@protoc_insertion_point(interface_extends:PlainTokenAction) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * A plaintext token import transaction
+     * 
+ * + * optional .PlainImport plain_import = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainImport getPlainImport(); + /** + *
+     * A plaintext token import transaction
+     * 
+ * + * optional .PlainImport plain_import = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainImportOrBuilder getPlainImportOrBuilder(); + + /** + *
+     * A plaintext token transfer transaction
+     * 
+ * + * optional .PlainTransfer plain_transfer = 2; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer getPlainTransfer(); + /** + *
+     * A plaintext token transfer transaction
+     * 
+ * + * optional .PlainTransfer plain_transfer = 2; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder getPlainTransferOrBuilder(); + + /** + *
+     * A plaintext token redeem transaction
+     * 
+ * + * optional .PlainTransfer plain_redeem = 3; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer getPlainRedeem(); + /** + *
+     * A plaintext token redeem transaction
+     * 
+ * + * optional .PlainTransfer plain_redeem = 3; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder getPlainRedeemOrBuilder(); + + /** + *
+     * A plaintext token approve transaction
+     * 
+ * + * optional .PlainApprove plain_approve = 4; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainApprove getPlainApprove(); + /** + *
+     * A plaintext token approve transaction
+     * 
+ * + * optional .PlainApprove plain_approve = 4; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainApproveOrBuilder getPlainApproveOrBuilder(); + + /** + *
+     * A plaintext token transfer from transaction
+     * 
+ * + * optional .PlainTransferFrom plain_transfer_From = 5; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom getPlainTransferFrom(); + /** + *
+     * A plaintext token transfer from transaction
+     * 
+ * + * optional .PlainTransferFrom plain_transfer_From = 5; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFromOrBuilder getPlainTransferFromOrBuilder(); + + public org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.DataCase getDataCase(); + } + /** + *
+   * PlainTokenAction governs the structure of a token action that is
+   * subjected to no privacy restrictions
+   * 
+ * + * Protobuf type {@code PlainTokenAction} + */ + public static final class PlainTokenAction extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:PlainTokenAction) + PlainTokenActionOrBuilder { + // Use PlainTokenAction.newBuilder() to construct. + private PlainTokenAction(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private PlainTokenAction() { + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private PlainTokenAction( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + org.hyperledger.fabric.protos.token.Transaction.PlainImport.Builder subBuilder = null; + if (dataCase_ == 1) { + subBuilder = ((org.hyperledger.fabric.protos.token.Transaction.PlainImport) data_).toBuilder(); + } + data_ = + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainImport.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainImport) data_); + data_ = subBuilder.buildPartial(); + } + dataCase_ = 1; + break; + } + case 18: { + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder subBuilder = null; + if (dataCase_ == 2) { + subBuilder = ((org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_).toBuilder(); + } + data_ = + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_); + data_ = subBuilder.buildPartial(); + } + dataCase_ = 2; + break; + } + case 26: { + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder subBuilder = null; + if (dataCase_ == 3) { + subBuilder = ((org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_).toBuilder(); + } + data_ = + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_); + data_ = subBuilder.buildPartial(); + } + dataCase_ = 3; + break; + } + case 34: { + org.hyperledger.fabric.protos.token.Transaction.PlainApprove.Builder subBuilder = null; + if (dataCase_ == 4) { + subBuilder = ((org.hyperledger.fabric.protos.token.Transaction.PlainApprove) data_).toBuilder(); + } + data_ = + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainApprove.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainApprove) data_); + data_ = subBuilder.buildPartial(); + } + dataCase_ = 4; + break; + } + case 42: { + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.Builder subBuilder = null; + if (dataCase_ == 5) { + subBuilder = ((org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) data_).toBuilder(); + } + data_ = + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) data_); + data_ = subBuilder.buildPartial(); + } + dataCase_ = 5; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTokenAction_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTokenAction_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.class, org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.Builder.class); + } + + private int dataCase_ = 0; + private java.lang.Object data_; + public enum DataCase + implements com.google.protobuf.Internal.EnumLite { + PLAIN_IMPORT(1), + PLAIN_TRANSFER(2), + PLAIN_REDEEM(3), + PLAIN_APPROVE(4), + PLAIN_TRANSFER_FROM(5), + DATA_NOT_SET(0); + private final int value; + private DataCase(int value) { + this.value = value; + } + /** + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static DataCase valueOf(int value) { + return forNumber(value); + } + + public static DataCase forNumber(int value) { + switch (value) { + case 1: return PLAIN_IMPORT; + case 2: return PLAIN_TRANSFER; + case 3: return PLAIN_REDEEM; + case 4: return PLAIN_APPROVE; + case 5: return PLAIN_TRANSFER_FROM; + case 0: return DATA_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public DataCase + getDataCase() { + return DataCase.forNumber( + dataCase_); + } + + public static final int PLAIN_IMPORT_FIELD_NUMBER = 1; + /** + *
+     * A plaintext token import transaction
+     * 
+ * + * optional .PlainImport plain_import = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainImport getPlainImport() { + if (dataCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainImport) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainImport.getDefaultInstance(); + } + /** + *
+     * A plaintext token import transaction
+     * 
+ * + * optional .PlainImport plain_import = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainImportOrBuilder getPlainImportOrBuilder() { + if (dataCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainImport) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainImport.getDefaultInstance(); + } + + public static final int PLAIN_TRANSFER_FIELD_NUMBER = 2; + /** + *
+     * A plaintext token transfer transaction
+     * 
+ * + * optional .PlainTransfer plain_transfer = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransfer getPlainTransfer() { + if (dataCase_ == 2) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } + /** + *
+     * A plaintext token transfer transaction
+     * 
+ * + * optional .PlainTransfer plain_transfer = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder getPlainTransferOrBuilder() { + if (dataCase_ == 2) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } + + public static final int PLAIN_REDEEM_FIELD_NUMBER = 3; + /** + *
+     * A plaintext token redeem transaction
+     * 
+ * + * optional .PlainTransfer plain_redeem = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransfer getPlainRedeem() { + if (dataCase_ == 3) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } + /** + *
+     * A plaintext token redeem transaction
+     * 
+ * + * optional .PlainTransfer plain_redeem = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder getPlainRedeemOrBuilder() { + if (dataCase_ == 3) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } + + public static final int PLAIN_APPROVE_FIELD_NUMBER = 4; + /** + *
+     * A plaintext token approve transaction
+     * 
+ * + * optional .PlainApprove plain_approve = 4; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainApprove getPlainApprove() { + if (dataCase_ == 4) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainApprove) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainApprove.getDefaultInstance(); + } + /** + *
+     * A plaintext token approve transaction
+     * 
+ * + * optional .PlainApprove plain_approve = 4; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainApproveOrBuilder getPlainApproveOrBuilder() { + if (dataCase_ == 4) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainApprove) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainApprove.getDefaultInstance(); + } + + public static final int PLAIN_TRANSFER_FROM_FIELD_NUMBER = 5; + /** + *
+     * A plaintext token transfer from transaction
+     * 
+ * + * optional .PlainTransferFrom plain_transfer_From = 5; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom getPlainTransferFrom() { + if (dataCase_ == 5) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.getDefaultInstance(); + } + /** + *
+     * A plaintext token transfer from transaction
+     * 
+ * + * optional .PlainTransferFrom plain_transfer_From = 5; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferFromOrBuilder getPlainTransferFromOrBuilder() { + if (dataCase_ == 5) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (dataCase_ == 1) { + output.writeMessage(1, (org.hyperledger.fabric.protos.token.Transaction.PlainImport) data_); + } + if (dataCase_ == 2) { + output.writeMessage(2, (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_); + } + if (dataCase_ == 3) { + output.writeMessage(3, (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_); + } + if (dataCase_ == 4) { + output.writeMessage(4, (org.hyperledger.fabric.protos.token.Transaction.PlainApprove) data_); + } + if (dataCase_ == 5) { + output.writeMessage(5, (org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) data_); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (dataCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (org.hyperledger.fabric.protos.token.Transaction.PlainImport) data_); + } + if (dataCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_); + } + if (dataCase_ == 3) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_); + } + if (dataCase_ == 4) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, (org.hyperledger.fabric.protos.token.Transaction.PlainApprove) data_); + } + if (dataCase_ == 5) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, (org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) data_); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction other = (org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) obj; + + boolean result = true; + result = result && getDataCase().equals( + other.getDataCase()); + if (!result) return false; + switch (dataCase_) { + case 1: + result = result && getPlainImport() + .equals(other.getPlainImport()); + break; + case 2: + result = result && getPlainTransfer() + .equals(other.getPlainTransfer()); + break; + case 3: + result = result && getPlainRedeem() + .equals(other.getPlainRedeem()); + break; + case 4: + result = result && getPlainApprove() + .equals(other.getPlainApprove()); + break; + case 5: + result = result && getPlainTransferFrom() + .equals(other.getPlainTransferFrom()); + break; + case 0: + default: + } + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + switch (dataCase_) { + case 1: + hash = (37 * hash) + PLAIN_IMPORT_FIELD_NUMBER; + hash = (53 * hash) + getPlainImport().hashCode(); + break; + case 2: + hash = (37 * hash) + PLAIN_TRANSFER_FIELD_NUMBER; + hash = (53 * hash) + getPlainTransfer().hashCode(); + break; + case 3: + hash = (37 * hash) + PLAIN_REDEEM_FIELD_NUMBER; + hash = (53 * hash) + getPlainRedeem().hashCode(); + break; + case 4: + hash = (37 * hash) + PLAIN_APPROVE_FIELD_NUMBER; + hash = (53 * hash) + getPlainApprove().hashCode(); + break; + case 5: + hash = (37 * hash) + PLAIN_TRANSFER_FROM_FIELD_NUMBER; + hash = (53 * hash) + getPlainTransferFrom().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * PlainTokenAction governs the structure of a token action that is
+     * subjected to no privacy restrictions
+     * 
+ * + * Protobuf type {@code PlainTokenAction} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:PlainTokenAction) + org.hyperledger.fabric.protos.token.Transaction.PlainTokenActionOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTokenAction_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTokenAction_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.class, org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + public Builder clear() { + super.clear(); + dataCase_ = 0; + data_ = null; + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTokenAction_descriptor; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction build() { + org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction buildPartial() { + org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction result = new org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction(this); + if (dataCase_ == 1) { + if (plainImportBuilder_ == null) { + result.data_ = data_; + } else { + result.data_ = plainImportBuilder_.build(); + } + } + if (dataCase_ == 2) { + if (plainTransferBuilder_ == null) { + result.data_ = data_; + } else { + result.data_ = plainTransferBuilder_.build(); + } + } + if (dataCase_ == 3) { + if (plainRedeemBuilder_ == null) { + result.data_ = data_; + } else { + result.data_ = plainRedeemBuilder_.build(); + } + } + if (dataCase_ == 4) { + if (plainApproveBuilder_ == null) { + result.data_ = data_; + } else { + result.data_ = plainApproveBuilder_.build(); + } + } + if (dataCase_ == 5) { + if (plainTransferFromBuilder_ == null) { + result.data_ = data_; + } else { + result.data_ = plainTransferFromBuilder_.build(); + } + } + result.dataCase_ = dataCase_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) { + return mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction other) { + if (other == org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction.getDefaultInstance()) return this; + switch (other.getDataCase()) { + case PLAIN_IMPORT: { + mergePlainImport(other.getPlainImport()); + break; + } + case PLAIN_TRANSFER: { + mergePlainTransfer(other.getPlainTransfer()); + break; + } + case PLAIN_REDEEM: { + mergePlainRedeem(other.getPlainRedeem()); + break; + } + case PLAIN_APPROVE: { + mergePlainApprove(other.getPlainApprove()); + break; + } + case PLAIN_TRANSFER_FROM: { + mergePlainTransferFrom(other.getPlainTransferFrom()); + break; + } + case DATA_NOT_SET: { + break; + } + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int dataCase_ = 0; + private java.lang.Object data_; + public DataCase + getDataCase() { + return DataCase.forNumber( + dataCase_); + } + + public Builder clearData() { + dataCase_ = 0; + data_ = null; + onChanged(); + return this; + } + + + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainImport, org.hyperledger.fabric.protos.token.Transaction.PlainImport.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainImportOrBuilder> plainImportBuilder_; + /** + *
+       * A plaintext token import transaction
+       * 
+ * + * optional .PlainImport plain_import = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainImport getPlainImport() { + if (plainImportBuilder_ == null) { + if (dataCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainImport) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainImport.getDefaultInstance(); + } else { + if (dataCase_ == 1) { + return plainImportBuilder_.getMessage(); + } + return org.hyperledger.fabric.protos.token.Transaction.PlainImport.getDefaultInstance(); + } + } + /** + *
+       * A plaintext token import transaction
+       * 
+ * + * optional .PlainImport plain_import = 1; + */ + public Builder setPlainImport(org.hyperledger.fabric.protos.token.Transaction.PlainImport value) { + if (plainImportBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + data_ = value; + onChanged(); + } else { + plainImportBuilder_.setMessage(value); + } + dataCase_ = 1; + return this; + } + /** + *
+       * A plaintext token import transaction
+       * 
+ * + * optional .PlainImport plain_import = 1; + */ + public Builder setPlainImport( + org.hyperledger.fabric.protos.token.Transaction.PlainImport.Builder builderForValue) { + if (plainImportBuilder_ == null) { + data_ = builderForValue.build(); + onChanged(); + } else { + plainImportBuilder_.setMessage(builderForValue.build()); + } + dataCase_ = 1; + return this; + } + /** + *
+       * A plaintext token import transaction
+       * 
+ * + * optional .PlainImport plain_import = 1; + */ + public Builder mergePlainImport(org.hyperledger.fabric.protos.token.Transaction.PlainImport value) { + if (plainImportBuilder_ == null) { + if (dataCase_ == 1 && + data_ != org.hyperledger.fabric.protos.token.Transaction.PlainImport.getDefaultInstance()) { + data_ = org.hyperledger.fabric.protos.token.Transaction.PlainImport.newBuilder((org.hyperledger.fabric.protos.token.Transaction.PlainImport) data_) + .mergeFrom(value).buildPartial(); + } else { + data_ = value; + } + onChanged(); + } else { + if (dataCase_ == 1) { + plainImportBuilder_.mergeFrom(value); + } + plainImportBuilder_.setMessage(value); + } + dataCase_ = 1; + return this; + } + /** + *
+       * A plaintext token import transaction
+       * 
+ * + * optional .PlainImport plain_import = 1; + */ + public Builder clearPlainImport() { + if (plainImportBuilder_ == null) { + if (dataCase_ == 1) { + dataCase_ = 0; + data_ = null; + onChanged(); + } + } else { + if (dataCase_ == 1) { + dataCase_ = 0; + data_ = null; + } + plainImportBuilder_.clear(); + } + return this; + } + /** + *
+       * A plaintext token import transaction
+       * 
+ * + * optional .PlainImport plain_import = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainImport.Builder getPlainImportBuilder() { + return getPlainImportFieldBuilder().getBuilder(); + } + /** + *
+       * A plaintext token import transaction
+       * 
+ * + * optional .PlainImport plain_import = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainImportOrBuilder getPlainImportOrBuilder() { + if ((dataCase_ == 1) && (plainImportBuilder_ != null)) { + return plainImportBuilder_.getMessageOrBuilder(); + } else { + if (dataCase_ == 1) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainImport) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainImport.getDefaultInstance(); + } + } + /** + *
+       * A plaintext token import transaction
+       * 
+ * + * optional .PlainImport plain_import = 1; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainImport, org.hyperledger.fabric.protos.token.Transaction.PlainImport.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainImportOrBuilder> + getPlainImportFieldBuilder() { + if (plainImportBuilder_ == null) { + if (!(dataCase_ == 1)) { + data_ = org.hyperledger.fabric.protos.token.Transaction.PlainImport.getDefaultInstance(); + } + plainImportBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainImport, org.hyperledger.fabric.protos.token.Transaction.PlainImport.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainImportOrBuilder>( + (org.hyperledger.fabric.protos.token.Transaction.PlainImport) data_, + getParentForChildren(), + isClean()); + data_ = null; + } + dataCase_ = 1; + onChanged();; + return plainImportBuilder_; + } + + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer, org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder> plainTransferBuilder_; + /** + *
+       * A plaintext token transfer transaction
+       * 
+ * + * optional .PlainTransfer plain_transfer = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransfer getPlainTransfer() { + if (plainTransferBuilder_ == null) { + if (dataCase_ == 2) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } else { + if (dataCase_ == 2) { + return plainTransferBuilder_.getMessage(); + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } + } + /** + *
+       * A plaintext token transfer transaction
+       * 
+ * + * optional .PlainTransfer plain_transfer = 2; + */ + public Builder setPlainTransfer(org.hyperledger.fabric.protos.token.Transaction.PlainTransfer value) { + if (plainTransferBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + data_ = value; + onChanged(); + } else { + plainTransferBuilder_.setMessage(value); + } + dataCase_ = 2; + return this; + } + /** + *
+       * A plaintext token transfer transaction
+       * 
+ * + * optional .PlainTransfer plain_transfer = 2; + */ + public Builder setPlainTransfer( + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder builderForValue) { + if (plainTransferBuilder_ == null) { + data_ = builderForValue.build(); + onChanged(); + } else { + plainTransferBuilder_.setMessage(builderForValue.build()); + } + dataCase_ = 2; + return this; + } + /** + *
+       * A plaintext token transfer transaction
+       * 
+ * + * optional .PlainTransfer plain_transfer = 2; + */ + public Builder mergePlainTransfer(org.hyperledger.fabric.protos.token.Transaction.PlainTransfer value) { + if (plainTransferBuilder_ == null) { + if (dataCase_ == 2 && + data_ != org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance()) { + data_ = org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.newBuilder((org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_) + .mergeFrom(value).buildPartial(); + } else { + data_ = value; + } + onChanged(); + } else { + if (dataCase_ == 2) { + plainTransferBuilder_.mergeFrom(value); + } + plainTransferBuilder_.setMessage(value); + } + dataCase_ = 2; + return this; + } + /** + *
+       * A plaintext token transfer transaction
+       * 
+ * + * optional .PlainTransfer plain_transfer = 2; + */ + public Builder clearPlainTransfer() { + if (plainTransferBuilder_ == null) { + if (dataCase_ == 2) { + dataCase_ = 0; + data_ = null; + onChanged(); + } + } else { + if (dataCase_ == 2) { + dataCase_ = 0; + data_ = null; + } + plainTransferBuilder_.clear(); + } + return this; + } + /** + *
+       * A plaintext token transfer transaction
+       * 
+ * + * optional .PlainTransfer plain_transfer = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder getPlainTransferBuilder() { + return getPlainTransferFieldBuilder().getBuilder(); + } + /** + *
+       * A plaintext token transfer transaction
+       * 
+ * + * optional .PlainTransfer plain_transfer = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder getPlainTransferOrBuilder() { + if ((dataCase_ == 2) && (plainTransferBuilder_ != null)) { + return plainTransferBuilder_.getMessageOrBuilder(); + } else { + if (dataCase_ == 2) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } + } + /** + *
+       * A plaintext token transfer transaction
+       * 
+ * + * optional .PlainTransfer plain_transfer = 2; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer, org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder> + getPlainTransferFieldBuilder() { + if (plainTransferBuilder_ == null) { + if (!(dataCase_ == 2)) { + data_ = org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } + plainTransferBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer, org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder>( + (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_, + getParentForChildren(), + isClean()); + data_ = null; + } + dataCase_ = 2; + onChanged();; + return plainTransferBuilder_; + } + + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer, org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder> plainRedeemBuilder_; + /** + *
+       * A plaintext token redeem transaction
+       * 
+ * + * optional .PlainTransfer plain_redeem = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransfer getPlainRedeem() { + if (plainRedeemBuilder_ == null) { + if (dataCase_ == 3) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } else { + if (dataCase_ == 3) { + return plainRedeemBuilder_.getMessage(); + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } + } + /** + *
+       * A plaintext token redeem transaction
+       * 
+ * + * optional .PlainTransfer plain_redeem = 3; + */ + public Builder setPlainRedeem(org.hyperledger.fabric.protos.token.Transaction.PlainTransfer value) { + if (plainRedeemBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + data_ = value; + onChanged(); + } else { + plainRedeemBuilder_.setMessage(value); + } + dataCase_ = 3; + return this; + } + /** + *
+       * A plaintext token redeem transaction
+       * 
+ * + * optional .PlainTransfer plain_redeem = 3; + */ + public Builder setPlainRedeem( + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder builderForValue) { + if (plainRedeemBuilder_ == null) { + data_ = builderForValue.build(); + onChanged(); + } else { + plainRedeemBuilder_.setMessage(builderForValue.build()); + } + dataCase_ = 3; + return this; + } + /** + *
+       * A plaintext token redeem transaction
+       * 
+ * + * optional .PlainTransfer plain_redeem = 3; + */ + public Builder mergePlainRedeem(org.hyperledger.fabric.protos.token.Transaction.PlainTransfer value) { + if (plainRedeemBuilder_ == null) { + if (dataCase_ == 3 && + data_ != org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance()) { + data_ = org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.newBuilder((org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_) + .mergeFrom(value).buildPartial(); + } else { + data_ = value; + } + onChanged(); + } else { + if (dataCase_ == 3) { + plainRedeemBuilder_.mergeFrom(value); + } + plainRedeemBuilder_.setMessage(value); + } + dataCase_ = 3; + return this; + } + /** + *
+       * A plaintext token redeem transaction
+       * 
+ * + * optional .PlainTransfer plain_redeem = 3; + */ + public Builder clearPlainRedeem() { + if (plainRedeemBuilder_ == null) { + if (dataCase_ == 3) { + dataCase_ = 0; + data_ = null; + onChanged(); + } + } else { + if (dataCase_ == 3) { + dataCase_ = 0; + data_ = null; + } + plainRedeemBuilder_.clear(); + } + return this; + } + /** + *
+       * A plaintext token redeem transaction
+       * 
+ * + * optional .PlainTransfer plain_redeem = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder getPlainRedeemBuilder() { + return getPlainRedeemFieldBuilder().getBuilder(); + } + /** + *
+       * A plaintext token redeem transaction
+       * 
+ * + * optional .PlainTransfer plain_redeem = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder getPlainRedeemOrBuilder() { + if ((dataCase_ == 3) && (plainRedeemBuilder_ != null)) { + return plainRedeemBuilder_.getMessageOrBuilder(); + } else { + if (dataCase_ == 3) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } + } + /** + *
+       * A plaintext token redeem transaction
+       * 
+ * + * optional .PlainTransfer plain_redeem = 3; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer, org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder> + getPlainRedeemFieldBuilder() { + if (plainRedeemBuilder_ == null) { + if (!(dataCase_ == 3)) { + data_ = org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } + plainRedeemBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer, org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder>( + (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) data_, + getParentForChildren(), + isClean()); + data_ = null; + } + dataCase_ = 3; + onChanged();; + return plainRedeemBuilder_; + } + + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainApprove, org.hyperledger.fabric.protos.token.Transaction.PlainApprove.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainApproveOrBuilder> plainApproveBuilder_; + /** + *
+       * A plaintext token approve transaction
+       * 
+ * + * optional .PlainApprove plain_approve = 4; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainApprove getPlainApprove() { + if (plainApproveBuilder_ == null) { + if (dataCase_ == 4) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainApprove) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainApprove.getDefaultInstance(); + } else { + if (dataCase_ == 4) { + return plainApproveBuilder_.getMessage(); + } + return org.hyperledger.fabric.protos.token.Transaction.PlainApprove.getDefaultInstance(); + } + } + /** + *
+       * A plaintext token approve transaction
+       * 
+ * + * optional .PlainApprove plain_approve = 4; + */ + public Builder setPlainApprove(org.hyperledger.fabric.protos.token.Transaction.PlainApprove value) { + if (plainApproveBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + data_ = value; + onChanged(); + } else { + plainApproveBuilder_.setMessage(value); + } + dataCase_ = 4; + return this; + } + /** + *
+       * A plaintext token approve transaction
+       * 
+ * + * optional .PlainApprove plain_approve = 4; + */ + public Builder setPlainApprove( + org.hyperledger.fabric.protos.token.Transaction.PlainApprove.Builder builderForValue) { + if (plainApproveBuilder_ == null) { + data_ = builderForValue.build(); + onChanged(); + } else { + plainApproveBuilder_.setMessage(builderForValue.build()); + } + dataCase_ = 4; + return this; + } + /** + *
+       * A plaintext token approve transaction
+       * 
+ * + * optional .PlainApprove plain_approve = 4; + */ + public Builder mergePlainApprove(org.hyperledger.fabric.protos.token.Transaction.PlainApprove value) { + if (plainApproveBuilder_ == null) { + if (dataCase_ == 4 && + data_ != org.hyperledger.fabric.protos.token.Transaction.PlainApprove.getDefaultInstance()) { + data_ = org.hyperledger.fabric.protos.token.Transaction.PlainApprove.newBuilder((org.hyperledger.fabric.protos.token.Transaction.PlainApprove) data_) + .mergeFrom(value).buildPartial(); + } else { + data_ = value; + } + onChanged(); + } else { + if (dataCase_ == 4) { + plainApproveBuilder_.mergeFrom(value); + } + plainApproveBuilder_.setMessage(value); + } + dataCase_ = 4; + return this; + } + /** + *
+       * A plaintext token approve transaction
+       * 
+ * + * optional .PlainApprove plain_approve = 4; + */ + public Builder clearPlainApprove() { + if (plainApproveBuilder_ == null) { + if (dataCase_ == 4) { + dataCase_ = 0; + data_ = null; + onChanged(); + } + } else { + if (dataCase_ == 4) { + dataCase_ = 0; + data_ = null; + } + plainApproveBuilder_.clear(); + } + return this; + } + /** + *
+       * A plaintext token approve transaction
+       * 
+ * + * optional .PlainApprove plain_approve = 4; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainApprove.Builder getPlainApproveBuilder() { + return getPlainApproveFieldBuilder().getBuilder(); + } + /** + *
+       * A plaintext token approve transaction
+       * 
+ * + * optional .PlainApprove plain_approve = 4; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainApproveOrBuilder getPlainApproveOrBuilder() { + if ((dataCase_ == 4) && (plainApproveBuilder_ != null)) { + return plainApproveBuilder_.getMessageOrBuilder(); + } else { + if (dataCase_ == 4) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainApprove) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainApprove.getDefaultInstance(); + } + } + /** + *
+       * A plaintext token approve transaction
+       * 
+ * + * optional .PlainApprove plain_approve = 4; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainApprove, org.hyperledger.fabric.protos.token.Transaction.PlainApprove.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainApproveOrBuilder> + getPlainApproveFieldBuilder() { + if (plainApproveBuilder_ == null) { + if (!(dataCase_ == 4)) { + data_ = org.hyperledger.fabric.protos.token.Transaction.PlainApprove.getDefaultInstance(); + } + plainApproveBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainApprove, org.hyperledger.fabric.protos.token.Transaction.PlainApprove.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainApproveOrBuilder>( + (org.hyperledger.fabric.protos.token.Transaction.PlainApprove) data_, + getParentForChildren(), + isClean()); + data_ = null; + } + dataCase_ = 4; + onChanged();; + return plainApproveBuilder_; + } + + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom, org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainTransferFromOrBuilder> plainTransferFromBuilder_; + /** + *
+       * A plaintext token transfer from transaction
+       * 
+ * + * optional .PlainTransferFrom plain_transfer_From = 5; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom getPlainTransferFrom() { + if (plainTransferFromBuilder_ == null) { + if (dataCase_ == 5) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.getDefaultInstance(); + } else { + if (dataCase_ == 5) { + return plainTransferFromBuilder_.getMessage(); + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.getDefaultInstance(); + } + } + /** + *
+       * A plaintext token transfer from transaction
+       * 
+ * + * optional .PlainTransferFrom plain_transfer_From = 5; + */ + public Builder setPlainTransferFrom(org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom value) { + if (plainTransferFromBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + data_ = value; + onChanged(); + } else { + plainTransferFromBuilder_.setMessage(value); + } + dataCase_ = 5; + return this; + } + /** + *
+       * A plaintext token transfer from transaction
+       * 
+ * + * optional .PlainTransferFrom plain_transfer_From = 5; + */ + public Builder setPlainTransferFrom( + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.Builder builderForValue) { + if (plainTransferFromBuilder_ == null) { + data_ = builderForValue.build(); + onChanged(); + } else { + plainTransferFromBuilder_.setMessage(builderForValue.build()); + } + dataCase_ = 5; + return this; + } + /** + *
+       * A plaintext token transfer from transaction
+       * 
+ * + * optional .PlainTransferFrom plain_transfer_From = 5; + */ + public Builder mergePlainTransferFrom(org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom value) { + if (plainTransferFromBuilder_ == null) { + if (dataCase_ == 5 && + data_ != org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.getDefaultInstance()) { + data_ = org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.newBuilder((org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) data_) + .mergeFrom(value).buildPartial(); + } else { + data_ = value; + } + onChanged(); + } else { + if (dataCase_ == 5) { + plainTransferFromBuilder_.mergeFrom(value); + } + plainTransferFromBuilder_.setMessage(value); + } + dataCase_ = 5; + return this; + } + /** + *
+       * A plaintext token transfer from transaction
+       * 
+ * + * optional .PlainTransferFrom plain_transfer_From = 5; + */ + public Builder clearPlainTransferFrom() { + if (plainTransferFromBuilder_ == null) { + if (dataCase_ == 5) { + dataCase_ = 0; + data_ = null; + onChanged(); + } + } else { + if (dataCase_ == 5) { + dataCase_ = 0; + data_ = null; + } + plainTransferFromBuilder_.clear(); + } + return this; + } + /** + *
+       * A plaintext token transfer from transaction
+       * 
+ * + * optional .PlainTransferFrom plain_transfer_From = 5; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.Builder getPlainTransferFromBuilder() { + return getPlainTransferFromFieldBuilder().getBuilder(); + } + /** + *
+       * A plaintext token transfer from transaction
+       * 
+ * + * optional .PlainTransferFrom plain_transfer_From = 5; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferFromOrBuilder getPlainTransferFromOrBuilder() { + if ((dataCase_ == 5) && (plainTransferFromBuilder_ != null)) { + return plainTransferFromBuilder_.getMessageOrBuilder(); + } else { + if (dataCase_ == 5) { + return (org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) data_; + } + return org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.getDefaultInstance(); + } + } + /** + *
+       * A plaintext token transfer from transaction
+       * 
+ * + * optional .PlainTransferFrom plain_transfer_From = 5; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom, org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainTransferFromOrBuilder> + getPlainTransferFromFieldBuilder() { + if (plainTransferFromBuilder_ == null) { + if (!(dataCase_ == 5)) { + data_ = org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.getDefaultInstance(); + } + plainTransferFromBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom, org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainTransferFromOrBuilder>( + (org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) data_, + getParentForChildren(), + isClean()); + data_ = null; + } + dataCase_ = 5; + onChanged();; + return plainTransferFromBuilder_; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:PlainTokenAction) + } + + // @@protoc_insertion_point(class_scope:PlainTokenAction) + private static final org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction(); + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public PlainTokenAction parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new PlainTokenAction(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainTokenAction getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface PlainImportOrBuilder extends + // @@protoc_insertion_point(interface_extends:PlainImport) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * An import transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + java.util.List + getOutputsList(); + /** + *
+     * An import transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutputs(int index); + /** + *
+     * An import transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + int getOutputsCount(); + /** + *
+     * An import transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + java.util.List + getOutputsOrBuilderList(); + /** + *
+     * An import transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputsOrBuilder( + int index); + } + /** + *
+   * PlainImport specifies an import of one or more tokens in plaintext format
+   * 
+ * + * Protobuf type {@code PlainImport} + */ + public static final class PlainImport extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:PlainImport) + PlainImportOrBuilder { + // Use PlainImport.newBuilder() to construct. + private PlainImport(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private PlainImport() { + outputs_ = java.util.Collections.emptyList(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private PlainImport( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + outputs_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000001; + } + outputs_.add( + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainOutput.parser(), extensionRegistry)); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + outputs_ = java.util.Collections.unmodifiableList(outputs_); + } + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainImport_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainImport_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainImport.class, org.hyperledger.fabric.protos.token.Transaction.PlainImport.Builder.class); + } + + public static final int OUTPUTS_FIELD_NUMBER = 1; + private java.util.List outputs_; + /** + *
+     * An import transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public java.util.List getOutputsList() { + return outputs_; + } + /** + *
+     * An import transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public java.util.List + getOutputsOrBuilderList() { + return outputs_; + } + /** + *
+     * An import transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public int getOutputsCount() { + return outputs_.size(); + } + /** + *
+     * An import transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutputs(int index) { + return outputs_.get(index); + } + /** + *
+     * An import transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputsOrBuilder( + int index) { + return outputs_.get(index); + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < outputs_.size(); i++) { + output.writeMessage(1, outputs_.get(i)); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < outputs_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, outputs_.get(i)); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.token.Transaction.PlainImport)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.token.Transaction.PlainImport other = (org.hyperledger.fabric.protos.token.Transaction.PlainImport) obj; + + boolean result = true; + result = result && getOutputsList() + .equals(other.getOutputsList()); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + if (getOutputsCount() > 0) { + hash = (37 * hash) + OUTPUTS_FIELD_NUMBER; + hash = (53 * hash) + getOutputsList().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainImport parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainImport parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainImport parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainImport parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainImport parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainImport parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainImport parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainImport parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainImport parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainImport parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.token.Transaction.PlainImport prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * PlainImport specifies an import of one or more tokens in plaintext format
+     * 
+ * + * Protobuf type {@code PlainImport} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:PlainImport) + org.hyperledger.fabric.protos.token.Transaction.PlainImportOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainImport_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainImport_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainImport.class, org.hyperledger.fabric.protos.token.Transaction.PlainImport.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.token.Transaction.PlainImport.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + getOutputsFieldBuilder(); + } + } + public Builder clear() { + super.clear(); + if (outputsBuilder_ == null) { + outputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + } else { + outputsBuilder_.clear(); + } + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainImport_descriptor; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainImport getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.token.Transaction.PlainImport.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainImport build() { + org.hyperledger.fabric.protos.token.Transaction.PlainImport result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainImport buildPartial() { + org.hyperledger.fabric.protos.token.Transaction.PlainImport result = new org.hyperledger.fabric.protos.token.Transaction.PlainImport(this); + int from_bitField0_ = bitField0_; + if (outputsBuilder_ == null) { + if (((bitField0_ & 0x00000001) == 0x00000001)) { + outputs_ = java.util.Collections.unmodifiableList(outputs_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.outputs_ = outputs_; + } else { + result.outputs_ = outputsBuilder_.build(); + } + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.token.Transaction.PlainImport) { + return mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainImport)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.token.Transaction.PlainImport other) { + if (other == org.hyperledger.fabric.protos.token.Transaction.PlainImport.getDefaultInstance()) return this; + if (outputsBuilder_ == null) { + if (!other.outputs_.isEmpty()) { + if (outputs_.isEmpty()) { + outputs_ = other.outputs_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureOutputsIsMutable(); + outputs_.addAll(other.outputs_); + } + onChanged(); + } + } else { + if (!other.outputs_.isEmpty()) { + if (outputsBuilder_.isEmpty()) { + outputsBuilder_.dispose(); + outputsBuilder_ = null; + outputs_ = other.outputs_; + bitField0_ = (bitField0_ & ~0x00000001); + outputsBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getOutputsFieldBuilder() : null; + } else { + outputsBuilder_.addAllMessages(other.outputs_); + } + } + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.token.Transaction.PlainImport parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.token.Transaction.PlainImport) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.util.List outputs_ = + java.util.Collections.emptyList(); + private void ensureOutputsIsMutable() { + if (!((bitField0_ & 0x00000001) == 0x00000001)) { + outputs_ = new java.util.ArrayList(outputs_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder> outputsBuilder_; + + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public java.util.List getOutputsList() { + if (outputsBuilder_ == null) { + return java.util.Collections.unmodifiableList(outputs_); + } else { + return outputsBuilder_.getMessageList(); + } + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public int getOutputsCount() { + if (outputsBuilder_ == null) { + return outputs_.size(); + } else { + return outputsBuilder_.getCount(); + } + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutputs(int index) { + if (outputsBuilder_ == null) { + return outputs_.get(index); + } else { + return outputsBuilder_.getMessage(index); + } + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder setOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOutputsIsMutable(); + outputs_.set(index, value); + onChanged(); + } else { + outputsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder setOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.set(index, builderForValue.build()); + onChanged(); + } else { + outputsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder addOutputs(org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOutputsIsMutable(); + outputs_.add(value); + onChanged(); + } else { + outputsBuilder_.addMessage(value); + } + return this; + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder addOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOutputsIsMutable(); + outputs_.add(index, value); + onChanged(); + } else { + outputsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder addOutputs( + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.add(builderForValue.build()); + onChanged(); + } else { + outputsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder addOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.add(index, builderForValue.build()); + onChanged(); + } else { + outputsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder addAllOutputs( + java.lang.Iterable values) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, outputs_); + onChanged(); + } else { + outputsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder clearOutputs() { + if (outputsBuilder_ == null) { + outputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + outputsBuilder_.clear(); + } + return this; + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public Builder removeOutputs(int index) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.remove(index); + onChanged(); + } else { + outputsBuilder_.remove(index); + } + return this; + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder getOutputsBuilder( + int index) { + return getOutputsFieldBuilder().getBuilder(index); + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputsOrBuilder( + int index) { + if (outputsBuilder_ == null) { + return outputs_.get(index); } else { + return outputsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public java.util.List + getOutputsOrBuilderList() { + if (outputsBuilder_ != null) { + return outputsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(outputs_); + } + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder addOutputsBuilder() { + return getOutputsFieldBuilder().addBuilder( + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance()); + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder addOutputsBuilder( + int index) { + return getOutputsFieldBuilder().addBuilder( + index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance()); + } + /** + *
+       * An import transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 1; + */ + public java.util.List + getOutputsBuilderList() { + return getOutputsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder> + getOutputsFieldBuilder() { + if (outputsBuilder_ == null) { + outputsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder>( + outputs_, + ((bitField0_ & 0x00000001) == 0x00000001), + getParentForChildren(), + isClean()); + outputs_ = null; + } + return outputsBuilder_; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:PlainImport) + } + + // @@protoc_insertion_point(class_scope:PlainImport) + private static final org.hyperledger.fabric.protos.token.Transaction.PlainImport DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.token.Transaction.PlainImport(); + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainImport getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public PlainImport parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new PlainImport(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainImport getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface PlainTransferOrBuilder extends + // @@protoc_insertion_point(interface_extends:PlainTransfer) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + java.util.List + getInputsList(); + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.InputId getInputs(int index); + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + int getInputsCount(); + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + java.util.List + getInputsOrBuilderList(); + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder getInputsOrBuilder( + int index); + + /** + *
+     * A transfer transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + java.util.List + getOutputsList(); + /** + *
+     * A transfer transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutputs(int index); + /** + *
+     * A transfer transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + int getOutputsCount(); + /** + *
+     * A transfer transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + java.util.List + getOutputsOrBuilderList(); + /** + *
+     * A transfer transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputsOrBuilder( + int index); + } + /** + *
+   * PlainTransfer specifies a transfer of one or more plaintext tokens to one or more outputs
+   * 
+ * + * Protobuf type {@code PlainTransfer} + */ + public static final class PlainTransfer extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:PlainTransfer) + PlainTransferOrBuilder { + // Use PlainTransfer.newBuilder() to construct. + private PlainTransfer(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private PlainTransfer() { + inputs_ = java.util.Collections.emptyList(); + outputs_ = java.util.Collections.emptyList(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private PlainTransfer( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + inputs_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000001; + } + inputs_.add( + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.InputId.parser(), extensionRegistry)); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + outputs_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + outputs_.add( + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainOutput.parser(), extensionRegistry)); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + inputs_ = java.util.Collections.unmodifiableList(inputs_); + } + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + outputs_ = java.util.Collections.unmodifiableList(outputs_); + } + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTransfer_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTransfer_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.class, org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder.class); + } + + public static final int INPUTS_FIELD_NUMBER = 1; + private java.util.List inputs_; + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List getInputsList() { + return inputs_; + } + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List + getInputsOrBuilderList() { + return inputs_; + } + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public int getInputsCount() { + return inputs_.size(); + } + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId getInputs(int index) { + return inputs_.get(index); + } + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder getInputsOrBuilder( + int index) { + return inputs_.get(index); + } + + public static final int OUTPUTS_FIELD_NUMBER = 2; + private java.util.List outputs_; + /** + *
+     * A transfer transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public java.util.List getOutputsList() { + return outputs_; + } + /** + *
+     * A transfer transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public java.util.List + getOutputsOrBuilderList() { + return outputs_; + } + /** + *
+     * A transfer transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public int getOutputsCount() { + return outputs_.size(); + } + /** + *
+     * A transfer transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutputs(int index) { + return outputs_.get(index); + } + /** + *
+     * A transfer transaction may contain one or more outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputsOrBuilder( + int index) { + return outputs_.get(index); + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < inputs_.size(); i++) { + output.writeMessage(1, inputs_.get(i)); + } + for (int i = 0; i < outputs_.size(); i++) { + output.writeMessage(2, outputs_.get(i)); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < inputs_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, inputs_.get(i)); + } + for (int i = 0; i < outputs_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, outputs_.get(i)); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.token.Transaction.PlainTransfer)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer other = (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) obj; + + boolean result = true; + result = result && getInputsList() + .equals(other.getInputsList()); + result = result && getOutputsList() + .equals(other.getOutputsList()); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + if (getInputsCount() > 0) { + hash = (37 * hash) + INPUTS_FIELD_NUMBER; + hash = (53 * hash) + getInputsList().hashCode(); + } + if (getOutputsCount() > 0) { + hash = (37 * hash) + OUTPUTS_FIELD_NUMBER; + hash = (53 * hash) + getOutputsList().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransfer parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransfer parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransfer parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransfer parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransfer parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransfer parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransfer parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransfer parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransfer parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransfer parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.token.Transaction.PlainTransfer prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * PlainTransfer specifies a transfer of one or more plaintext tokens to one or more outputs
+     * 
+ * + * Protobuf type {@code PlainTransfer} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:PlainTransfer) + org.hyperledger.fabric.protos.token.Transaction.PlainTransferOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTransfer_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTransfer_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.class, org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + getInputsFieldBuilder(); + getOutputsFieldBuilder(); + } + } + public Builder clear() { + super.clear(); + if (inputsBuilder_ == null) { + inputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + } else { + inputsBuilder_.clear(); + } + if (outputsBuilder_ == null) { + outputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + } else { + outputsBuilder_.clear(); + } + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTransfer_descriptor; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainTransfer getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainTransfer build() { + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainTransfer buildPartial() { + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer result = new org.hyperledger.fabric.protos.token.Transaction.PlainTransfer(this); + int from_bitField0_ = bitField0_; + if (inputsBuilder_ == null) { + if (((bitField0_ & 0x00000001) == 0x00000001)) { + inputs_ = java.util.Collections.unmodifiableList(inputs_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.inputs_ = inputs_; + } else { + result.inputs_ = inputsBuilder_.build(); + } + if (outputsBuilder_ == null) { + if (((bitField0_ & 0x00000002) == 0x00000002)) { + outputs_ = java.util.Collections.unmodifiableList(outputs_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.outputs_ = outputs_; + } else { + result.outputs_ = outputsBuilder_.build(); + } + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) { + return mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainTransfer)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.token.Transaction.PlainTransfer other) { + if (other == org.hyperledger.fabric.protos.token.Transaction.PlainTransfer.getDefaultInstance()) return this; + if (inputsBuilder_ == null) { + if (!other.inputs_.isEmpty()) { + if (inputs_.isEmpty()) { + inputs_ = other.inputs_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureInputsIsMutable(); + inputs_.addAll(other.inputs_); + } + onChanged(); + } + } else { + if (!other.inputs_.isEmpty()) { + if (inputsBuilder_.isEmpty()) { + inputsBuilder_.dispose(); + inputsBuilder_ = null; + inputs_ = other.inputs_; + bitField0_ = (bitField0_ & ~0x00000001); + inputsBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getInputsFieldBuilder() : null; + } else { + inputsBuilder_.addAllMessages(other.inputs_); + } + } + } + if (outputsBuilder_ == null) { + if (!other.outputs_.isEmpty()) { + if (outputs_.isEmpty()) { + outputs_ = other.outputs_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureOutputsIsMutable(); + outputs_.addAll(other.outputs_); + } + onChanged(); + } + } else { + if (!other.outputs_.isEmpty()) { + if (outputsBuilder_.isEmpty()) { + outputsBuilder_.dispose(); + outputsBuilder_ = null; + outputs_ = other.outputs_; + bitField0_ = (bitField0_ & ~0x00000002); + outputsBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getOutputsFieldBuilder() : null; + } else { + outputsBuilder_.addAllMessages(other.outputs_); + } + } + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.token.Transaction.PlainTransfer parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.token.Transaction.PlainTransfer) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.util.List inputs_ = + java.util.Collections.emptyList(); + private void ensureInputsIsMutable() { + if (!((bitField0_ & 0x00000001) == 0x00000001)) { + inputs_ = new java.util.ArrayList(inputs_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.InputId, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder, org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder> inputsBuilder_; + + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List getInputsList() { + if (inputsBuilder_ == null) { + return java.util.Collections.unmodifiableList(inputs_); + } else { + return inputsBuilder_.getMessageList(); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public int getInputsCount() { + if (inputsBuilder_ == null) { + return inputs_.size(); + } else { + return inputsBuilder_.getCount(); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId getInputs(int index) { + if (inputsBuilder_ == null) { + return inputs_.get(index); + } else { + return inputsBuilder_.getMessage(index); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder setInputs( + int index, org.hyperledger.fabric.protos.token.Transaction.InputId value) { + if (inputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureInputsIsMutable(); + inputs_.set(index, value); + onChanged(); + } else { + inputsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder setInputs( + int index, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder builderForValue) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + inputs_.set(index, builderForValue.build()); + onChanged(); + } else { + inputsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addInputs(org.hyperledger.fabric.protos.token.Transaction.InputId value) { + if (inputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureInputsIsMutable(); + inputs_.add(value); + onChanged(); + } else { + inputsBuilder_.addMessage(value); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addInputs( + int index, org.hyperledger.fabric.protos.token.Transaction.InputId value) { + if (inputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureInputsIsMutable(); + inputs_.add(index, value); + onChanged(); + } else { + inputsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addInputs( + org.hyperledger.fabric.protos.token.Transaction.InputId.Builder builderForValue) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + inputs_.add(builderForValue.build()); + onChanged(); + } else { + inputsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addInputs( + int index, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder builderForValue) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + inputs_.add(index, builderForValue.build()); + onChanged(); + } else { + inputsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addAllInputs( + java.lang.Iterable values) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, inputs_); + onChanged(); + } else { + inputsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder clearInputs() { + if (inputsBuilder_ == null) { + inputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + inputsBuilder_.clear(); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder removeInputs(int index) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + inputs_.remove(index); + onChanged(); + } else { + inputsBuilder_.remove(index); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId.Builder getInputsBuilder( + int index) { + return getInputsFieldBuilder().getBuilder(index); + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder getInputsOrBuilder( + int index) { + if (inputsBuilder_ == null) { + return inputs_.get(index); } else { + return inputsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List + getInputsOrBuilderList() { + if (inputsBuilder_ != null) { + return inputsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(inputs_); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId.Builder addInputsBuilder() { + return getInputsFieldBuilder().addBuilder( + org.hyperledger.fabric.protos.token.Transaction.InputId.getDefaultInstance()); + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId.Builder addInputsBuilder( + int index) { + return getInputsFieldBuilder().addBuilder( + index, org.hyperledger.fabric.protos.token.Transaction.InputId.getDefaultInstance()); + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List + getInputsBuilderList() { + return getInputsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.InputId, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder, org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder> + getInputsFieldBuilder() { + if (inputsBuilder_ == null) { + inputsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.InputId, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder, org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder>( + inputs_, + ((bitField0_ & 0x00000001) == 0x00000001), + getParentForChildren(), + isClean()); + inputs_ = null; + } + return inputsBuilder_; + } + + private java.util.List outputs_ = + java.util.Collections.emptyList(); + private void ensureOutputsIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + outputs_ = new java.util.ArrayList(outputs_); + bitField0_ |= 0x00000002; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder> outputsBuilder_; + + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public java.util.List getOutputsList() { + if (outputsBuilder_ == null) { + return java.util.Collections.unmodifiableList(outputs_); + } else { + return outputsBuilder_.getMessageList(); + } + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public int getOutputsCount() { + if (outputsBuilder_ == null) { + return outputs_.size(); + } else { + return outputsBuilder_.getCount(); + } + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutputs(int index) { + if (outputsBuilder_ == null) { + return outputs_.get(index); + } else { + return outputsBuilder_.getMessage(index); + } + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder setOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOutputsIsMutable(); + outputs_.set(index, value); + onChanged(); + } else { + outputsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder setOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.set(index, builderForValue.build()); + onChanged(); + } else { + outputsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder addOutputs(org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOutputsIsMutable(); + outputs_.add(value); + onChanged(); + } else { + outputsBuilder_.addMessage(value); + } + return this; + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder addOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOutputsIsMutable(); + outputs_.add(index, value); + onChanged(); + } else { + outputsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder addOutputs( + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.add(builderForValue.build()); + onChanged(); + } else { + outputsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder addOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.add(index, builderForValue.build()); + onChanged(); + } else { + outputsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder addAllOutputs( + java.lang.Iterable values) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, outputs_); + onChanged(); + } else { + outputsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder clearOutputs() { + if (outputsBuilder_ == null) { + outputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + } else { + outputsBuilder_.clear(); + } + return this; + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder removeOutputs(int index) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.remove(index); + onChanged(); + } else { + outputsBuilder_.remove(index); + } + return this; + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder getOutputsBuilder( + int index) { + return getOutputsFieldBuilder().getBuilder(index); + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputsOrBuilder( + int index) { + if (outputsBuilder_ == null) { + return outputs_.get(index); } else { + return outputsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public java.util.List + getOutputsOrBuilderList() { + if (outputsBuilder_ != null) { + return outputsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(outputs_); + } + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder addOutputsBuilder() { + return getOutputsFieldBuilder().addBuilder( + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance()); + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder addOutputsBuilder( + int index) { + return getOutputsFieldBuilder().addBuilder( + index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance()); + } + /** + *
+       * A transfer transaction may contain one or more outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public java.util.List + getOutputsBuilderList() { + return getOutputsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder> + getOutputsFieldBuilder() { + if (outputsBuilder_ == null) { + outputsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder>( + outputs_, + ((bitField0_ & 0x00000002) == 0x00000002), + getParentForChildren(), + isClean()); + outputs_ = null; + } + return outputsBuilder_; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:PlainTransfer) + } + + // @@protoc_insertion_point(class_scope:PlainTransfer) + private static final org.hyperledger.fabric.protos.token.Transaction.PlainTransfer DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.token.Transaction.PlainTransfer(); + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransfer getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public PlainTransfer parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new PlainTransfer(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainTransfer getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface PlainApproveOrBuilder extends + // @@protoc_insertion_point(interface_extends:PlainApprove) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + java.util.List + getInputsList(); + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.InputId getInputs(int index); + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + int getInputsCount(); + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + java.util.List + getInputsOrBuilderList(); + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder getInputsOrBuilder( + int index); + + /** + *
+     * An approve transaction contains one or more plain delegated outputs
+     * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + java.util.List + getDelegatedOutputsList(); + /** + *
+     * An approve transaction contains one or more plain delegated outputs
+     * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput getDelegatedOutputs(int index); + /** + *
+     * An approve transaction contains one or more plain delegated outputs
+     * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + int getDelegatedOutputsCount(); + /** + *
+     * An approve transaction contains one or more plain delegated outputs
+     * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + java.util.List + getDelegatedOutputsOrBuilderList(); + /** + *
+     * An approve transaction contains one or more plain delegated outputs
+     * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder getDelegatedOutputsOrBuilder( + int index); + + /** + *
+     * An approve transaction contains one plain output
+     * 
+ * + * optional .PlainOutput output = 3; + */ + boolean hasOutput(); + /** + *
+     * An approve transaction contains one plain output
+     * 
+ * + * optional .PlainOutput output = 3; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutput(); + /** + *
+     * An approve transaction contains one plain output
+     * 
+ * + * optional .PlainOutput output = 3; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputOrBuilder(); + } + /** + *
+   * PlainApprove specifies an approve of one or more tokens in plaintext format
+   * 
+ * + * Protobuf type {@code PlainApprove} + */ + public static final class PlainApprove extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:PlainApprove) + PlainApproveOrBuilder { + // Use PlainApprove.newBuilder() to construct. + private PlainApprove(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private PlainApprove() { + inputs_ = java.util.Collections.emptyList(); + delegatedOutputs_ = java.util.Collections.emptyList(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private PlainApprove( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + inputs_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000001; + } + inputs_.add( + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.InputId.parser(), extensionRegistry)); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + delegatedOutputs_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + delegatedOutputs_.add( + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.parser(), extensionRegistry)); + break; + } + case 26: { + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder subBuilder = null; + if (output_ != null) { + subBuilder = output_.toBuilder(); + } + output_ = input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainOutput.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(output_); + output_ = subBuilder.buildPartial(); + } + + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + inputs_ = java.util.Collections.unmodifiableList(inputs_); + } + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + delegatedOutputs_ = java.util.Collections.unmodifiableList(delegatedOutputs_); + } + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainApprove_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainApprove_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainApprove.class, org.hyperledger.fabric.protos.token.Transaction.PlainApprove.Builder.class); + } + + private int bitField0_; + public static final int INPUTS_FIELD_NUMBER = 1; + private java.util.List inputs_; + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List getInputsList() { + return inputs_; + } + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List + getInputsOrBuilderList() { + return inputs_; + } + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public int getInputsCount() { + return inputs_.size(); + } + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId getInputs(int index) { + return inputs_.get(index); + } + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder getInputsOrBuilder( + int index) { + return inputs_.get(index); + } + + public static final int DELEGATED_OUTPUTS_FIELD_NUMBER = 2; + private java.util.List delegatedOutputs_; + /** + *
+     * An approve transaction contains one or more plain delegated outputs
+     * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public java.util.List getDelegatedOutputsList() { + return delegatedOutputs_; + } + /** + *
+     * An approve transaction contains one or more plain delegated outputs
+     * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public java.util.List + getDelegatedOutputsOrBuilderList() { + return delegatedOutputs_; + } + /** + *
+     * An approve transaction contains one or more plain delegated outputs
+     * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public int getDelegatedOutputsCount() { + return delegatedOutputs_.size(); + } + /** + *
+     * An approve transaction contains one or more plain delegated outputs
+     * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput getDelegatedOutputs(int index) { + return delegatedOutputs_.get(index); + } + /** + *
+     * An approve transaction contains one or more plain delegated outputs
+     * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder getDelegatedOutputsOrBuilder( + int index) { + return delegatedOutputs_.get(index); + } + + public static final int OUTPUT_FIELD_NUMBER = 3; + private org.hyperledger.fabric.protos.token.Transaction.PlainOutput output_; + /** + *
+     * An approve transaction contains one plain output
+     * 
+ * + * optional .PlainOutput output = 3; + */ + public boolean hasOutput() { + return output_ != null; + } + /** + *
+     * An approve transaction contains one plain output
+     * 
+ * + * optional .PlainOutput output = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutput() { + return output_ == null ? org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance() : output_; + } + /** + *
+     * An approve transaction contains one plain output
+     * 
+ * + * optional .PlainOutput output = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputOrBuilder() { + return getOutput(); + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < inputs_.size(); i++) { + output.writeMessage(1, inputs_.get(i)); + } + for (int i = 0; i < delegatedOutputs_.size(); i++) { + output.writeMessage(2, delegatedOutputs_.get(i)); + } + if (output_ != null) { + output.writeMessage(3, getOutput()); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < inputs_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, inputs_.get(i)); + } + for (int i = 0; i < delegatedOutputs_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, delegatedOutputs_.get(i)); + } + if (output_ != null) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getOutput()); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.token.Transaction.PlainApprove)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.token.Transaction.PlainApprove other = (org.hyperledger.fabric.protos.token.Transaction.PlainApprove) obj; + + boolean result = true; + result = result && getInputsList() + .equals(other.getInputsList()); + result = result && getDelegatedOutputsList() + .equals(other.getDelegatedOutputsList()); + result = result && (hasOutput() == other.hasOutput()); + if (hasOutput()) { + result = result && getOutput() + .equals(other.getOutput()); + } + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + if (getInputsCount() > 0) { + hash = (37 * hash) + INPUTS_FIELD_NUMBER; + hash = (53 * hash) + getInputsList().hashCode(); + } + if (getDelegatedOutputsCount() > 0) { + hash = (37 * hash) + DELEGATED_OUTPUTS_FIELD_NUMBER; + hash = (53 * hash) + getDelegatedOutputsList().hashCode(); + } + if (hasOutput()) { + hash = (37 * hash) + OUTPUT_FIELD_NUMBER; + hash = (53 * hash) + getOutput().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainApprove parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainApprove parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainApprove parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainApprove parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainApprove parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainApprove parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainApprove parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainApprove parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainApprove parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainApprove parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.token.Transaction.PlainApprove prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * PlainApprove specifies an approve of one or more tokens in plaintext format
+     * 
+ * + * Protobuf type {@code PlainApprove} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:PlainApprove) + org.hyperledger.fabric.protos.token.Transaction.PlainApproveOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainApprove_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainApprove_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainApprove.class, org.hyperledger.fabric.protos.token.Transaction.PlainApprove.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.token.Transaction.PlainApprove.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + getInputsFieldBuilder(); + getDelegatedOutputsFieldBuilder(); + } + } + public Builder clear() { + super.clear(); + if (inputsBuilder_ == null) { + inputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + } else { + inputsBuilder_.clear(); + } + if (delegatedOutputsBuilder_ == null) { + delegatedOutputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + } else { + delegatedOutputsBuilder_.clear(); + } + if (outputBuilder_ == null) { + output_ = null; + } else { + output_ = null; + outputBuilder_ = null; + } + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainApprove_descriptor; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainApprove getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.token.Transaction.PlainApprove.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainApprove build() { + org.hyperledger.fabric.protos.token.Transaction.PlainApprove result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainApprove buildPartial() { + org.hyperledger.fabric.protos.token.Transaction.PlainApprove result = new org.hyperledger.fabric.protos.token.Transaction.PlainApprove(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (inputsBuilder_ == null) { + if (((bitField0_ & 0x00000001) == 0x00000001)) { + inputs_ = java.util.Collections.unmodifiableList(inputs_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.inputs_ = inputs_; + } else { + result.inputs_ = inputsBuilder_.build(); + } + if (delegatedOutputsBuilder_ == null) { + if (((bitField0_ & 0x00000002) == 0x00000002)) { + delegatedOutputs_ = java.util.Collections.unmodifiableList(delegatedOutputs_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.delegatedOutputs_ = delegatedOutputs_; + } else { + result.delegatedOutputs_ = delegatedOutputsBuilder_.build(); + } + if (outputBuilder_ == null) { + result.output_ = output_; + } else { + result.output_ = outputBuilder_.build(); + } + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.token.Transaction.PlainApprove) { + return mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainApprove)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.token.Transaction.PlainApprove other) { + if (other == org.hyperledger.fabric.protos.token.Transaction.PlainApprove.getDefaultInstance()) return this; + if (inputsBuilder_ == null) { + if (!other.inputs_.isEmpty()) { + if (inputs_.isEmpty()) { + inputs_ = other.inputs_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureInputsIsMutable(); + inputs_.addAll(other.inputs_); + } + onChanged(); + } + } else { + if (!other.inputs_.isEmpty()) { + if (inputsBuilder_.isEmpty()) { + inputsBuilder_.dispose(); + inputsBuilder_ = null; + inputs_ = other.inputs_; + bitField0_ = (bitField0_ & ~0x00000001); + inputsBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getInputsFieldBuilder() : null; + } else { + inputsBuilder_.addAllMessages(other.inputs_); + } + } + } + if (delegatedOutputsBuilder_ == null) { + if (!other.delegatedOutputs_.isEmpty()) { + if (delegatedOutputs_.isEmpty()) { + delegatedOutputs_ = other.delegatedOutputs_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureDelegatedOutputsIsMutable(); + delegatedOutputs_.addAll(other.delegatedOutputs_); + } + onChanged(); + } + } else { + if (!other.delegatedOutputs_.isEmpty()) { + if (delegatedOutputsBuilder_.isEmpty()) { + delegatedOutputsBuilder_.dispose(); + delegatedOutputsBuilder_ = null; + delegatedOutputs_ = other.delegatedOutputs_; + bitField0_ = (bitField0_ & ~0x00000002); + delegatedOutputsBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getDelegatedOutputsFieldBuilder() : null; + } else { + delegatedOutputsBuilder_.addAllMessages(other.delegatedOutputs_); + } + } + } + if (other.hasOutput()) { + mergeOutput(other.getOutput()); + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.token.Transaction.PlainApprove parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.token.Transaction.PlainApprove) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.util.List inputs_ = + java.util.Collections.emptyList(); + private void ensureInputsIsMutable() { + if (!((bitField0_ & 0x00000001) == 0x00000001)) { + inputs_ = new java.util.ArrayList(inputs_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.InputId, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder, org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder> inputsBuilder_; + + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List getInputsList() { + if (inputsBuilder_ == null) { + return java.util.Collections.unmodifiableList(inputs_); + } else { + return inputsBuilder_.getMessageList(); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public int getInputsCount() { + if (inputsBuilder_ == null) { + return inputs_.size(); + } else { + return inputsBuilder_.getCount(); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId getInputs(int index) { + if (inputsBuilder_ == null) { + return inputs_.get(index); + } else { + return inputsBuilder_.getMessage(index); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder setInputs( + int index, org.hyperledger.fabric.protos.token.Transaction.InputId value) { + if (inputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureInputsIsMutable(); + inputs_.set(index, value); + onChanged(); + } else { + inputsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder setInputs( + int index, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder builderForValue) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + inputs_.set(index, builderForValue.build()); + onChanged(); + } else { + inputsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addInputs(org.hyperledger.fabric.protos.token.Transaction.InputId value) { + if (inputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureInputsIsMutable(); + inputs_.add(value); + onChanged(); + } else { + inputsBuilder_.addMessage(value); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addInputs( + int index, org.hyperledger.fabric.protos.token.Transaction.InputId value) { + if (inputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureInputsIsMutable(); + inputs_.add(index, value); + onChanged(); + } else { + inputsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addInputs( + org.hyperledger.fabric.protos.token.Transaction.InputId.Builder builderForValue) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + inputs_.add(builderForValue.build()); + onChanged(); + } else { + inputsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addInputs( + int index, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder builderForValue) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + inputs_.add(index, builderForValue.build()); + onChanged(); + } else { + inputsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addAllInputs( + java.lang.Iterable values) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, inputs_); + onChanged(); + } else { + inputsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder clearInputs() { + if (inputsBuilder_ == null) { + inputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + inputsBuilder_.clear(); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder removeInputs(int index) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + inputs_.remove(index); + onChanged(); + } else { + inputsBuilder_.remove(index); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId.Builder getInputsBuilder( + int index) { + return getInputsFieldBuilder().getBuilder(index); + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder getInputsOrBuilder( + int index) { + if (inputsBuilder_ == null) { + return inputs_.get(index); } else { + return inputsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List + getInputsOrBuilderList() { + if (inputsBuilder_ != null) { + return inputsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(inputs_); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId.Builder addInputsBuilder() { + return getInputsFieldBuilder().addBuilder( + org.hyperledger.fabric.protos.token.Transaction.InputId.getDefaultInstance()); + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId.Builder addInputsBuilder( + int index) { + return getInputsFieldBuilder().addBuilder( + index, org.hyperledger.fabric.protos.token.Transaction.InputId.getDefaultInstance()); + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List + getInputsBuilderList() { + return getInputsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.InputId, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder, org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder> + getInputsFieldBuilder() { + if (inputsBuilder_ == null) { + inputsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.InputId, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder, org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder>( + inputs_, + ((bitField0_ & 0x00000001) == 0x00000001), + getParentForChildren(), + isClean()); + inputs_ = null; + } + return inputsBuilder_; + } + + private java.util.List delegatedOutputs_ = + java.util.Collections.emptyList(); + private void ensureDelegatedOutputsIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + delegatedOutputs_ = new java.util.ArrayList(delegatedOutputs_); + bitField0_ |= 0x00000002; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder> delegatedOutputsBuilder_; + + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public java.util.List getDelegatedOutputsList() { + if (delegatedOutputsBuilder_ == null) { + return java.util.Collections.unmodifiableList(delegatedOutputs_); + } else { + return delegatedOutputsBuilder_.getMessageList(); + } + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public int getDelegatedOutputsCount() { + if (delegatedOutputsBuilder_ == null) { + return delegatedOutputs_.size(); + } else { + return delegatedOutputsBuilder_.getCount(); + } + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput getDelegatedOutputs(int index) { + if (delegatedOutputsBuilder_ == null) { + return delegatedOutputs_.get(index); + } else { + return delegatedOutputsBuilder_.getMessage(index); + } + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public Builder setDelegatedOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput value) { + if (delegatedOutputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureDelegatedOutputsIsMutable(); + delegatedOutputs_.set(index, value); + onChanged(); + } else { + delegatedOutputsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public Builder setDelegatedOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder builderForValue) { + if (delegatedOutputsBuilder_ == null) { + ensureDelegatedOutputsIsMutable(); + delegatedOutputs_.set(index, builderForValue.build()); + onChanged(); + } else { + delegatedOutputsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public Builder addDelegatedOutputs(org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput value) { + if (delegatedOutputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureDelegatedOutputsIsMutable(); + delegatedOutputs_.add(value); + onChanged(); + } else { + delegatedOutputsBuilder_.addMessage(value); + } + return this; + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public Builder addDelegatedOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput value) { + if (delegatedOutputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureDelegatedOutputsIsMutable(); + delegatedOutputs_.add(index, value); + onChanged(); + } else { + delegatedOutputsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public Builder addDelegatedOutputs( + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder builderForValue) { + if (delegatedOutputsBuilder_ == null) { + ensureDelegatedOutputsIsMutable(); + delegatedOutputs_.add(builderForValue.build()); + onChanged(); + } else { + delegatedOutputsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public Builder addDelegatedOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder builderForValue) { + if (delegatedOutputsBuilder_ == null) { + ensureDelegatedOutputsIsMutable(); + delegatedOutputs_.add(index, builderForValue.build()); + onChanged(); + } else { + delegatedOutputsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public Builder addAllDelegatedOutputs( + java.lang.Iterable values) { + if (delegatedOutputsBuilder_ == null) { + ensureDelegatedOutputsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, delegatedOutputs_); + onChanged(); + } else { + delegatedOutputsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public Builder clearDelegatedOutputs() { + if (delegatedOutputsBuilder_ == null) { + delegatedOutputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + } else { + delegatedOutputsBuilder_.clear(); + } + return this; + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public Builder removeDelegatedOutputs(int index) { + if (delegatedOutputsBuilder_ == null) { + ensureDelegatedOutputsIsMutable(); + delegatedOutputs_.remove(index); + onChanged(); + } else { + delegatedOutputsBuilder_.remove(index); + } + return this; + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder getDelegatedOutputsBuilder( + int index) { + return getDelegatedOutputsFieldBuilder().getBuilder(index); + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder getDelegatedOutputsOrBuilder( + int index) { + if (delegatedOutputsBuilder_ == null) { + return delegatedOutputs_.get(index); } else { + return delegatedOutputsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public java.util.List + getDelegatedOutputsOrBuilderList() { + if (delegatedOutputsBuilder_ != null) { + return delegatedOutputsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(delegatedOutputs_); + } + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder addDelegatedOutputsBuilder() { + return getDelegatedOutputsFieldBuilder().addBuilder( + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.getDefaultInstance()); + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder addDelegatedOutputsBuilder( + int index) { + return getDelegatedOutputsFieldBuilder().addBuilder( + index, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.getDefaultInstance()); + } + /** + *
+       * An approve transaction contains one or more plain delegated outputs
+       * 
+ * + * repeated .PlainDelegatedOutput delegated_outputs = 2; + */ + public java.util.List + getDelegatedOutputsBuilderList() { + return getDelegatedOutputsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder> + getDelegatedOutputsFieldBuilder() { + if (delegatedOutputsBuilder_ == null) { + delegatedOutputsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder>( + delegatedOutputs_, + ((bitField0_ & 0x00000002) == 0x00000002), + getParentForChildren(), + isClean()); + delegatedOutputs_ = null; + } + return delegatedOutputsBuilder_; + } + + private org.hyperledger.fabric.protos.token.Transaction.PlainOutput output_ = null; + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder> outputBuilder_; + /** + *
+       * An approve transaction contains one plain output
+       * 
+ * + * optional .PlainOutput output = 3; + */ + public boolean hasOutput() { + return outputBuilder_ != null || output_ != null; + } + /** + *
+       * An approve transaction contains one plain output
+       * 
+ * + * optional .PlainOutput output = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutput() { + if (outputBuilder_ == null) { + return output_ == null ? org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance() : output_; + } else { + return outputBuilder_.getMessage(); + } + } + /** + *
+       * An approve transaction contains one plain output
+       * 
+ * + * optional .PlainOutput output = 3; + */ + public Builder setOutput(org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + output_ = value; + onChanged(); + } else { + outputBuilder_.setMessage(value); + } + + return this; + } + /** + *
+       * An approve transaction contains one plain output
+       * 
+ * + * optional .PlainOutput output = 3; + */ + public Builder setOutput( + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputBuilder_ == null) { + output_ = builderForValue.build(); + onChanged(); + } else { + outputBuilder_.setMessage(builderForValue.build()); + } + + return this; + } + /** + *
+       * An approve transaction contains one plain output
+       * 
+ * + * optional .PlainOutput output = 3; + */ + public Builder mergeOutput(org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputBuilder_ == null) { + if (output_ != null) { + output_ = + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.newBuilder(output_).mergeFrom(value).buildPartial(); + } else { + output_ = value; + } + onChanged(); + } else { + outputBuilder_.mergeFrom(value); + } + + return this; + } + /** + *
+       * An approve transaction contains one plain output
+       * 
+ * + * optional .PlainOutput output = 3; + */ + public Builder clearOutput() { + if (outputBuilder_ == null) { + output_ = null; + onChanged(); + } else { + output_ = null; + outputBuilder_ = null; + } + + return this; + } + /** + *
+       * An approve transaction contains one plain output
+       * 
+ * + * optional .PlainOutput output = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder getOutputBuilder() { + + onChanged(); + return getOutputFieldBuilder().getBuilder(); + } + /** + *
+       * An approve transaction contains one plain output
+       * 
+ * + * optional .PlainOutput output = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputOrBuilder() { + if (outputBuilder_ != null) { + return outputBuilder_.getMessageOrBuilder(); + } else { + return output_ == null ? + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance() : output_; + } + } + /** + *
+       * An approve transaction contains one plain output
+       * 
+ * + * optional .PlainOutput output = 3; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder> + getOutputFieldBuilder() { + if (outputBuilder_ == null) { + outputBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder>( + getOutput(), + getParentForChildren(), + isClean()); + output_ = null; + } + return outputBuilder_; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:PlainApprove) + } + + // @@protoc_insertion_point(class_scope:PlainApprove) + private static final org.hyperledger.fabric.protos.token.Transaction.PlainApprove DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.token.Transaction.PlainApprove(); + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainApprove getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public PlainApprove parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new PlainApprove(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainApprove getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface PlainTransferFromOrBuilder extends + // @@protoc_insertion_point(interface_extends:PlainTransferFrom) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + java.util.List + getInputsList(); + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.InputId getInputs(int index); + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + int getInputsCount(); + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + java.util.List + getInputsOrBuilderList(); + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder getInputsOrBuilder( + int index); + + /** + *
+     * A transferFrom transaction contains multiple outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + java.util.List + getOutputsList(); + /** + *
+     * A transferFrom transaction contains multiple outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutputs(int index); + /** + *
+     * A transferFrom transaction contains multiple outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + int getOutputsCount(); + /** + *
+     * A transferFrom transaction contains multiple outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + java.util.List + getOutputsOrBuilderList(); + /** + *
+     * A transferFrom transaction contains multiple outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputsOrBuilder( + int index); + + /** + *
+     * A transferFrom transaction may contain one delegatable output
+     * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + boolean hasDelegatedOutput(); + /** + *
+     * A transferFrom transaction may contain one delegatable output
+     * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput getDelegatedOutput(); + /** + *
+     * A transferFrom transaction may contain one delegatable output
+     * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder getDelegatedOutputOrBuilder(); + } + /** + *
+   * PlainTransferFrom specifies a transfer of one or more plaintext delegated tokens to one or more outputs
+   * an to a delegated output
+   * 
+ * + * Protobuf type {@code PlainTransferFrom} + */ + public static final class PlainTransferFrom extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:PlainTransferFrom) + PlainTransferFromOrBuilder { + // Use PlainTransferFrom.newBuilder() to construct. + private PlainTransferFrom(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private PlainTransferFrom() { + inputs_ = java.util.Collections.emptyList(); + outputs_ = java.util.Collections.emptyList(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private PlainTransferFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + inputs_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000001; + } + inputs_.add( + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.InputId.parser(), extensionRegistry)); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + outputs_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + outputs_.add( + input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainOutput.parser(), extensionRegistry)); + break; + } + case 26: { + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder subBuilder = null; + if (delegatedOutput_ != null) { + subBuilder = delegatedOutput_.toBuilder(); + } + delegatedOutput_ = input.readMessage(org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.parser(), extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(delegatedOutput_); + delegatedOutput_ = subBuilder.buildPartial(); + } + + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + inputs_ = java.util.Collections.unmodifiableList(inputs_); + } + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + outputs_ = java.util.Collections.unmodifiableList(outputs_); + } + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTransferFrom_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTransferFrom_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.class, org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.Builder.class); + } + + private int bitField0_; + public static final int INPUTS_FIELD_NUMBER = 1; + private java.util.List inputs_; + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List getInputsList() { + return inputs_; + } + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List + getInputsOrBuilderList() { + return inputs_; + } + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public int getInputsCount() { + return inputs_.size(); + } + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId getInputs(int index) { + return inputs_.get(index); + } + /** + *
+     * The inputs to the transfer transaction are specified by their ID
+     * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder getInputsOrBuilder( + int index) { + return inputs_.get(index); + } + + public static final int OUTPUTS_FIELD_NUMBER = 2; + private java.util.List outputs_; + /** + *
+     * A transferFrom transaction contains multiple outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public java.util.List getOutputsList() { + return outputs_; + } + /** + *
+     * A transferFrom transaction contains multiple outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public java.util.List + getOutputsOrBuilderList() { + return outputs_; + } + /** + *
+     * A transferFrom transaction contains multiple outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public int getOutputsCount() { + return outputs_.size(); + } + /** + *
+     * A transferFrom transaction contains multiple outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutputs(int index) { + return outputs_.get(index); + } + /** + *
+     * A transferFrom transaction contains multiple outputs
+     * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputsOrBuilder( + int index) { + return outputs_.get(index); + } + + public static final int DELEGATED_OUTPUT_FIELD_NUMBER = 3; + private org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput delegatedOutput_; + /** + *
+     * A transferFrom transaction may contain one delegatable output
+     * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + public boolean hasDelegatedOutput() { + return delegatedOutput_ != null; + } + /** + *
+     * A transferFrom transaction may contain one delegatable output
+     * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput getDelegatedOutput() { + return delegatedOutput_ == null ? org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.getDefaultInstance() : delegatedOutput_; + } + /** + *
+     * A transferFrom transaction may contain one delegatable output
+     * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder getDelegatedOutputOrBuilder() { + return getDelegatedOutput(); + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < inputs_.size(); i++) { + output.writeMessage(1, inputs_.get(i)); + } + for (int i = 0; i < outputs_.size(); i++) { + output.writeMessage(2, outputs_.get(i)); + } + if (delegatedOutput_ != null) { + output.writeMessage(3, getDelegatedOutput()); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < inputs_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, inputs_.get(i)); + } + for (int i = 0; i < outputs_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, outputs_.get(i)); + } + if (delegatedOutput_ != null) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, getDelegatedOutput()); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom other = (org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) obj; + + boolean result = true; + result = result && getInputsList() + .equals(other.getInputsList()); + result = result && getOutputsList() + .equals(other.getOutputsList()); + result = result && (hasDelegatedOutput() == other.hasDelegatedOutput()); + if (hasDelegatedOutput()) { + result = result && getDelegatedOutput() + .equals(other.getDelegatedOutput()); + } + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + if (getInputsCount() > 0) { + hash = (37 * hash) + INPUTS_FIELD_NUMBER; + hash = (53 * hash) + getInputsList().hashCode(); + } + if (getOutputsCount() > 0) { + hash = (37 * hash) + OUTPUTS_FIELD_NUMBER; + hash = (53 * hash) + getOutputsList().hashCode(); + } + if (hasDelegatedOutput()) { + hash = (37 * hash) + DELEGATED_OUTPUT_FIELD_NUMBER; + hash = (53 * hash) + getDelegatedOutput().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * PlainTransferFrom specifies a transfer of one or more plaintext delegated tokens to one or more outputs
+     * an to a delegated output
+     * 
+ * + * Protobuf type {@code PlainTransferFrom} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:PlainTransferFrom) + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFromOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTransferFrom_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTransferFrom_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.class, org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + getInputsFieldBuilder(); + getOutputsFieldBuilder(); + } + } + public Builder clear() { + super.clear(); + if (inputsBuilder_ == null) { + inputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + } else { + inputsBuilder_.clear(); + } + if (outputsBuilder_ == null) { + outputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + } else { + outputsBuilder_.clear(); + } + if (delegatedOutputBuilder_ == null) { + delegatedOutput_ = null; + } else { + delegatedOutput_ = null; + delegatedOutputBuilder_ = null; + } + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainTransferFrom_descriptor; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom build() { + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom buildPartial() { + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom result = new org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (inputsBuilder_ == null) { + if (((bitField0_ & 0x00000001) == 0x00000001)) { + inputs_ = java.util.Collections.unmodifiableList(inputs_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.inputs_ = inputs_; + } else { + result.inputs_ = inputsBuilder_.build(); + } + if (outputsBuilder_ == null) { + if (((bitField0_ & 0x00000002) == 0x00000002)) { + outputs_ = java.util.Collections.unmodifiableList(outputs_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.outputs_ = outputs_; + } else { + result.outputs_ = outputsBuilder_.build(); + } + if (delegatedOutputBuilder_ == null) { + result.delegatedOutput_ = delegatedOutput_; + } else { + result.delegatedOutput_ = delegatedOutputBuilder_.build(); + } + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) { + return mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom other) { + if (other == org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom.getDefaultInstance()) return this; + if (inputsBuilder_ == null) { + if (!other.inputs_.isEmpty()) { + if (inputs_.isEmpty()) { + inputs_ = other.inputs_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureInputsIsMutable(); + inputs_.addAll(other.inputs_); + } + onChanged(); + } + } else { + if (!other.inputs_.isEmpty()) { + if (inputsBuilder_.isEmpty()) { + inputsBuilder_.dispose(); + inputsBuilder_ = null; + inputs_ = other.inputs_; + bitField0_ = (bitField0_ & ~0x00000001); + inputsBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getInputsFieldBuilder() : null; + } else { + inputsBuilder_.addAllMessages(other.inputs_); + } + } + } + if (outputsBuilder_ == null) { + if (!other.outputs_.isEmpty()) { + if (outputs_.isEmpty()) { + outputs_ = other.outputs_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureOutputsIsMutable(); + outputs_.addAll(other.outputs_); + } + onChanged(); + } + } else { + if (!other.outputs_.isEmpty()) { + if (outputsBuilder_.isEmpty()) { + outputsBuilder_.dispose(); + outputsBuilder_ = null; + outputs_ = other.outputs_; + bitField0_ = (bitField0_ & ~0x00000002); + outputsBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getOutputsFieldBuilder() : null; + } else { + outputsBuilder_.addAllMessages(other.outputs_); + } + } + } + if (other.hasDelegatedOutput()) { + mergeDelegatedOutput(other.getDelegatedOutput()); + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.util.List inputs_ = + java.util.Collections.emptyList(); + private void ensureInputsIsMutable() { + if (!((bitField0_ & 0x00000001) == 0x00000001)) { + inputs_ = new java.util.ArrayList(inputs_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.InputId, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder, org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder> inputsBuilder_; + + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List getInputsList() { + if (inputsBuilder_ == null) { + return java.util.Collections.unmodifiableList(inputs_); + } else { + return inputsBuilder_.getMessageList(); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public int getInputsCount() { + if (inputsBuilder_ == null) { + return inputs_.size(); + } else { + return inputsBuilder_.getCount(); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId getInputs(int index) { + if (inputsBuilder_ == null) { + return inputs_.get(index); + } else { + return inputsBuilder_.getMessage(index); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder setInputs( + int index, org.hyperledger.fabric.protos.token.Transaction.InputId value) { + if (inputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureInputsIsMutable(); + inputs_.set(index, value); + onChanged(); + } else { + inputsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder setInputs( + int index, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder builderForValue) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + inputs_.set(index, builderForValue.build()); + onChanged(); + } else { + inputsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addInputs(org.hyperledger.fabric.protos.token.Transaction.InputId value) { + if (inputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureInputsIsMutable(); + inputs_.add(value); + onChanged(); + } else { + inputsBuilder_.addMessage(value); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addInputs( + int index, org.hyperledger.fabric.protos.token.Transaction.InputId value) { + if (inputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureInputsIsMutable(); + inputs_.add(index, value); + onChanged(); + } else { + inputsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addInputs( + org.hyperledger.fabric.protos.token.Transaction.InputId.Builder builderForValue) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + inputs_.add(builderForValue.build()); + onChanged(); + } else { + inputsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addInputs( + int index, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder builderForValue) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + inputs_.add(index, builderForValue.build()); + onChanged(); + } else { + inputsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder addAllInputs( + java.lang.Iterable values) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, inputs_); + onChanged(); + } else { + inputsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder clearInputs() { + if (inputsBuilder_ == null) { + inputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + inputsBuilder_.clear(); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public Builder removeInputs(int index) { + if (inputsBuilder_ == null) { + ensureInputsIsMutable(); + inputs_.remove(index); + onChanged(); + } else { + inputsBuilder_.remove(index); + } + return this; + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId.Builder getInputsBuilder( + int index) { + return getInputsFieldBuilder().getBuilder(index); + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder getInputsOrBuilder( + int index) { + if (inputsBuilder_ == null) { + return inputs_.get(index); } else { + return inputsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List + getInputsOrBuilderList() { + if (inputsBuilder_ != null) { + return inputsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(inputs_); + } + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId.Builder addInputsBuilder() { + return getInputsFieldBuilder().addBuilder( + org.hyperledger.fabric.protos.token.Transaction.InputId.getDefaultInstance()); + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public org.hyperledger.fabric.protos.token.Transaction.InputId.Builder addInputsBuilder( + int index) { + return getInputsFieldBuilder().addBuilder( + index, org.hyperledger.fabric.protos.token.Transaction.InputId.getDefaultInstance()); + } + /** + *
+       * The inputs to the transfer transaction are specified by their ID
+       * 
+ * + * repeated .InputId inputs = 1; + */ + public java.util.List + getInputsBuilderList() { + return getInputsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.InputId, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder, org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder> + getInputsFieldBuilder() { + if (inputsBuilder_ == null) { + inputsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.InputId, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder, org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder>( + inputs_, + ((bitField0_ & 0x00000001) == 0x00000001), + getParentForChildren(), + isClean()); + inputs_ = null; + } + return inputsBuilder_; + } + + private java.util.List outputs_ = + java.util.Collections.emptyList(); + private void ensureOutputsIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + outputs_ = new java.util.ArrayList(outputs_); + bitField0_ |= 0x00000002; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder> outputsBuilder_; + + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public java.util.List getOutputsList() { + if (outputsBuilder_ == null) { + return java.util.Collections.unmodifiableList(outputs_); + } else { + return outputsBuilder_.getMessageList(); + } + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public int getOutputsCount() { + if (outputsBuilder_ == null) { + return outputs_.size(); + } else { + return outputsBuilder_.getCount(); + } + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput getOutputs(int index) { + if (outputsBuilder_ == null) { + return outputs_.get(index); + } else { + return outputsBuilder_.getMessage(index); + } + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder setOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOutputsIsMutable(); + outputs_.set(index, value); + onChanged(); + } else { + outputsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder setOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.set(index, builderForValue.build()); + onChanged(); + } else { + outputsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder addOutputs(org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOutputsIsMutable(); + outputs_.add(value); + onChanged(); + } else { + outputsBuilder_.addMessage(value); + } + return this; + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder addOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput value) { + if (outputsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureOutputsIsMutable(); + outputs_.add(index, value); + onChanged(); + } else { + outputsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder addOutputs( + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.add(builderForValue.build()); + onChanged(); + } else { + outputsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder addOutputs( + int index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder builderForValue) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.add(index, builderForValue.build()); + onChanged(); + } else { + outputsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder addAllOutputs( + java.lang.Iterable values) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, outputs_); + onChanged(); + } else { + outputsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder clearOutputs() { + if (outputsBuilder_ == null) { + outputs_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + } else { + outputsBuilder_.clear(); + } + return this; + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public Builder removeOutputs(int index) { + if (outputsBuilder_ == null) { + ensureOutputsIsMutable(); + outputs_.remove(index); + onChanged(); + } else { + outputsBuilder_.remove(index); + } + return this; + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder getOutputsBuilder( + int index) { + return getOutputsFieldBuilder().getBuilder(index); + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder getOutputsOrBuilder( + int index) { + if (outputsBuilder_ == null) { + return outputs_.get(index); } else { + return outputsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public java.util.List + getOutputsOrBuilderList() { + if (outputsBuilder_ != null) { + return outputsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(outputs_); + } + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder addOutputsBuilder() { + return getOutputsFieldBuilder().addBuilder( + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance()); + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder addOutputsBuilder( + int index) { + return getOutputsFieldBuilder().addBuilder( + index, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance()); + } + /** + *
+       * A transferFrom transaction contains multiple outputs
+       * 
+ * + * repeated .PlainOutput outputs = 2; + */ + public java.util.List + getOutputsBuilderList() { + return getOutputsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder> + getOutputsFieldBuilder() { + if (outputsBuilder_ == null) { + outputsBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainOutput, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder>( + outputs_, + ((bitField0_ & 0x00000002) == 0x00000002), + getParentForChildren(), + isClean()); + outputs_ = null; + } + return outputsBuilder_; + } + + private org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput delegatedOutput_ = null; + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder> delegatedOutputBuilder_; + /** + *
+       * A transferFrom transaction may contain one delegatable output
+       * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + public boolean hasDelegatedOutput() { + return delegatedOutputBuilder_ != null || delegatedOutput_ != null; + } + /** + *
+       * A transferFrom transaction may contain one delegatable output
+       * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput getDelegatedOutput() { + if (delegatedOutputBuilder_ == null) { + return delegatedOutput_ == null ? org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.getDefaultInstance() : delegatedOutput_; + } else { + return delegatedOutputBuilder_.getMessage(); + } + } + /** + *
+       * A transferFrom transaction may contain one delegatable output
+       * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + public Builder setDelegatedOutput(org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput value) { + if (delegatedOutputBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + delegatedOutput_ = value; + onChanged(); + } else { + delegatedOutputBuilder_.setMessage(value); + } + + return this; + } + /** + *
+       * A transferFrom transaction may contain one delegatable output
+       * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + public Builder setDelegatedOutput( + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder builderForValue) { + if (delegatedOutputBuilder_ == null) { + delegatedOutput_ = builderForValue.build(); + onChanged(); + } else { + delegatedOutputBuilder_.setMessage(builderForValue.build()); + } + + return this; + } + /** + *
+       * A transferFrom transaction may contain one delegatable output
+       * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + public Builder mergeDelegatedOutput(org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput value) { + if (delegatedOutputBuilder_ == null) { + if (delegatedOutput_ != null) { + delegatedOutput_ = + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.newBuilder(delegatedOutput_).mergeFrom(value).buildPartial(); + } else { + delegatedOutput_ = value; + } + onChanged(); + } else { + delegatedOutputBuilder_.mergeFrom(value); + } + + return this; + } + /** + *
+       * A transferFrom transaction may contain one delegatable output
+       * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + public Builder clearDelegatedOutput() { + if (delegatedOutputBuilder_ == null) { + delegatedOutput_ = null; + onChanged(); + } else { + delegatedOutput_ = null; + delegatedOutputBuilder_ = null; + } + + return this; + } + /** + *
+       * A transferFrom transaction may contain one delegatable output
+       * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder getDelegatedOutputBuilder() { + + onChanged(); + return getDelegatedOutputFieldBuilder().getBuilder(); + } + /** + *
+       * A transferFrom transaction may contain one delegatable output
+       * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder getDelegatedOutputOrBuilder() { + if (delegatedOutputBuilder_ != null) { + return delegatedOutputBuilder_.getMessageOrBuilder(); + } else { + return delegatedOutput_ == null ? + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.getDefaultInstance() : delegatedOutput_; + } + } + /** + *
+       * A transferFrom transaction may contain one delegatable output
+       * 
+ * + * optional .PlainDelegatedOutput delegated_output = 3; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder> + getDelegatedOutputFieldBuilder() { + if (delegatedOutputBuilder_ == null) { + delegatedOutputBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder>( + getDelegatedOutput(), + getParentForChildren(), + isClean()); + delegatedOutput_ = null; + } + return delegatedOutputBuilder_; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:PlainTransferFrom) + } + + // @@protoc_insertion_point(class_scope:PlainTransferFrom) + private static final org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom(); + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public PlainTransferFrom parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new PlainTransferFrom(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainTransferFrom getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface PlainOutputOrBuilder extends + // @@protoc_insertion_point(interface_extends:PlainOutput) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * The owner is the serialization of a SerializedIdentity struct
+     * 
+ * + * optional bytes owner = 1; + */ + com.google.protobuf.ByteString getOwner(); + + /** + *
+     * The token type
+     * 
+ * + * optional string type = 2; + */ + java.lang.String getType(); + /** + *
+     * The token type
+     * 
+ * + * optional string type = 2; + */ + com.google.protobuf.ByteString + getTypeBytes(); + + /** + *
+     * The quantity of tokens
+     * 
+ * + * optional uint64 quantity = 3; + */ + long getQuantity(); + } + /** + *
+   * A PlainOutput is the result of import and transfer transactions using plaintext tokens
+   * 
+ * + * Protobuf type {@code PlainOutput} + */ + public static final class PlainOutput extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:PlainOutput) + PlainOutputOrBuilder { + // Use PlainOutput.newBuilder() to construct. + private PlainOutput(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private PlainOutput() { + owner_ = com.google.protobuf.ByteString.EMPTY; + type_ = ""; + quantity_ = 0L; + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private PlainOutput( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + + owner_ = input.readBytes(); + break; + } + case 18: { + java.lang.String s = input.readStringRequireUtf8(); + + type_ = s; + break; + } + case 24: { + + quantity_ = input.readUInt64(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainOutput_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainOutput_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.class, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder.class); + } + + public static final int OWNER_FIELD_NUMBER = 1; + private com.google.protobuf.ByteString owner_; + /** + *
+     * The owner is the serialization of a SerializedIdentity struct
+     * 
+ * + * optional bytes owner = 1; + */ + public com.google.protobuf.ByteString getOwner() { + return owner_; + } + + public static final int TYPE_FIELD_NUMBER = 2; + private volatile java.lang.Object type_; + /** + *
+     * The token type
+     * 
+ * + * optional string type = 2; + */ + public java.lang.String getType() { + java.lang.Object ref = type_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + type_ = s; + return s; + } + } + /** + *
+     * The token type
+     * 
+ * + * optional string type = 2; + */ + public com.google.protobuf.ByteString + getTypeBytes() { + java.lang.Object ref = type_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + type_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int QUANTITY_FIELD_NUMBER = 3; + private long quantity_; + /** + *
+     * The quantity of tokens
+     * 
+ * + * optional uint64 quantity = 3; + */ + public long getQuantity() { + return quantity_; + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!owner_.isEmpty()) { + output.writeBytes(1, owner_); + } + if (!getTypeBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, type_); + } + if (quantity_ != 0L) { + output.writeUInt64(3, quantity_); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!owner_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, owner_); + } + if (!getTypeBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, type_); + } + if (quantity_ != 0L) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size(3, quantity_); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.token.Transaction.PlainOutput)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.token.Transaction.PlainOutput other = (org.hyperledger.fabric.protos.token.Transaction.PlainOutput) obj; + + boolean result = true; + result = result && getOwner() + .equals(other.getOwner()); + result = result && getType() + .equals(other.getType()); + result = result && (getQuantity() + == other.getQuantity()); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + hash = (37 * hash) + OWNER_FIELD_NUMBER; + hash = (53 * hash) + getOwner().hashCode(); + hash = (37 * hash) + TYPE_FIELD_NUMBER; + hash = (53 * hash) + getType().hashCode(); + hash = (37 * hash) + QUANTITY_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + getQuantity()); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainOutput parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainOutput parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainOutput parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainOutput parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainOutput parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainOutput parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainOutput parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainOutput parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainOutput parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainOutput parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.token.Transaction.PlainOutput prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * A PlainOutput is the result of import and transfer transactions using plaintext tokens
+     * 
+ * + * Protobuf type {@code PlainOutput} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:PlainOutput) + org.hyperledger.fabric.protos.token.Transaction.PlainOutputOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainOutput_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainOutput_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainOutput.class, org.hyperledger.fabric.protos.token.Transaction.PlainOutput.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.token.Transaction.PlainOutput.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + public Builder clear() { + super.clear(); + owner_ = com.google.protobuf.ByteString.EMPTY; + + type_ = ""; + + quantity_ = 0L; + + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainOutput_descriptor; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput build() { + org.hyperledger.fabric.protos.token.Transaction.PlainOutput result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput buildPartial() { + org.hyperledger.fabric.protos.token.Transaction.PlainOutput result = new org.hyperledger.fabric.protos.token.Transaction.PlainOutput(this); + result.owner_ = owner_; + result.type_ = type_; + result.quantity_ = quantity_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.token.Transaction.PlainOutput) { + return mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainOutput)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.token.Transaction.PlainOutput other) { + if (other == org.hyperledger.fabric.protos.token.Transaction.PlainOutput.getDefaultInstance()) return this; + if (other.getOwner() != com.google.protobuf.ByteString.EMPTY) { + setOwner(other.getOwner()); + } + if (!other.getType().isEmpty()) { + type_ = other.type_; + onChanged(); + } + if (other.getQuantity() != 0L) { + setQuantity(other.getQuantity()); + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.token.Transaction.PlainOutput parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.token.Transaction.PlainOutput) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private com.google.protobuf.ByteString owner_ = com.google.protobuf.ByteString.EMPTY; + /** + *
+       * The owner is the serialization of a SerializedIdentity struct
+       * 
+ * + * optional bytes owner = 1; + */ + public com.google.protobuf.ByteString getOwner() { + return owner_; + } + /** + *
+       * The owner is the serialization of a SerializedIdentity struct
+       * 
+ * + * optional bytes owner = 1; + */ + public Builder setOwner(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + + owner_ = value; + onChanged(); + return this; + } + /** + *
+       * The owner is the serialization of a SerializedIdentity struct
+       * 
+ * + * optional bytes owner = 1; + */ + public Builder clearOwner() { + + owner_ = getDefaultInstance().getOwner(); + onChanged(); + return this; + } + + private java.lang.Object type_ = ""; + /** + *
+       * The token type
+       * 
+ * + * optional string type = 2; + */ + public java.lang.String getType() { + java.lang.Object ref = type_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + type_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+       * The token type
+       * 
+ * + * optional string type = 2; + */ + public com.google.protobuf.ByteString + getTypeBytes() { + java.lang.Object ref = type_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + type_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+       * The token type
+       * 
+ * + * optional string type = 2; + */ + public Builder setType( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + type_ = value; + onChanged(); + return this; + } + /** + *
+       * The token type
+       * 
+ * + * optional string type = 2; + */ + public Builder clearType() { + + type_ = getDefaultInstance().getType(); + onChanged(); + return this; + } + /** + *
+       * The token type
+       * 
+ * + * optional string type = 2; + */ + public Builder setTypeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + type_ = value; + onChanged(); + return this; + } + + private long quantity_ ; + /** + *
+       * The quantity of tokens
+       * 
+ * + * optional uint64 quantity = 3; + */ + public long getQuantity() { + return quantity_; + } + /** + *
+       * The quantity of tokens
+       * 
+ * + * optional uint64 quantity = 3; + */ + public Builder setQuantity(long value) { + + quantity_ = value; + onChanged(); + return this; + } + /** + *
+       * The quantity of tokens
+       * 
+ * + * optional uint64 quantity = 3; + */ + public Builder clearQuantity() { + + quantity_ = 0L; + onChanged(); + return this; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:PlainOutput) + } + + // @@protoc_insertion_point(class_scope:PlainOutput) + private static final org.hyperledger.fabric.protos.token.Transaction.PlainOutput DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.token.Transaction.PlainOutput(); + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainOutput getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public PlainOutput parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new PlainOutput(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainOutput getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface InputIdOrBuilder extends + // @@protoc_insertion_point(interface_extends:InputId) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * The transaction ID
+     * 
+ * + * optional string tx_id = 1; + */ + java.lang.String getTxId(); + /** + *
+     * The transaction ID
+     * 
+ * + * optional string tx_id = 1; + */ + com.google.protobuf.ByteString + getTxIdBytes(); + + /** + *
+     * The index of the output in the transaction
+     * 
+ * + * optional uint32 index = 2; + */ + int getIndex(); + } + /** + *
+   * An InputId specifies an output using the transaction ID and the index of the output in the transaction
+   * 
+ * + * Protobuf type {@code InputId} + */ + public static final class InputId extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:InputId) + InputIdOrBuilder { + // Use InputId.newBuilder() to construct. + private InputId(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private InputId() { + txId_ = ""; + index_ = 0; + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private InputId( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + + txId_ = s; + break; + } + case 16: { + + index_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_InputId_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_InputId_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.InputId.class, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder.class); + } + + public static final int TX_ID_FIELD_NUMBER = 1; + private volatile java.lang.Object txId_; + /** + *
+     * The transaction ID
+     * 
+ * + * optional string tx_id = 1; + */ + public java.lang.String getTxId() { + java.lang.Object ref = txId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + txId_ = s; + return s; + } + } + /** + *
+     * The transaction ID
+     * 
+ * + * optional string tx_id = 1; + */ + public com.google.protobuf.ByteString + getTxIdBytes() { + java.lang.Object ref = txId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + txId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int INDEX_FIELD_NUMBER = 2; + private int index_; + /** + *
+     * The index of the output in the transaction
+     * 
+ * + * optional uint32 index = 2; + */ + public int getIndex() { + return index_; + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!getTxIdBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, txId_); + } + if (index_ != 0) { + output.writeUInt32(2, index_); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!getTxIdBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, txId_); + } + if (index_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(2, index_); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.token.Transaction.InputId)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.token.Transaction.InputId other = (org.hyperledger.fabric.protos.token.Transaction.InputId) obj; + + boolean result = true; + result = result && getTxId() + .equals(other.getTxId()); + result = result && (getIndex() + == other.getIndex()); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + hash = (37 * hash) + TX_ID_FIELD_NUMBER; + hash = (53 * hash) + getTxId().hashCode(); + hash = (37 * hash) + INDEX_FIELD_NUMBER; + hash = (53 * hash) + getIndex(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.token.Transaction.InputId parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.InputId parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.InputId parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.InputId parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.InputId parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.InputId parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.InputId parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.InputId parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.InputId parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.InputId parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.token.Transaction.InputId prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * An InputId specifies an output using the transaction ID and the index of the output in the transaction
+     * 
+ * + * Protobuf type {@code InputId} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:InputId) + org.hyperledger.fabric.protos.token.Transaction.InputIdOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_InputId_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_InputId_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.InputId.class, org.hyperledger.fabric.protos.token.Transaction.InputId.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.token.Transaction.InputId.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + public Builder clear() { + super.clear(); + txId_ = ""; + + index_ = 0; + + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_InputId_descriptor; + } + + public org.hyperledger.fabric.protos.token.Transaction.InputId getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.token.Transaction.InputId.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.token.Transaction.InputId build() { + org.hyperledger.fabric.protos.token.Transaction.InputId result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.token.Transaction.InputId buildPartial() { + org.hyperledger.fabric.protos.token.Transaction.InputId result = new org.hyperledger.fabric.protos.token.Transaction.InputId(this); + result.txId_ = txId_; + result.index_ = index_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.token.Transaction.InputId) { + return mergeFrom((org.hyperledger.fabric.protos.token.Transaction.InputId)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.token.Transaction.InputId other) { + if (other == org.hyperledger.fabric.protos.token.Transaction.InputId.getDefaultInstance()) return this; + if (!other.getTxId().isEmpty()) { + txId_ = other.txId_; + onChanged(); + } + if (other.getIndex() != 0) { + setIndex(other.getIndex()); + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.token.Transaction.InputId parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.token.Transaction.InputId) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private java.lang.Object txId_ = ""; + /** + *
+       * The transaction ID
+       * 
+ * + * optional string tx_id = 1; + */ + public java.lang.String getTxId() { + java.lang.Object ref = txId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + txId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+       * The transaction ID
+       * 
+ * + * optional string tx_id = 1; + */ + public com.google.protobuf.ByteString + getTxIdBytes() { + java.lang.Object ref = txId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + txId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+       * The transaction ID
+       * 
+ * + * optional string tx_id = 1; + */ + public Builder setTxId( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + txId_ = value; + onChanged(); + return this; + } + /** + *
+       * The transaction ID
+       * 
+ * + * optional string tx_id = 1; + */ + public Builder clearTxId() { + + txId_ = getDefaultInstance().getTxId(); + onChanged(); + return this; + } + /** + *
+       * The transaction ID
+       * 
+ * + * optional string tx_id = 1; + */ + public Builder setTxIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + txId_ = value; + onChanged(); + return this; + } + + private int index_ ; + /** + *
+       * The index of the output in the transaction
+       * 
+ * + * optional uint32 index = 2; + */ + public int getIndex() { + return index_; + } + /** + *
+       * The index of the output in the transaction
+       * 
+ * + * optional uint32 index = 2; + */ + public Builder setIndex(int value) { + + index_ = value; + onChanged(); + return this; + } + /** + *
+       * The index of the output in the transaction
+       * 
+ * + * optional uint32 index = 2; + */ + public Builder clearIndex() { + + index_ = 0; + onChanged(); + return this; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:InputId) + } + + // @@protoc_insertion_point(class_scope:InputId) + private static final org.hyperledger.fabric.protos.token.Transaction.InputId DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.token.Transaction.InputId(); + } + + public static org.hyperledger.fabric.protos.token.Transaction.InputId getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public InputId parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new InputId(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.token.Transaction.InputId getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface PlainDelegatedOutputOrBuilder extends + // @@protoc_insertion_point(interface_extends:PlainDelegatedOutput) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * The owner is the serialization of a SerializedIdentity struct
+     * 
+ * + * optional bytes owner = 1; + */ + com.google.protobuf.ByteString getOwner(); + + /** + *
+     * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+     * the owner
+     * 
+ * + * repeated bytes delegatees = 2; + */ + java.util.List getDelegateesList(); + /** + *
+     * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+     * the owner
+     * 
+ * + * repeated bytes delegatees = 2; + */ + int getDelegateesCount(); + /** + *
+     * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+     * the owner
+     * 
+ * + * repeated bytes delegatees = 2; + */ + com.google.protobuf.ByteString getDelegatees(int index); + + /** + *
+     * The token type
+     * 
+ * + * optional string type = 3; + */ + java.lang.String getType(); + /** + *
+     * The token type
+     * 
+ * + * optional string type = 3; + */ + com.google.protobuf.ByteString + getTypeBytes(); + + /** + *
+     * The quantity of tokens
+     * 
+ * + * optional uint64 quantity = 4; + */ + long getQuantity(); + } + /** + *
+   * A PlainDelegatedOutput is the result of approve transactions using plaintext tokens
+   * 
+ * + * Protobuf type {@code PlainDelegatedOutput} + */ + public static final class PlainDelegatedOutput extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:PlainDelegatedOutput) + PlainDelegatedOutputOrBuilder { + // Use PlainDelegatedOutput.newBuilder() to construct. + private PlainDelegatedOutput(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private PlainDelegatedOutput() { + owner_ = com.google.protobuf.ByteString.EMPTY; + delegatees_ = java.util.Collections.emptyList(); + type_ = ""; + quantity_ = 0L; + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); + } + private PlainDelegatedOutput( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!input.skipField(tag)) { + done = true; + } + break; + } + case 10: { + + owner_ = input.readBytes(); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + delegatees_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + delegatees_.add(input.readBytes()); + break; + } + case 26: { + java.lang.String s = input.readStringRequireUtf8(); + + type_ = s; + break; + } + case 32: { + + quantity_ = input.readUInt64(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + delegatees_ = java.util.Collections.unmodifiableList(delegatees_); + } + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainDelegatedOutput_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainDelegatedOutput_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.class, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder.class); + } + + private int bitField0_; + public static final int OWNER_FIELD_NUMBER = 1; + private com.google.protobuf.ByteString owner_; + /** + *
+     * The owner is the serialization of a SerializedIdentity struct
+     * 
+ * + * optional bytes owner = 1; + */ + public com.google.protobuf.ByteString getOwner() { + return owner_; + } + + public static final int DELEGATEES_FIELD_NUMBER = 2; + private java.util.List delegatees_; + /** + *
+     * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+     * the owner
+     * 
+ * + * repeated bytes delegatees = 2; + */ + public java.util.List + getDelegateesList() { + return delegatees_; + } + /** + *
+     * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+     * the owner
+     * 
+ * + * repeated bytes delegatees = 2; + */ + public int getDelegateesCount() { + return delegatees_.size(); + } + /** + *
+     * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+     * the owner
+     * 
+ * + * repeated bytes delegatees = 2; + */ + public com.google.protobuf.ByteString getDelegatees(int index) { + return delegatees_.get(index); + } + + public static final int TYPE_FIELD_NUMBER = 3; + private volatile java.lang.Object type_; + /** + *
+     * The token type
+     * 
+ * + * optional string type = 3; + */ + public java.lang.String getType() { + java.lang.Object ref = type_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + type_ = s; + return s; + } + } + /** + *
+     * The token type
+     * 
+ * + * optional string type = 3; + */ + public com.google.protobuf.ByteString + getTypeBytes() { + java.lang.Object ref = type_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + type_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int QUANTITY_FIELD_NUMBER = 4; + private long quantity_; + /** + *
+     * The quantity of tokens
+     * 
+ * + * optional uint64 quantity = 4; + */ + public long getQuantity() { + return quantity_; + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!owner_.isEmpty()) { + output.writeBytes(1, owner_); + } + for (int i = 0; i < delegatees_.size(); i++) { + output.writeBytes(2, delegatees_.get(i)); + } + if (!getTypeBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, type_); + } + if (quantity_ != 0L) { + output.writeUInt64(4, quantity_); + } + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!owner_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, owner_); + } + { + int dataSize = 0; + for (int i = 0; i < delegatees_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeBytesSizeNoTag(delegatees_.get(i)); + } + size += dataSize; + size += 1 * getDelegateesList().size(); + } + if (!getTypeBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, type_); + } + if (quantity_ != 0L) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size(4, quantity_); + } + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput)) { + return super.equals(obj); + } + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput other = (org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput) obj; + + boolean result = true; + result = result && getOwner() + .equals(other.getOwner()); + result = result && getDelegateesList() + .equals(other.getDelegateesList()); + result = result && getType() + .equals(other.getType()); + result = result && (getQuantity() + == other.getQuantity()); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + hash = (37 * hash) + OWNER_FIELD_NUMBER; + hash = (53 * hash) + getOwner().hashCode(); + if (getDelegateesCount() > 0) { + hash = (37 * hash) + DELEGATEES_FIELD_NUMBER; + hash = (53 * hash) + getDelegateesList().hashCode(); + } + hash = (37 * hash) + TYPE_FIELD_NUMBER; + hash = (53 * hash) + getType().hashCode(); + hash = (37 * hash) + QUANTITY_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + getQuantity()); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+     * A PlainDelegatedOutput is the result of approve transactions using plaintext tokens
+     * 
+ * + * Protobuf type {@code PlainDelegatedOutput} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:PlainDelegatedOutput) + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutputOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainDelegatedOutput_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainDelegatedOutput_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.class, org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.Builder.class); + } + + // Construct using org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + public Builder clear() { + super.clear(); + owner_ = com.google.protobuf.ByteString.EMPTY; + + delegatees_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + type_ = ""; + + quantity_ = 0L; + + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.hyperledger.fabric.protos.token.Transaction.internal_static_PlainDelegatedOutput_descriptor; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput getDefaultInstanceForType() { + return org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.getDefaultInstance(); + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput build() { + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput buildPartial() { + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput result = new org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + result.owner_ = owner_; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + delegatees_ = java.util.Collections.unmodifiableList(delegatees_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.delegatees_ = delegatees_; + result.type_ = type_; + result.quantity_ = quantity_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput) { + return mergeFrom((org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput other) { + if (other == org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput.getDefaultInstance()) return this; + if (other.getOwner() != com.google.protobuf.ByteString.EMPTY) { + setOwner(other.getOwner()); + } + if (!other.delegatees_.isEmpty()) { + if (delegatees_.isEmpty()) { + delegatees_ = other.delegatees_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureDelegateesIsMutable(); + delegatees_.addAll(other.delegatees_); + } + onChanged(); + } + if (!other.getType().isEmpty()) { + type_ = other.type_; + onChanged(); + } + if (other.getQuantity() != 0L) { + setQuantity(other.getQuantity()); + } + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private com.google.protobuf.ByteString owner_ = com.google.protobuf.ByteString.EMPTY; + /** + *
+       * The owner is the serialization of a SerializedIdentity struct
+       * 
+ * + * optional bytes owner = 1; + */ + public com.google.protobuf.ByteString getOwner() { + return owner_; + } + /** + *
+       * The owner is the serialization of a SerializedIdentity struct
+       * 
+ * + * optional bytes owner = 1; + */ + public Builder setOwner(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + + owner_ = value; + onChanged(); + return this; + } + /** + *
+       * The owner is the serialization of a SerializedIdentity struct
+       * 
+ * + * optional bytes owner = 1; + */ + public Builder clearOwner() { + + owner_ = getDefaultInstance().getOwner(); + onChanged(); + return this; + } + + private java.util.List delegatees_ = java.util.Collections.emptyList(); + private void ensureDelegateesIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + delegatees_ = new java.util.ArrayList(delegatees_); + bitField0_ |= 0x00000002; + } + } + /** + *
+       * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+       * the owner
+       * 
+ * + * repeated bytes delegatees = 2; + */ + public java.util.List + getDelegateesList() { + return java.util.Collections.unmodifiableList(delegatees_); + } + /** + *
+       * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+       * the owner
+       * 
+ * + * repeated bytes delegatees = 2; + */ + public int getDelegateesCount() { + return delegatees_.size(); + } + /** + *
+       * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+       * the owner
+       * 
+ * + * repeated bytes delegatees = 2; + */ + public com.google.protobuf.ByteString getDelegatees(int index) { + return delegatees_.get(index); + } + /** + *
+       * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+       * the owner
+       * 
+ * + * repeated bytes delegatees = 2; + */ + public Builder setDelegatees( + int index, com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + ensureDelegateesIsMutable(); + delegatees_.set(index, value); + onChanged(); + return this; + } + /** + *
+       * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+       * the owner
+       * 
+ * + * repeated bytes delegatees = 2; + */ + public Builder addDelegatees(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + ensureDelegateesIsMutable(); + delegatees_.add(value); + onChanged(); + return this; + } + /** + *
+       * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+       * the owner
+       * 
+ * + * repeated bytes delegatees = 2; + */ + public Builder addAllDelegatees( + java.lang.Iterable values) { + ensureDelegateesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, delegatees_); + onChanged(); + return this; + } + /** + *
+       * The delegatees is an arrary of the serialized identities that can spend the output on behalf
+       * the owner
+       * 
+ * + * repeated bytes delegatees = 2; + */ + public Builder clearDelegatees() { + delegatees_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + + private java.lang.Object type_ = ""; + /** + *
+       * The token type
+       * 
+ * + * optional string type = 3; + */ + public java.lang.String getType() { + java.lang.Object ref = type_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + type_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+       * The token type
+       * 
+ * + * optional string type = 3; + */ + public com.google.protobuf.ByteString + getTypeBytes() { + java.lang.Object ref = type_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + type_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+       * The token type
+       * 
+ * + * optional string type = 3; + */ + public Builder setType( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + type_ = value; + onChanged(); + return this; + } + /** + *
+       * The token type
+       * 
+ * + * optional string type = 3; + */ + public Builder clearType() { + + type_ = getDefaultInstance().getType(); + onChanged(); + return this; + } + /** + *
+       * The token type
+       * 
+ * + * optional string type = 3; + */ + public Builder setTypeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + type_ = value; + onChanged(); + return this; + } + + private long quantity_ ; + /** + *
+       * The quantity of tokens
+       * 
+ * + * optional uint64 quantity = 4; + */ + public long getQuantity() { + return quantity_; + } + /** + *
+       * The quantity of tokens
+       * 
+ * + * optional uint64 quantity = 4; + */ + public Builder setQuantity(long value) { + + quantity_ = value; + onChanged(); + return this; + } + /** + *
+       * The quantity of tokens
+       * 
+ * + * optional uint64 quantity = 4; + */ + public Builder clearQuantity() { + + quantity_ = 0L; + onChanged(); + return this; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return this; + } + + + // @@protoc_insertion_point(builder_scope:PlainDelegatedOutput) + } + + // @@protoc_insertion_point(class_scope:PlainDelegatedOutput) + private static final org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput(); + } + + public static org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public PlainDelegatedOutput parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new PlainDelegatedOutput(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public org.hyperledger.fabric.protos.token.Transaction.PlainDelegatedOutput getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_TokenTransaction_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_TokenTransaction_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_PlainTokenAction_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_PlainTokenAction_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_PlainImport_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_PlainImport_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_PlainTransfer_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_PlainTransfer_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_PlainApprove_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_PlainApprove_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_PlainTransferFrom_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_PlainTransferFrom_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_PlainOutput_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_PlainOutput_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_InputId_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_InputId_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_PlainDelegatedOutput_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_PlainDelegatedOutput_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\027token/transaction.proto\"G\n\020TokenTransa" + + "ction\022)\n\014plain_action\030\001 \001(\0132\021.PlainToken" + + "ActionH\000B\010\n\006action\"\355\001\n\020PlainTokenAction\022" + + "$\n\014plain_import\030\001 \001(\0132\014.PlainImportH\000\022(\n" + + "\016plain_transfer\030\002 \001(\0132\016.PlainTransferH\000\022" + + "&\n\014plain_redeem\030\003 \001(\0132\016.PlainTransferH\000\022" + + "&\n\rplain_approve\030\004 \001(\0132\r.PlainApproveH\000\022" + + "1\n\023plain_transfer_From\030\005 \001(\0132\022.PlainTran" + + "sferFromH\000B\006\n\004data\",\n\013PlainImport\022\035\n\007out" + + "puts\030\001 \003(\0132\014.PlainOutput\"H\n\rPlainTransfe", + "r\022\030\n\006inputs\030\001 \003(\0132\010.InputId\022\035\n\007outputs\030\002" + + " \003(\0132\014.PlainOutput\"x\n\014PlainApprove\022\030\n\006in" + + "puts\030\001 \003(\0132\010.InputId\0220\n\021delegated_output" + + "s\030\002 \003(\0132\025.PlainDelegatedOutput\022\034\n\006output" + + "\030\003 \001(\0132\014.PlainOutput\"}\n\021PlainTransferFro" + + "m\022\030\n\006inputs\030\001 \003(\0132\010.InputId\022\035\n\007outputs\030\002" + + " \003(\0132\014.PlainOutput\022/\n\020delegated_output\030\003" + + " \001(\0132\025.PlainDelegatedOutput\"<\n\013PlainOutp" + + "ut\022\r\n\005owner\030\001 \001(\014\022\014\n\004type\030\002 \001(\t\022\020\n\010quant" + + "ity\030\003 \001(\004\"\'\n\007InputId\022\r\n\005tx_id\030\001 \001(\t\022\r\n\005i", + "ndex\030\002 \001(\r\"Y\n\024PlainDelegatedOutput\022\r\n\005ow" + + "ner\030\001 \001(\014\022\022\n\ndelegatees\030\002 \003(\014\022\014\n\004type\030\003 " + + "\001(\t\022\020\n\010quantity\030\004 \001(\004BQ\n#org.hyperledger" + + ".fabric.protos.tokenZ*github.com/hyperle" + + "dger/fabric/protos/tokenb\006proto3" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }, assigner); + internal_static_TokenTransaction_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_TokenTransaction_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_TokenTransaction_descriptor, + new java.lang.String[] { "PlainAction", "Action", }); + internal_static_PlainTokenAction_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_PlainTokenAction_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_PlainTokenAction_descriptor, + new java.lang.String[] { "PlainImport", "PlainTransfer", "PlainRedeem", "PlainApprove", "PlainTransferFrom", "Data", }); + internal_static_PlainImport_descriptor = + getDescriptor().getMessageTypes().get(2); + internal_static_PlainImport_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_PlainImport_descriptor, + new java.lang.String[] { "Outputs", }); + internal_static_PlainTransfer_descriptor = + getDescriptor().getMessageTypes().get(3); + internal_static_PlainTransfer_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_PlainTransfer_descriptor, + new java.lang.String[] { "Inputs", "Outputs", }); + internal_static_PlainApprove_descriptor = + getDescriptor().getMessageTypes().get(4); + internal_static_PlainApprove_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_PlainApprove_descriptor, + new java.lang.String[] { "Inputs", "DelegatedOutputs", "Output", }); + internal_static_PlainTransferFrom_descriptor = + getDescriptor().getMessageTypes().get(5); + internal_static_PlainTransferFrom_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_PlainTransferFrom_descriptor, + new java.lang.String[] { "Inputs", "Outputs", "DelegatedOutput", }); + internal_static_PlainOutput_descriptor = + getDescriptor().getMessageTypes().get(6); + internal_static_PlainOutput_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_PlainOutput_descriptor, + new java.lang.String[] { "Owner", "Type", "Quantity", }); + internal_static_InputId_descriptor = + getDescriptor().getMessageTypes().get(7); + internal_static_InputId_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_InputId_descriptor, + new java.lang.String[] { "TxId", "Index", }); + internal_static_PlainDelegatedOutput_descriptor = + getDescriptor().getMessageTypes().get(8); + internal_static_PlainDelegatedOutput_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_PlainDelegatedOutput_descriptor, + new java.lang.String[] { "Owner", "Delegatees", "Type", "Quantity", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/fabric-chaincode-protos/src/main/protos/common/common.proto b/fabric-chaincode-protos/src/main/protos/common/common.proto index e93d5117..cb3befb3 100644 --- a/fabric-chaincode-protos/src/main/protos/common/common.proto +++ b/fabric-chaincode-protos/src/main/protos/common/common.proto @@ -58,8 +58,10 @@ enum BlockMetadataIndex { SIGNATURES = 0; // Block metadata array position for block signatures LAST_CONFIG = 1; // Block metadata array position to store last configuration block sequence number TRANSACTIONS_FILTER = 2; // Block metadata array position to store serialized bit array filter of invalid transactions - ORDERER = 3; // Block metadata array position to store operational metadata for orderers - // e.g. For Kafka, this is where we store the last offset written to the local ledger. + ORDERER = 3; /* Block metadata array position to store operational metadata for orderers e.g. For Kafka, + this is where we store the last offset written to the local ledger */ + COMMIT_HASH = 4; /* Block metadata array position to store the hash of TRANSACTIONS_FILTER, State Updates, + and the COMMIT_HASH of the previous block */ } // LastConfig is the encoded value for the Metadata message which is encoded in the LAST_CONFIGURATION block metadata index @@ -175,3 +177,9 @@ message BlockData { message BlockMetadata { repeated bytes metadata = 1; } + +// OrdererBlockMetadata defines metadata that is set by the ordering service. +message OrdererBlockMetadata { + LastConfig last_config = 1; + bytes consenter_metadata = 2; +} diff --git a/fabric-chaincode-protos/src/main/protos/peer/chaincode_shim.proto b/fabric-chaincode-protos/src/main/protos/peer/chaincode_shim.proto index 85a0e0c1..e49e573f 100644 --- a/fabric-chaincode-protos/src/main/protos/peer/chaincode_shim.proto +++ b/fabric-chaincode-protos/src/main/protos/peer/chaincode_shim.proto @@ -38,6 +38,7 @@ message ChaincodeMessage { GET_HISTORY_FOR_KEY = 19; GET_STATE_METADATA = 20; PUT_STATE_METADATA = 21; + GET_PRIVATE_DATA_HASH = 22; } Type type = 1; diff --git a/fabric-chaincode-protos/src/main/protos/peer/proposal.proto b/fabric-chaincode-protos/src/main/protos/peer/proposal.proto index 73f1d8e2..81a8d04d 100644 --- a/fabric-chaincode-protos/src/main/protos/peer/proposal.proto +++ b/fabric-chaincode-protos/src/main/protos/peer/proposal.proto @@ -24,6 +24,7 @@ package protos; import "peer/chaincode.proto"; import "peer/proposal_response.proto"; +import "token/expectations.proto"; /* The flow to get a generic transaction approved goes as follows: @@ -271,4 +272,8 @@ message ChaincodeAction { // Adding ChaincodeID to keep version opens up the possibility of multiple // ChaincodeAction per transaction. ChaincodeID chaincode_id = 4; -} + + // This field contains the token expectation generated by the chaincode + // executing this invocation + TokenExpectation token_expectation = 5; +} \ No newline at end of file diff --git a/fabric-chaincode-protos/src/main/protos/token/expectations.proto b/fabric-chaincode-protos/src/main/protos/token/expectations.proto new file mode 100644 index 00000000..c4cc5954 --- /dev/null +++ b/fabric-chaincode-protos/src/main/protos/token/expectations.proto @@ -0,0 +1,40 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +syntax = "proto3"; + +option go_package = "github.com/hyperledger/fabric/protos/token"; +option java_package = "org.hyperledger.fabric.protos.token"; + +package protos; + +import "google/protobuf/timestamp.proto"; +import "token/transaction.proto"; + +// TokenExpectation represent the belief that someone should achieve in terms of a token action +message TokenExpectation { + oneof Expectation { + // PlainExpectation describes a plain token expectation + PlainExpectation plain_expectation = 1; + } +} + +// PlainExpectation represent the plain expectation where no confidentiality is provided. +message PlainExpectation { + oneof payload { + // ImportExpectation describes an token import expectation + PlainTokenExpectation import_expectation = 1; + // TransferExpectation describes a token transfer expectation + PlainTokenExpectation transfer_expectation = 2; + } +} + +// PlainTokenExpectation represents the expecation that +// certain outputs will be matched +message PlainTokenExpectation { + // Outputs contains the expected outputs + repeated PlainOutput outputs = 1; +} diff --git a/fabric-chaincode-protos/src/main/protos/token/transaction.proto b/fabric-chaincode-protos/src/main/protos/token/transaction.proto new file mode 100644 index 00000000..2c47324b --- /dev/null +++ b/fabric-chaincode-protos/src/main/protos/token/transaction.proto @@ -0,0 +1,158 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +syntax = "proto3"; + +option go_package = "github.com/hyperledger/fabric/protos/token"; +option java_package = "org.hyperledger.fabric.protos.token"; + +// ================ Existing Fabric Transaction structure =============== +// +//In Summary, Fabric supports the following transaction structure: +// +// Envelope +// |\_ Signature (signature on the common.Payload message +// | including the transaction by the creator +// | specified in the Payload.header) +// \_ Payload +// |\_ Header (1) (the header of the proposal that requested this +// | action; containing channel header, and +// | signature header) +// \_ Data (1) (serialised Transaction message) +// \_ Transaction +// \_ TransactionAction (1...n) +// |\_ Header (1) (the header of the proposal that +// | requested this action) +// \_ ChaincodeActionPayload (1) +// +// +// +// +// =============== Changes to Existing Fabric Transaction structure =============== +// For envelopes that carry FabToken transaction we still maintain the same structure +// such that the orderers functionality is not disturbed: +// +// Envelope +// |\_ Signature (signature on the Payload message including +// | the transaction by the creator +// | specified in the Payload.header) +// \_ Payload +// |\_ Header (1) (the header of the proposal that requested +// | this action; containing +// | channel header, and signature header) +// \_ Data (1) (serialised Transaction message) +// \_ TokenTransaction (1) +// \_ action (1) (a oneof for the different types of transactions) + + + +// TokenTransaction governs the structure of Payload.data, when +// the transaction's envelope header indicates a transaction of type +// "Token" +message TokenTransaction { + // action carries the content of this transaction. + oneof action { + PlainTokenAction plain_action = 1; + } +} + +// PlainTokenAction governs the structure of a token action that is +// subjected to no privacy restrictions +message PlainTokenAction { + oneof data { + // A plaintext token import transaction + PlainImport plain_import = 1; + // A plaintext token transfer transaction + PlainTransfer plain_transfer = 2; + // A plaintext token redeem transaction + PlainTransfer plain_redeem = 3; + // A plaintext token approve transaction + PlainApprove plain_approve = 4; + // A plaintext token transfer from transaction + PlainTransferFrom plain_transfer_From = 5; + } +} + +// PlainImport specifies an import of one or more tokens in plaintext format +message PlainImport { + + // An import transaction may contain one or more outputs + repeated PlainOutput outputs = 1; +} + +// PlainTransfer specifies a transfer of one or more plaintext tokens to one or more outputs +message PlainTransfer { + + // The inputs to the transfer transaction are specified by their ID + repeated InputId inputs = 1; + + // A transfer transaction may contain one or more outputs + repeated PlainOutput outputs = 2; +} + +// PlainApprove specifies an approve of one or more tokens in plaintext format +message PlainApprove { + // The inputs to the transfer transaction are specified by their ID + repeated InputId inputs = 1; + + // An approve transaction contains one or more plain delegated outputs + repeated PlainDelegatedOutput delegated_outputs = 2; + + // An approve transaction contains one plain output + PlainOutput output = 3; +} + +// PlainTransferFrom specifies a transfer of one or more plaintext delegated tokens to one or more outputs +// an to a delegated output +message PlainTransferFrom { + // The inputs to the transfer transaction are specified by their ID + repeated InputId inputs = 1; + + // A transferFrom transaction contains multiple outputs + repeated PlainOutput outputs = 2; + + // A transferFrom transaction may contain one delegatable output + PlainDelegatedOutput delegated_output = 3; +} + +// A PlainOutput is the result of import and transfer transactions using plaintext tokens +message PlainOutput { + + // The owner is the serialization of a SerializedIdentity struct + bytes owner = 1; + + // The token type + string type = 2; + + // The quantity of tokens + uint64 quantity = 3; +} + +// An InputId specifies an output using the transaction ID and the index of the output in the transaction +message InputId { + + // The transaction ID + string tx_id = 1; + + // The index of the output in the transaction + uint32 index = 2; +} + +// A PlainDelegatedOutput is the result of approve transactions using plaintext tokens +message PlainDelegatedOutput { + // The owner is the serialization of a SerializedIdentity struct + bytes owner = 1; + + // The delegatees is an arrary of the serialized identities that can spend the output on behalf + // the owner + repeated bytes delegatees = 2; + + // The token type + string type = 3; + + // The quantity of tokens + uint64 quantity = 4; +} \ No newline at end of file diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 20b0de87..4b096116 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -11,11 +11,36 @@ plugins { id 'signing' } +tasks.withType(org.gradle.api.tasks.testing.Test) { + systemProperty 'CORE_CHAINCODE_LOGGING_LEVEL', 'DEBUG' +} + +test { + // Always run tests, even when nothing changed. + dependsOn 'cleanTest' + + // Show test results. Potentially useful for debugging. Comment this block + // testLogging { + // events "passed", "skipped", "failed" + // showExceptions true + // showCauses true + // showStandardStreams true + // exceptionFormat "full" + + // } +} + dependencies { compile project(':fabric-chaincode-protos') - compile 'io.netty:netty-tcnative-boringssl-static:2.0.7.Final' - compile 'org.bouncycastle:bcpkix-jdk15on:1.59' - compile 'org.bouncycastle:bcprov-jdk15on:1.59' + compile 'io.netty:netty-tcnative-boringssl-static:2.0.25.Final' + compile 'org.bouncycastle:bcpkix-jdk15on:1.62' + compile 'org.bouncycastle:bcprov-jdk15on:1.62' + compile group: 'io.github.classgraph', name: 'classgraph', version: '4.8.47' + implementation 'com.github.everit-org.json-schema:org.everit.json.schema:1.11.1' + compile 'io.swagger.core.v3:swagger-annotations:2.0.0' + implementation group: 'org.json', name: 'json', version: '20180813' + // Required if using Java 11+ as no longer bundled in the core libraries + testCompile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1' } sourceSets { @@ -49,6 +74,9 @@ jacoco { } jacocoTestReport { + reports { + xml.enabled true + } afterEvaluate { classDirectories = files(classDirectories.files.collect { fileTree(dir: it, exclude: 'org/hyperledger/fabric/protos/**') @@ -62,7 +90,22 @@ jacocoTestCoverageVerification { element = 'CLASS' excludes = ['org.hyperledger.fabric.shim.helper.Channel', 'org.hyperledger.fabric.shim.impl.Handler', - 'org.hyperledger.fabric.shim.impl.ChaincodeSupportStream.1'] + 'org.hyperledger.fabric.shim.impl.ChaincodeSupportStream.1', + 'org.hyperledger.fabric.contract.ContractRouter', + 'org.hyperledger.fabric.contract.routing.impl.ContractDefinitionImpl', + 'org.hyperledger.fabric.contract.routing.RoutingRegistry', + 'org.hyperledger.fabric.contract.routing.impl.RoutingRegistryImpl', + 'org.hyperledger.fabric.contract.execution.impl.ContractInvocationRequest', + 'org.hyperledger.fabric.contract.routing.TransactionType', + 'org.hyperledger.fabric.contract.metadata.MetadataBuilder', + 'org.hyperledger.fabric.shim.ChaincodeBase*', + 'org.hyperledger.fabric.shim.impl.InnvocationTaskManager', + 'org.hyperledger.fabric.shim.impl.InnvocationStubImpl*', + 'org.hyperledger.fabric.shim.impl.ChaincodeSupportClient*', + 'org.hyperledger.fabric.shim.impl.InnvocationTaskExecutor', + 'org.hyperledger.fabric.shim.impl.ChaincodeInnvocationTask', + 'org.hyperledger.fabric.shim.impl.QueryResultsIteratorImpl*', + 'org.hyperledger.fabric.shim.impl.ChaincodeMessageFactory'] limit { minimum = 0.86 } @@ -71,9 +114,20 @@ jacocoTestCoverageVerification { rule { element = 'CLASS' includes = ['org.hyperledger.fabric.shim.helper.Channel', - 'org.hyperledger.fabric.shim.impl.Handler'] + 'org.hyperledger.fabric.contract.ContractRouter', + 'org.hyperledger.fabric.contract.execution.impl.ContractInvocationRequest', + 'org.hyperledger.fabric.contract.routing.impl.ContractDefinitionImpl', + 'org.hyperledger.fabric.contract.routing.RoutingRegistry', + 'org.hyperledger.fabric.contract.routing.impl.RoutingRegistryImpl', + 'org.hyperledger.fabric.shim.impl.Handler', + 'org.hyperledger.fabric.shim.ChaincodeBase', + 'org.hyperledger.fabric.contract.metadata.MetadataBuilder', + 'org.hyperledger.fabric.shim.impl.InnvocationTaskManager', + 'org.hyperledger.fabric.shim.impl.InnvocationTaskExecutor', + 'org.hyperledger.fabric.shim.impl.ChaincodeSupportClient', + 'org.hyperledger.fabric.shim.impl.ChaincodeMessageFactory'] limit { - minimum = 0.79 + minimum = 0.71 } } } @@ -93,6 +147,7 @@ task licenseCheck { sourceSet -> sourceSet.allSource.findAll { !it.path.contains("build") && !it.path.contains("test/resources")}.each { file -> + if (!file.name.contains("json")){ BufferedReader r = new BufferedReader(new FileReader(file)) def line, hasSPDX = false, hasTraditional = false while ((line = r.readLine()) != null) { @@ -112,6 +167,7 @@ task licenseCheck { missing.add(file) } } + } } } @@ -139,13 +195,22 @@ task licenseCheck { javadoc { - failOnError = false - excludes = ['org/hyperledger/fabric/shim/impl/**', - 'org/hyperledger/fabric/shim/helper/**', - 'org/hyperledger/fabric/shim/ChaincodeBase.java'] + failOnError = true + excludes = ['org/hyperledger/fabric/contract/ContextFactory.java', + 'org/hyperledger/fabric/contract/ContractRouter.java', + 'org/hyperledger/fabric/contract/ContractRuntimeException.java', + 'org/hyperledger/fabric/contract/execution/**', + 'org/hyperledger/fabric/contract/metadata/**', + 'org/hyperledger/fabric/contract/routing/**', + 'org/hyperledger/fabric/contract/systemcontract/**', + 'org/hyperledger/fabric/**/impl/**', + 'org/hyperledger/fabric/shim/helper/**'] + source = sourceSets.main.allJava - classpath = sourceSets.main.compileClasspath + classpath = sourceSets.main.runtimeClasspath + + javadoc.options.addStringOption('Xdoclint:none', '-quiet') } if (JavaVersion.current().isJava8Compatible()) { @@ -220,6 +285,8 @@ uploadArchives { } } + + task sourcesJar(type: Jar) { classifier = 'sources' from sourceSets.main.allSource diff --git a/fabric-chaincode-shim/src/main/java/commons-logging.properties b/fabric-chaincode-shim/src/main/java/commons-logging.properties deleted file mode 100644 index 57a53c99..00000000 --- a/fabric-chaincode-shim/src/main/java/commons-logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# - -# jdk handlers -handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler - -# default log level -.level=INFO - -# Specific logger level -example.Example.level=DEBUG -example.SimpleSample.level=FINE - -# FileHandler options - can also be set to the ConsoleHandler -# FileHandler level can be set to override the global level: -java.util.logging.FileHandler.level=DEBUG - -# log file name for the File Handler -java.util.logging.FileHandler.pattern=java-chaincode%u.log - -# Specify the style of output (simple or xml) -java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter - -# Optional - Limit the size of the file (in bytes) -java.util.logging.FileHandler.limit=50000 - -# Optional - The number of files to cycle through, by -# appending an integer to the base file name: -java.util.logging.FileHandler.count=10 - diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java new file mode 100644 index 00000000..67e8e4a1 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java @@ -0,0 +1,96 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.logging.LogManager; + +/** + * Logger class to use throughout the Contract Implementation + * + * Only available within the 1.4.3 release, this class was a helper class that wrapped + * the standard java.util.logging. + * + * This being deprecated as it doesn't enough extra function and also + * log calls made via this can loose their 'caller method info' + * + * For chaincode/contract implementations please use java.util.logging + * or your own framework. All the Hyperledger Fabric code here is logged + * in loggers with names starting org.hyperledger + * + * @deprecated + */ +public class Logger extends java.util.logging.Logger { + + protected Logger(String name) { + super(name, null); + + // ensure that the parent logger is set + this.setParent(java.util.logging.Logger.getLogger("org.hyperledger.fabric")); + } + + public static Logger getLogger(String name) { + return new Logger(name); + } + + /** + * @deprecated + */ + public void debug(Supplier msgSupplier) { + log(Level.FINEST, msgSupplier); + } + + /** + * @deprecated + */ + public void debug(String msg) { + log(Level.FINEST, msg); + } + + public static Logger getLogger(Class class1) { + // important to add the logger to the log manager + Logger l = Logger.getLogger(class1.getName()); + LogManager.getLogManager().addLogger(l); + return l; + } + + /** + * @deprecated + */ + public void error(String message) { + log(Level.SEVERE, message); + } + + /** + * @deprecated + */ + public void error(Supplier msgSupplier) { + log(Level.SEVERE, msgSupplier); + } + + /** + * @deprecated + */ + public String formatError(Throwable throwable) { + if (throwable == null) + return null; + final StringWriter buffer = new StringWriter(); + buffer.append(throwable.getMessage()); + throwable.printStackTrace(new PrintWriter(buffer)); + + Throwable cause = throwable.getCause(); + if (cause != null) { + buffer.append(".. caused by .."); + buffer.append(this.formatError(cause)); + } + + return buffer.toString(); + } + +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java new file mode 100644 index 00000000..08719a83 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java @@ -0,0 +1,96 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.logging.Level; +import java.util.logging.LogManager; + +/** + * Assistance class to use when logging. + * + * For chaincode/contract implementations please use java.util.logging or your + * own framework. All the Hyperledger Fabric code here is logged in loggers with + * names starting org.hyperledger + * + * Control of this is via the environment variables + * 'CORE_CHAINCODE_LOGGING_LEVEL' this takes a string that matches the following + * Java.util.logging levels (case insensitive) + * + * CRITICAL, ERROR -> Level.SEVERE, WARNING -> Level.WARNING, INFO -> Level.INFO + * NOTICE -> Level.CONFIG, DEBUG -> Level.FINEST + * + */ +public class Logging { + + public static final String PERFLOGGER = "org.hyperledger.Performance"; + + /** + * Formats a Throwable to a string with details of all the causes as well + * + * @param throwable Exception + * @return String formatted with all the details + */ + public static String formatError(final Throwable throwable) { + if (throwable == null) { + return null; + } + final StringWriter buffer = new StringWriter(); + buffer.append(throwable.getMessage()).append(System.lineSeparator()); + + throwable.printStackTrace(new PrintWriter(buffer)); + + final Throwable cause = throwable.getCause(); + if (cause != null) { + buffer.append(".. caused by ..").append(System.lineSeparator()); + buffer.append(Logging.formatError(cause)); + } + + return buffer.toString(); + + } + + /** + * Sets the log level to the the + */ + public static void setLogLevel(String newLevel) { + + Level l = mapLevel(newLevel); + LogManager logManager = LogManager.getLogManager(); + // slightly cumbersome approach - but the loggers don't have a 'get children' + // so find those that have the correct stem. + final ArrayList allLoggers = Collections.list(logManager.getLoggerNames()); + allLoggers.add("org.hyperledger"); + allLoggers.stream().filter(name -> name.startsWith("org.hyperledger")).map(name -> logManager.getLogger(name)) + .forEach(logger -> { + if (logger != null) { + logger.setLevel(l); + } + }); + } + + private static Level mapLevel(final String level) { + if (level != null) { + switch (level.toUpperCase().trim()) { + case "ERROR": + case "CRITICAL": + return Level.SEVERE; + case "WARNING": + return Level.WARNING; + case "INFO": + return Level.INFO; + case "NOTICE": + return Level.CONFIG; + case "DEBUG": + return Level.FINEST; + } + } + return Level.INFO; + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java new file mode 100644 index 00000000..f9c53d3f --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java @@ -0,0 +1,184 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.logging.Logger; + +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DEROctetString; +import org.hyperledger.fabric.Logging; +import org.hyperledger.fabric.protos.msp.Identities.SerializedIdentity; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * ClientIdentity represents information about the identity that submitted a + * transaction. Chaincodes can use this class to obtain information about the + * submitting identity including a unique ID, the MSP (Membership Service + * Provider) ID, and attributes. Such information is useful in enforcing access + * control by the chaincode. + * + */ +public final class ClientIdentity { + private static Logger logger = Logger.getLogger(ContractRouter.class.getName()); + + private final String mspId; + private final X509Certificate cert; + private Map attrs; + private final String id; + // special OID used by Fabric to save attributes in x.509 certificates + private static final String FABRIC_CERT_ATTR_OID = "1.2.3.4.5.6.7.8.1"; + + public ClientIdentity(final ChaincodeStub stub) throws CertificateException, JSONException, IOException { + final byte[] signingId = stub.getCreator(); + + // Create a Serialized Identity protobuf + final SerializedIdentity si = SerializedIdentity.parseFrom(signingId); + this.mspId = si.getMspid(); + + final byte[] idBytes = si.getIdBytes().toByteArray(); + + final X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X509") + .generateCertificate(new ByteArrayInputStream(idBytes)); + this.cert = cert; + + this.attrs = new HashMap(); + // Get the extension where the identity attributes are stored + final byte[] extensionValue = cert.getExtensionValue(FABRIC_CERT_ATTR_OID); + if (extensionValue != null) { + this.attrs = parseAttributes(extensionValue); + } + + // Populate identity + this.id = "x509::" + cert.getSubjectDN().getName() + "::" + cert.getIssuerDN().getName(); + } + + /** + * getId returns the ID associated with the invoking identity. This ID is + * guaranteed to be unique within the MSP. + * + * @return {String} A string in the format: "x509::{subject DN}::{issuer DN}" + */ + public String getId() { + return this.id; + } + + /** + * getMSPID returns the MSP ID of the invoking identity. + * + * @return {String} + */ + public String getMSPID() { + return this.mspId; + } + + /** + * parseAttributes returns a map of the attributes associated with an identity + * + * @param extensionValue DER-encoded Octet string stored in the attributes + * extension of the certificate, as a byte array + * @return attrMap {Map} a map of identity attributes as key + * value pair strings + */ + private Map parseAttributes(final byte[] extensionValue) throws IOException { + + final Map attrMap = new HashMap(); + + // Create ASN1InputStream from extensionValue + try (ByteArrayInputStream inStream = new ByteArrayInputStream(extensionValue); + ASN1InputStream asn1InputStream = new ASN1InputStream(inStream)) { + + // Read the DER object + final ASN1Primitive derObject = asn1InputStream.readObject(); + if (derObject instanceof DEROctetString) { + final DEROctetString derOctetString = (DEROctetString) derObject; + + // Create attributeString from octets and create JSON object + final String attributeString = new String(derOctetString.getOctets(), UTF_8); + final JSONObject extJSON = new JSONObject(attributeString); + final JSONObject attrs = extJSON.getJSONObject("attrs"); + + final Iterator keys = attrs.keys(); + while (keys.hasNext()) { + final String key = keys.next(); + // Populate map with attributes and values + attrMap.put(key, attrs.getString(key)); + } + } + } catch (final JSONException error) { + // creating a JSON object failed + // decoded extensionValue is not a string containing JSON + logger.severe(() -> Logging.formatError(error)); + // return empty map + } + return attrMap; + } + + /** + * getAttributeValue returns the value of the client's attribute named + * `attrName`. If the invoking identity possesses the attribute, returns the + * value of the attribute. If the invoking identity does not possess the + * attribute, returns null. + * + * @param attrName Name of the attribute to retrieve the value from the + * identity's credentials (such as x.509 certificate for + * PKI-based MSPs). + * @return {String | null} Value of the attribute or null if the invoking + * identity does not possess the attribute. + */ + public String getAttributeValue(final String attrName) { + if (this.attrs.containsKey(attrName)) { + return this.attrs.get(attrName); + } else { + return null; + } + } + + /** + * assertAttributeValue verifies that the invoking identity has the attribute + * named `attrName` with a value of `attrValue`. + * + * @param attrName Name of the attribute to retrieve the value from the + * identity's credentials (such as x.509 certificate for + * PKI-based MSPs) + * @param attrValue Expected value of the attribute + * @return {boolean} True if the invoking identity possesses the attribute and + * the attribute value matches the expected value. Otherwise, returns + * false. + */ + public boolean assertAttributeValue(final String attrName, final String attrValue) { + if (!this.attrs.containsKey(attrName)) { + return false; + } else { + return attrValue.equals(this.attrs.get(attrName)); + } + } + + /** + * getX509Certificate returns the X509 certificate associated with the invoking + * identity, or null if it was not identified by an X509 certificate, for + * instance if the MSP is implemented with an alternative to PKI such as + * [Identity Mixer](https://jira.hyperledger.org/browse/FAB-5673). + * + * @return {X509Certificate | null} + */ + public X509Certificate getX509Certificate() { + return this.cert; + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/Context.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/Context.java new file mode 100644 index 00000000..561c9ae4 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/Context.java @@ -0,0 +1,70 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract; + +import java.io.IOException; +import java.security.cert.CertificateException; + +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.json.JSONException; + +/** + * + * This context is available to all 'transaction functions' and provides the + * transaction context. It also provides access to the APIs for the world state + * using {@link #getStub()} + *

+ * Applications can implement their own versions if they wish to add + * functionality. All subclasses MUST implement a constructor, for example + *

+ * {@code
+ *
+ * public MyContext extends Context {
+ *
+ *     public MyContext(ChaincodeStub stub) {
+ *        super(stub);
+ *     }
+ * }
+ *
+ *}
+ *
+ * + */ +public class Context { + protected ChaincodeStub stub; + protected ClientIdentity clientIdentity; + + /** + * Constructor + * Creates new client identity and sets it as a property of the stub + * @param stub Instance of the {@link ChaincodeStub} to use + */ + public Context(ChaincodeStub stub) { + this.stub = stub; + try { + this.clientIdentity = new ClientIdentity(stub); + } catch (CertificateException | JSONException | IOException e) { + throw new ContractRuntimeException("Could not create new client identity", e); + } + } + + /** + * + * @return ChaincodeStub instance to use + */ + public ChaincodeStub getStub() { + return this.stub; + } + + /** + * + * @return ClientIdentity object to use + */ + public ClientIdentity getClientIdentity() { + return this.clientIdentity; + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContextFactory.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContextFactory.java new file mode 100644 index 00000000..11a3a6fe --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContextFactory.java @@ -0,0 +1,30 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract; + +import org.hyperledger.fabric.shim.ChaincodeStub; + +/** + * Factory to create {@link Context} from {@link ChaincodeStub} by wrapping stub + * with dynamic proxy. + */ +public class ContextFactory { + private static ContextFactory cf; + + static synchronized public ContextFactory getInstance() { + if (cf == null) { + cf = new ContextFactory(); + } + return cf; + } + + public Context createContext(final ChaincodeStub stub) { + Context newContext = new Context(stub); + return newContext; + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractInterface.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractInterface.java new file mode 100644 index 00000000..1a4be631 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractInterface.java @@ -0,0 +1,102 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract; + +import org.hyperledger.fabric.contract.annotation.Contract; +import org.hyperledger.fabric.contract.annotation.Transaction; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.hyperledger.fabric.shim.ChaincodeException; + +/** + * All Contracts should implement this interface, in addition to the + * {@link Contract} annotation. + *

+ * All the of the methods on this is inteface have default implementations; for + * many contracts it may not be needed to sub-class these. + *

+ * Each method on the Contract that is marked with the {@link Transaction} + * annotation is considered a Transaction Function. This is eligible for + * calling. Each transaction function is supplied with it's first parameter + * being a {@link org.hyperledger.fabric.contract.Context} the other parameters + * are at the developer's discretion. + *

+ * The sequence of calls is + * + *

+ * createContext()  -> beforeTransaction() -> the transaction function -> afterTransaction()
+ * 
+ *

+ * If any of these functions throws an exception it is considered an error case, + * and the whole transaction is failed. The {@link org.hyperledger.fabric.contract.Context} is + * a very important object as it provides transactional context for access to current transaction id, + * ledger state, etc. + *

+ * Note on Threading + *

+ * All code should be 'Thread Friendly'. Each method must not rely on instance + * fields or class side variables for storage. Nor should they use any + * ThreadLocal Storage. Ledger data is stored via the ledger api available via + * the {@link Context}. + *

+ * If information needs to be passed from the {@link #beforeTransaction(Context)} + * {@link #afterTransaction(Context, Object)} or between separate transaction functions when + * called directory, then a subclass of the + * {@link Context} should be provided. + *

+ * + */ +public interface ContractInterface { + + /** + * Create context from {@link ChaincodeStub}, default impl provided, but can be + * overwritten by contract + * + * @param stub Instance of the ChaincodeStub to use for this transaction + * @return instance of the context to use for the current transaciton being + * executed + */ + default Context createContext(ChaincodeStub stub) { + return ContextFactory.getInstance().createContext(stub); + } + + /** + * Invoked for any transaction that does not exist. + * + * This will throw an exception. If you wish to alter the exception thrown or if + * you wish to consider requests for transactions that don't exist as not an + * error, subclass this method. + * + * @param ctx the context as created by {@link #createContext(ChaincodeStub)}. + */ + default void unknownTransaction(Context ctx) { + throw new ChaincodeException("Undefined contract method called"); + } + + /** + * Invoked once before each transaction. + * + * Any exceptions thrown will fail the transaction, and neither the required + * transaction or the {@link #afterTransaction(Context, Object)} will be called + * + * @param ctx the context as created by {@link #createContext(ChaincodeStub)}. + */ + default void beforeTransaction(Context ctx) { + } + + /** + * Invoked once after each transaction. + * + * Any exceptions thrown will fail the transaction. + * + * @param ctx the context as created by {@link #createContext(ChaincodeStub)}. + * @param result The object returned from the transaction function if any. As + * this is a Java object and therefore pass-by-reference it is + * possible to modify this object. + */ + default void afterTransaction(Context ctx, Object result) { + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java new file mode 100644 index 00000000..4edd4587 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java @@ -0,0 +1,161 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract; + +import java.util.Map; +import java.util.Properties; +import java.util.logging.Logger; + +import org.hyperledger.fabric.Logging; +import org.hyperledger.fabric.contract.execution.ExecutionFactory; +import org.hyperledger.fabric.contract.execution.ExecutionService; +import org.hyperledger.fabric.contract.execution.InvocationRequest; +import org.hyperledger.fabric.contract.metadata.MetadataBuilder; +import org.hyperledger.fabric.contract.routing.ContractDefinition; +import org.hyperledger.fabric.contract.routing.RoutingRegistry; +import org.hyperledger.fabric.contract.routing.TxFunction; +import org.hyperledger.fabric.contract.routing.TypeRegistry; +import org.hyperledger.fabric.contract.routing.impl.RoutingRegistryImpl; +import org.hyperledger.fabric.contract.routing.impl.TypeRegistryImpl; +import org.hyperledger.fabric.metrics.Metrics; +import org.hyperledger.fabric.shim.ChaincodeBase; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.hyperledger.fabric.shim.ResponseUtils; + +/** + * Router class routes Init/Invoke requests to contracts. Implements + * {@link org.hyperledger.fabric.shim.Chaincode} interface. + */ +public class ContractRouter extends ChaincodeBase { + private static Logger logger = Logger.getLogger(ContractRouter.class.getName()); + + private RoutingRegistry registry; + private TypeRegistry typeRegistry; + private ExecutionService executor; + + /** + * Take the arguments from the cli, and initiate processing of cli options and + * environment variables. + * + * Create the Contract scanner, and the Execution service + * + * @param args + */ + public ContractRouter(String[] args) { + super.initializeLogging(); + super.processEnvironmentOptions(); + super.processCommandLineOptions(args); + + Properties props = super.getChaincodeConfig(); + Metrics.initialize(props); + + super.validateOptions(); + logger.fine("ContractRouter"); + registry = new RoutingRegistryImpl(); + typeRegistry = new TypeRegistryImpl(); + executor = ExecutionFactory.getInstance().createExecutionService(typeRegistry); + + } + + /** + * Locate all the contracts that are available on the classpath + */ + protected void findAllContracts() { + registry.findAndSetContracts(this.typeRegistry); + } + + /** + * Start the chaincode container off and running, this will send the initial + * flow back to the peer + * + * @throws Exception + */ + void startRouting() { + try { + super.connectToPeer(); + } catch (Exception e) { + ContractRuntimeException cre = new ContractRuntimeException("Unable to start routing",e); + logger.severe(() -> Logging.formatError(cre)); + throw cre; + } + } + + private Response processRequest(ChaincodeStub stub) { + logger.info(() -> "Got invoke routing request"); + try { + if (stub.getStringArgs().size() > 0) { + logger.info(() -> "Got the invoke request for:" + stub.getFunction() + " " + stub.getParameters()); + InvocationRequest request = ExecutionFactory.getInstance().createRequest(stub); + TxFunction txFn = getRouting(request); + + logger.info(() -> "Got routing:" + txFn.getRouting()); + return executor.executeRequest(txFn, request, stub); + } else { + return ResponseUtils.newSuccessResponse(); + } + } catch (Throwable throwable) { + return ResponseUtils.newErrorResponse(throwable); + } + } + + @Override + public Response invoke(ChaincodeStub stub) { + return processRequest(stub); + } + + @Override + public Response init(ChaincodeStub stub) { + return processRequest(stub); + } + + /** + * Given the Invocation Request, return the routing object for this call + * + * @param request + * @return + */ + TxFunction getRouting(InvocationRequest request) { + // request name is the fully qualified 'name:txname' + if (registry.containsRoute(request)) { + return registry.getTxFn(request); + } else { + logger.fine(() -> "Namespace is " + request); + ContractDefinition contract = registry.getContract(request.getNamespace()); + return contract.getUnknownRoute(); + } + } + + /** + * Main method to start the contract based chaincode + * + */ + public static void main(String[] args) { + + logger.info("Starting ContractRouter..."); + + ContractRouter cfc = new ContractRouter(args); + cfc.findAllContracts(); + + // Create the Metadata ahead of time rather than have to produce every + // time + MetadataBuilder.initialize(cfc.getRoutingRegistry(), cfc.getTypeRegistry()); + logger.info(() -> "Metadata follows:" + MetadataBuilder.debugString()); + + // commence routing, once this has returned the chaincode and contract api is + // 'open for chaining' + cfc.startRouting(); + logger.info("Ending main thread ContractRouter..."); + } + + protected TypeRegistry getTypeRegistry() { + return this.typeRegistry; + } + + protected RoutingRegistry getRoutingRegistry() { + return this.registry; + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRuntimeException.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRuntimeException.java new file mode 100644 index 00000000..3c10cc19 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRuntimeException.java @@ -0,0 +1,37 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract; + +import org.hyperledger.fabric.shim.ChaincodeException; + +/** + * Specific RuntimeException for events that occur in the calling and handling + * of the Contracts, NOT within the contract logic itself. + *

+ * FUTURE At some future point we wish to add more diagnostic information into this, + * for example current tx id + * + */ +public class ContractRuntimeException extends ChaincodeException { + + public ContractRuntimeException(String string) { + super(string); + } + + public ContractRuntimeException(String string, Throwable cause) { + super(string, cause); + } + + public ContractRuntimeException(Throwable cause) { + super(cause); + } + + /** + * Generated serial version id + */ + private static final long serialVersionUID = -884373036398750450L; + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contact.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contact.java new file mode 100644 index 00000000..aa76afcd --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contact.java @@ -0,0 +1,30 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.annotation; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Class level annotation that identifies this class as being a contact. Can + * be populated with email, name and url fields. + * + */ +@Retention(RUNTIME) +@Target(ElementType.TYPE) +public @interface Contact { + + String email() default ""; + + String name() default ""; + + String url() default ""; + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contract.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contract.java new file mode 100644 index 00000000..d964fe4d --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contract.java @@ -0,0 +1,41 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.annotation; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import org.hyperledger.fabric.contract.annotation.Info; + +/** + * Class level annotation that identifies this class as being a contract. Can + * supply information and an alternative name for the contract rather than the + * classname + */ +@Retention(RUNTIME) +@Target(ElementType.TYPE) +public @interface Contract { + + /** + * The Info object can be supplied to provide additional information about the + * contract, including title, description, version and license + * + * @return Info object + */ + Info info() default @Info(); + + /** + * Normally the name of the class is used to refer to the contract (name without package). + * This can be altered if wished. + * + * @return Name of the contract to be used instead of the Classname + */ + String name() default ""; +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/DataType.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/DataType.java new file mode 100644 index 00000000..a5fc5223 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/DataType.java @@ -0,0 +1,30 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.annotation; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Class level annotation indicating this class represents one of the complex + * types that can be returned or passed to the transaction functions. + *

+ * These datatypes are used (within the current implementation) for determining the data flow protocol + * from the Contracts to the SDK and for permitting a fully formed Interface Definition to be created for the + * contract. + *

+ * Complex types can appear within this definition, and these are identified using this annotation. + *

+ * FUTURE To take these annotations are also utilize them for leverage storage + */ +@Retention(RUNTIME) +@Target(ElementType.TYPE) +public @interface DataType { + String namespace() default ""; +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Default.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Default.java new file mode 100644 index 00000000..510e0b99 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Default.java @@ -0,0 +1,21 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Class level annotation that defines the contract that is the default contract, + * and as such invoke of the transaction functions does not need to be qualified by the contract name + */ +@Retention(RUNTIME) +@Target(ElementType.TYPE) +public @interface Default { +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Info.java new file mode 100644 index 00000000..566bc73e --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Info.java @@ -0,0 +1,51 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.annotation; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import org.hyperledger.fabric.contract.annotation.License; +import org.hyperledger.fabric.contract.annotation.Contact; + +/** + * Class level annotation that identifies this class as being an info object. Can + * supply additional information about the contract, including title, description, + * version, license and contact information. + * + */ +@Retention(RUNTIME) +@Target(ElementType.TYPE) +public @interface Info { + + String title() default ""; + + String description() default ""; + + String version() default ""; + + String termsOfService() default ""; + + /** + * License object that can be populated to include name and url. + * + * @return License object + * + */ + License license() default @License(); + + /** + * Contact object that can be populated with email, name and url fields. + * + * @return Contact object + * + */ + Contact contact() default @Contact(); + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/License.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/License.java new file mode 100644 index 00000000..084dbf6c --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/License.java @@ -0,0 +1,28 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.annotation; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Class level annotation that identifies this class as being a license object. Can + * be populated to include name and url. + * + */ +@Retention(RUNTIME) +@Target(ElementType.TYPE) +public @interface License { + + String name() default ""; + + String url() default ""; + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Property.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Property.java new file mode 100644 index 00000000..323d1dc2 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Property.java @@ -0,0 +1,45 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.annotation; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Field and parameter level annotation defining a property of the class + * (identified by {@link DataType}) Can also be used on the parameters of + * transaction functions + *

+ * Example of using this annotation + * + *

+ *
+ * // max 15 character string, a-z with spaces
+ * @Property(schema = { "pattern", "^[a-zA-Z\\s]{0,15}$" })
+ * private String text;
+ *
+ * // How friendly is this on a scale of 1-5, 1 being formal, 5 being familar
+ * @Property(schema = { "minimum", "1", "maximum", "5" })
+ * private int friendliness = 1;
+ *
+ * 
+ */ +@Retention(RUNTIME) +@Target({ ElementType.FIELD, ElementType.PARAMETER }) +public @interface Property { + + /** + * Allows each property to be defined a detail set of rules to determine the + * valid types of this data. The format follows the syntax of the OpenAPI Schema + * object. + * + * @return String array of the key-value pairs of the schema + */ + String[] schema() default {}; +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Transaction.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Transaction.java new file mode 100644 index 00000000..661ca977 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Transaction.java @@ -0,0 +1,44 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.annotation; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Method level annotation indicating the method to be a callable transaction + * function. + *

+ * These functions are called in client SDKs by the combination of

 [contractname]:[transactioname] 
+ * Unless specified otherwise, the contract name is the class name (without package) and the transaction + * name is the method name. + */ +@Retention(RUNTIME) +@Target(METHOD) +public @interface Transaction { + /** + * TRUE indicates that this function is intended to be called with the 'submit' + * semantics + * + * FALSE indicates that this is intended to be called with the evaluate + * semantics + * + * @return boolean, default is true + */ + boolean submit() default true; + + /** + * The name of the callable transaction if it should be different to the method + * name. + * + * @return the transaction name + */ + String name() default ""; +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionFactory.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionFactory.java new file mode 100644 index 00000000..288ee4fb --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionFactory.java @@ -0,0 +1,35 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.execution; + +import org.hyperledger.fabric.contract.execution.impl.ContractExecutionService; +import org.hyperledger.fabric.contract.execution.impl.ContractInvocationRequest; +import org.hyperledger.fabric.contract.routing.TypeRegistry; +import org.hyperledger.fabric.shim.ChaincodeStub; + +public class ExecutionFactory { + private static ExecutionFactory rf; + private static ExecutionService es; + + public static ExecutionFactory getInstance() { + if (rf == null) { + rf = new ExecutionFactory(); + } + return rf; + } + + public InvocationRequest createRequest(ChaincodeStub context) { + return new ContractInvocationRequest(context); + } + + public ExecutionService createExecutionService(TypeRegistry typeRegistry) { + if (es == null) { + es = new ContractExecutionService(typeRegistry); + } + return es; + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionService.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionService.java new file mode 100644 index 00000000..e55a3a92 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionService.java @@ -0,0 +1,20 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.execution; + +import org.hyperledger.fabric.contract.routing.TxFunction; +import org.hyperledger.fabric.contract.routing.TxFunction.Routing; +import org.hyperledger.fabric.shim.Chaincode; +import org.hyperledger.fabric.shim.ChaincodeStub; + +/** + * Service that executes {@link InvocationRequest} (wrapped Init/Invoke + extra data) using routing information {@link Routing} + */ +public interface ExecutionService { + + Chaincode.Response executeRequest(TxFunction txFn, InvocationRequest req, ChaincodeStub stub); +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/InvocationRequest.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/InvocationRequest.java new file mode 100644 index 00000000..fa0a5cbd --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/InvocationRequest.java @@ -0,0 +1,21 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.execution; + +import java.util.List; + +/** + * All information needed to find {@link org.hyperledger.fabric.contract.annotation.Contract} and invoke the request + */ +public interface InvocationRequest { + String DEFAULT_NAMESPACE = "default"; + + String getNamespace(); + String getMethod(); + List getArgs(); + String getRequestName(); +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java new file mode 100644 index 00000000..3ada8f92 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java @@ -0,0 +1,185 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.execution; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.Iterator; +import java.util.Map; +import java.util.logging.Logger; + +import org.hyperledger.fabric.contract.ContractRuntimeException; +import org.hyperledger.fabric.contract.metadata.TypeSchema; +import org.hyperledger.fabric.contract.routing.DataTypeDefinition; +import org.hyperledger.fabric.contract.routing.PropertyDefinition; +import org.hyperledger.fabric.contract.routing.TypeRegistry; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Used as a the default serialisation for transmission from SDK to Contract + */ +public class JSONTransactionSerializer { + private static Logger logger = Logger.getLogger(JSONTransactionSerializer.class.getName()); + private final TypeRegistry typeRegistry; + + /** + * Create a new serialiser and maintain a reference to the TypeRegistry + * + * @param typeRegistry + */ + public JSONTransactionSerializer(final TypeRegistry typeRegistry) { + this.typeRegistry = typeRegistry; + } + + /** + * Convert the value supplied to a byte array, according to the TypeSchema + * + * @param value + * @param ts + * @return Byte buffer + */ + public byte[] toBuffer(final Object value, final TypeSchema ts) { + logger.fine(() -> "Schema to convert is " + ts); + byte[] buffer = null; + if (value != null) { + final String type = ts.getType(); + if (type != null) { + switch (type) { + case "array": + final JSONArray array = new JSONArray(value); + buffer = array.toString().getBytes(UTF_8); + break; + case "string": + buffer = ((String) value).getBytes(UTF_8); + break; + case "number": + case "integer": + case "boolean": + default: + buffer = (value).toString().getBytes(UTF_8); + } + } else { + final JSONObject obj = new JSONObject(value); + buffer = obj.toString().getBytes(UTF_8); + } + } + return buffer; + } + + /** + * Take the byte buffer and return the object as required + * + * @param buffer Byte buffer from the wire + * @param ts TypeSchema representing the type + * + * @return Object created; relies on Java auto-boxing for primitives + * + * @throws InstantiationException + * @throws IllegalAccessException + */ + public Object fromBuffer(final byte[] buffer, final TypeSchema ts) { + try { + final String stringData = new String(buffer, StandardCharsets.UTF_8); + Object value = null; + + value = _convert(stringData, ts); + + return value; + } catch (InstantiationException | IllegalAccessException e) { + final ContractRuntimeException cre = new ContractRuntimeException(e); + throw cre; + } + } + + /* + * Internal method to do the conversion + */ + private Object _convert(final String stringData, final TypeSchema ts) + throws IllegalArgumentException, IllegalAccessException, InstantiationException { + logger.fine(() -> "Schema to convert is " + ts); + String type = ts.getType(); + String format = null; + Object value = null; + if (type == null) { + type = "object"; + final String ref = ts.getRef(); + format = ref.substring(ref.lastIndexOf("/") + 1); + } + + if (type.contentEquals("string")) { + value = stringData; + } else if (type.contentEquals("integer")) { + final String intFormat = ts.getFormat(); + if (intFormat.contentEquals("int32")) { + value = Integer.parseInt(stringData); + } else { + value = Long.parseLong(stringData); + } + } else if (type.contentEquals("number")) { + final String numFormat = ts.getFormat(); + if (numFormat.contentEquals("float")) { + value = Float.parseFloat(stringData); + } else { + value = Double.parseDouble(stringData); + } + } else if (type.contentEquals("boolean")) { + value = Boolean.parseBoolean(stringData); + } else if (type.contentEquals("object")) { + value = createComponentInstance(format, stringData, ts); + } else if (type.contentEquals("array")) { + final JSONArray jsonArray = new JSONArray(stringData); + final TypeSchema itemSchema = ts.getItems(); + final Object[] data = (Object[]) Array.newInstance(itemSchema.getTypeClass(this.typeRegistry), + jsonArray.length()); + for (int i = 0; i < jsonArray.length(); i++) { + data[i] = _convert(jsonArray.get(i).toString(), itemSchema); + } + value = data; + + } + return value; + } + + Object createComponentInstance(final String format, final String jsonString, final TypeSchema ts) { + + final DataTypeDefinition dtd = this.typeRegistry.getDataType(format); + Object obj; + try { + obj = dtd.getTypeClass().newInstance(); + } catch (InstantiationException | IllegalAccessException e1) { + throw new ContractRuntimeException("Unable to to create new instance of type", e1); + } + + final JSONObject json = new JSONObject(jsonString); + // request validation of the type may throw an exception if validation fails + ts.validate(json); + + try { + final Map fields = dtd.getProperties(); + for (final Iterator iterator = fields.values().iterator(); iterator.hasNext();) { + final PropertyDefinition prop = iterator.next(); + + final Field f = prop.getField(); + f.setAccessible(true); + final Object newValue = _convert(json.get(prop.getName()).toString(), prop.getSchema()); + + f.set(obj, newValue); + + } + return obj; + } catch (SecurityException | IllegalArgumentException | IllegalAccessException | InstantiationException + | JSONException e) { + throw new ContractRuntimeException("Unable to convert JSON to object", e); + } + + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractExecutionService.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractExecutionService.java new file mode 100644 index 00000000..3bef4cda --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractExecutionService.java @@ -0,0 +1,100 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.execution.impl; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.ContractRuntimeException; +import org.hyperledger.fabric.contract.execution.ExecutionService; +import org.hyperledger.fabric.contract.execution.InvocationRequest; +import org.hyperledger.fabric.contract.execution.JSONTransactionSerializer; +import org.hyperledger.fabric.contract.metadata.TypeSchema; +import org.hyperledger.fabric.contract.routing.ParameterDefinition; +import org.hyperledger.fabric.contract.routing.TxFunction; +import org.hyperledger.fabric.contract.routing.TypeRegistry; +import org.hyperledger.fabric.shim.Chaincode; +import org.hyperledger.fabric.shim.ChaincodeException; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.hyperledger.fabric.shim.ResponseUtils; + +public class ContractExecutionService implements ExecutionService { + + private static Logger logger = Logger.getLogger(ContractExecutionService.class.getName()); + + private JSONTransactionSerializer serializer; + Map proxies = new HashMap<>(); + + public ContractExecutionService(TypeRegistry typeRegistry) { + // FUTURE: Permit this to swapped out as per node.js + this.serializer = new JSONTransactionSerializer(typeRegistry); + } + + @Override + public Chaincode.Response executeRequest(TxFunction txFn, InvocationRequest req, ChaincodeStub stub) { + logger.fine(() -> "Routing Request" + txFn); + TxFunction.Routing rd = txFn.getRouting(); + Chaincode.Response response; + + try { + ContractInterface contractObject = rd.getContractInstance(); + Context context = contractObject.createContext(stub); + + final List args = convertArgs(req.getArgs(), txFn); + args.add(0, context); // force context into 1st position, other elements move up + + contractObject.beforeTransaction(context); + Object value = rd.getMethod().invoke(contractObject, args.toArray()); + contractObject.afterTransaction(context, value); + + if (value == null) { + response = ResponseUtils.newSuccessResponse(); + } else { + response = ResponseUtils.newSuccessResponse(convertReturn(value, txFn)); + } + + } catch (IllegalAccessException | InstantiationException e) { + String message = String.format("Could not execute contract method: %s", rd.toString()); + throw new ContractRuntimeException(message, e); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + + if (cause instanceof ChaincodeException) { + throw (ChaincodeException) cause; + } else { + throw new ContractRuntimeException("Error during contract method execution", cause); + } + } + + return response; + } + + private byte[] convertReturn(Object obj, TxFunction txFn) { + byte[] buffer; + TypeSchema ts = txFn.getReturnSchema(); + buffer = serializer.toBuffer(obj, ts); + + return buffer; + } + + private List convertArgs(List stubArgs, TxFunction txFn) { + + List schemaParams = txFn.getParamsList(); + List args = new ArrayList<>(stubArgs.size() + 1); // allow for context as the first argument + for (int i = 0; i < schemaParams.size(); i++) { + args.add(i, serializer.fromBuffer(stubArgs.get(i), schemaParams.get(i).getSchema())); + } + return args; + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java new file mode 100644 index 00000000..cb34b805 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java @@ -0,0 +1,66 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.execution.impl; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hyperledger.fabric.contract.execution.InvocationRequest; +import org.hyperledger.fabric.shim.ChaincodeStub; + +public class ContractInvocationRequest implements InvocationRequest { + String namespace; + String method; + List args = Collections.emptyList(); + + private static Log logger = LogFactory.getLog(ContractInvocationRequest.class); + public ContractInvocationRequest(ChaincodeStub context) { + String func = context.getStringArgs().size() > 0 ? context.getStringArgs().get(0) : null; + String funcParts[] = func.split(":"); + logger.debug(func); + if (funcParts.length == 2) { + namespace = funcParts[0]; + method = funcParts[1]; + } else { + namespace = DEFAULT_NAMESPACE; + method = funcParts[0]; + } + + args = context.getArgs().stream().skip(1).collect(Collectors.toList()); + logger.debug(namespace+" "+method+" "+args); + } + + @Override + public String getNamespace() { + return namespace; + } + + + + @Override + public String getMethod() { + return method; + } + + @Override + public List getArgs() { + return args; + } + + @Override + public String getRequestName() { + return namespace + ":" + method; + } + + @Override + public String toString() { + return namespace + ":" + method+" @"+Integer.toHexString(System.identityHashCode(this)); + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java new file mode 100644 index 00000000..c006131b --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java @@ -0,0 +1,257 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.metadata; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import org.everit.json.schema.Schema; +import org.everit.json.schema.ValidationException; +import org.everit.json.schema.loader.SchemaClient; +import org.everit.json.schema.loader.SchemaLoader; +import org.everit.json.schema.loader.internal.DefaultSchemaClient; +import org.hyperledger.fabric.Logging; +import org.hyperledger.fabric.contract.annotation.Contract; +import org.hyperledger.fabric.contract.annotation.Info; +import org.hyperledger.fabric.contract.routing.ContractDefinition; +import org.hyperledger.fabric.contract.routing.DataTypeDefinition; +import org.hyperledger.fabric.contract.routing.RoutingRegistry; +import org.hyperledger.fabric.contract.routing.TransactionType; +import org.hyperledger.fabric.contract.routing.TxFunction; +import org.hyperledger.fabric.contract.routing.TypeRegistry; +import org.json.JSONObject; +import org.json.JSONTokener; + +/** + * Builder to assist in production of the metadata + *

+ * This class is used to build up the JSON structure to be returned as the + * metadata It is not a store of information, rather a set of functional data to + * process to and from metadata json to the internal data structure + */ +public class MetadataBuilder { + private static Logger logger = Logger.getLogger(MetadataBuilder.class.getName()); + + @SuppressWarnings("serial") + static class MetadataMap extends HashMap { + + V putIfNotNull(final K key, final V value) { + logger.info(key + " " + value); + if (value != null && !value.toString().isEmpty()) { + return put(key, value); + } else { + return null; + } + } + } + + // Metadata is composed of three primary sections + // each of which is stored in a map + static Map> contractMap = new HashMap<>(); + static Map overallInfoMap = new HashMap(); + static Map componentMap = new HashMap(); + + // The schema client used to load any other referenced schemas + static SchemaClient schemaClient = new DefaultSchemaClient(); + + /** + * Validation method + * + * @throws ValidationException if the metadata is not valid + */ + public static void validate() { + logger.info("Running schema test validation"); + final ClassLoader cl = MetadataBuilder.class.getClassLoader(); + try (InputStream contractSchemaInputStream = cl.getResourceAsStream("contract-schema.json"); + InputStream jsonSchemaInputStream = cl.getResourceAsStream("json-schema-draft-04-schema.json")) { + final JSONObject rawContractSchema = new JSONObject(new JSONTokener(contractSchemaInputStream)); + final JSONObject rawJsonSchema = new JSONObject(new JSONTokener(jsonSchemaInputStream)); + final SchemaLoader schemaLoader = SchemaLoader.builder().schemaClient(schemaClient) + .schemaJson(rawContractSchema) + .registerSchemaByURI(URI.create("http://json-schema.org/draft-04/schema"), rawJsonSchema).build(); + final Schema schema = schemaLoader.load().build(); + schema.validate(metadata()); + + } catch (final IOException e) { + throw new RuntimeException(e); + } catch (final ValidationException e) { + logger.severe(Logging.formatError(e)); + e.getCausingExceptions().stream().map(ValidationException::getMessage).forEach(logger::info); + logger.severe(debugString()); + throw e; + } + + } + + /** + * Setup the metadata from the found contracts + */ + public static void initialize(final RoutingRegistry registry, final TypeRegistry typeRegistry) { + final Collection contractDefinitions = registry.getAllDefinitions(); + contractDefinitions.forEach(MetadataBuilder::addContract); + + final Collection dataTypes = typeRegistry.getAllDataTypes(); + dataTypes.forEach(MetadataBuilder::addComponent); + + // need to validate that the metadata that has been created is really valid + // it should be as it's been created by code, but this is a valuable double + // check + logger.info("Validating schema created"); + MetadataBuilder.validate(); + + } + + /** + * Adds a component/ complex data-type + */ + public static void addComponent(final DataTypeDefinition datatype) { + + final Map component = new HashMap<>(); + + component.put("$id", datatype.getName()); + component.put("type", "object"); + component.put("additionalProperties", false); + + final Map propertiesMap = datatype.getProperties().entrySet().stream() + .collect(Collectors.toMap(Entry::getKey, e -> (e.getValue().getSchema()))); + component.put("properties", propertiesMap); + + componentMap.put(datatype.getSimpleName(), component); + } + + /** + * Adds a new contract to the metadata as represented by the class object + * + * @param contractDefinition Class of the object to use as a contract + * @return the key that the contract class is referred to in the meteadata + */ + @SuppressWarnings("serial") + public static String addContract(final ContractDefinition contractDefinition) { + + final String key = contractDefinition.getName(); + + final Contract annotation = contractDefinition.getAnnotation(); + + final Info info = annotation.info(); + final HashMap infoMap = new HashMap(); + infoMap.put("title", info.title()); + infoMap.put("description", info.description()); + infoMap.put("termsOfService", info.termsOfService()); + infoMap.put("contact", new MetadataMap() { + { + putIfNotNull("email", info.contact().email()); + putIfNotNull("name", info.contact().name()); + putIfNotNull("url", info.contact().url()); + } + }); + infoMap.put("license", new MetadataMap() { + { + put("name", info.license().name()); + putIfNotNull("url", info.license().url()); + } + }); + infoMap.put("version", info.version()); + + final HashMap contract = new HashMap(); + contract.put("name", key); + contract.put("transactions", new ArrayList()); + contract.put("info", infoMap); + + contractMap.put(key, contract); + final boolean defaultContract = true; + if (defaultContract) { + overallInfoMap.putAll(infoMap); + } + + final Collection fns = contractDefinition.getTxFunctions(); + fns.forEach(txFn -> { + MetadataBuilder.addTransaction(txFn, key); + }); + + return key; + } + + /** + * Adds a new transaction function to the metadata for the given contract + * + * @param txFunction Object representing the transaction function + * @param contractName Name of the contract that this function belongs to + */ + public static void addTransaction(final TxFunction txFunction, final String contractName) { + final TypeSchema transaction = new TypeSchema(); + final TypeSchema returnSchema = txFunction.getReturnSchema(); + if (returnSchema != null) { + transaction.put("returns", returnSchema); + } + + final ArrayList tags = new ArrayList(); + tags.add(txFunction.getType()); + + final Map contract = contractMap.get(contractName); + @SuppressWarnings("unchecked") + final List txs = (ArrayList) contract.get("transactions"); + + final ArrayList paramsList = new ArrayList(); + txFunction.getParamsList().forEach(pd -> { + final TypeSchema paramMap = pd.getSchema(); + paramMap.put("name", pd.getName()); + paramsList.add(paramMap); + }); + + transaction.put("parameters", paramsList); + + if (tags.size() != 0) { + transaction.put("tags", tags.toArray()); + transaction.put("name", txFunction.getName()); + txs.add(transaction); + } + } + + /** + * Returns the metadata as a JSON string (compact) + */ + public static String getMetadata() { + return metadata().toString(); + } + + /** + * Returns the metadata as a JSON string (spaced out for humans) + */ + public static String debugString() { + return metadata().toString(3); + } + + /** + * Create a JSONObject representing the schema + * + */ + private static JSONObject metadata() { + final HashMap metadata = new HashMap(); + + metadata.put("$schema", "https://fabric-shim.github.io/release-1.4/contract-schema.json"); + metadata.put("info", overallInfoMap); + metadata.put("contracts", contractMap); + metadata.put("components", Collections.singletonMap("schemas", componentMap)); + + final JSONObject joMetadata = new JSONObject(metadata); + return joMetadata; + } + + public static Map getComponents() { + return componentMap; + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java new file mode 100644 index 00000000..93668711 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java @@ -0,0 +1,215 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.metadata; + +import java.lang.reflect.Array; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +import org.everit.json.schema.Schema; +import org.everit.json.schema.ValidationException; +import org.everit.json.schema.loader.SchemaLoader; +import org.hyperledger.fabric.contract.ContractRuntimeException; +import org.hyperledger.fabric.contract.routing.TypeRegistry; +import org.json.JSONObject; + +/** + * + * Custom sub-type of Map that helps with the case where if there's no value + * then do not insert the property at all + * + * Does not include the "schema" top level map + */ +@SuppressWarnings("serial") +public class TypeSchema extends HashMap { + private static Logger logger = Logger.getLogger(TypeSchema.class.getName()); + + public TypeSchema() { + + } + + private Object _putIfNotNull(String key, Object value) { + if (value != null && !value.toString().isEmpty()) { + return put(key, value); + } else { + return null; + } + } + + String putIfNotNull(String key, String value) { + return (String) this._putIfNotNull(key, value); + } + + String[] putIfNotNull(String key, String[] value) { + return (String[]) this._putIfNotNull(key, value); + } + + TypeSchema putIfNotNull(String key, TypeSchema value) { + return (TypeSchema) this._putIfNotNull(key, value); + } + + TypeSchema[] putIfNotNull(String key, TypeSchema[] value) { + return (TypeSchema[]) this._putIfNotNull(key, value); + } + + public String getType() { + if (this.containsKey("schema")) { + Map intermediateMap = (Map) this.get("schema"); + return (String) intermediateMap.get("type"); + } + return (String) this.get("type"); + } + + public TypeSchema getItems() { + if (this.containsKey("schema")) { + Map intermediateMap = (Map) this.get("schema"); + return (TypeSchema) intermediateMap.get("items"); + } + return (TypeSchema) this.get("items"); + } + + public String getRef() { + if (this.containsKey("schema")) { + Map intermediateMap = (Map) this.get("schema"); + return (String) intermediateMap.get("$ref"); + } + return (String) this.get("$ref"); + + } + + public String getFormat() { + if (this.containsKey("schema")) { + Map intermediateMap = (Map) this.get("schema"); + return (String) intermediateMap.get("format"); + } + return (String) this.get("format"); + } + + public Class getTypeClass(TypeRegistry typeRegistry) { + Class clz = null; + String type = getType(); + if (type == null) { + type = "object"; + } + + if (type.contentEquals("string")) { + clz = String.class; + } else if (type.contentEquals("integer")) { + clz = int.class; + } else if (type.contentEquals("boolean")) { + clz = boolean.class; + } else if (type.contentEquals("object")) { + String ref = this.getRef(); + String format = ref.substring(ref.lastIndexOf("/") + 1); + clz = typeRegistry.getDataType(format).getTypeClass(); + } else if (type.contentEquals("array")) { + TypeSchema typdef = this.getItems(); + Class arrayType = typdef.getTypeClass(typeRegistry); + clz = Array.newInstance(arrayType, 0).getClass(); + } + + return clz; + } + + /** + * Provide a mapping between the Java Language types and the OpenAPI based types + * + */ + public static TypeSchema typeConvert(Class clz) { + TypeSchema returnschema = new TypeSchema(); + String className = clz.getTypeName(); + if (className == "void") { + return null; + } + + TypeSchema schema; + + if (clz.isArray()) { + returnschema.put("type", "array"); + schema = new TypeSchema(); + returnschema.put("items", schema); + className = className.substring(0, className.length() - 2); + } else { + schema = returnschema; + } + + switch (className) { + case "java.lang.String": + schema.put("type", "string"); + break; + case "byte": + case "java.lang.Byte": + schema.put("type", "integer"); + schema.put("format", "int8"); + break; + case "short": + case "java.lang.Short": + schema.put("type", "integer"); + schema.put("format", "int16"); + break; + case "int": + case "java.lang.Integer": + schema.put("type", "integer"); + schema.put("format", "int32"); + break; + case "long": + case "java.lang.Long": + schema.put("type", "integer"); + schema.put("format", "int64"); + break; + case "double": + case "java.lang.Double": + schema.put("type", "number"); + schema.put("format", "double"); + break; + case "float": + case "java.lang.Float": + schema.put("type", "number"); + schema.put("format", "float"); + break; + case "boolean": + case "java.lang.Boolean": + schema.put("type", "boolean"); + break; + default: + + schema.put("$ref", "#/components/schemas/" + className.substring(className.lastIndexOf('.') + 1)); + } + + return returnschema; + } + + public void validate(JSONObject obj) { + // get the components bit of the main metadata + + JSONObject toValidate = new JSONObject(); + toValidate.put("prop", obj); + + JSONObject schemaJSON; + if (this.containsKey("schema")) { + schemaJSON = new JSONObject((Map) this.get("schema")); + } else { + schemaJSON = new JSONObject(this); + } + + JSONObject rawSchema = new JSONObject(); + rawSchema.put("properties", new JSONObject().put("prop", schemaJSON)); + rawSchema.put("components", new JSONObject().put("schemas", MetadataBuilder.getComponents())); + Schema schema = SchemaLoader.load(rawSchema); + try { + schema.validate(toValidate); + } catch (ValidationException e) { + StringBuilder sb = new StringBuilder("Validation Errors::"); + e.getCausingExceptions().stream().map(ValidationException::getMessage).forEach(sb::append); + logger.info(sb.toString()); + throw new ContractRuntimeException(sb.toString(), e); + } + + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/package-info.java new file mode 100644 index 00000000..c30f7af3 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/package-info.java @@ -0,0 +1,20 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +/** + *

+ * This is the project to support the writing of Contracts with the JVM runtime - enabling development of using Java language or other JVM based languages + *

+ * The {@link org.hyperledger.fabric.contract} package implements the Fabric programming model as described in the + * Developing Applications + * chapter of the Fabric documentation.

+ *

+ * The main interface to implement is {@link org.hyperledger.fabric.contract#ContractInterface} + * + * @see Developing Fabric Applications + * + */ +package org.hyperledger.fabric.contract; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ContractDefinition.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ContractDefinition.java new file mode 100644 index 00000000..d74354b2 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ContractDefinition.java @@ -0,0 +1,84 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.routing; + +import java.lang.reflect.Method; +import java.util.Collection; + +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.annotation.Contract; + +/** + * Definition of the Contract + * + * A data structure that represents the contract that will be executed in the + * chaincode. Primarily has + * + * Name - either defined by the Contract annotation or the Class name (can be + * referred to as Namespace) Default - is the default contract (defined by the + * Default annotation) TxFunctions in this contract do not need the name prefix + * when invoked TxFunctions - the transaction functions defined in this contract + * + * Will embedded the ContgractInterface instance, as well as the annotation + * itself, and the routing for any tx function that is unknown + * + */ +public interface ContractDefinition { + + /** + * @return the fully qualififed name of the Contract + */ + String getName(); + + /** + * @return Complete collection of all the transaction functions in this contract + */ + Collection getTxFunctions(); + + /** + * @return Object reference to the instantiated object that is 'the contract' + */ + Class getContractImpl(); + + /** + * @param m The java.lang.reflect object that is the method that is a tx + * function + * @return TxFunction object representing this method + */ + TxFunction addTxFunction(Method m); + + /** + * + * @return if this is contract is the default one or not + */ + boolean isDefault(); + + /** + * + * @param method name to be returned + * @return TxFunction that represents this requested method + */ + TxFunction getTxFunction(String method); + + /** + * + * @param method name to be checked + * @return true if this txFunction exists or not + */ + boolean hasTxFunction(String method); + + /** + * @return The TxFunction to be used for this contract in case of unknown + * request + */ + TxFunction getUnknownRoute(); + + /** + * @return Underlying raw annotation + */ + Contract getAnnotation(); +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/DataTypeDefinition.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/DataTypeDefinition.java new file mode 100644 index 00000000..d2d97311 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/DataTypeDefinition.java @@ -0,0 +1,19 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +import java.util.Map; + +public interface DataTypeDefinition { + + String getName(); + + Map getProperties(); + + String getSimpleName(); + + Class getTypeClass(); +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ParameterDefinition.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ParameterDefinition.java new file mode 100644 index 00000000..8471e642 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ParameterDefinition.java @@ -0,0 +1,22 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +import java.lang.reflect.Parameter; + +import org.hyperledger.fabric.contract.metadata.TypeSchema; + +public interface ParameterDefinition { + + Class getTypeClass(); + + TypeSchema getSchema(); + + Parameter getParameter(); + + String getName(); + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/PropertyDefinition.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/PropertyDefinition.java new file mode 100644 index 00000000..cdf9af71 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/PropertyDefinition.java @@ -0,0 +1,22 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +import java.lang.reflect.Field; + +import org.hyperledger.fabric.contract.metadata.TypeSchema; + +public interface PropertyDefinition { + + Class getTypeClass(); + + TypeSchema getSchema(); + + Field getField(); + + String getName(); + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/RoutingRegistry.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/RoutingRegistry.java new file mode 100644 index 00000000..b1fefe33 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/RoutingRegistry.java @@ -0,0 +1,69 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +import java.util.Collection; + +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.execution.InvocationRequest; + +public interface RoutingRegistry { + + /** + * Add a new contract definition based on the class object located + * + * @param clz Class Object to process into a ContractDefinition + * @return ContractDefinition Instance + */ + ContractDefinition addNewContract(Class clz); + + /** + * Based on the Invocation Request, can we create a route for this? + * + * @param request + * @return ture/false + */ + boolean containsRoute(InvocationRequest request); + + /** + * Get the route for invocation request + * + * @param request + * @return Routing obect + */ + TxFunction.Routing getRoute(InvocationRequest request); + + /** + * Get the txFunction that matches the routing request + * + * @param request + * @return Transaction Function + */ + TxFunction getTxFn(InvocationRequest request); + + /** + * Get the contract that matches the supplied name + * + * @param name + * @return Contract Definition + */ + ContractDefinition getContract(String name); + + /** + * Returns all the ContractDefinitions for this registry + * + * @return Collection of all defintions + */ + Collection getAllDefinitions(); + + /** + * Locate all the contracts in this chaincode + * + * @param typeRegistry + */ + void findAndSetContracts(TypeRegistry typeRegistry); + +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TransactionType.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TransactionType.java new file mode 100644 index 00000000..31b2a5bf --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TransactionType.java @@ -0,0 +1,12 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +public enum TransactionType { + INVOKE, + QUERY, + DEFAULT +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TxFunction.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TxFunction.java new file mode 100644 index 00000000..8e241847 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TxFunction.java @@ -0,0 +1,47 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +import java.lang.reflect.Method; +import java.util.List; + +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.metadata.TypeSchema; + +public interface TxFunction { + + interface Routing { + + Method getMethod(); + + Class getContractClass(); + + ContractInterface getContractInstance() throws InstantiationException, IllegalAccessException; + + } + + boolean isUnknownTx(); + + void setUnknownTx(boolean unknown); + + String getName(); + + Routing getRouting(); + + Class getReturnType(); + + java.lang.reflect.Parameter[] getParameters(); + + TransactionType getType(); + + void setReturnSchema(TypeSchema returnSchema); + + TypeSchema getReturnSchema(); + + void setParameterDefinitions(List list); + + List getParamsList(); +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TypeRegistry.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TypeRegistry.java new file mode 100644 index 00000000..a7d0bfd8 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TypeRegistry.java @@ -0,0 +1,20 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +import java.util.Collection; + +public interface TypeRegistry { + + void addDataType(DataTypeDefinition dtd); + + void addDataType(Class cl); + + DataTypeDefinition getDataType(String name); + + Collection getAllDataTypes(); + +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java new file mode 100644 index 00000000..597f2751 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java @@ -0,0 +1,130 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing.impl; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +import org.hyperledger.fabric.Logging; +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.ContractRuntimeException; +import org.hyperledger.fabric.contract.annotation.Contract; +import org.hyperledger.fabric.contract.annotation.Default; +import org.hyperledger.fabric.contract.routing.ContractDefinition; +import org.hyperledger.fabric.contract.routing.TxFunction; + +/** + * Implementation of the ContractDefinition + * + * Contains information about the contract, including transaction functions and + * unknown transaction routing + * + */ +public class ContractDefinitionImpl implements ContractDefinition { + private static Logger logger = Logger.getLogger(ContractDefinitionImpl.class.getName()); + + private final Map txFunctions = new HashMap<>(); + private String name; + private final boolean isDefault; + private final Class contractClz; + private final Contract contractAnnotation; + private TxFunction unknownTx; + + public ContractDefinitionImpl(final Class cl) { + + final Contract annotation = cl.getAnnotation(Contract.class); + logger.fine(() -> "Class Contract Annotation: " + annotation); + + final String annotationName = annotation.name(); + + if (annotationName == null || annotationName.isEmpty()) { + this.name = cl.getSimpleName(); + } else { + this.name = annotationName; + } + + isDefault = (cl.getAnnotation(Default.class) != null); + contractAnnotation = cl.getAnnotation(Contract.class); + contractClz = cl; + + try { + final Method m = cl.getMethod("unknownTransaction", new Class[] { Context.class }); + unknownTx = new TxFunctionImpl(m, this); + unknownTx.setUnknownTx(true); + } catch (NoSuchMethodException | SecurityException e) { + final ContractRuntimeException cre = new ContractRuntimeException( + "Failure to find unknownTransaction method", e); + logger.severe(() -> Logging.formatError(cre)); + throw cre; + } + + logger.info(() -> "Found class: " + cl.getCanonicalName()); + logger.fine(() -> "Namespace: " + this.name); + } + + @Override + public String getName() { + return name; + } + + @Override + public Collection getTxFunctions() { + return txFunctions.values(); + } + + @Override + public Class getContractImpl() { + return contractClz; + } + + @Override + public TxFunction addTxFunction(final Method m) { + logger.fine(() -> "Adding method " + m.getName()); + final TxFunction txFn = new TxFunctionImpl(m, this); + final TxFunction previousTxnFn = txFunctions.put(txFn.getName(), txFn); + if (previousTxnFn != null) { + final String message = String.format("Duplicate transaction method %s", previousTxnFn.getName()); + final ContractRuntimeException cre = new ContractRuntimeException(message); + logger.severe(() -> Logging.formatError(cre)); + throw cre; + } + return txFn; + } + + @Override + public boolean isDefault() { + return isDefault; + } + + @Override + public TxFunction getTxFunction(final String method) { + return txFunctions.get(method); + } + + @Override + public boolean hasTxFunction(final String method) { + return txFunctions.containsKey(method); + } + + @Override + public TxFunction getUnknownRoute() { + return unknownTx; + } + + @Override + public Contract getAnnotation() { + return this.contractAnnotation; + } + + @Override + public String toString() { + return name + ":" + txFunctions + " @" + Integer.toHexString(System.identityHashCode(this)); + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java new file mode 100644 index 00000000..2ed7d81a --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java @@ -0,0 +1,105 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing.impl; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +import org.hyperledger.fabric.contract.annotation.Property; +import org.hyperledger.fabric.contract.metadata.TypeSchema; +import org.hyperledger.fabric.contract.routing.DataTypeDefinition; +import org.hyperledger.fabric.contract.routing.PropertyDefinition; + +public class DataTypeDefinitionImpl implements DataTypeDefinition { + + Map properties = new HashMap<>(); + Map fields = new HashMap<>(); + String name; + String simpleName; + Class clazz; + + public DataTypeDefinitionImpl(Class componentClass) { + this.clazz = componentClass; + this.name = componentClass.getName(); + this.simpleName = componentClass.getSimpleName(); + // given this class extract the property elements + Field[] fields = componentClass.getDeclaredFields(); + + for (Field f : fields) { + Property propAnnotation = f.getAnnotation(Property.class); + if (propAnnotation != null) { + TypeSchema ts = TypeSchema.typeConvert(f.getType()); + + // array of strings, "a","b","c","d" to become map of {a:b}, {c:d} + String[] userSupplied = propAnnotation.schema(); + for (int i = 0; i < userSupplied.length; i += 2) { + String userKey = userSupplied[i]; + Object userValue; + switch (userKey.toLowerCase()) { + case "title": + case "pattern": + userValue = userSupplied[i + 1]; + break; + case "uniqueitems": + userValue = Boolean.parseBoolean(userSupplied[i + 1]); + break; + case "required": + case "enum": + userValue = Stream.of(userSupplied[i + 1].split(",")).map(String::trim).toArray(String[]::new); + break; + default: + userValue = Integer.parseInt(userSupplied[i + 1]); + break; + } + ts.put(userKey, userValue); + } + + PropertyDefinition propDef = new PropertyDefinitionImpl(f.getName(), f.getClass(), ts, f); + this.properties.put(f.getName(), propDef); + } + } + + } + + public Class getTypeClass() { + return this.clazz; + } + + /* + * (non-Javadoc) + * + * @see org.hyperledger.fabric.contract.routing.DataTypeDefinition#getName() + */ + @Override + public String getName() { + return this.name; + } + + /* + * (non-Javadoc) + * + * @see + * org.hyperledger.fabric.contract.routing.DataTypeDefinition#getProperties() + */ + @Override + public Map getProperties() { + return properties; + } + + /* + * (non-Javadoc) + * + * @see + * org.hyperledger.fabric.contract.routing.DataTypeDefinition#getSimpleName() + */ + @Override + public String getSimpleName() { + return simpleName; + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ParameterDefinitionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ParameterDefinitionImpl.java new file mode 100644 index 00000000..9a4069d6 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ParameterDefinitionImpl.java @@ -0,0 +1,50 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.routing.impl; + +import java.lang.reflect.Parameter; + +import org.hyperledger.fabric.contract.metadata.TypeSchema; +import org.hyperledger.fabric.contract.routing.ParameterDefinition; + +public class ParameterDefinitionImpl implements ParameterDefinition { + + private Class typeClass; + private TypeSchema schema; + private Parameter parameter; + private String name; + + public ParameterDefinitionImpl(String name, Class typeClass, TypeSchema schema, Parameter p) { + this.typeClass = typeClass; + this.schema = schema; + this.parameter = p; + this.name =name; + } + + @Override + public Class getTypeClass() { + return this.typeClass; + } + + @Override + public TypeSchema getSchema() { + return this.schema; + } + + @Override + public Parameter getParameter() { + return this.parameter; + } + + @Override + public String getName() { + return this.name; + } + public String toString() { + return this.name+"-"+this.typeClass+"-"+this.schema+"-"+this.parameter; + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/PropertyDefinitionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/PropertyDefinitionImpl.java new file mode 100644 index 00000000..faff96ed --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/PropertyDefinitionImpl.java @@ -0,0 +1,48 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.routing.impl; + +import java.lang.reflect.Field; + +import org.hyperledger.fabric.contract.metadata.TypeSchema; +import org.hyperledger.fabric.contract.routing.PropertyDefinition; + +public class PropertyDefinitionImpl implements PropertyDefinition { + + private Class typeClass; + private TypeSchema schema; + private Field field; + private String name; + + public PropertyDefinitionImpl(String name, Class typeClass, TypeSchema schema, Field f) { + this.typeClass = typeClass; + this.schema = schema; + this.field = f; + this.name =name; + } + + @Override + public Class getTypeClass() { + return this.typeClass; + } + + @Override + public TypeSchema getSchema() { + return this.schema; + } + + @Override + public Field getField() { + return this.field; + } + + @Override + public String getName() { + return this.name; + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java new file mode 100644 index 00000000..0598ce9b --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java @@ -0,0 +1,222 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing.impl; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; + +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.ContractRuntimeException; +import org.hyperledger.fabric.contract.annotation.Contract; +import org.hyperledger.fabric.contract.annotation.DataType; +import org.hyperledger.fabric.contract.annotation.Transaction; +import org.hyperledger.fabric.contract.execution.InvocationRequest; +import org.hyperledger.fabric.contract.routing.ContractDefinition; +import org.hyperledger.fabric.contract.routing.RoutingRegistry; +import org.hyperledger.fabric.contract.routing.TxFunction; +import org.hyperledger.fabric.contract.routing.TypeRegistry; + +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ScanResult; + +/** + * Registry to hold permit access to the routing definitions. This is the + * primary internal data structure to permit access to information about the + * contracts, and their transaction functions. + * + * Contracts are added, and processed. At runtime, this can then be accessed to + * locate a specific 'Route' that can be handed off to the ExecutionService + * + */ +public class RoutingRegistryImpl implements RoutingRegistry { + private static Logger logger = Logger.getLogger(RoutingRegistryImpl.class.getName()); + + private final Map contracts = new HashMap<>(); + + /* + * (non-Javadoc) + * + * @see + * org.hyperledger.fabric.contract.routing.RoutingRegistry#addNewContract(java. + * lang.Class) + */ + @Override + public ContractDefinition addNewContract(final Class clz) { + logger.fine(() -> "Adding new Contract Class " + clz.getCanonicalName()); + ContractDefinition contract; + contract = new ContractDefinitionImpl(clz); + + // index this by the full qualified name + contracts.put(contract.getName(), contract); + if (contract.isDefault()) { + contracts.put(InvocationRequest.DEFAULT_NAMESPACE, contract); + } + + logger.fine(() -> "Put new contract in under name " + contract.getName()); + return contract; + } + + /* + * (non-Javadoc) + * + * @see + * org.hyperledger.fabric.contract.routing.RoutingRegistry#containsRoute(org. + * hyperledger.fabric.contract.execution.InvocationRequest) + */ + @Override + public boolean containsRoute(final InvocationRequest request) { + if (contracts.containsKey(request.getNamespace())) { + final ContractDefinition cd = contracts.get(request.getNamespace()); + + if (cd.hasTxFunction(request.getMethod())) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.hyperledger.fabric.contract.routing.RoutingRegistry#getRoute(org. + * hyperledger.fabric.contract.execution.InvocationRequest) + */ + @Override + public TxFunction.Routing getRoute(final InvocationRequest request) { + final TxFunction txFunction = contracts.get(request.getNamespace()).getTxFunction(request.getMethod()); + return txFunction.getRouting(); + } + + @Override + public TxFunction getTxFn(final InvocationRequest request) { + final TxFunction txFunction = contracts.get(request.getNamespace()).getTxFunction(request.getMethod()); + return txFunction; + } + + /* + * (non-Javadoc) + * + * @see + * org.hyperledger.fabric.contract.routing.RoutingRegistry#getContract(java.lang + * .String) + */ + @Override + public ContractDefinition getContract(final String namespace) { + final ContractDefinition contract = contracts.get(namespace); + + if (contract == null) { + throw new ContractRuntimeException("Undefined contract called"); + } + + return contract; + } + + /* + * (non-Javadoc) + * + * @see + * org.hyperledger.fabric.contract.routing.RoutingRegistry#getAllDefinitions() + */ + @Override + public Collection getAllDefinitions() { + return contracts.values(); + + } + + /* + * (non-Javadoc) + * + * @see + * org.hyperledger.fabric.contract.routing.RoutingRegistry#findAndSetContracts() + */ + @SuppressWarnings("unchecked") + @Override + public void findAndSetContracts(TypeRegistry typeRegistry) { + + // Find all classes that are valid contract or data type instances. + ClassGraph classGraph = new ClassGraph() + .enableClassInfo() + .enableAnnotationInfo(); + List> contractClasses = new ArrayList<>(); + List> dataTypeClasses = new ArrayList<>(); + try (ScanResult scanResult = classGraph.scan()) { + for (ClassInfo classInfo : scanResult.getClassesWithAnnotation(Contract.class.getCanonicalName())) { + logger.fine("Found class with contract annotation: " + classInfo.getName()); + try { + Class contractClass = classInfo.loadClass(); + logger.fine("Loaded class"); + Contract annotation = contractClass.getAnnotation(Contract.class); + if (annotation == null) { + // Since we check by name above, it makes sense to check it's actually compatible, + // and not some random class with the same name. + logger.fine("Class does not have compatible contract annotation"); + } else if (!ContractInterface.class.isAssignableFrom(contractClass)) { + logger.fine("Class is not assignable from ContractInterface"); + } else { + logger.fine("Class is assignable from ContractInterface"); + contractClasses.add((Class) contractClass); + } + } catch (IllegalArgumentException e) { + logger.fine("Failed to load class: " + e); + } + } + for (ClassInfo classInfo : scanResult.getClassesWithAnnotation(DataType.class.getCanonicalName())) { + logger.fine("Found class with data type annotation: " + classInfo.getName()); + try { + Class dataTypeClass = classInfo.loadClass(); + logger.fine("Loaded class"); + DataType annotation = dataTypeClass.getAnnotation(DataType.class); + if (annotation == null) { + // Since we check by name above, it makes sense to check it's actually compatible, + // and not some random class with the same name. + logger.fine("Class does not have compatible data type annotation"); + } else { + logger.fine("Class has compatible data type annotation"); + dataTypeClasses.add(dataTypeClass); + } + } catch (IllegalArgumentException e) { + logger.fine("Failed to load class: " + e); + } + } + } + + // set to ensure that we don't scan the same class twice + final Set seenClass = new HashSet<>(); + + // loop over all the classes that have the Contract annotation + for (Class contractClass : contractClasses) { + String className = contractClass.getCanonicalName(); + if (!seenClass.contains(className)) { + ContractDefinition contract = addNewContract((Class) contractClass); + + logger.fine("Searching annotated methods"); + for (Method m : contractClass.getMethods()) { + if (m.getAnnotation(Transaction.class) != null) { + logger.fine("Found annotated method " + m.getName()); + + contract.addTxFunction(m); + + } + } + + seenClass.add(className); + } + } + + // now need to look for the data types have been set with the + dataTypeClasses.forEach(typeRegistry::addDataType); + + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java new file mode 100644 index 00000000..bcd0f56e --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java @@ -0,0 +1,205 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing.impl; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Logger; + +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.ContractRuntimeException; +import org.hyperledger.fabric.contract.annotation.Property; +import org.hyperledger.fabric.contract.annotation.Transaction; +import org.hyperledger.fabric.contract.metadata.TypeSchema; +import org.hyperledger.fabric.contract.routing.ContractDefinition; +import org.hyperledger.fabric.contract.routing.ParameterDefinition; +import org.hyperledger.fabric.contract.routing.TransactionType; +import org.hyperledger.fabric.contract.routing.TxFunction; + +public class TxFunctionImpl implements TxFunction { + private static Logger logger = Logger.getLogger(TxFunctionImpl.class.getName()); + + private final Method method; + private String name; + private TransactionType type; + private final Routing routing; + private TypeSchema returnSchema; + private List paramsList = new ArrayList<>(); + private boolean isUnknownTx; + + public class RoutingImpl implements Routing { + + Method method; + Class clazz; + + public RoutingImpl(final Method method, final Class clazz) { + this.method = method; + this.clazz = clazz; + } + + @Override + public Method getMethod() { + return method; + } + + @Override + public Class getContractClass() { + return clazz; + } + + @Override + public ContractInterface getContractInstance() throws InstantiationException, IllegalAccessException { + + return clazz.newInstance(); + + } + + @Override + public String toString() { + return method.getName() + ":" + clazz.getCanonicalName(); + } + } + + /** + * New TxFunction Definition Impl + * + * @param m Reflect method object + * @param contract ContractDefinition this is part of + */ + public TxFunctionImpl(final Method m, final ContractDefinition contract) { + + this.method = m; + if (m.getAnnotation(Transaction.class) != null) { + logger.fine("Found Transaction method: " + m.getName()); + if (m.getAnnotation(Transaction.class).submit()) { + this.type = TransactionType.INVOKE; + } else { + this.type = TransactionType.QUERY; + } + + final String txnName = m.getAnnotation(Transaction.class).name(); + if (!txnName.isEmpty()) { + this.name = txnName; + } + } + + if (name == null) { + this.name = m.getName(); + } + + this.routing = new RoutingImpl(m, contract.getContractImpl()); + + // set the return schema + this.returnSchema = TypeSchema.typeConvert(m.getReturnType()); + + // parameter processing + final List params = new ArrayList( + Arrays.asList(method.getParameters())); + + // validate the first one is a context object + if (!Context.class.isAssignableFrom(params.get(0).getType())) { + throw new ContractRuntimeException( + "First argument should be of type Context " + method.getName() + " " + params.get(0).getType()); + } else { + + params.remove(0); + } + + // FUTURE: if ever the method of creating the instance where to change, + // the routing could be changed here, a different implementation could be made + // here encapsulating the change. eg use an annotation to define where the + // context goes + + for (final java.lang.reflect.Parameter parameter : params) { + final TypeSchema paramMap = new TypeSchema(); + final TypeSchema schema = TypeSchema.typeConvert(parameter.getType()); + + final Property annotation = parameter + .getAnnotation(org.hyperledger.fabric.contract.annotation.Property.class); + if (annotation != null) { + final String[] userSupplied = annotation.schema(); + for (int i = 0; i < userSupplied.length; i += 2) { + schema.put(userSupplied[i], userSupplied[i + 1]); + } + } + + paramMap.put("name", parameter.getName()); + paramMap.put("schema", schema); + final ParameterDefinition pd = new ParameterDefinitionImpl(parameter.getName(), parameter.getClass(), + paramMap, parameter); + paramsList.add(pd); + } + } + + @Override + public String getName() { + return name; + } + + @Override + public Routing getRouting() { + return this.routing; + } + + @Override + public Class getReturnType() { + return method.getReturnType(); + } + + @Override + public java.lang.reflect.Parameter[] getParameters() { + return method.getParameters(); + } + + @Override + public TransactionType getType() { + return this.type; + } + + @Override + public String toString() { + return name + " @" + Integer.toHexString(System.identityHashCode(this)); + } + + @Override + public void setReturnSchema(final TypeSchema returnSchema) { + this.returnSchema = returnSchema; + } + + @Override + public List getParamsList() { + return paramsList; + } + + public void setParamsList(final ArrayList paramsList) { + this.paramsList = paramsList; + } + + @Override + public TypeSchema getReturnSchema() { + return returnSchema; + } + + @Override + public void setParameterDefinitions(final List list) { + this.paramsList = list; + + } + + @Override + public boolean isUnknownTx() { + return isUnknownTx; + } + + @Override + public void setUnknownTx(final boolean unknown) { + this.isUnknownTx = unknown; + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TypeRegistryImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TypeRegistryImpl.java new file mode 100644 index 00000000..606b9fec --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TypeRegistryImpl.java @@ -0,0 +1,52 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing.impl; + + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.hyperledger.fabric.contract.routing.DataTypeDefinition; +import org.hyperledger.fabric.contract.routing.TypeRegistry; + +/** + * Registry to hold the complex data types as defined in the contract + * Not used extensively at present but will have a great role when data handling comes up + * + */ +public class TypeRegistryImpl implements TypeRegistry { + + private Map components = new HashMap<>(); + + /* (non-Javadoc) + * @see org.hyperledger.fabric.contract.routing.TypeRegistry#addDataType(java.lang.Class) + */ + @Override + public void addDataType(Class cl) { + DataTypeDefinitionImpl type = new DataTypeDefinitionImpl(cl); + components.put(type.getSimpleName(), type); + } + + /* (non-Javadoc) + * @see org.hyperledger.fabric.contract.routing.TypeRegistry#getAllDataTypes() + */ + @Override + public Collection getAllDataTypes() { + return components.values(); + } + + @Override + public void addDataType(DataTypeDefinition type) { + components.put(type.getName(), type); + } + + @Override + public DataTypeDefinition getDataType(String name) { + return this.components.get(name); + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java new file mode 100644 index 00000000..fbdca9c5 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java @@ -0,0 +1,28 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.systemcontract; + +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.annotation.Contract; +import org.hyperledger.fabric.contract.annotation.Transaction; +import org.hyperledger.fabric.contract.annotation.Info; +import org.hyperledger.fabric.contract.metadata.MetadataBuilder; + +@Contract(name = "org.hyperledger.fabric", info = @Info(title = "Fabric System Contract", description = "Provides information about the contracts within this container")) +public class SystemContract implements ContractInterface { + + public SystemContract() { + + } + + @Transaction(submit = false, name = "GetMetadata") + public String getMetadata(Context ctx) { + String jsonmetadata = MetadataBuilder.getMetadata(); + return jsonmetadata; + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/Metrics.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/Metrics.java new file mode 100644 index 00000000..71ab086b --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/Metrics.java @@ -0,0 +1,63 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.metrics; +import java.lang.reflect.InvocationTargetException; +import java.util.Properties; +import java.util.logging.Logger; + +import org.hyperledger.fabric.metrics.impl.DefaultProvider; +import org.hyperledger.fabric.metrics.impl.NullProvider; + +/** + * Metrics setups up the provider in use from the configuration supplied + * If not enabled, nothing happens, but if enabled but no specific logger default is used + * that uses the org.hyperledger.Performance logger + */ +public class Metrics { + + private static final String CHAINCODE_METRICS_ENABLED = "CHAINCODE_METRICS_ENABLED"; + private static final String CHAINCODE_METRICS_PROVIDER = "CHAINCODE_METRICS_PROVIDER"; + + private static Logger logger = Logger.getLogger(Metrics.class.getName()); + + private static MetricsProvider provider; + + public static MetricsProvider initialize(Properties props) { + if ( Boolean.parseBoolean((String)props.get(CHAINCODE_METRICS_ENABLED))) { + try { + logger.info("Metrics enabled"); + if (props.containsKey(CHAINCODE_METRICS_PROVIDER)){ + String providerClass = (String)props.get(CHAINCODE_METRICS_PROVIDER); + + @SuppressWarnings("unchecked") // it must be this type otherwise an error + Class clazz = (Class) Class.forName(providerClass); + provider = (MetricsProvider) clazz.getConstructor().newInstance(); + } else { + logger.info("Using default metrics provider (logs to org.hyperledger.Performance)"); + provider = new DefaultProvider(); + } + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { + throw new RuntimeException("Unable to start metrics",e); + } + } else { + // return a 'null' provider + logger.info("Metrics disabled"); + provider = new NullProvider(); + + } + + provider.initialize(props); + return provider; + } + + public static MetricsProvider getProvider() { + if (provider == null) { + throw new IllegalStateException("No provider set, this should have been set"); + } + return provider; + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/MetricsProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/MetricsProvider.java new file mode 100644 index 00000000..e84d9fbc --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/MetricsProvider.java @@ -0,0 +1,43 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.metrics; +import java.util.Properties; + +/** Interface to be implemented to send metrics on the chaincode to the 'backend-of-choice'. + * + * An instance of this will be created, and provided with the resources from which chaincode + * specific metrics can be collected. (via the no-argument constructor). + * + * The choice of when, where and what to collect etc are within the remit of the provider. + * + * This is the effective call sequence. + * + * MyMetricsProvider mmp = new MyMetricsProvider() + * mmp.initalize(props_from_environment); + * // short while later.... + * mmp.setTaskMetricsCollector(taskService); + */ +public interface MetricsProvider { + + /** + * Initialize method that is called immediately after creation. + * + */ + default void initialize(Properties props) {}; + + /** + * Pass a reference to this task service for information gathering. This is related + * specifically to the handling of tasks within the chaincode. i.e. how individual transactions + * are dispatched for execution. + * + * @param taskService + */ + default void setTaskMetricsCollector(TaskMetricsCollector taskService) {}; + + + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/TaskMetricsCollector.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/TaskMetricsCollector.java new file mode 100644 index 00000000..821ced7c --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/TaskMetricsCollector.java @@ -0,0 +1,59 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.metrics; + +/** + * Collect metrics relating to the task execution. + * + * The task execution (of which each fabric transaction is one) is backed by a thread pool that implements + * this interface. As that is an implementation class this interface abstracts the information available + * from it (as far as metrics go). + * + */ +public interface TaskMetricsCollector { + + /** + * Currently executing tasks + * @return int > 0 + */ + int getCurrentTaskCount(); + + /** + * Currently waiting tasks; should not be a higher number + * @return int > 0 + */ + int getCurrentQueueCount(); + + /** + * Currently executing threads + * @return int > 0 + */ + int getActiveCount(); + + /** + * Gets the current size of the pool + * @return int >0 + */ + int getPoolSize(); + + /** + * Gets the core (minimum) pool size + * @return int > 0 + */ + int getCorePoolSize(); + + /** + * Gets the largest pool size so far + * @return int > 0 + */ + int getLargestPoolSize(); + + /** + * Gets the upper limitw pool size + * @return int > 0 + */ + int getMaximumPoolSize(); +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/DefaultProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/DefaultProvider.java new file mode 100644 index 00000000..7a917f6e --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/DefaultProvider.java @@ -0,0 +1,62 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.metrics.impl; + +import java.util.Properties; +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Logger; + +import org.hyperledger.fabric.Logging; +import org.hyperledger.fabric.metrics.MetricsProvider; +import org.hyperledger.fabric.metrics.TaskMetricsCollector; + +/** + * Simple default provider that logs to the org.hyperledger.Performance logger the basic metrics + * + */ +public class DefaultProvider implements MetricsProvider { + static Logger perflogger = Logger.getLogger(Logging.PERFLOGGER); + + private TaskMetricsCollector taskService; + + public DefaultProvider() { + perflogger.info("Default Metrics Provider started"); + } + + @Override + public void setTaskMetricsCollector(TaskMetricsCollector taskService) { + this.taskService = taskService; + } + + @Override + public void initialize(Properties props) { + Timer metricTimer = new Timer(true); + metricTimer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + DefaultProvider.this.logMetrics(); + } + }, 0, 5000); + + } + + protected void logMetrics() { + + perflogger.info(() -> { + StringBuilder sb = new StringBuilder(); + sb.append('{'); + sb.append(String.format(" \"active_count\":%d ", DefaultProvider.this.taskService.getActiveCount())).append(','); + sb.append(String.format(" \"pool_size\":%d ", DefaultProvider.this.taskService.getPoolSize())).append(','); + sb.append(String.format(" \"core_pool_size\":%d ", DefaultProvider.this.taskService.getCorePoolSize())).append(','); + sb.append(String.format(" \"current_task_count\":%d ", DefaultProvider.this.taskService.getCurrentTaskCount())).append(','); + sb.append(String.format(" \"current_queue_depth\":%d ", DefaultProvider.this.taskService.getCurrentQueueCount())); + return sb.append('}').toString(); + }); + + } + +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/NullProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/NullProvider.java new file mode 100644 index 00000000..d329aebd --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/NullProvider.java @@ -0,0 +1,18 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.metrics.impl; + +import org.hyperledger.fabric.metrics.MetricsProvider; + +/** + * Very simple provider that does absolutely nothing. Used when metrics are disabled. + * + */ +public class NullProvider implements MetricsProvider { + + public NullProvider() { } + +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/package-info.java new file mode 100644 index 00000000..13839aca --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/package-info.java @@ -0,0 +1,37 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +/** + *

+ * Supports collection of metrics + *

+ * The main metrics that are available are the statistics around the number of tasks that are + * running, and how the thread pool is handling these. + * + * Note a 'task' is a message from the Peer to the Chaincode - this message is either + * a new transaction, or a response from a stub API, eg getState(). Query apis + * may return more than one response. + * + * To enable metrics ensure that there is a standard format Java properites file called `config.props` + * in the root of your contract code. For example this path

myjava-contract-project/java/src/main/resources/config.props
+ * + * This should contain the following + * + *
+ * CHAINCODE_METRICS_ENABLED=true
+ * TP_CORE_POOL_SIZE=5
+ * TP_MAX_POOL_SIZE=5
+ * TP_QUEUE_SIZE=5000
+ * 
+ * + * The metrics enabled flag will turn on default metrics logging. (it's off by default) + * The TP values establish the core thread pool size, max thread poolsize, and the number of + * of tasks that will wait. (5, 5, 5000 are the default values, so don't need to be explicitly + * specified). + * + * If no file is supplied mertics are not enabled, the values shown for the thread pool are used. + */ +package org.hyperledger.fabric.metrics; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/package-info.java new file mode 100644 index 00000000..5dd67e01 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/package-info.java @@ -0,0 +1,19 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +/** + *

+ * This is the project to support the writing of Contracts with the JVM runtime - enabling development of using Java language or other JVM based languages + *

+ * The {@link org.hyperledger.fabric.contract} package implements the Fabric programming model as described in the + * Developing Applications + * chapter of the Fabric documentation.

+ * + + * @see Developing Fabric Applications + * @see org.hyperleder.fabric.contract + */ +package org.hyperledger.fabric; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java index 1c7e152f..63436813 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java @@ -6,11 +6,11 @@ package org.hyperledger.fabric.shim; +import static java.nio.charset.StandardCharsets.UTF_8; + import java.util.HashMap; import java.util.Map; -import static java.nio.charset.StandardCharsets.UTF_8; - /** * Defines methods that all chaincodes must implement. */ @@ -28,8 +28,9 @@ public interface Chaincode { public Response invoke(ChaincodeStub stub); /** - * Wrapper around protobuf Response, contains status, message and payload. Object returned by - * call to {@link #init(ChaincodeStub)} and{@link #invoke(ChaincodeStub)} + * Wrapper around protobuf Response, contains status, message and payload. + * Object returned by call to {@link #init(ChaincodeStub)} + * and{@link #invoke(ChaincodeStub)} */ class Response { @@ -37,13 +38,13 @@ class Response { private final String message; private final byte[] payload; - public Response(Status status, String message, byte[] payload) { + public Response(final Status status, final String message, final byte[] payload) { this.statusCode = status.getCode(); this.message = message; this.payload = payload; } - public Response(int statusCode, String message, byte[] payload) { + public Response(final int statusCode, final String message, final byte[] payload) { this.statusCode = statusCode; this.message = message; this.payload = payload; @@ -70,21 +71,19 @@ public byte[] getPayload() { } public String getStringPayload() { - return new String(payload, UTF_8); + return (payload == null) ? null : new String(payload, UTF_8); } /** * {@link Response} status enum. */ public enum Status { - SUCCESS(200), - ERROR_THRESHOLD(400), - INTERNAL_SERVER_ERROR(500); + SUCCESS(200), ERROR_THRESHOLD(400), INTERNAL_SERVER_ERROR(500); private static final Map codeToStatus = new HashMap<>(); private final int code; - private Status(int code) { + private Status(final int code) { this.code = code; } @@ -92,18 +91,20 @@ public int getCode() { return code; } - public static Status forCode(int code) { + public static Status forCode(final int code) { final Status result = codeToStatus.get(code); - if (result == null) throw new IllegalArgumentException("no status for code " + code); + if (result == null) { + throw new IllegalArgumentException("no status for code " + code); + } return result; } - public static boolean hasStatusForCode(int code) { + public static boolean hasStatusForCode(final int code) { return codeToStatus.containsKey(code); } static { - for (Status status : Status.values()) { + for (final Status status : Status.values()) { codeToStatus.put(status.code, status); } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java index 2c029515..0793534d 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java @@ -1,41 +1,54 @@ /* -Copyright IBM Corp., DTCC All Rights Reserved. +Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package org.hyperledger.fabric.shim; -import io.grpc.ManagedChannelBuilder; -import io.grpc.netty.GrpcSslContexts; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; -import io.netty.handler.ssl.SslContext; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.Options; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeID; -import org.hyperledger.fabric.shim.impl.ChaincodeSupportStream; -import org.hyperledger.fabric.shim.impl.Handler; +import static java.lang.String.format; -import java.io.*; -import java.nio.charset.StandardCharsets; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; import java.nio.file.Files; import java.nio.file.Paths; import java.security.Security; +import java.util.ArrayList; import java.util.Base64; +import java.util.Collections; +import java.util.Date; +import java.util.Map; +import java.util.Properties; +import java.util.logging.ConsoleHandler; +import java.util.logging.Formatter; import java.util.logging.Level; +import java.util.logging.LogManager; import java.util.logging.LogRecord; import java.util.logging.Logger; -import java.util.logging.SimpleFormatter; -import static java.lang.String.format; -import static java.util.logging.Level.ALL; -import static org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR; -import static org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.hyperledger.fabric.Logging; +import org.hyperledger.fabric.metrics.Metrics; +import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeID; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage; +import org.hyperledger.fabric.shim.impl.ChaincodeSupportClient; +import org.hyperledger.fabric.shim.impl.InnvocationTaskManager; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; + +import io.grpc.ManagedChannelBuilder; +import io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.NegotiationType; +import io.grpc.netty.NettyChannelBuilder; +import io.netty.handler.ssl.SslContext; public abstract class ChaincodeBase implements Chaincode { @@ -48,7 +61,7 @@ public abstract class ChaincodeBase implements Chaincode { @Override public abstract Response invoke(ChaincodeStub stub); - private static Log logger = LogFactory.getLog(ChaincodeBase.class); + private static final Logger logger = Logger.getLogger(ChaincodeBase.class.getName()); public static final String DEFAULT_HOST = "127.0.0.1"; public static final int DEFAULT_PORT = 7051; @@ -68,6 +81,8 @@ public abstract class ChaincodeBase implements Chaincode { private static final String CORE_PEER_TLS_ROOTCERT_FILE = "CORE_PEER_TLS_ROOTCERT_FILE"; private static final String ENV_TLS_CLIENT_KEY_PATH = "CORE_TLS_CLIENT_KEY_PATH"; private static final String ENV_TLS_CLIENT_CERT_PATH = "CORE_TLS_CLIENT_CERT_PATH"; + private Properties props; + private Level logLevel; static { Security.addProvider(new BouncyCastleProvider()); @@ -78,99 +93,151 @@ public abstract class ChaincodeBase implements Chaincode { * * @param args command line arguments */ + public void start(String[] args) { try { processEnvironmentOptions(); processCommandLineOptions(args); initializeLogging(); + + Properties props = getChaincodeConfig(); + Metrics.initialize(props); validateOptions(); - final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName(this.id).build(); - final ManagedChannelBuilder channelBuilder = newChannelBuilder(); - final Handler handler = new Handler(chaincodeId, this); - new ChaincodeSupportStream(channelBuilder, handler::onChaincodeMessage, handler::nextOutboundChaincodeMessage); - } catch (Exception e) { - logger.fatal("Chaincode could not start", e); + connectToPeer(); + } catch (final Exception e) { + logger.severe("Chaincode could not start"); + logger.severe(Logging.formatError(e)); + throw new RuntimeException(e); } } - void initializeLogging() { - System.setProperty("java.util.logging.SimpleFormatter.format", "%1$tH:%1$tM:%1$tS:%1$tL %4$-7.7s %2$s %5$s%6$s%n"); - final Logger rootLogger = Logger.getLogger(""); - for (java.util.logging.Handler handler : rootLogger.getHandlers()) { - handler.setLevel(ALL); - handler.setFormatter(new SimpleFormatter() { - @Override - public synchronized String format(LogRecord record) { - return super.format(record) - .replaceFirst(".*SEVERE\\s*\\S*\\s*\\S*", "\u001B[1;31m$0\u001B[0m") - .replaceFirst(".*WARNING\\s*\\S*\\s*\\S*", "\u001B[1;33m$0\u001B[0m") - .replaceFirst(".*CONFIG\\s*\\S*\\s*\\S*", "\u001B[35m$0\u001B[0m") - .replaceFirst(".*FINE\\s*\\S*\\s*\\S*", "\u001B[36m$0\u001B[0m") - .replaceFirst(".*FINER\\s*\\S*\\s*\\S*", "\u001B[36m$0\u001B[0m") - .replaceFirst(".*FINEST\\s*\\S*\\s*\\S*", "\u001B[36m$0\u001B[0m"); + protected void connectToPeer() throws IOException { + + // The ChaincodeSupport Client is a wrapper around the gRPC streams that + // come from the single 'register' call that is made back to the peer + // + // Once this has been created, the InnvocationTaskManager that is responsible + // for the thread management can be created. + // + // This is then passed to the ChaincodeSupportClient to be connected to the + // gRPC streams + + final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName(this.id).build(); + final ManagedChannelBuilder channelBuilder = newChannelBuilder(); + ChaincodeSupportClient chaincodeSupportClient = new ChaincodeSupportClient(channelBuilder); + + InnvocationTaskManager itm = InnvocationTaskManager.getManager(this, chaincodeId); + chaincodeSupportClient.start(itm); + + } + + protected void initializeLogging() { + + LogManager logManager = LogManager.getLogManager(); + + Formatter f = new Formatter() { + + private final Date dat = new Date(); + private final String format = "%1$tH:%1$tM:%1$tS:%1$tL %4$-7.7s %2$-80.80s %5$s%6$s%n"; + + @Override + public String format(final LogRecord record) { + dat.setTime(record.getMillis()); + String source; + if (record.getSourceClassName() != null) { + source = record.getSourceClassName(); + if (record.getSourceMethodName() != null) { + source += " " + record.getSourceMethodName(); + } + } else { + source = record.getLoggerName(); } - }); - } - // set logging level of chaincode logger - Level chaincodeLogLevel = mapLevel(System.getenv(CORE_CHAINCODE_LOGGING_LEVEL)); - Package chaincodePackage = this.getClass().getPackage(); - if (chaincodePackage != null) { - Logger.getLogger(chaincodePackage.getName()).setLevel(chaincodeLogLevel); - } else { - // If chaincode declared without package, i.e. default package, lets set level to root logger - // Chaincode should never be declared without package - Logger.getLogger("").setLevel(chaincodeLogLevel); - } + final String message = formatMessage(record); + String throwable = ""; + if (record.getThrown() != null) { + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); + pw.println(); + record.getThrown().printStackTrace(pw); + pw.close(); + throwable = sw.toString(); + } + return String.format(format, dat, source, record.getLoggerName(), record.getLevel(), message, + throwable); - // set logging level of shim logger - Level shimLogLevel = mapLevel(System.getenv(CORE_CHAINCODE_LOGGING_SHIM)); - Logger.getLogger(ChaincodeBase.class.getPackage().getName()).setLevel(shimLogLevel); + } + + }; + + final Logger rootLogger = Logger.getLogger("org.hyperledger"); + rootLogger.setUseParentHandlers(false); + rootLogger.addHandler(new ConsoleHandler()); + + final ArrayList allLoggers = Collections.list(logManager.getLoggerNames()); + allLoggers.add("org.hyperledger"); + allLoggers.stream().filter(name -> name.startsWith("org.hyperledger")).peek(System.out::println) + .map(name -> logManager.getLogger(name)).forEach(logger -> { + if (logger != null) { + logger.setLevel(Level.ALL); + for (final java.util.logging.Handler handler : logger.getHandlers()) { + handler.setLevel(Level.ALL); + handler.setFormatter(f); + } + } + }); + + rootLogger.info("Loglevel set to " + this.logLevel); } - private Level mapLevel(String level) { + private Level mapLevel(final String level) { if (level != null) { - switch (level) { - case "CRITICAL": - case "ERROR": - return Level.SEVERE; - case "WARNING": - return Level.WARNING; - case "INFO": - return Level.INFO; - case "NOTICE": - return Level.CONFIG; - case "DEBUG": - return Level.FINEST; + switch (level.toUpperCase().trim()) { + case "CRITICAL": + case "ERROR": + return Level.SEVERE; + case "WARNING": + return Level.WARNING; + case "INFO": + return Level.INFO; + case "NOTICE": + return Level.CONFIG; + case "DEBUG": + return Level.FINEST; } } return Level.INFO; } - void validateOptions() { + protected void validateOptions() { if (this.id == null) { - throw new IllegalArgumentException(format("The chaincode id must be specified using either the -i or --i command line options or the %s environment variable.", CORE_CHAINCODE_ID_NAME)); + throw new IllegalArgumentException(format( + "The chaincode id must be specified using either the -i or --i command line options or the %s environment variable.", + CORE_CHAINCODE_ID_NAME)); } if (this.tlsEnabled) { if (tlsClientCertPath == null) { - throw new IllegalArgumentException(format("Client key certificate chain (%s) was not specified.", ENV_TLS_CLIENT_CERT_PATH)); + throw new IllegalArgumentException( + format("Client key certificate chain (%s) was not specified.", ENV_TLS_CLIENT_CERT_PATH)); } if (tlsClientKeyPath == null) { - throw new IllegalArgumentException(format("Client key (%s) was not specified.", ENV_TLS_CLIENT_KEY_PATH)); + throw new IllegalArgumentException( + format("Client key (%s) was not specified.", ENV_TLS_CLIENT_KEY_PATH)); } if (tlsClientRootCertPath == null) { - throw new IllegalArgumentException(format("Peer certificate trust store (%s) was not specified.", CORE_PEER_TLS_ROOTCERT_FILE)); + throw new IllegalArgumentException( + format("Peer certificate trust store (%s) was not specified.", CORE_PEER_TLS_ROOTCERT_FILE)); } } } - void processCommandLineOptions(String[] args) { - Options options = new Options(); + protected void processCommandLineOptions(final String[] args) { + final Options options = new Options(); options.addOption("a", "peer.address", true, "Address of peer to connect to"); options.addOption(null, "peerAddress", true, "Address of peer to connect to"); options.addOption("i", "id", true, "Identity of chaincode"); try { - CommandLine cl = new DefaultParser().parse(options, args); + final CommandLine cl = new DefaultParser().parse(options, args); if (cl.hasOption("peerAddress") || cl.hasOption('a')) { String hostAddrStr; if (cl.hasOption('a')) { @@ -178,44 +245,48 @@ void processCommandLineOptions(String[] args) { } else { hostAddrStr = cl.getOptionValue("peerAddress"); } - String[] hostArr = hostAddrStr.split(":"); + final String[] hostArr = hostAddrStr.split(":"); if (hostArr.length == 2) { port = Integer.valueOf(hostArr[1].trim()); host = hostArr[0].trim(); } else { - String msg = String.format("peer address argument should be in host:port format, current %s in wrong", hostAddrStr); - logger.error(msg); + final String msg = String.format( + "peer address argument should be in host:port format, current %s in wrong", hostAddrStr); + logger.severe(msg); throw new IllegalArgumentException(msg); } } if (cl.hasOption('i')) { id = cl.getOptionValue('i'); } - } catch (Exception e) { - logger.warn("cli parsing failed with exception", e); + } catch (final Exception e) { + logger.warning(() -> "cli parsing failed with exception" + Logging.formatError(e)); } logger.info("<<<<<<<<<<<<>>>>>>>>>>>"); logger.info("CORE_CHAINCODE_ID_NAME: " + this.id); logger.info("CORE_PEER_ADDRESS: " + this.host + ":" + this.port); logger.info("CORE_PEER_TLS_ENABLED: " + this.tlsEnabled); - logger.info("CORE_PEER_TLS_ROOTCERT_FILE" + this.tlsClientRootCertPath); - logger.info("CORE_TLS_CLIENT_KEY_PATH" + this.tlsClientKeyPath); - logger.info("CORE_TLS_CLIENT_CERT_PATH" + this.tlsClientCertPath); + logger.info("CORE_PEER_TLS_ROOTCERT_FILE: " + this.tlsClientRootCertPath); + logger.info("CORE_TLS_CLIENT_KEY_PATH: " + this.tlsClientKeyPath); + logger.info("CORE_TLS_CLIENT_CERT_PATH: " + this.tlsClientCertPath); } - void processEnvironmentOptions() { + protected void processEnvironmentOptions() { + if (System.getenv().containsKey(CORE_CHAINCODE_ID_NAME)) { this.id = System.getenv(CORE_CHAINCODE_ID_NAME); } if (System.getenv().containsKey(CORE_PEER_ADDRESS)) { - String[] hostArr = System.getenv(CORE_PEER_ADDRESS).split(":"); + final String[] hostArr = System.getenv(CORE_PEER_ADDRESS).split(":"); if (hostArr.length == 2) { this.port = Integer.valueOf(hostArr[1].trim()); this.host = hostArr[0].trim(); } else { - String msg = String.format("peer address argument should be in host:port format, ignoring current %s", System.getenv(CORE_PEER_ADDRESS)); - logger.error(msg); + final String msg = String.format( + "peer address argument should be in host:port format, ignoring current %s", + System.getenv(CORE_PEER_ADDRESS)); + logger.severe(msg); } } this.tlsEnabled = Boolean.parseBoolean(System.getenv(CORE_PEER_TLS_ENABLED)); @@ -225,18 +296,62 @@ void processEnvironmentOptions() { this.tlsClientCertPath = System.getenv(ENV_TLS_CLIENT_CERT_PATH); } + Level chaincodeLogLevel = mapLevel(System.getenv(CORE_CHAINCODE_LOGGING_LEVEL)); + final Level shimLogLevel = mapLevel(System.getenv(CORE_CHAINCODE_LOGGING_SHIM)); + if (chaincodeLogLevel.intValue() > shimLogLevel.intValue()) { + chaincodeLogLevel = shimLogLevel; + } + + this.logLevel = chaincodeLogLevel; + logger.info("<<<<<<<<<<<<>>>>>>>>>>>"); logger.info("CORE_CHAINCODE_ID_NAME: " + this.id); logger.info("CORE_PEER_ADDRESS: " + this.host); logger.info("CORE_PEER_TLS_ENABLED: " + this.tlsEnabled); - logger.info("CORE_PEER_TLS_ROOTCERT_FILE" + this.tlsClientRootCertPath); - logger.info("CORE_TLS_CLIENT_KEY_PATH" + this.tlsClientKeyPath); - logger.info("CORE_TLS_CLIENT_CERT_PATH" + this.tlsClientCertPath); + logger.info("CORE_PEER_TLS_ROOTCERT_FILE: " + this.tlsClientRootCertPath); + logger.info("CORE_TLS_CLIENT_KEY_PATH: " + this.tlsClientKeyPath); + logger.info("CORE_TLS_CLIENT_CERT_PATH: " + this.tlsClientCertPath); + logger.info("LOGLEVEL: " + this.logLevel); + } + + /** + * Obtains configuration specificially for running the chaincode, and settable on a per chaincode + * basis, rather than taking properties from the Peers' configuration + */ + public Properties getChaincodeConfig() { + if (this.props == null) { + + ClassLoader cl = this.getClass().getClassLoader(); + // determine the location of the properties file to control the metrics etc. + + props = new Properties(); + + try (InputStream inStream = cl.getResourceAsStream("config.props")) { + if (inStream != null) { + props.load(inStream); + } + } catch (IOException e) { + logger.warning(() -> "Can not open the properties file for input " + Logging.formatError(e)); + } + + // will be useful + props.setProperty(CORE_CHAINCODE_ID_NAME, this.id); + props.setProperty(CORE_PEER_ADDRESS, this.host); + + logger.info("<<<<<<<<<<<<>>>>>>>>>>>"); + logger.info(() -> this.props.toString()); + } + + return this.props; } + @SuppressWarnings("deprecation") ManagedChannelBuilder newChannelBuilder() throws IOException { + + // TODO: consider moving this to be pure GRPC + // This is being reworked in master so leaving this 'as-is' final NettyChannelBuilder builder = NettyChannelBuilder.forAddress(host, port); - logger.info("Configuring channel connection to peer."); + logger.info("()->Configuring channel connection to peer." + host + ":" + port + " tlsenabled " + tlsEnabled); if (tlsEnabled) { builder.negotiationType(NegotiationType.TLS); @@ -244,62 +359,67 @@ ManagedChannelBuilder newChannelBuilder() throws IOException { } else { builder.usePlaintext(true); } + + // there is a optional in GRPC to use 'directExecutor' rather than the inbuilt + // gRPC thread management + // not seen to make a marked difference in performance. + // However if it ever does, then this is where it should be enabled return builder; } SslContext createSSLContext() throws IOException { - byte ckb[] = Files.readAllBytes(Paths.get(this.tlsClientKeyPath)); - byte ccb[] = Files.readAllBytes(Paths.get(this.tlsClientCertPath)); + final byte[] ckb = Files.readAllBytes(Paths.get(this.tlsClientKeyPath)); + final byte[] ccb = Files.readAllBytes(Paths.get(this.tlsClientCertPath)); - return GrpcSslContexts.forClient() - .trustManager(new File(this.tlsClientRootCertPath)) - .keyManager( - new ByteArrayInputStream(Base64.getDecoder().decode(ccb)), + return GrpcSslContexts.forClient().trustManager(new File(this.tlsClientRootCertPath)) + .keyManager(new ByteArrayInputStream(Base64.getDecoder().decode(ccb)), new ByteArrayInputStream(Base64.getDecoder().decode(ckb))) .build(); } - protected static Response newSuccessResponse(String message, byte[] payload) { - return new Response(SUCCESS, message, payload); + @Deprecated + protected static Response newSuccessResponse(final String message, final byte[] payload) { + return ResponseUtils.newSuccessResponse(message, payload); } + @Deprecated protected static Response newSuccessResponse() { - return newSuccessResponse(null, null); + return ResponseUtils.newSuccessResponse(); } - protected static Response newSuccessResponse(String message) { - return newSuccessResponse(message, null); + @Deprecated + protected static Response newSuccessResponse(final String message) { + return ResponseUtils.newSuccessResponse(message); } - protected static Response newSuccessResponse(byte[] payload) { - return newSuccessResponse(null, payload); + @Deprecated + protected static Response newSuccessResponse(final byte[] payload) { + return ResponseUtils.newSuccessResponse(payload); } - protected static Response newErrorResponse(String message, byte[] payload) { - return new Response(INTERNAL_SERVER_ERROR, message, payload); + @Deprecated + protected static Response newErrorResponse(final String message, final byte[] payload) { + return ResponseUtils.newErrorResponse(message, payload); } + @Deprecated protected static Response newErrorResponse() { - return newErrorResponse(null, null); + return ResponseUtils.newErrorResponse(); } - protected static Response newErrorResponse(String message) { - return newErrorResponse(message, null); + @Deprecated + protected static Response newErrorResponse(final String message) { + return ResponseUtils.newErrorResponse(message); } - protected static Response newErrorResponse(byte[] payload) { - return newErrorResponse(null, payload); + @Deprecated + protected static Response newErrorResponse(final byte[] payload) { + return ResponseUtils.newErrorResponse(payload); } - protected static Response newErrorResponse(Throwable throwable) { - return newErrorResponse(throwable.getMessage(), printStackTrace(throwable)); - } - - private static byte[] printStackTrace(Throwable throwable) { - if (throwable == null) return null; - final StringWriter buffer = new StringWriter(); - throwable.printStackTrace(new PrintWriter(buffer)); - return buffer.toString().getBytes(StandardCharsets.UTF_8); + @Deprecated + protected static Response newErrorResponse(final Throwable throwable) { + return ResponseUtils.newErrorResponse(throwable); } String getHost() { @@ -329,4 +449,26 @@ String getTlsClientRootCertPath() { String getId() { return id; } + + public enum CCState { + CREATED, ESTABLISHED, READY + } + + CCState state = CCState.CREATED; + + public CCState getState() { + return this.state; + } + + public void setState(CCState newState) { + this.state = newState; + } + + public static String toJsonString(ChaincodeMessage message) { + try { + return JsonFormat.printer().print(message); + } catch (InvalidProtocolBufferException e) { + return String.format("{ Type: %s, TxId: %s }", message.getType(), message.getTxid()); + } + } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeException.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeException.java new file mode 100644 index 00000000..919a99ba --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeException.java @@ -0,0 +1,137 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.shim; + +import static java.nio.charset.StandardCharsets.UTF_8; + +/** + * Contracts should use {@code ChaincodeException} to indicate when an error + * occurs in Smart Contract logic. + * + *

+ * When a {@code ChaincodeException} is thrown an error response will be + * returned from the chaincode container containing the exception message and + * payload, if specified. + * + *

+ * {@code ChaincodeException} may be extended to provide application specific + * error information. Subclasses should ensure that {@link #getPayload} returns + * a serialized representation of the error in a suitable format for client + * applications to process. + */ +public class ChaincodeException extends RuntimeException { + + private static final long serialVersionUID = 3664437023130016393L; + + private byte[] payload; + + /** + * Constructs a new {@code ChaincodeException} with no detail message. + */ + public ChaincodeException() { + super(); + } + + /** + * Constructs a new {@code ChaincodeException} with the specified detail + * message. + * + * @param message the detail message. + */ + public ChaincodeException(String message) { + super(message); + } + + /** + * Constructs a new {@code ChaincodeException} with the specified cause. + * + * @param cause the cause. + */ + public ChaincodeException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new {@code ChaincodeException} with the specified detail + * message and cause. + * + * @param message the detail message. + * @param cause the cause. + */ + public ChaincodeException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new {@code ChaincodeException} with the specified detail + * message and response payload. + * + * @param message the detail message. + * @param payload the response payload. + */ + public ChaincodeException(String message, byte[] payload) { + super(message); + + this.payload = payload; + } + + /** + * Constructs a new {@code ChaincodeException} with the specified detail + * message, response payload and cause. + * + * @param message the detail message. + * @param payload the response payload. + * @param cause the cause. + */ + public ChaincodeException(String message, byte[] payload, Throwable cause) { + super(message, cause); + + this.payload = payload; + } + + /** + * Constructs a new {@code ChaincodeException} with the specified detail + * message and response payload. + * + * @param message the detail message. + * @param payload the response payload. + */ + public ChaincodeException(String message, String payload) { + super(message); + + this.payload = payload.getBytes(UTF_8); + } + + /** + * Constructs a new {@code ChaincodeException} with the specified detail + * message, response payload and cause. + * + * @param message the detail message. + * @param payload the response payload. + * @param cause the cause. + */ + public ChaincodeException(String message, String payload, Throwable cause) { + super(message, cause); + + this.payload = payload.getBytes(UTF_8); + } + + /** + * Returns the response payload or {@code null} if there is no response. + * + *

+ * The payload should represent the chaincode error in a way that client + * applications written in different programming languages can interpret. For + * example it could include a domain specific error code, in addition to any + * state information which would allow client applications to respond + * appropriately. + * + * @return the response payload or {@code null} if there is no response. + */ + public byte[] getPayload() { + return payload; + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java index 7a04f70d..db956db2 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java @@ -6,22 +6,28 @@ package org.hyperledger.fabric.shim; -import org.hyperledger.fabric.protos.peer.ChaincodeEventPackage.ChaincodeEvent; -import org.hyperledger.fabric.protos.peer.ProposalPackage.SignedProposal; -import org.hyperledger.fabric.shim.Chaincode.Response; -import org.hyperledger.fabric.shim.ledger.*; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.stream.Collectors.toList; import java.time.Instant; import java.util.Arrays; import java.util.List; import java.util.Map; -import static java.nio.charset.StandardCharsets.UTF_8; -import static java.util.stream.Collectors.toList; +import org.hyperledger.fabric.protos.peer.ChaincodeEventPackage.ChaincodeEvent; +import org.hyperledger.fabric.protos.peer.ProposalPackage.SignedProposal; +import org.hyperledger.fabric.shim.Chaincode.Response; +import org.hyperledger.fabric.shim.ledger.CompositeKey; +import org.hyperledger.fabric.shim.ledger.KeyModification; +import org.hyperledger.fabric.shim.ledger.KeyValue; +import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; +import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata; public interface ChaincodeStub { - /** + + + /** * Returns the arguments corresponding to the call to * {@link Chaincode#init(ChaincodeStub)} or * {@link Chaincode#invoke(ChaincodeStub)}, each argument represented as byte array. @@ -197,7 +203,7 @@ public interface ChaincodeStub { * @param endKey * @param pageSize * @param bookmark - * @return + * @return QueryIterator */ QueryResultsIteratorWithMetadata getStateByRangeWithPagination(String startKey, String endKey, int pageSize, String bookmark); @@ -238,8 +244,8 @@ public interface ChaincodeStub { *

* Call close() on the returned {@link QueryResultsIterator#close()} object when done. * - * @param objectType: ObjectType of the compositeKey - * @param attributes: Attributes of the composite key + * @param objectType ObjectType of the compositeKey + * @param attributes Attributes of the composite key * @return an {@link Iterable} of {@link KeyValue} */ QueryResultsIterator getStateByPartialCompositeKey(String objectType, String... attributes); @@ -270,7 +276,7 @@ public interface ChaincodeStub { * @param compositeKey * @param pageSize * @param bookmark - * @return + * @return QueryIterator */ QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination(CompositeKey compositeKey, int pageSize, String bookmark); @@ -323,7 +329,7 @@ public interface ChaincodeStub { * @param query * @param pageSize * @param bookmark - * @return + * @return QueryIterator */ QueryResultsIteratorWithMetadata getQueryResultWithPagination(String query, int pageSize, String bookmark); @@ -355,6 +361,14 @@ public interface ChaincodeStub { * @return value the value read from the collection */ byte[] getPrivateData(String collection, String key); + + /** + * @param collection name of the collection + * @param key name of the value + * @return hash + */ + byte[] getPrivateDataHash(String collection, String key); + /** * Retrieves the key-level endorsement * policy for the private data specified by key. Note that this introduces @@ -362,7 +376,7 @@ public interface ChaincodeStub { * * @param collection name of the collection * @param key key to get endorsement policy - * @return + * @return Key Level endorsement as byte array */ byte[] getPrivateDataValidationParameter(String collection, String key); @@ -481,8 +495,8 @@ public interface ChaincodeStub { *

* * @param collection name of the collection - * @param objectType: ObjectType of the compositeKey - * @param attributes: Attributes of the composite key + * @param objectType ObjectType of the compositeKey + * @param attributes Attributes of the composite key * @return an {@link Iterable} of {@link KeyValue} */ QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, String objectType, String... attributes); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java new file mode 100644 index 00000000..eb67fd00 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java @@ -0,0 +1,67 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.shim; + +import static org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR; +import static org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS; + +import java.util.logging.Logger; + +import org.hyperledger.fabric.Logging; + +public class ResponseUtils { + + private static Logger logger = Logger.getLogger(ResponseUtils.class.getName()); + + public static Chaincode.Response newSuccessResponse(final String message, final byte[] payload) { + return new Chaincode.Response(SUCCESS, message, payload); + } + + public static Chaincode.Response newSuccessResponse() { + return newSuccessResponse(null, null); + } + + public static Chaincode.Response newSuccessResponse(final String message) { + return newSuccessResponse(message, null); + } + + public static Chaincode.Response newSuccessResponse(final byte[] payload) { + return newSuccessResponse(null, payload); + } + + public static Chaincode.Response newErrorResponse(final String message, final byte[] payload) { + return new Chaincode.Response(INTERNAL_SERVER_ERROR, message, payload); + } + + public static Chaincode.Response newErrorResponse() { + return newErrorResponse(null, null); + } + + public static Chaincode.Response newErrorResponse(final String message) { + return newErrorResponse(message, null); + } + + public static Chaincode.Response newErrorResponse(final byte[] payload) { + return newErrorResponse(null, payload); + } + + public static Chaincode.Response newErrorResponse(final Throwable throwable) { + // Responses should not include internals like stack trace but make sure it gets + // logged + logger.severe(() -> Logging.formatError(throwable)); + + String message = null; + byte[] payload = null; + if (throwable instanceof ChaincodeException) { + message = throwable.getMessage(); + payload = ((ChaincodeException) throwable).getPayload(); + } else { + message = "Unexpected error"; + } + + return ResponseUtils.newErrorResponse(message, payload); + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsement.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsement.java index 7054cef0..58c4017c 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsement.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsement.java @@ -18,7 +18,7 @@ public interface StateBasedEndorsement { /** * Returns the endorsement policy as bytes - * @return + * @return byte[] */ byte[] policy(); @@ -45,7 +45,7 @@ public interface StateBasedEndorsement { /** * Returns an array of channel orgs that are required to endorse changes * - * @return + * @return List of organizations */ List listOrgs(); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactory.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactory.java index cd4fa7c8..15d4a6d8 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactory.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactory.java @@ -24,7 +24,7 @@ public static synchronized StateBasedEndorsementFactory getInstance() { * serialized EP byte array. If the byte array is empty, a new EP is created. * * @param ep - * @return + * @return New StateBasedEndorsement instance */ public StateBasedEndorsement newStateBasedEndorsement(byte[] ep) { return new StateBasedEndorsementImpl(ep); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/helper/Channel.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/helper/Channel.java deleted file mode 100644 index c44220db..00000000 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/helper/Channel.java +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright IBM Corp., DTCC All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package org.hyperledger.fabric.shim.helper; - -import java.io.Closeable; -import java.util.HashSet; -import java.util.concurrent.LinkedBlockingQueue; - -public class Channel extends LinkedBlockingQueue implements Closeable { - - private boolean closed = false; - - private HashSet waiting = new HashSet<>(); - - // TODO add other methods to secure closing behavior - - @Override - public E take() throws InterruptedException { - synchronized (waiting) { - if (closed) throw new InterruptedException("Channel closed"); - waiting.add(Thread.currentThread()); - } - E e = super.take(); - synchronized (waiting) { - waiting.remove(Thread.currentThread()); - } - return e; - } - - @Override - public boolean add(E e) { - if (closed) { - throw new IllegalStateException("Channel is closed"); - } - return super.add(e); - } - - @Override - public void close() { - synchronized (waiting) { - closed = true; - for (Thread t : waiting) { - t.interrupt(); - } - waiting.clear(); - clear(); - } - } - -} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInnvocationTask.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInnvocationTask.java new file mode 100644 index 00000000..c0dd8569 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInnvocationTask.java @@ -0,0 +1,200 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.shim.impl; + +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.COMPLETED; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.ERROR; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.RESPONSE; + +import java.util.concurrent.Callable; +import java.util.concurrent.Exchanger; +import java.util.function.Consumer; +import java.util.logging.Logger; + +import org.hyperledger.fabric.Logging; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type; +import org.hyperledger.fabric.shim.Chaincode; +import org.hyperledger.fabric.shim.ChaincodeStub; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; + +/** + * A 'Callable' implementation the has the job of invoking the chaincode, and + * matching the response and requests + * + */ +public class ChaincodeInnvocationTask implements Callable { + + private static Logger logger = Logger.getLogger(ChaincodeInnvocationTask.class.getName()); + private static Logger perflogger = Logger.getLogger(Logging.PERFLOGGER); + + private String key; + private Type type; + private String txId; + private Consumer outgoingMessageConsumer; + private Exchanger messageExchange = new Exchanger<>(); + private ChaincodeMessage message; + private Chaincode chaincode; + + /** + * + * @param message The incoming message that has triggered this task into + * execution + * @param type Is this init or invoke? (v2 Fabric deprecates init) + * @param outgoingMessage The Consumer functional interface to send any requests + * for ledger state + * @param chaincode A instance of the end users chaincode + * + */ + public ChaincodeInnvocationTask(ChaincodeMessage message, Type type, Consumer outgoingMessage, + Chaincode chaincode) { + + this.key = message.getChannelId() + message.getTxid(); + this.type = type; + this.outgoingMessageConsumer = outgoingMessage; + this.txId = message.getTxid(); + this.chaincode = chaincode; + this.message = message; + } + + /** + * Main method to power the invocation of the chaincode; + */ + @Override + public ChaincodeMessage call() { + ChaincodeMessage finalResponseMessage; + + try { + perflogger.fine(() -> "> taskStart " + this.txId); + + // A key interface for the chaincode's invoke() method implementation + // is the 'ChaincodeStub' interface. An instance of this is created + // per transaction invocation. + // + // This needs to be passed the message triggering the invoke, as well + // as the interface to be used for sending any requests to the peer + ChaincodeStub stub = new InnvocationStubImpl(message, this); + + // result is what will be sent to the peer as a response to this invocation + final Chaincode.Response result; + + // Call chaincode's invoke + // Note in Fabric v2, there won't be any INIT + if (this.type.equals(Type.INIT)) { + result = chaincode.init(stub); + } else { + result = chaincode.invoke(stub); + } + + if (result.getStatus().getCode() >= Chaincode.Response.Status.INTERNAL_SERVER_ERROR.getCode()) { + // Send ERROR with entire result.Message as payload + logger.severe(() -> String.format("[%-8.8s] Invoke failed with error code %d. Sending %s", + message.getTxid(), result.getStatus().getCode(), ERROR)); + finalResponseMessage = ChaincodeMessageFactory.newErrorEventMessage(message.getChannelId(), + message.getTxid(), result.getMessage(), stub.getEvent()); + } else { + // Send COMPLETED with entire result as payload + logger.fine(() -> String.format("[%-8.8s] Invoke succeeded. Sending %s", message.getTxid(), COMPLETED)); + finalResponseMessage = ChaincodeMessageFactory.newCompletedEventMessage(message.getChannelId(), + message.getTxid(), result, stub.getEvent()); + } + + } catch (InvalidProtocolBufferException | RuntimeException e) { + logger.severe(() -> String.format("[%-8.8s] Invoke failed. Sending %s: %s", message.getTxid(), ERROR, e)); + finalResponseMessage = ChaincodeMessageFactory.newErrorEventMessage(message.getChannelId(), + message.getTxid(), e); + } + + // send the final response message to the peer + outgoingMessageConsumer.accept(finalResponseMessage); + + // also return for reference + return finalResponseMessage; + } + + /** + * Identifier of this task, channel id and transaction id + */ + public String getTxKey() { + return this.key; + } + + /** + * Use the Key as to determine equality + * + * @param task + * @return + */ + public boolean equals(ChaincodeInnvocationTask task) { + return key.equals(task.getTxKey()); + } + + /** + * Posts the message that the peer has responded with to this task's request + * Uses an 'Exhanger' concurrent lock; this lets two threads exchange values + * atomically. + * + * In this case the data is only passed to the executing tasks. + * + * @param msg Chaincode message to pass pack + * @throws InterruptedException should something really really go wrong + */ + public void postMessage(ChaincodeMessage msg) throws InterruptedException { + messageExchange.exchange(msg); + } + + /** + * Send the chaincode message back to the peer. + * + * Implementation of the Functional interface 'InvokeChaincodeSupport' + * + * It will send the message, via the outgoingMessageConsumer, and then block on + * the 'Exchanger' to wait for the response to come. + * + * This Exchange is an atomic operation between the thread that is running this + * task, and the thread that is handling the communication from the peer. + * + * @param message The chaincode message from the peer + * @return ByteString to be parsed by the caller + * + */ + protected ByteString invoke(final ChaincodeMessage message) { + + // send the message + logger.info(() -> "Sending message to the peer " + message.getTxid()); + outgoingMessageConsumer.accept(message); + + // wait for response + ChaincodeMessage response; + try { + response = messageExchange.exchange(null); + logger.info(() -> "Got response back from the peer" + response); + } catch (InterruptedException e) { + logger.severe(() -> "Interuptted exchaning messages "); + throw new RuntimeException(String.format("[%-8.8s]InterruptedException received.", txId), e); + } + logger.fine(() -> String.format("[%-8.8s] %s response received.", txId, response.getType())); + + // handle response + switch (response.getType()) { + case RESPONSE: + logger.fine(() -> String.format("[%-8.8s] Successful response received.", txId)); + return response.getPayload(); + case ERROR: + logger.severe(() -> String.format("[%-8.8s] Unsuccessful response received.", txId)); + throw new RuntimeException(String.format("[%-8.8s]Unsuccessful response received.", txId)); + default: + logger.severe(() -> String.format("[%-8.8s] Unexpected %s response received. Expected %s or %s.", txId, + response.getType(), RESPONSE, ERROR)); + throw new RuntimeException(String.format("[%-8.8s] Unexpected %s response received. Expected %s or %s.", + txId, response.getType(), RESPONSE, ERROR)); + } + + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactory.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactory.java new file mode 100644 index 00000000..b852f008 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactory.java @@ -0,0 +1,150 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.shim.impl; + +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.COMPLETED; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.DEL_STATE; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.ERROR; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.GET_STATE; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.GET_PRIVATE_DATA_HASH; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.GET_STATE_METADATA; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.INVOKE_CHAINCODE; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.PUT_STATE; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.PUT_STATE_METADATA; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.REGISTER; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeID; +import org.hyperledger.fabric.protos.peer.ChaincodeEventPackage.ChaincodeEvent; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type; +import org.hyperledger.fabric.protos.peer.ProposalResponsePackage.Response; +import org.hyperledger.fabric.protos.peer.ProposalResponsePackage.Response.Builder; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.DelState; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.GetState; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.GetStateMetadata; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.PutState; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.PutStateMetadata; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.StateMetadata; +import org.hyperledger.fabric.shim.Chaincode; + +import com.google.protobuf.ByteString; + +public class ChaincodeMessageFactory { + protected static ChaincodeMessage newGetPrivateDataHashEventMessage(final String channelId, final String txId, final String collection, final String key) { + return newEventMessage(GET_PRIVATE_DATA_HASH, channelId, txId, GetState.newBuilder() + .setCollection(collection) + .setKey(key) + .build().toByteString()); + } + + protected static ChaincodeMessage newGetStateEventMessage(final String channelId, final String txId, final String collection, final String key) { + return newEventMessage(GET_STATE, channelId, txId, GetState.newBuilder() + .setCollection(collection) + .setKey(key) + .build().toByteString()); + } + + protected static ChaincodeMessage newGetStateMetadataEventMessage(final String channelId, final String txId, final String collection, final String key) { + return newEventMessage(GET_STATE_METADATA, channelId, txId, + GetStateMetadata.newBuilder() + .setCollection(collection) + .setKey(key) + .build().toByteString()); + } + + protected static ChaincodeMessage newPutStateEventMessage(final String channelId, final String txId, final String collection, final String key, final ByteString value) { + return newEventMessage(PUT_STATE, channelId, txId, PutState.newBuilder() + .setCollection(collection) + .setKey(key) + .setValue(value) + .build().toByteString()); + } + + protected static ChaincodeMessage newPutStateMatadateEventMessage(final String channelId, final String txId, final String collection, final String key, final String metakey, final ByteString value) { + return newEventMessage(PUT_STATE_METADATA, channelId, txId, + PutStateMetadata.newBuilder() + .setCollection(collection) + .setKey(key) + .setMetadata(StateMetadata.newBuilder() + .setMetakey(metakey) + .setValue(value) + .build()) + .build().toByteString()); + } + + protected static ChaincodeMessage newDeleteStateEventMessage(final String channelId, final String txId, final String collection, final String key) { + return newEventMessage(DEL_STATE, channelId, txId, DelState.newBuilder() + .setCollection(collection) + .setKey(key) + .build().toByteString()); + } + + protected static ChaincodeMessage newErrorEventMessage(final String channelId, final String txId, final Throwable throwable) { + return newErrorEventMessage(channelId, txId, printStackTrace(throwable)); + } + + protected static ChaincodeMessage newErrorEventMessage(final String channelId, final String txId, final String message) { + return newErrorEventMessage(channelId, txId, message, null); + } + + protected static ChaincodeMessage newErrorEventMessage(final String channelId, final String txId, final String message, final ChaincodeEvent event) { + return newEventMessage(ERROR, channelId, txId, ByteString.copyFromUtf8(message), event); + } + + protected static ChaincodeMessage newCompletedEventMessage(final String channelId, final String txId, final Chaincode.Response response, final ChaincodeEvent event) { + ChaincodeMessage message = newEventMessage(COMPLETED, channelId, txId, toProtoResponse(response).toByteString(), event); + return message; + } + + protected static ChaincodeMessage newInvokeChaincodeMessage(final String channelId, final String txId, final ByteString payload) { + return newEventMessage(INVOKE_CHAINCODE, channelId, txId, payload, null); + } + + protected static ChaincodeMessage newRegisterChaincodeMessage(final ChaincodeID chaincodeId) { + return ChaincodeMessage.newBuilder() + .setType(REGISTER) + .setPayload(chaincodeId.toByteString()) + .build(); + } + + protected static ChaincodeMessage newEventMessage(final Type type, final String channelId, final String txId, final ByteString payload) { + return newEventMessage(type, channelId, txId, payload, null); + } + + protected static ChaincodeMessage newEventMessage(final Type type, final String channelId, final String txId, final ByteString payload, final ChaincodeEvent event) { + ChaincodeMessage.Builder builder = ChaincodeMessage.newBuilder() + .setType(type) + .setChannelId(channelId) + .setTxid(txId) + .setPayload(payload); + if (event != null) { + builder.setChaincodeEvent(event); + } + return builder.build(); + } + + private static Response toProtoResponse(Chaincode.Response response) { + final Builder builder = Response.newBuilder(); + builder.setStatus(response.getStatus().getCode()); + if (response.getMessage() != null) { + builder.setMessage(response.getMessage()); + } + if (response.getPayload() != null) { + builder.setPayload(ByteString.copyFrom(response.getPayload())); + } + return builder.build(); + } + + private static String printStackTrace(Throwable throwable) { + if (throwable == null) return null; + final StringWriter buffer = new StringWriter(); + throwable.printStackTrace(new PrintWriter(buffer)); + return buffer.toString(); + } +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClient.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClient.java index ac72463b..4b31c81a 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClient.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClient.java @@ -5,16 +5,23 @@ */ package org.hyperledger.fabric.shim.impl; -import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; -import io.grpc.stub.StreamObserver; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; +import java.util.logging.Logger; + +import org.hyperledger.fabric.Logging; import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage; import org.hyperledger.fabric.protos.peer.ChaincodeSupportGrpc; import org.hyperledger.fabric.protos.peer.ChaincodeSupportGrpc.ChaincodeSupportStub; -import java.util.concurrent.TimeUnit; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.stub.StreamObserver; public class ChaincodeSupportClient { + private static Logger logger = Logger.getLogger(ChaincodeSupportClient.class.getName()); + private static Logger perflogger = Logger.getLogger(Logging.PERFLOGGER); private final ManagedChannel channel; private final ChaincodeSupportStub stub; @@ -24,12 +31,109 @@ public ChaincodeSupportClient(ManagedChannelBuilder channelBuilder) { this.stub = ChaincodeSupportGrpc.newStub(channel); } - public void shutdown() throws InterruptedException { - this.channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); - } + private void shutdown(InnvocationTaskManager itm) { + + // first shutdown the thread pool + itm.shutdown(); + try { + this.channel.shutdown(); + if (!channel.awaitTermination(5, TimeUnit.SECONDS)) { + channel.shutdownNow(); + if (!channel.awaitTermination(5, TimeUnit.SECONDS)) { + System.err.println("Channel did not terminate"); + } + } + ; + } catch (InterruptedException e) { + channel.shutdownNow(); + Thread.currentThread().interrupt(); + } - public StreamObserver register(StreamObserver responseObserver) { - return stub.register(responseObserver); } + public void start(InnvocationTaskManager itm) { + + // This is a critical method - it is the one time that a + // protobuf service is invoked. The single 'register' call + // is made, and two streams are created. + // + // It is confusing how these streams are then used to send messages + // to and from the peer. + // + // the response stream is the message flow FROM the peer + // the 'request observer' is the message flow TO the peer + // + // Messages coming from the peer will be requests to invoke + // chaincode, or will be the responses to stub APIs, such as getState + // Message to the peer will be the getState APIs, and the results of + // transaction invocations + + // The InnvocationTaskManager's way of being told there is a new + // message, until this is received and processed there is now + // knowing if this is a new transaction function or the answer to say getState + Consumer consumer = itm::onChaincodeMessage; + + logger.info("making the grpc call"); + // for any error - shut everything down + // as this is long lived (well forever) then any completion means something + // has stopped in the peer or the network comms, so also shutdown + StreamObserver requestObserver = this.stub.register( + + new StreamObserver() { + @Override + public void onNext(ChaincodeMessage chaincodeMessage) { + // message off to the ITM... + consumer.accept(chaincodeMessage); + } + + @Override + public void onError(Throwable t) { + logger.severe( + () -> "An error occured on the chaincode stream. Shutting down the chaincode stream." + + Logging.formatError(t)); + + ChaincodeSupportClient.this.shutdown(itm); + } + + @Override + public void onCompleted() { + logger.severe("Chaincode stream is complete. Shutting down the chaincode stream."); + ChaincodeSupportClient.this.shutdown(itm); + } + } + + ); + + // Consumer function for response messages (those going back to the peer) + // gRPC streams need to be accesed by one thread at a time, so + // use a lock to protect this. + // + // Previous implementations used a dedicated thread for this. However this extra + // thread is not really required. The main thread executing the transaction will + // not be + // held up for long, nor can any one transaction invoke more that one stub api + // at a time. + Consumer c = new Consumer() { + + // create a lock, with fair property + ReentrantLock lock = new ReentrantLock(true); + + @Override + public void accept(ChaincodeMessage t) { + lock.lock(); + perflogger.fine(() -> "> sendToPeer " + t.getTxid()); + requestObserver.onNext(t); + perflogger.fine(() -> "< sendToPeer " + t.getTxid()); + lock.unlock(); + } + }; + + // Pass a Consumer interface back to the the task manager. This is for tasks to + // use to respond back to the peer. + // + // NOTE the register() - very important - as this triggers the ITM to send the + // first message to the peer; otherwise the both sides will sit there waiting + itm.setResponseConsumer(c).register(); + + } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportStream.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportStream.java deleted file mode 100644 index 36ea0c3c..00000000 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportStream.java +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ -package org.hyperledger.fabric.shim.impl; - -import io.grpc.ManagedChannelBuilder; -import io.grpc.stub.StreamObserver; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage; - -import java.util.function.Consumer; -import java.util.function.Supplier; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class ChaincodeSupportStream { - - private final Logger logger = Logger.getLogger(ChaincodeSupportStream.class.getName()); - private final ChaincodeSupportClient chaincodeSupportClient; - private final Consumer consumer; - private final Supplier supplier; - private final StreamObserver requestObserver; - private final StreamObserver responseObserver = new StreamObserver() { - @Override - public void onNext(ChaincodeMessage chaincodeMessage) { - consumer.accept(chaincodeMessage); - } - - @Override - public void onError(Throwable t) { - logger.log(Level.SEVERE, "An error occured on the chaincode stream. Shutting down the chaincode stream.", t); - ChaincodeSupportStream.this.shutdown(); - } - - @Override - public void onCompleted() { - logger.info("Chaincode stream is shutting down."); - ChaincodeSupportStream.this.shutdown(); - } - }; - final private Thread supplierComsumptionThread = new Thread() { - @Override - public void run() { - while (!Thread.currentThread().isInterrupted()) { - ChaincodeSupportStream.this.requestObserver.onNext(ChaincodeSupportStream.this.supplier.get()); - } - } - }; - - public ChaincodeSupportStream(ManagedChannelBuilder channelBuilder, Consumer consumer, Supplier supplier) { - this.chaincodeSupportClient = new ChaincodeSupportClient(channelBuilder); - this.consumer = consumer; - this.requestObserver = this.chaincodeSupportClient.register(this.responseObserver); - this.supplier = supplier; - this.supplierComsumptionThread.start(); - } - - private void shutdown() { - this.supplierComsumptionThread.interrupt(); - try { - this.chaincodeSupportClient.shutdown(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - -} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/Handler.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/Handler.java deleted file mode 100644 index 6a4749ec..00000000 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/Handler.java +++ /dev/null @@ -1,610 +0,0 @@ -/* -Copyright IBM Corp., DTCC All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package org.hyperledger.fabric.shim.impl; - -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.util.JsonFormat; -import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeID; -import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeInput; -import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeSpec; -import org.hyperledger.fabric.protos.peer.ChaincodeEventPackage.ChaincodeEvent; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.*; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type; -import org.hyperledger.fabric.protos.peer.ProposalResponsePackage.Response; -import org.hyperledger.fabric.protos.peer.ProposalResponsePackage.Response.Builder; -import org.hyperledger.fabric.shim.Chaincode; -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.shim.helper.Channel; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import static java.lang.String.format; -import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.*; - -public class Handler { - - private static Logger logger = Logger.getLogger(Handler.class.getName()); - private final Chaincode chaincode; - private final Map isTransaction = new HashMap<>(); - private final Map> responseChannel = new HashMap<>(); - private Channel outboundChaincodeMessages = new Channel<>(); - private CCState state; - - public Handler(ChaincodeID chaincodeId, Chaincode chaincode) { - this.chaincode = chaincode; - this.state = CCState.CREATED; - queueOutboundChaincodeMessage(newRegisterChaincodeMessage(chaincodeId)); - } - - public ChaincodeMessage nextOutboundChaincodeMessage() { - try { - return outboundChaincodeMessages.take(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Unable to get next outbound ChaincodeMessage"); - } - return newErrorEventMessage("UNKNOWN", "UNKNOWN", e); - } - } - - public void onChaincodeMessage(ChaincodeMessage chaincodeMessage) { - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] %s", chaincodeMessage.getTxid(), toJsonString(chaincodeMessage))); - } - handleChaincodeMessage(chaincodeMessage); - } - - private synchronized void handleChaincodeMessage(ChaincodeMessage message) { - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] Handling ChaincodeMessage of type: %s, handler state %s", message.getTxid(), message.getType(), this.state)); - } - if (message.getType() == KEEPALIVE) { - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] Received KEEPALIVE: nothing to do", message.getTxid())); - } - return; - } - switch (this.state) { - case CREATED: - handleCreated(message); - break; - case ESTABLISHED: - handleEstablished(message); - break; - case READY: - handleReady(message); - break; - default: - if (logger.isLoggable(Level.WARNING)) { - logger.warning(format("[%-8.8s] Received %s: cannot handle", message.getTxid(), message.getType())); - } - break; - } - } - - private void handleCreated(ChaincodeMessage message) { - if (message.getType() == REGISTERED) { - this.state = CCState.ESTABLISHED; - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] Received REGISTERED: moving to established state", message.getTxid())); - } - } else { - if (logger.isLoggable(Level.WARNING)) { - logger.warning(format("[%-8.8s] Received %s: cannot handle", message.getTxid(), message.getType())); - } - } - } - - private void handleEstablished(ChaincodeMessage message) { - if (message.getType() == READY) { - this.state = CCState.READY; - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] Received READY: ready for invocations", message.getTxid())); - } - } else { - if (logger.isLoggable(Level.WARNING)) { - logger.warning(format("[%-8.8s] Received %s: cannot handle", message.getTxid(), message.getType())); - } - } - } - - private void handleReady(ChaincodeMessage message) { - switch (message.getType()) { - case RESPONSE: - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] Received RESPONSE: publishing to channel", message.getTxid())); - } - sendChannel(message); - break; - case ERROR: - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] Received ERROR: publishing to channel", message.getTxid())); - } - sendChannel(message); - break; - case INIT: - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] Received INIT: invoking chaincode init", message.getTxid())); - } - handleInit(message); - break; - case TRANSACTION: - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] Received TRANSACTION: invoking chaincode", message.getTxid())); - } - handleTransaction(message); - break; - default: - if (logger.isLoggable(Level.WARNING)) { - logger.warning(format("[%-8.8s] Received %s: cannot handle", message.getTxid(), message.getType())); - } - break; - } - } - - private String getTxKey(final String channelId, final String txid) { - return channelId + txid; - } - - private void queueOutboundChaincodeMessage(ChaincodeMessage chaincodeMessage) { - this.outboundChaincodeMessages.add(chaincodeMessage); - } - - private synchronized Channel aquireResponseChannelForTx(final String channelId, final String txId) { - final Channel channel = new Channel<>(); - String key = getTxKey(channelId, txId); - if (this.responseChannel.putIfAbsent(key, channel) != null) { - throw new IllegalStateException(format("[%-8.8s] Response channel already exists. Another request must be pending.", txId)); - } - if (logger.isLoggable(Level.FINEST)) { - logger.finest(format("[%-8.8s] Response channel created.", txId)); - } - return channel; - } - - private synchronized void sendChannel(ChaincodeMessage message) { - String key = getTxKey(message.getChannelId(), message.getTxid()); - if (!responseChannel.containsKey(key)) { - throw new IllegalStateException(format("[%-8.8s] sendChannel does not exist", message.getTxid())); - } - responseChannel.get(key).add(message); - } - - private ChaincodeMessage receiveChannel(Channel channel) { - try { - return channel.take(); - } catch (InterruptedException e) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("channel.take() failed with InterruptedException"); - } - - // Channel has been closed? - // TODO - return null; - } - } - - private synchronized void releaseResponseChannelForTx(String channelId, String txId) { - String key = getTxKey(channelId, txId); - final Channel channel = responseChannel.remove(key); - if (channel != null) channel.close(); - if (logger.isLoggable(Level.FINER)) { - logger.finer(format("[%-8.8s] Response channel closed.", txId)); - } - } - - /** - * Marks a CHANNELID+UUID as either a transaction or a query - * - * @param uuid ID to be marked - * @param isTransaction true for transaction, false for query - * @return whether or not the UUID was successfully marked - */ - private synchronized boolean markIsTransaction(String channelId, String uuid, boolean isTransaction) { - if (this.isTransaction == null) { - return false; - } - - String key = getTxKey(channelId, uuid); - this.isTransaction.put(key, isTransaction); - return true; - } - - private synchronized void deleteIsTransaction(String channelId, String uuid) { - String key = getTxKey(channelId, uuid); - isTransaction.remove(key); - } - - /** - * Handles requests to initialize chaincode - * - * @param message chaincode to be initialized - */ - private void handleInit(ChaincodeMessage message) { - new Thread(() -> { - try { - - // Get the function and args from Payload - final ChaincodeInput input = ChaincodeInput.parseFrom(message.getPayload()); - - // Mark as a transaction (allow put/del state) - markIsTransaction(message.getChannelId(), message.getTxid(), true); - - // Create the ChaincodeStub which the chaincode can use to - // callback - final ChaincodeStub stub = new ChaincodeStubImpl(message.getChannelId(), message.getTxid(), this, input.getArgsList(), message.getProposal()); - - // Call chaincode's init - final Chaincode.Response result = chaincode.init(stub); - - if (result.getStatus().getCode() >= Chaincode.Response.Status.INTERNAL_SERVER_ERROR.getCode()) { - // Send ERROR with entire result.Message as payload - logger.severe(format("[%-8.8s] Init failed. Sending %s", message.getTxid(), ERROR)); - queueOutboundChaincodeMessage(newErrorEventMessage(message.getChannelId(), message.getTxid(), result.getMessage(), stub.getEvent())); - } else { - // Send COMPLETED with entire result as payload - if (logger.isLoggable(Level.FINE)) { - logger.fine(format(format("[%-8.8s] Init succeeded. Sending %s", message.getTxid(), COMPLETED))); - } - queueOutboundChaincodeMessage(newCompletedEventMessage(message.getChannelId(), message.getTxid(), result, stub.getEvent())); - } - } catch (InvalidProtocolBufferException | RuntimeException e) { - logger.severe(format("[%-8.8s] Init failed. Sending %s: %s", message.getTxid(), ERROR, e)); - queueOutboundChaincodeMessage(newErrorEventMessage(message.getChannelId(), message.getTxid(), e)); - } finally { - // delete isTransaction entry - deleteIsTransaction(message.getChannelId(), message.getTxid()); - } - }).start(); - } - - // handleTransaction Handles request to execute a transaction. - private void handleTransaction(ChaincodeMessage message) { - new Thread(() -> { - try { - - // Get the function and args from Payload - final ChaincodeInput input = ChaincodeInput.parseFrom(message.getPayload()); - - // Mark as a transaction (allow put/del state) - markIsTransaction(message.getChannelId(), message.getTxid(), true); - - // Create the ChaincodeStub which the chaincode can use to - // callback - final ChaincodeStub stub = new ChaincodeStubImpl(message.getChannelId(), message.getTxid(), this, input.getArgsList(), message.getProposal()); - - // Call chaincode's invoke - final Chaincode.Response result = chaincode.invoke(stub); - - if (result.getStatus().getCode() >= Chaincode.Response.Status.INTERNAL_SERVER_ERROR.getCode()) { - // Send ERROR with entire result.Message as payload - logger.severe(format("[%-8.8s] Invoke failed. Sending %s", message.getTxid(), ERROR)); - queueOutboundChaincodeMessage(newErrorEventMessage(message.getChannelId(), message.getTxid(), result.getMessage(), stub.getEvent())); - } else { - // Send COMPLETED with entire result as payload - if (logger.isLoggable(Level.FINE)) { - logger.fine(format(format("[%-8.8s] Invoke succeeded. Sending %s", message.getTxid(), COMPLETED))); - } - queueOutboundChaincodeMessage(newCompletedEventMessage(message.getChannelId(), message.getTxid(), result, stub.getEvent())); - } - - } catch (InvalidProtocolBufferException | RuntimeException e) { - logger.severe(format("[%-8.8s] Invoke failed. Sending %s: %s", message.getTxid(), ERROR, e)); - queueOutboundChaincodeMessage(newErrorEventMessage(message.getChannelId(), message.getTxid(), e)); - } finally { - // delete isTransaction entry - deleteIsTransaction(message.getChannelId(), message.getTxid()); - } - }).start(); - } - - // handleGetState communicates with the validator to fetch the requested state information from the ledger. - ByteString getState(String channelId, String txId, String collection, String key) { - return invokeChaincodeSupport(newGetStateEventMessage(channelId, txId, collection, key)); - } - - Map getStateMetadata(String channelId, String txId, String collection, String key) { - ByteString payload = invokeChaincodeSupport(newGetStateMetadataEventMessage(channelId, txId, collection, key)); - try { - StateMetadataResult stateMetadataResult = StateMetadataResult.parseFrom(payload); - Map stateMetadataMap = new HashMap<>(); - stateMetadataResult.getEntriesList().forEach(entry -> stateMetadataMap.put(entry.getMetakey(), entry.getValue())); - return stateMetadataMap; - } catch (InvalidProtocolBufferException e) { - logger.severe(String.format("[%-8.8s] unmarshall error", txId)); - throw new RuntimeException("Error unmarshalling StateMetadataResult.", e); - } - } - - private boolean isTransaction(String channelId, String uuid) { - String key = getTxKey(channelId, uuid); - return isTransaction.containsKey(key) && isTransaction.get(key); - } - - void putState(String channelId, String txId, String collection, String key, ByteString value) { - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] Inside putstate (\"%s\":\"%s\":\"%s\"), isTransaction = %s", txId, collection, key, value, isTransaction(channelId, txId))); - } - if (!isTransaction(channelId, txId)) throw new IllegalStateException("Cannot put state in query context"); - invokeChaincodeSupport(newPutStateEventMessage(channelId, txId, collection, key, value)); - } - - void putStateMetadata(String channelId, String txId, String collection, String key, String metakey, ByteString value) { - if (!isTransaction(channelId, txId)) { - throw new IllegalStateException("Cannot put state metadata in query context"); - } - invokeChaincodeSupport(newPutStateMatadateEventMessage(channelId, txId, collection, key, metakey, value)); - } - - void deleteState(String channelId, String txId, String collection, String key) { - if (!isTransaction(channelId, txId)) throw new RuntimeException("Cannot del state in query context"); - invokeChaincodeSupport(newDeleteStateEventMessage(channelId, txId, collection, key)); - } - - QueryResponse getStateByRange(String channelId, String txId, String collection, String startKey, String endKey, ByteString metadata) { - GetStateByRange.Builder msgBuilder = GetStateByRange.newBuilder() - .setCollection(collection) - .setStartKey(startKey) - .setEndKey(endKey); - if (metadata != null) { - msgBuilder.setMetadata(metadata); - } - return invokeQueryResponseMessage(channelId, txId, GET_STATE_BY_RANGE, msgBuilder.build().toByteString()); - } - - QueryResponse queryStateNext(String channelId, String txId, String queryId) { - return invokeQueryResponseMessage(channelId, txId, QUERY_STATE_NEXT, QueryStateNext.newBuilder() - .setId(queryId) - .build().toByteString()); - } - - void queryStateClose(String channelId, String txId, String queryId) { - invokeQueryResponseMessage(channelId, txId, QUERY_STATE_CLOSE, QueryStateClose.newBuilder() - .setId(queryId) - .build().toByteString()); - } - - QueryResponse getQueryResult(String channelId, String txId, String collection, String query, ByteString metadata) { - GetQueryResult.Builder msgBuilder = GetQueryResult.newBuilder() - .setCollection(collection) - .setQuery(query); - if (metadata != null) { - msgBuilder.setMetadata(metadata); - } - return invokeQueryResponseMessage(channelId, txId, GET_QUERY_RESULT, msgBuilder.build().toByteString()); - } - - QueryResponse getHistoryForKey(String channelId, String txId, String key) { - return invokeQueryResponseMessage(channelId, txId, Type.GET_HISTORY_FOR_KEY, GetQueryResult.newBuilder() - .setQuery(key) - .build().toByteString()); - } - - private QueryResponse invokeQueryResponseMessage(String channelId, String txId, ChaincodeMessage.Type type, ByteString payload) { - try { - return QueryResponse.parseFrom(invokeChaincodeSupport(newEventMessage(type, channelId, txId, payload))); - } catch (InvalidProtocolBufferException e) { - logger.severe(String.format("[%-8.8s] unmarshall error", txId)); - throw new RuntimeException("Error unmarshalling QueryResponse.", e); - } - } - - private ByteString invokeChaincodeSupport(final ChaincodeMessage message) { - final String channelId = message.getChannelId(); - final String txId = message.getTxid(); - - try { - // create a new response channel - Channel responseChannel = aquireResponseChannelForTx(channelId, txId); - - // send the message - queueOutboundChaincodeMessage(message); - - // wait for response - final ChaincodeMessage response = receiveChannel(responseChannel); - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] %s response received.", txId, response.getType())); - } - - // handle response - switch (response.getType()) { - case RESPONSE: - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] Successful response received.", txId)); - } - return response.getPayload(); - case ERROR: - logger.severe(format("[%-8.8s] Unsuccessful response received.", txId)); - throw new RuntimeException(format("[%-8.8s]Unsuccessful response received.", txId)); - default: - logger.severe(format("[%-8.8s] Unexpected %s response received. Expected %s or %s.", txId, response.getType(), RESPONSE, ERROR)); - throw new RuntimeException(format("[%-8.8s]Unexpected %s response received. Expected %s or %s.", txId, response.getType(), RESPONSE, ERROR)); - } - } finally { - releaseResponseChannelForTx(channelId, txId); - } - } - - Chaincode.Response invokeChaincode(String channelId, String txId, String chaincodeName, List args) { - try { - // create invocation specification of the chaincode to invoke - final ChaincodeSpec invocationSpec = ChaincodeSpec.newBuilder() - .setChaincodeId(ChaincodeID.newBuilder() - .setName(chaincodeName) - .build()) - .setInput(ChaincodeInput.newBuilder() - .addAllArgs(args.stream().map(ByteString::copyFrom).collect(Collectors.toList())) - .build()) - .build(); - - // invoke other chaincode - final ByteString payload = invokeChaincodeSupport(newInvokeChaincodeMessage(channelId, txId, invocationSpec.toByteString())); - - // response message payload should be yet another chaincode - // message (the actual response message) - final ChaincodeMessage responseMessage = ChaincodeMessage.parseFrom(payload); - // the actual response message must be of type COMPLETED - if (logger.isLoggable(Level.FINE)) { - logger.fine(format("[%-8.8s] %s response received from other chaincode.", txId, responseMessage.getType())); - } - if (responseMessage.getType() == COMPLETED) { - // success - return toChaincodeResponse(Response.parseFrom(responseMessage.getPayload())); - } else { - // error - return newErrorChaincodeResponse(responseMessage.getPayload().toStringUtf8()); - } - } catch (InvalidProtocolBufferException e) { - throw new RuntimeException(e); - } - } - - private static String toJsonString(ChaincodeMessage message) { - try { - return JsonFormat.printer().print(message); - } catch (InvalidProtocolBufferException e) { - return String.format("{ Type: %s, TxId: %s }", message.getType(), message.getTxid()); - } - } - - private static Chaincode.Response newErrorChaincodeResponse(String message) { - return new Chaincode.Response(Chaincode.Response.Status.INTERNAL_SERVER_ERROR, message, null); - } - - private static ChaincodeMessage newGetStateEventMessage(final String channelId, final String txId, final String collection, final String key) { - return newEventMessage(GET_STATE, channelId, txId, GetState.newBuilder() - .setCollection(collection) - .setKey(key) - .build().toByteString()); - } - - private static ChaincodeMessage newGetStateMetadataEventMessage(final String channelId, final String txId, final String collection, final String key) { - return newEventMessage(GET_STATE_METADATA, channelId, txId, - GetStateMetadata.newBuilder() - .setCollection(collection) - .setKey(key) - .build().toByteString()); - } - - private static ChaincodeMessage newPutStateEventMessage(final String channelId, final String txId, final String collection, final String key, final ByteString value) { - return newEventMessage(PUT_STATE, channelId, txId, PutState.newBuilder() - .setCollection(collection) - .setKey(key) - .setValue(value) - .build().toByteString()); - } - - private static ChaincodeMessage newPutStateMatadateEventMessage(final String channelId, final String txId, final String collection, final String key, final String metakey, final ByteString value) { - return newEventMessage(PUT_STATE_METADATA, channelId, txId, - PutStateMetadata.newBuilder() - .setCollection(collection) - .setKey(key) - .setMetadata(StateMetadata.newBuilder() - .setMetakey(metakey) - .setValue(value) - .build()) - .build().toByteString()); - } - - private static ChaincodeMessage newDeleteStateEventMessage(final String channelId, final String txId, final String collection, final String key) { - return newEventMessage(DEL_STATE, channelId, txId, DelState.newBuilder() - .setCollection(collection) - .setKey(key) - .build().toByteString()); - } - - private static ChaincodeMessage newErrorEventMessage(final String channelId, final String txId, final Throwable throwable) { - return newErrorEventMessage(channelId, txId, printStackTrace(throwable)); - } - - private static ChaincodeMessage newErrorEventMessage(final String channelId, final String txId, final String message) { - return newErrorEventMessage(channelId, txId, message, null); - } - - private static ChaincodeMessage newErrorEventMessage(final String channelId, final String txId, final String message, final ChaincodeEvent event) { - return newEventMessage(ERROR, channelId, txId, ByteString.copyFromUtf8(message), event); - } - - private static ChaincodeMessage newCompletedEventMessage(final String channelId, final String txId, final Chaincode.Response response, final ChaincodeEvent event) { - ChaincodeMessage message = newEventMessage(COMPLETED, channelId, txId, toProtoResponse(response).toByteString(), event); - return message; - } - - private static ChaincodeMessage newInvokeChaincodeMessage(final String channelId, final String txId, final ByteString payload) { - return newEventMessage(INVOKE_CHAINCODE, channelId, txId, payload, null); - } - - private static ChaincodeMessage newRegisterChaincodeMessage(final ChaincodeID chaincodeId) { - return ChaincodeMessage.newBuilder() - .setType(REGISTER) - .setPayload(chaincodeId.toByteString()) - .build(); - } - - private static ChaincodeMessage newEventMessage(final Type type, final String channelId, final String txId, final ByteString payload) { - return newEventMessage(type, channelId, txId, payload, null); - } - - private static ChaincodeMessage newEventMessage(final Type type, final String channelId, final String txId, final ByteString payload, final ChaincodeEvent event) { - ChaincodeMessage.Builder builder = ChaincodeMessage.newBuilder() - .setType(type) - .setChannelId(channelId) - .setTxid(txId) - .setPayload(payload); - if (event != null) { - builder.setChaincodeEvent(event); - } - return builder.build(); - } - - private static Response toProtoResponse(Chaincode.Response response) { - final Builder builder = Response.newBuilder(); - builder.setStatus(response.getStatus().getCode()); - if (response.getMessage() != null) { - builder.setMessage(response.getMessage()); - } - if (response.getPayload() != null) { - builder.setPayload(ByteString.copyFrom(response.getPayload())); - } - return builder.build(); - } - - private static Chaincode.Response toChaincodeResponse(Response response) { - return new Chaincode.Response( - Chaincode.Response.Status.forCode(response.getStatus()), - response.getMessage(), - response.getPayload() == null ? null : response.getPayload().toByteArray() - ); - } - - private static String printStackTrace(Throwable throwable) { - if (throwable == null) return null; - final StringWriter buffer = new StringWriter(); - throwable.printStackTrace(new PrintWriter(buffer)); - return buffer.toString(); - } - - public enum CCState { - CREATED, - ESTABLISHED, - READY - } - - CCState getState() { - return this.state; - } - -} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeStubImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationStubImpl.java similarity index 52% rename from fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeStubImpl.java rename to fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationStubImpl.java index cb536a03..3e79d365 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeStubImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationStubImpl.java @@ -1,14 +1,31 @@ /* -Copyright IBM Corp., DTCC All Rights Reserved. +Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package org.hyperledger.fabric.shim.impl; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Timestamp; +import static java.util.stream.Collectors.toList; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.COMPLETED; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.GET_HISTORY_FOR_KEY; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.GET_PRIVATE_DATA_HASH; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.GET_QUERY_RESULT; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.GET_STATE_BY_RANGE; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.time.Instant; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.logging.Logger; +import java.util.stream.Collectors; + import org.hyperledger.fabric.protos.common.Common; import org.hyperledger.fabric.protos.common.Common.ChannelHeader; import org.hyperledger.fabric.protos.common.Common.Header; @@ -16,37 +33,44 @@ import org.hyperledger.fabric.protos.common.Common.SignatureHeader; import org.hyperledger.fabric.protos.ledger.queryresult.KvQueryResult; import org.hyperledger.fabric.protos.ledger.queryresult.KvQueryResult.KV; +import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeID; +import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeInput; +import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeSpec; import org.hyperledger.fabric.protos.peer.ChaincodeEventPackage.ChaincodeEvent; import org.hyperledger.fabric.protos.peer.ChaincodeShim; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.GetQueryResult; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.GetState; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.GetStateByRange; import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryResultBytes; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.StateMetadataResult; import org.hyperledger.fabric.protos.peer.ProposalPackage.ChaincodeProposalPayload; import org.hyperledger.fabric.protos.peer.ProposalPackage.Proposal; import org.hyperledger.fabric.protos.peer.ProposalPackage.SignedProposal; +import org.hyperledger.fabric.protos.peer.ProposalResponsePackage; import org.hyperledger.fabric.protos.peer.TransactionPackage; +import org.hyperledger.fabric.shim.Chaincode; import org.hyperledger.fabric.shim.Chaincode.Response; import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.shim.ledger.*; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.time.Instant; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; +import org.hyperledger.fabric.shim.ledger.CompositeKey; +import org.hyperledger.fabric.shim.ledger.KeyModification; +import org.hyperledger.fabric.shim.ledger.KeyValue; +import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; +import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata; -import static java.util.stream.Collectors.toList; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Timestamp; -class ChaincodeStubImpl implements ChaincodeStub { +class InnvocationStubImpl implements ChaincodeStub { private static final String UNSPECIFIED_KEY = new String(Character.toChars(0x000001)); + private static final Logger logger = Logger.getLogger(InnvocationStubImpl.class.getName()); + public static final String MAX_UNICODE_RUNE = "\udbff\udfff"; private final String channelId; private final String txId; - private final Handler handler; + private final ChaincodeInnvocationTask handler; private final List args; private final SignedProposal signedProposal; private final Instant txTimestamp; @@ -55,12 +79,15 @@ class ChaincodeStubImpl implements ChaincodeStub { private final byte[] binding; private ChaincodeEvent event; - ChaincodeStubImpl(String channelId, String txId, Handler handler, List args, SignedProposal signedProposal) { - this.channelId = channelId; - this.txId = txId; + public InnvocationStubImpl(ChaincodeMessage message, ChaincodeInnvocationTask handler) + throws InvalidProtocolBufferException { + this.channelId = message.getChannelId(); + this.txId = message.getTxid(); this.handler = handler; - this.args = Collections.unmodifiableList(args); - this.signedProposal = signedProposal; + final ChaincodeInput input = ChaincodeInput.parseFrom(message.getPayload()); + + this.args = Collections.unmodifiableList(input.getArgsList()); + this.signedProposal = message.getProposal(); if (this.signedProposal == null || this.signedProposal.getProposalBytes().isEmpty()) { this.creator = null; this.txTimestamp = null; @@ -73,7 +100,8 @@ class ChaincodeStubImpl implements ChaincodeStub { final ChannelHeader channelHeader = ChannelHeader.parseFrom(header.getChannelHeader()); validateProposalType(channelHeader); final SignatureHeader signatureHeader = SignatureHeader.parseFrom(header.getSignatureHeader()); - final ChaincodeProposalPayload chaincodeProposalPayload = ChaincodeProposalPayload.parseFrom(proposal.getPayload()); + final ChaincodeProposalPayload chaincodeProposalPayload = ChaincodeProposalPayload + .parseFrom(proposal.getPayload()); final Timestamp timestamp = channelHeader.getTimestamp(); this.txTimestamp = Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos()); @@ -86,12 +114,12 @@ class ChaincodeStubImpl implements ChaincodeStub { } } - private byte[] computeBinding(final ChannelHeader channelHeader, final SignatureHeader signatureHeader) throws NoSuchAlgorithmException { + private byte[] computeBinding(final ChannelHeader channelHeader, final SignatureHeader signatureHeader) + throws NoSuchAlgorithmException { final MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); messageDigest.update(signatureHeader.getNonce().asReadOnlyByteBuffer()); messageDigest.update(this.creator.asReadOnlyByteBuffer()); - final ByteBuffer epochBytes = ByteBuffer.allocate(Long.BYTES) - .order(ByteOrder.LITTLE_ENDIAN) + final ByteBuffer epochBytes = ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN) .putLong(channelHeader.getEpoch()); epochBytes.flip(); messageDigest.update(epochBytes); @@ -100,11 +128,12 @@ private byte[] computeBinding(final ChannelHeader channelHeader, final Signature private void validateProposalType(ChannelHeader channelHeader) { switch (Common.HeaderType.forNumber(channelHeader.getType())) { - case ENDORSER_TRANSACTION: - case CONFIG: - return; - default: - throw new RuntimeException(String.format("Unexpected transaction type: %s", HeaderType.forNumber(channelHeader.getType()))); + case ENDORSER_TRANSACTION: + case CONFIG: + return; + default: + throw new RuntimeException( + String.format("Unexpected transaction type: %s", HeaderType.forNumber(channelHeader.getType()))); } } @@ -134,14 +163,10 @@ public void setEvent(String name, byte[] payload) { throw new IllegalArgumentException("event name can not be nil string"); } if (payload != null) { - this.event = ChaincodeEvent.newBuilder() - .setEventName(name) - .setPayload(ByteString.copyFrom(payload)) + this.event = ChaincodeEvent.newBuilder().setEventName(name).setPayload(ByteString.copyFrom(payload)) .build(); } else { - this.event = ChaincodeEvent.newBuilder() - .setEventName(name) - .build(); + this.event = ChaincodeEvent.newBuilder().setEventName(name).build(); } } @@ -162,33 +187,53 @@ public String getTxId() { @Override public byte[] getState(String key) { - return handler.getState(channelId, txId, "", key).toByteArray(); + return this.handler.invoke(ChaincodeMessageFactory.newGetStateEventMessage(channelId, txId, "", key)) + .toByteArray(); } @Override public byte[] getStateValidationParameter(String key) { - Map metadata = handler.getStateMetadata(channelId, txId, "", key); - if (metadata.containsKey(TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString())) { - return metadata.get(TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString()).toByteArray(); + + ByteString payload = handler + .invoke(ChaincodeMessageFactory.newGetStateMetadataEventMessage(channelId, txId, "", key)); + try { + StateMetadataResult stateMetadataResult = StateMetadataResult.parseFrom(payload); + Map stateMetadataMap = new HashMap<>(); + stateMetadataResult.getEntriesList() + .forEach(entry -> stateMetadataMap.put(entry.getMetakey(), entry.getValue())); + + if (stateMetadataMap.containsKey(TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString())) { + return stateMetadataMap.get(TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString()) + .toByteArray(); + } + } catch (InvalidProtocolBufferException e) { + logger.severe(String.format("[%-8.8s] unmarshall error", txId)); + throw new RuntimeException("Error unmarshalling StateMetadataResult.", e); } + return null; + } @Override public void putState(String key, byte[] value) { validateKey(key); - handler.putState(channelId, txId, "", key, ByteString.copyFrom(value)); + this.handler.invoke( + ChaincodeMessageFactory.newPutStateEventMessage(channelId, txId, "", key, ByteString.copyFrom(value))); } @Override public void setStateValidationParameter(String key, byte[] value) { validateKey(key); - handler.putStateMetadata(channelId, txId, "", key, TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString(), ByteString.copyFrom(value)); + ChaincodeMessage msg = ChaincodeMessageFactory.newPutStateMatadateEventMessage(channelId, txId, "", key, + TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString(), ByteString.copyFrom(value)); + this.handler.invoke(msg); } @Override public void delState(String key) { - handler.deleteState(channelId, txId, "", key); + ChaincodeMessage msg = ChaincodeMessageFactory.newDeleteStateEventMessage(channelId, txId, "", key); + this.handler.invoke(msg); } @Override @@ -205,10 +250,17 @@ public QueryResultsIterator getStateByRange(String startKey, String en } private QueryResultsIterator executeGetStateByRange(String collection, String startKey, String endKey) { - return new QueryResultsIteratorImpl<>(this.handler, getChannelId(), getTxId(), - handler.getStateByRange(getChannelId(), getTxId(), collection, startKey, endKey, null), - queryResultBytesToKv.andThen(KeyValueImpl::new) - ); + + ByteString requestPayload = GetStateByRange.newBuilder().setCollection(collection).setStartKey(startKey) + .setEndKey(endKey).build().toByteString(); + + ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_STATE_BY_RANGE, channelId, txId, + requestPayload); + ByteString response = handler.invoke(requestMessage); + + return new QueryResultsIteratorImpl(this.handler, channelId, txId, response, + queryResultBytesToKv.andThen(KeyValueImpl::new)); + } private Function queryResultBytesToKv = new Function() { @@ -223,7 +275,8 @@ public KV apply(QueryResultBytes queryResultBytes) { }; @Override - public QueryResultsIteratorWithMetadata getStateByRangeWithPagination(String startKey, String endKey, int pageSize, String bookmark) { + public QueryResultsIteratorWithMetadata getStateByRangeWithPagination(String startKey, String endKey, + int pageSize, String bookmark) { if (startKey == null || startKey.isEmpty()) { startKey = UNSPECIFIED_KEY; } @@ -233,21 +286,27 @@ public QueryResultsIteratorWithMetadata getStateByRangeWithPagination( CompositeKey.validateSimpleKeys(startKey, endKey); - ChaincodeShim.QueryMetadata queryMetadata = ChaincodeShim.QueryMetadata.newBuilder() - .setBookmark(bookmark) - .setPageSize(pageSize) - .build(); + ChaincodeShim.QueryMetadata queryMetadata = ChaincodeShim.QueryMetadata.newBuilder().setBookmark(bookmark) + .setPageSize(pageSize).build(); return executeGetStateByRangeWithMetadata("", startKey, endKey, queryMetadata.toByteString()); } - private QueryResultsIteratorWithMetadataImpl executeGetStateByRangeWithMetadata(String collection, String startKey, String endKey, ByteString metadata) { - return new QueryResultsIteratorWithMetadataImpl<>(this.handler, getChannelId(), getTxId(), - handler.getStateByRange(getChannelId(), getTxId(), collection, startKey, endKey, metadata), - queryResultBytesToKv.andThen(KeyValueImpl::new) - ); - } + private QueryResultsIteratorWithMetadataImpl executeGetStateByRangeWithMetadata(String collection, + String startKey, String endKey, ByteString metadata) { + + ByteString payload = GetStateByRange.newBuilder().setCollection(collection).setStartKey(startKey) + .setEndKey(endKey).setMetadata(metadata).build().toByteString(); + + final ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_STATE_BY_RANGE, channelId, txId, + payload); + ByteString response = this.handler.invoke(requestMessage); + + return new QueryResultsIteratorWithMetadataImpl<>(this.handler, getChannelId(), getTxId(), response, + queryResultBytesToKv.andThen(KeyValueImpl::new)); + + } @Override public QueryResultsIterator getStateByPartialCompositeKey(String compositeKey) { @@ -280,19 +339,19 @@ public QueryResultsIterator getStateByPartialCompositeKey(CompositeKey } @Override - public QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination(CompositeKey compositeKey, int pageSize, String bookmark) { + public QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination( + CompositeKey compositeKey, int pageSize, String bookmark) { if (compositeKey == null) { compositeKey = new CompositeKey(UNSPECIFIED_KEY); } String cKeyAsString = compositeKey.toString(); - ChaincodeShim.QueryMetadata queryMetadata = ChaincodeShim.QueryMetadata.newBuilder() - .setBookmark(bookmark) - .setPageSize(pageSize) - .build(); + ChaincodeShim.QueryMetadata queryMetadata = ChaincodeShim.QueryMetadata.newBuilder().setBookmark(bookmark) + .setPageSize(pageSize).build(); - return executeGetStateByRangeWithMetadata("", cKeyAsString, cKeyAsString + MAX_UNICODE_RUNE, queryMetadata.toByteString()); + return executeGetStateByRangeWithMetadata("", cKeyAsString, cKeyAsString + MAX_UNICODE_RUNE, + queryMetadata.toByteString()); } @Override @@ -307,30 +366,45 @@ public CompositeKey splitCompositeKey(String compositeKey) { @Override public QueryResultsIterator getQueryResult(String query) { - return new QueryResultsIteratorImpl(this.handler, getChannelId(), getTxId(), - handler.getQueryResult(getChannelId(), getTxId(), "", query, null), - queryResultBytesToKv.andThen(KeyValueImpl::new) - ); + + ByteString requestPayload = GetQueryResult.newBuilder().setCollection("").setQuery(query).build() + .toByteString(); + ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, txId, + requestPayload); + ByteString response = handler.invoke(requestMessage); + + return new QueryResultsIteratorImpl(this.handler, channelId, txId, response, + queryResultBytesToKv.andThen(KeyValueImpl::new)); } @Override - public QueryResultsIteratorWithMetadata getQueryResultWithPagination(String query, int pageSize, String bookmark){ - ChaincodeShim.QueryMetadata queryMetadata = ChaincodeShim.QueryMetadata.newBuilder() - .setBookmark(bookmark) - .setPageSize(pageSize) - .build(); - return new QueryResultsIteratorWithMetadataImpl(this.handler, getChannelId(), getTxId(), - handler.getQueryResult(getChannelId(), getTxId(), "", query, queryMetadata.toByteString()), - queryResultBytesToKv.andThen(KeyValueImpl::new) - ); + public QueryResultsIteratorWithMetadata getQueryResultWithPagination(String query, int pageSize, + String bookmark) { + + ByteString queryMetadataPayload = ChaincodeShim.QueryMetadata.newBuilder().setBookmark(bookmark) + .setPageSize(pageSize).build().toByteString(); + ByteString requestPayload = GetQueryResult.newBuilder().setCollection("").setQuery(query) + .setMetadata(queryMetadataPayload).build().toByteString(); + ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, txId, + requestPayload); + ByteString response = handler.invoke(requestMessage); + + return new QueryResultsIteratorWithMetadataImpl(this.handler, channelId, txId, response, + queryResultBytesToKv.andThen(KeyValueImpl::new)); + } @Override public QueryResultsIterator getHistoryForKey(String key) { - return new QueryResultsIteratorImpl(this.handler, getChannelId(), getTxId(), - handler.getHistoryForKey(getChannelId(), getTxId(), key), - queryResultBytesToKeyModification.andThen(KeyModificationImpl::new) - ); + + ByteString requestPayload = GetQueryResult.newBuilder().setCollection("").setQuery(key).build().toByteString(); + ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_HISTORY_FOR_KEY, channelId, txId, + requestPayload); + ByteString response = handler.invoke(requestMessage); + + return new QueryResultsIteratorImpl(this.handler, channelId, txId, response, + queryResultBytesToKeyModification.andThen(KeyModificationImpl::new)); + } private Function queryResultBytesToKeyModification = new Function() { @@ -346,16 +420,43 @@ public KvQueryResult.KeyModification apply(QueryResultBytes queryResultBytes) { @Override public byte[] getPrivateData(String collection, String key) { validateCollection(collection); - return handler.getState(channelId, txId, collection, key).toByteArray(); + return this.handler.invoke(ChaincodeMessageFactory.newGetStateEventMessage(channelId, txId, collection, key)) + .toByteArray(); + } + + @Override + public byte[] getPrivateDataHash(String collection, String key) { + + validateCollection(collection); + + ByteString requestPayload = GetState.newBuilder().setCollection(collection).setKey(key).build().toByteString(); + ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_PRIVATE_DATA_HASH, channelId, + txId, requestPayload); + + return handler.invoke(requestMessage).toByteArray(); } @Override public byte[] getPrivateDataValidationParameter(String collection, String key) { validateCollection(collection); - Map metadata = handler.getStateMetadata(channelId, txId, collection, key); - if (metadata.containsKey(TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString())) { - return metadata.get(TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString()).toByteArray(); + + ByteString payload = handler + .invoke(ChaincodeMessageFactory.newGetStateMetadataEventMessage(channelId, txId, collection, key)); + try { + StateMetadataResult stateMetadataResult = StateMetadataResult.parseFrom(payload); + Map stateMetadataMap = new HashMap<>(); + stateMetadataResult.getEntriesList() + .forEach(entry -> stateMetadataMap.put(entry.getMetakey(), entry.getValue())); + + if (stateMetadataMap.containsKey(TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString())) { + return stateMetadataMap.get(TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString()) + .toByteArray(); + } + } catch (InvalidProtocolBufferException e) { + logger.severe(String.format("[%-8.8s] unmarshall error", txId)); + throw new RuntimeException("Error unmarshalling StateMetadataResult.", e); } + return null; } @@ -363,20 +464,24 @@ public byte[] getPrivateDataValidationParameter(String collection, String key) { public void putPrivateData(String collection, String key, byte[] value) { validateKey(key); validateCollection(collection); - handler.putState(channelId, txId, collection, key, ByteString.copyFrom(value)); + this.handler.invoke( + ChaincodeMessageFactory.newPutStateEventMessage(channelId, txId, collection, key, ByteString.copyFrom(value))); } @Override public void setPrivateDataValidationParameter(String collection, String key, byte[] value) { validateKey(key); validateCollection(collection); - handler.putStateMetadata(channelId, txId, collection, key, TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString(), ByteString.copyFrom(value)); + ChaincodeMessage msg = ChaincodeMessageFactory.newPutStateMatadateEventMessage(channelId, txId, collection, key, + TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString(), ByteString.copyFrom(value)); + this.handler.invoke(msg); } @Override public void delPrivateData(String collection, String key) { validateCollection(collection); - handler.deleteState(channelId, txId, collection, key); + ChaincodeMessage msg = ChaincodeMessageFactory.newDeleteStateEventMessage(channelId, txId, collection, key); + this.handler.invoke(msg); } @Override @@ -412,7 +517,8 @@ public QueryResultsIterator getPrivateDataByPartialCompositeKey(String } @Override - public QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, CompositeKey compositeKey) { + public QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, + CompositeKey compositeKey) { if (compositeKey == null) { compositeKey = new CompositeKey(UNSPECIFIED_KEY); @@ -424,19 +530,23 @@ public QueryResultsIterator getPrivateDataByPartialCompositeKey(String } @Override - public QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, String objectType, String... attributes) { + public QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, String objectType, + String... attributes) { return getPrivateDataByPartialCompositeKey(collection, new CompositeKey(objectType, attributes)); } @Override public QueryResultsIterator getPrivateDataQueryResult(String collection, String query) { validateCollection(collection); - return new QueryResultsIteratorImpl(this.handler, getChannelId(), getTxId(), - handler.getQueryResult(getChannelId(), getTxId(), collection, query, null), - queryResultBytesToKv.andThen(KeyValueImpl::new) - ); - } + ByteString requestPayload = GetQueryResult.newBuilder().setCollection(collection).setQuery(query).build() + .toByteString(); + ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, txId, + requestPayload); + ByteString response = handler.invoke(requestMessage); + return new QueryResultsIteratorImpl(this.handler, channelId, txId, response, + queryResultBytesToKv.andThen(KeyValueImpl::new)); + } @Override public Response invokeChaincode(final String chaincodeName, final List args, final String channel) { @@ -447,7 +557,42 @@ public Response invokeChaincode(final String chaincodeName, final List a } else { compositeName = chaincodeName; } - return handler.invokeChaincode(this.channelId, this.txId, compositeName, args); + + // create invocation specification of the chaincode to invoke + final ByteString invocationSpecPayload = ChaincodeSpec.newBuilder() + .setChaincodeId(ChaincodeID.newBuilder().setName(compositeName).build()) + .setInput(ChaincodeInput.newBuilder() + .addAllArgs(args.stream().map(ByteString::copyFrom).collect(Collectors.toList())).build()) + .build().toByteString(); + + ChaincodeMessage invokeChaincodeMessage = ChaincodeMessageFactory.newInvokeChaincodeMessage(this.channelId, + this.txId, invocationSpecPayload); + ByteString response = this.handler.invoke(invokeChaincodeMessage); + + try { + // response message payload should be yet another chaincode + // message (the actual response message) + final ChaincodeMessage responseMessage = ChaincodeMessage.parseFrom(response); + // the actual response message must be of type COMPLETED + + logger.fine(String.format("[%-8.8s] %s response received from other chaincode.", txId, + responseMessage.getType())); + + if (responseMessage.getType() == COMPLETED) { + // success + ProposalResponsePackage.Response r = ProposalResponsePackage.Response + .parseFrom(responseMessage.getPayload()); + return new Chaincode.Response(Chaincode.Response.Status.forCode(r.getStatus()), r.getMessage(), + r.getPayload() == null ? null : r.getPayload().toByteArray()); + } else { + // error + String message = responseMessage.getPayload().toStringUtf8(); + return new Chaincode.Response(Chaincode.Response.Status.INTERNAL_SERVER_ERROR, message, null); + } + } catch (InvalidProtocolBufferException e) { + throw new RuntimeException(e); + } + } @Override @@ -462,13 +607,15 @@ public Instant getTxTimestamp() { @Override public byte[] getCreator() { - if (creator == null) return null; + if (creator == null) + return null; return creator.toByteArray(); } @Override public Map getTransient() { - return transientMap.entrySet().stream().collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue().toByteArray())); + return transientMap.entrySet().stream() + .collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue().toByteArray())); } @Override diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationTaskExecutor.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationTaskExecutor.java new file mode 100644 index 00000000..fd71c88c --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationTaskExecutor.java @@ -0,0 +1,51 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.shim.impl; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Logger; + +import org.hyperledger.fabric.metrics.TaskMetricsCollector; + +public class InnvocationTaskExecutor extends ThreadPoolExecutor implements TaskMetricsCollector { + private static Logger logger = Logger.getLogger(InnvocationTaskExecutor.class.getName()); + + public InnvocationTaskExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, + BlockingQueue workQueue, ThreadFactory factory, RejectedExecutionHandler handler) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, factory, handler); + prestartCoreThread(); + logger.info("Thread pool created"); + } + + AtomicInteger count = new AtomicInteger(); + + @Override + protected void beforeExecute(Thread thread, Runnable task) { + super.beforeExecute(thread, task); + count.incrementAndGet(); + + } + + @Override + protected void afterExecute(Runnable task, Throwable throwable) { + count.decrementAndGet(); + super.afterExecute(task, throwable); + } + + public int getCurrentTaskCount() { + return count.get(); + } + + public int getCurrentQueueCount() { + return this.getQueue().size(); + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManager.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManager.java new file mode 100644 index 00000000..a5cb09e6 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManager.java @@ -0,0 +1,304 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.shim.impl; + +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.READY; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.REGISTERED; + +import java.util.Properties; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.logging.Logger; + +import org.hyperledger.fabric.Logging; +import org.hyperledger.fabric.metrics.Metrics; +import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeID; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type; +import org.hyperledger.fabric.shim.ChaincodeBase; + +/** + * The InnvocationTask Manager handles the message level communication with the peer. + * + * In the current 1.4 Fabric Protocol this is in practice a singleton - because + * the peer will ignore multiple 'register' calls. And an instance of this will + * be created per register call for a given chaincodeID. + * + */ +public class InnvocationTaskManager { + + private static Logger logger = Logger.getLogger(InnvocationTaskManager.class.getName()); + private static Logger perflogger = Logger.getLogger(Logging.PERFLOGGER); + + /** + * Get an instance of the Invocation Task Manager + * + * @param chaincode Chaincode Instance + * @param chaincodeId ID of the chaincode + * @return InvocationTaskManager + */ + public static InnvocationTaskManager getManager(ChaincodeBase chaincode, ChaincodeID chaincodeId) { + return new InnvocationTaskManager(chaincode, chaincodeId); + } + + // Keeping a map here of the tasks that are currently ongoing, and the key + // + // Key = txid + channleid + // One task = one transaction invocation + private ConcurrentHashMap innvocationTasks = new ConcurrentHashMap<>(); + + // Way to send back the events and data that make up the requests + private Consumer outgoingMessage; + + // references to the chaincode, and the chaincode id + private ChaincodeBase chaincode; + private ChaincodeID chaincodeId; + + // Thread Pool creation and settings + private int queueSize; + private int maximumPoolSize; + private int corePoolSize; + private long keepAliveTime; + private TimeUnit unit = TimeUnit.MILLISECONDS; + private BlockingQueue workQueue; + ThreadFactory threadFactory = Executors.defaultThreadFactory(); + RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); + + InnvocationTaskExecutor taskService; + + /** + * New InvocationTaskManager + * + * @param chaincode Chaincode Instance + * @param chaincodeId ID of the chaincode + */ + public InnvocationTaskManager(ChaincodeBase chaincode, ChaincodeID chaincodeId) { + this.chaincode = chaincode; + this.chaincodeId = chaincodeId; + + // setup the thread pool here + Properties props = chaincode.getChaincodeConfig(); + queueSize = Integer.parseInt((String) props.getOrDefault("TP_QUEUE_SIZE", "5000")); + maximumPoolSize = Integer.parseInt((String) props.getOrDefault("TP_MAX_POOL_SIZE", "5")); + corePoolSize = Integer.parseInt((String) props.getOrDefault("TP_CORE_POOL_SIZE", "5")); + keepAliveTime = Long.parseLong((String) props.getOrDefault("TP_KEEP_ALIVE_MS", "5000")); + + logger.info(() -> "Max Pool Size [TP_MAX_POOL_SIZE]" + maximumPoolSize); + logger.info(() -> "Queue Size [TP_CORE_POOL_SIZE]" + queueSize); + logger.info(() -> "Core Pool Size [TP_QUEUE_SIZE]" + corePoolSize); + logger.info(() -> "Keep Alive Time [TP_KEEP_ALIVE_MS]" + keepAliveTime); + + workQueue = new LinkedBlockingQueue(queueSize); + taskService = new InnvocationTaskExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + threadFactory, handler); + + Metrics.getProvider().setTaskMetricsCollector(taskService); + + } + + /** + * Called when a new message has arrived that needs to be processed; + * + * @param chaincodeMessage ChaincodeMessage + */ + public void onChaincodeMessage(ChaincodeMessage chaincodeMessage) { + logger.fine(() -> String.format("[%-8.8s] %s", chaincodeMessage.getTxid(), + ChaincodeBase.toJsonString(chaincodeMessage))); + + try { + Type msgType = chaincodeMessage.getType(); + switch (chaincode.getState()) { + case CREATED: + if (msgType == REGISTERED){ + chaincode.setState(org.hyperledger.fabric.shim.ChaincodeBase.CCState.ESTABLISHED); + logger.fine(() -> String.format("[%-8.8s] Received REGISTERED: moving to established state", + chaincodeMessage.getTxid())); + } else { + logger.warning( + () -> String.format("[%-8.8s] Received %s: cannot handle", chaincodeMessage.getTxid(), msgType)); + } + break; + case ESTABLISHED: + if (msgType == READY) { + chaincode.setState(org.hyperledger.fabric.shim.ChaincodeBase.CCState.READY); + logger.fine(() -> String.format("[%-8.8s] Received READY: ready for invocations", chaincodeMessage.getTxid())); + } else { + logger.warning( + () -> String.format("[%-8.8s] Received %s: cannot handle", chaincodeMessage.getTxid(), msgType)); + } + break; + case READY: + handleMsg(chaincodeMessage,msgType); + break; + default: + logger.warning(() -> String.format("[%-8.8s] Received %s: cannot handle", chaincodeMessage.getTxid(), + chaincodeMessage.getType())); + break; + } + } catch (RuntimeException e) { + // catch any issues with say the comms dropping or something else completely unknown + // and shutdown the pool + this.shutdown(); + throw e; + } + } + + + /** + * Key method to take the message, determine if it is a new transaction or an answer (good or bad) to a + * stub api. + * + * @param message + */ + private void handleMsg(ChaincodeMessage message,Type msgType) { + logger.fine(() -> String.format("[%-8.8s] Received %s", message.getTxid(), msgType.toString())); + switch (msgType) { + case RESPONSE: + case ERROR: + sendToTask(message); + break; + case INIT: + case TRANSACTION: + newTask(message, msgType); + break; + default: + logger.warning( + () -> String.format("[%-8.8s] Received %s: cannot handle", message.getTxid(), message.getType())); + break; + } + } + + /** + * Send a message from the peer to the correct task. This will be a response to + * something like a getState() call. + * + * @param message ChaincodeMessage from the peer + */ + private void sendToTask(ChaincodeMessage message) { + try { + perflogger.fine(() -> "> sendToTask " + message.getTxid()); + + String key = message.getChannelId() + message.getTxid(); + ChaincodeInnvocationTask task = this.innvocationTasks.get(key); + task.postMessage(message); + + perflogger.fine(() -> "< sendToTask " + message.getTxid()); + } catch (InterruptedException e) { + logger.severe( + () -> "Failed to send response to the task task " + message.getTxid() + Logging.formatError(e)); + + ChaincodeMessage m = ChaincodeMessageFactory.newErrorEventMessage(message.getChannelId(), message.getTxid(), + "Failed to send response to task"); + this.outgoingMessage.accept(m); + } + } + + /** + * Create a new task to handle this transaction function. + * + * @param message ChaincodeMessage to process + * @param type Type of message = INIT or INVOKE. INIT is deprecated in future + * versions + * @throws InterruptedException + */ + private void newTask(ChaincodeMessage message, Type type) { + ChaincodeInnvocationTask task = new ChaincodeInnvocationTask(message, type, this.outgoingMessage, + this.chaincode); + + perflogger.fine(() -> "> newTask:created " + message.getTxid()); + + this.innvocationTasks.put(task.getTxKey(), task); + try { + perflogger.fine(() -> "> newTask:submitting " + message.getTxid()); + + // submit the task to run, with the taskService providing the + // threading support. + CompletableFuture response = CompletableFuture.runAsync(()->{ + task.call(); + },taskService); + + // we have a future of the chaincode message that should be returned. + // but waiting for this does not need to block this thread + // it is important to wait for it however, as we need to remove it from the task list + response.thenRun(() -> { + innvocationTasks.remove(task.getTxKey()); + perflogger.fine(() -> "< newTask:completed " + message.getTxid()); + }); + + perflogger.fine(() -> "< newTask:submitted " + message.getTxid()); + + } catch (RejectedExecutionException e) { + logger.warning(() -> "Failed to submit task " + message.getTxid() + Logging.formatError(e)); + // this means that there is no way that this can be handed off to another + // thread for processing, and there's no space left in the queue to hold + // it pending + + ChaincodeMessage m = ChaincodeMessageFactory.newErrorEventMessage(message.getChannelId(), message.getTxid(), + "Failed to submit task for processing"); + this.outgoingMessage.accept(m); + } + + } + + /** + * Set the Consumer function to be used for sending messages back to the peer + * + * @param outgoingMessage + * @return + */ + public InnvocationTaskManager setResponseConsumer(Consumer outgoingMessage) { + this.outgoingMessage = outgoingMessage; + + return this; + } + + /** + * Send the initial protocol message for the 'register' phase + * + * @return + */ + public InnvocationTaskManager register() { + + logger.info(() -> "Registering new chaincode " + this.chaincodeId); + chaincode.setState(ChaincodeBase.CCState.CREATED); + this.outgoingMessage.accept(ChaincodeMessageFactory.newRegisterChaincodeMessage(this.chaincodeId)); + + return this; + } + + public void shutdown() { + // Recommended shutdown process from + // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html + // Disable new tasks from being submitted + this.taskService.shutdown(); + try { + // Wait a while for existing tasks to terminate + if (!taskService.awaitTermination(60, TimeUnit.SECONDS)) { + // Cancel currently executing tasks + taskService.shutdownNow(); + // Wait a while for tasks to respond to being cancelled + if (!taskService.awaitTermination(60, TimeUnit.SECONDS)) { + System.err.println("Pool did not terminate"); + } + } + } catch (InterruptedException ex) { + // (Re-)Cancel if current thread also interrupted + taskService.shutdownNow(); + // Preserve interrupt status + Thread.currentThread().interrupt(); + } + } + +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java index b8a52896..a75de31f 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java @@ -6,68 +6,114 @@ package org.hyperledger.fabric.shim.impl; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryResponse; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryResultBytes; -import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.QUERY_STATE_CLOSE; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.QUERY_STATE_NEXT; import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.function.Function; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryResponse; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryResultBytes; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryStateClose; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryStateNext; +import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; + +/** + * This class provides an ITERABLE object of query results; NOTE the class name + * is misleading - as this class is not an iterator itself, rather it implements + * java.lang.Iterable via the QueryResultsIterator + * + * public interface QueryResultsIterator extends Iterable, AutoCloseable + * + * @param + */ class QueryResultsIteratorImpl implements QueryResultsIterator { - private final Handler handler; - private final String channelId; - private final String txId; - private Iterator currentIterator; - private QueryResponse currentQueryResponse; - private Function mapper; - - public QueryResultsIteratorImpl(final Handler handler, final String channelId, final String txId, final QueryResponse queryResponse, Function mapper) { - this.handler = handler; - this.channelId = channelId; - this.txId = txId; - this.currentQueryResponse = queryResponse; - this.currentIterator = currentQueryResponse.getResultsList().iterator(); - this.mapper = mapper; - } - - @Override - public Iterator iterator() { - return new Iterator() { - - @Override - public boolean hasNext() { - return currentIterator.hasNext() || currentQueryResponse.getHasMore(); - } - - @Override - public T next() { - - // return next fetched result, if any - if (currentIterator.hasNext()) return mapper.apply(currentIterator.next()); - - // throw exception if there are no more expected results - if (!currentQueryResponse.getHasMore()) throw new NoSuchElementException(); - - // get more results from peer - currentQueryResponse = handler.queryStateNext(channelId, txId, currentQueryResponse.getId()); - currentIterator = currentQueryResponse.getResultsList().iterator(); - - // return next fetched result - return mapper.apply(currentIterator.next()); - - } - - }; - } - - @Override - public void close() throws Exception { - this.handler.queryStateClose(channelId, txId, currentQueryResponse.getId()); - this.currentIterator = Collections.emptyIterator(); - this.currentQueryResponse = QueryResponse.newBuilder().setHasMore(false).build(); - } + private final ChaincodeInnvocationTask handler; + private final String channelId; + private final String txId; + private Iterator currentIterator; + private QueryResponse currentQueryResponse; + private Function mapper; + + public QueryResultsIteratorImpl(final ChaincodeInnvocationTask handler, + final String channelId, final String txId, final ByteString responseBuffer, + Function mapper) { + + try { + this.handler = handler; + this.channelId = channelId; + this.txId = txId; + this.currentQueryResponse = QueryResponse.parseFrom(responseBuffer); + this.currentIterator = currentQueryResponse.getResultsList().iterator(); + this.mapper = mapper; + } catch (InvalidProtocolBufferException e) { + throw new RuntimeException(e); + } + } + + + + @Override + public Iterator iterator() { + return new Iterator() { + + @Override + public boolean hasNext() { + return currentIterator.hasNext() || currentQueryResponse.getHasMore(); + } + + @Override + public T next() { + + // return next fetched result, if any + if (currentIterator.hasNext()) + return mapper.apply(currentIterator.next()); + + // throw exception if there are no more expected results + if (!currentQueryResponse.getHasMore()) + throw new NoSuchElementException(); + + // get more results from peer + + ByteString requestPayload = QueryStateNext.newBuilder().setId(currentQueryResponse.getId()).build() + .toByteString(); + ChaincodeMessage requestNextMessage = ChaincodeMessageFactory.newEventMessage(QUERY_STATE_NEXT, channelId, txId, requestPayload); + + ByteString responseMessage = QueryResultsIteratorImpl.this.handler.invoke(requestNextMessage); + try { + currentQueryResponse = QueryResponse.parseFrom(responseMessage); + } catch (InvalidProtocolBufferException e) { + throw new RuntimeException(e); + } + currentIterator = currentQueryResponse.getResultsList().iterator(); + + // return next fetched result + return mapper.apply(currentIterator.next()); + + } + + }; + } + + @Override + public void close() throws Exception { + + ByteString requestPayload = QueryStateClose.newBuilder() + .setId(currentQueryResponse.getId()) + .build().toByteString(); + + ChaincodeMessage requestNextMessage = ChaincodeMessageFactory.newEventMessage(QUERY_STATE_CLOSE, channelId, txId, requestPayload); + this.handler.invoke(requestNextMessage); + + this.currentIterator = Collections.emptyIterator(); + this.currentQueryResponse = QueryResponse.newBuilder().setHasMore(false).build(); + } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImpl.java index b1be0d07..77a7a4ac 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImpl.java @@ -6,12 +6,16 @@ package org.hyperledger.fabric.shim.impl; -import com.google.protobuf.InvalidProtocolBufferException; +import java.util.function.Function; +import java.util.logging.Logger; + import org.hyperledger.fabric.protos.peer.ChaincodeShim; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryResponse; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryResultBytes; import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata; -import java.util.function.Function; -import java.util.logging.Logger; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; /** * Implementation of {@link QueryResultsIteratorWithMetadata}, by extending {@link org.hyperledger.fabric.shim.ledger.QueryResultsIterator} implementations, {@link QueryResultsIteratorImpl} @@ -23,9 +27,12 @@ public class QueryResultsIteratorWithMetadataImpl extends QueryResultsIterato ChaincodeShim.QueryResponseMetadata metadata; - public QueryResultsIteratorWithMetadataImpl(Handler handler, String channelId, String txId, ChaincodeShim.QueryResponse queryResponse, Function mapper) { - super(handler, channelId, txId, queryResponse, mapper); + public QueryResultsIteratorWithMetadataImpl(final ChaincodeInnvocationTask handler, + final String channelId, final String txId, final ByteString responseBuffer, + Function mapper) { + super(handler,channelId,txId,responseBuffer,mapper); try { + QueryResponse queryResponse = QueryResponse.parseFrom(responseBuffer); metadata = ChaincodeShim.QueryResponseMetadata.parseFrom(queryResponse.getMetadata()); } catch (InvalidProtocolBufferException e) { logger.warning("can't parse response metadata"); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/package-info.java new file mode 100644 index 00000000..83574450 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/package-info.java @@ -0,0 +1,16 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +/** + *

+ * This is the pacakge the supports the chaincode style of development. + *

+ * The main interface to implement is {@link org.hyperledger.fabric.shim#ChaincodeBase} + * + * @see Developing Fabric Applications + * + */ +package org.hyperledger.fabric.shim; diff --git a/fabric-chaincode-shim/src/main/resources/contract-schema.json b/fabric-chaincode-shim/src/main/resources/contract-schema.json new file mode 100644 index 00000000..524312fd --- /dev/null +++ b/fabric-chaincode-shim/src/main/resources/contract-schema.json @@ -0,0 +1,352 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "title": "Hyperledger Fabric Contract Definition JSON Schema", + "required": [ + "info", + "contracts" + ], + "properties": { + "info": { + "$ref": "#/definitions/info" + }, + "contracts": { + "type": "object", + "patternProperties": { + "^.*$": { + "$ref": "#/definitions/contract" + } + } + }, + "components": { + "$ref": "#/definitions/components" + } + }, + "definitions": { + "info": { + "type": "object", + "description": "General information about the API.", + "required": [ + "version", + "title" + ], + "properties": { + "title": { + "type": "string", + "description": "A unique and precise title of the API." + }, + "version": { + "type": "string", + "description": "A semantic version number of the API." + }, + "description": { + "type": "string", + "description": "A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed." + }, + "termsOfService": { + "type": "string", + "description": "The terms of service for the API." + }, + "contact": { + "$ref": "#/definitions/contact" + }, + "license": { + "$ref": "#/definitions/license" + } + } + }, + "contact": { + "type": "object", + "description": "Contact information for the owners of the API.", + "properties": { + "name": { + "type": "string", + "description": "The identifying name of the contact person/organization." + }, + "url": { + "type": "string", + "description": "The URL pointing to the contact information.", + "format": "uri" + }, + "email": { + "type": "string", + "description": "The email address of the contact person/organization.", + "format": "email" + } + } + }, + "license": { + "type": "object", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The name of the license type. It's encouraged to use an OSI compatible license." + }, + "url": { + "type": "string", + "description": "The URL pointing to the license.", + "format": "uri" + } + } + }, + "contract": { + "type": "object", + "description": "", + "required": [ + "name", + "transactions" + ], + "properties": { + "info": { + "$ref": "#/definitions/info" + }, + "name": { + "type": "string", + "description": "A unique and precise title of the API." + }, + "transactions": { + "type": "array", + "items": { + "$ref": "#/definitions/transaction" + } + } + } + }, + "objecttype": { + "type": "object", + "description": "A complex type used in a domain", + "required": [ + "$id", + "properties" + ], + "properties": { + "$id": { + "type": "string" + }, + "properties": { + "^.*$": { + "$ref": "#/definitions/schema" + } + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + } + } + }, + "parametersList": { + "type": "array", + "description": "The parameters needed to send a valid API call.", + "additionalItems": false, + "items": { + "oneOf": [ + { + "$ref": "#/definitions/parameter" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "uniqueItems": true + }, + "transaction": { + "type": "object", + "description": "single transaction specification", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "name of the transaction " + }, + "tag": { + "type": "array", + "items": { + "type": "string", + "description": "free format tags" + } + }, + "parameters": { + "$ref": "#/definitions/parametersList" + }, + "returns": { + "$ref": "#/definitions/schema" + } + } + }, + "parameter": { + "type": "object", + "required": [ + "name", + "schema" + ], + "properties": { + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "schema": { + "$ref": "#/definitions/schema" + } + }, + "additionalProperties": false + }, + "jsonReference": { + "type": "object", + "required": [ + "$ref" + ], + "additionalProperties": false, + "properties": { + "$ref": { + "type": "string" + } + } + }, + "schema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "properties": { + "$ref": { + "type": "string" + }, + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "maxProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "additionalProperties": { + "anyOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "boolean" + } + ], + "default": {} + }, + "type": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/type" + }, + "items": { + "anyOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + } + ], + "default": {} + }, + "allOf": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "default": {} + }, + "discriminator": { + "type": "string" + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "example": {} + }, + "additionalProperties": false + }, + "components": { + "type": "object", + "properties": { + "schemas": { + "type": "object", + "patternProperties": { + "^.*$": { + "$ref": "#/definitions/objecttype" + } + } + } + } + } + } +} diff --git a/fabric-chaincode-shim/src/main/resources/json-schema-draft-04-schema.json b/fabric-chaincode-shim/src/main/resources/json-schema-draft-04-schema.json new file mode 100644 index 00000000..bcbb8474 --- /dev/null +++ b/fabric-chaincode-shim/src/main/resources/json-schema-draft-04-schema.json @@ -0,0 +1,149 @@ +{ + "id": "http://json-schema.org/draft-04/schema#", + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "positiveInteger": { + "type": "integer", + "minimum": 0 + }, + "positiveIntegerDefault0": { + "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] + }, + "simpleTypes": { + "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "uniqueItems": true + } + }, + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "$schema": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": {}, + "multipleOf": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "boolean", + "default": false + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "boolean", + "default": false + }, + "maxLength": { "$ref": "#/definitions/positiveInteger" }, + "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": {} + }, + "maxItems": { "$ref": "#/definitions/positiveInteger" }, + "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxProperties": { "$ref": "#/definitions/positiveInteger" }, + "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "enum": { + "type": "array", + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { "type": "string" }, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "dependencies": { + "exclusiveMaximum": [ "maximum" ], + "exclusiveMinimum": [ "minimum" ] + }, + "default": {} +} diff --git a/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java b/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java index 1dafcc2d..cee725b5 100644 --- a/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java +++ b/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java @@ -4,8 +4,16 @@ SPDX-License-Identifier: Apache-2.0 */ +import static org.hamcrest.Matchers.is; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.READY; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.REGISTER; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + import org.hyperledger.fabric.shim.ChaincodeBase; -import org.hyperledger.fabric.shim.fvt.ChaincodeFVTest; import org.hyperledger.fabric.shim.mock.peer.ChaincodeMockPeer; import org.hyperledger.fabric.shim.mock.peer.RegisterStep; import org.hyperledger.fabric.shim.mock.peer.ScenarioStep; @@ -14,15 +22,6 @@ import org.junit.Test; import org.junit.contrib.java.lang.system.EnvironmentVariables; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import static org.hamcrest.Matchers.is; -import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.READY; -import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.REGISTER; -import static org.junit.Assert.assertThat; - public class ChaincodeWithoutPackageTest { @Rule public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @@ -48,7 +47,7 @@ public void testRegisterChaincodeWithoutPackage() throws Exception { cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"}); - ChaincodeFVTest.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(READY)); assertThat(server.getLastMessageRcvd().getType(), is(REGISTER)); diff --git a/fabric-chaincode-shim/src/test/java/EmptyChaincodeWithoutPackage.java b/fabric-chaincode-shim/src/test/java/EmptyChaincodeWithoutPackage.java index 065e0c14..db0de440 100644 --- a/fabric-chaincode-shim/src/test/java/EmptyChaincodeWithoutPackage.java +++ b/fabric-chaincode-shim/src/test/java/EmptyChaincodeWithoutPackage.java @@ -6,15 +6,16 @@ import org.hyperledger.fabric.shim.ChaincodeBase; import org.hyperledger.fabric.shim.ChaincodeStub; +import org.hyperledger.fabric.shim.ResponseUtils; public class EmptyChaincodeWithoutPackage extends ChaincodeBase { @Override public Response init(ChaincodeStub stub) { - return newSuccessResponse(); + return ResponseUtils.newSuccessResponse(); } @Override public Response invoke(ChaincodeStub stub) { - return newSuccessResponse(); + return ResponseUtils.newSuccessResponse(); } } diff --git a/fabric-chaincode-shim/src/test/java/contract/Greeting.java b/fabric-chaincode-shim/src/test/java/contract/Greeting.java new file mode 100644 index 00000000..d4e4d088 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/contract/Greeting.java @@ -0,0 +1,70 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package contract; + +import org.hyperledger.fabric.contract.annotation.DataType; +import org.hyperledger.fabric.contract.annotation.Property; +import org.json.JSONObject; + +@DataType() +public class Greeting { + + @Property() + private String text; + + @Property() + private int textLength; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public int getTextLength() { + return textLength; + } + + public void setTextLength(int textLength) { + this.textLength = textLength; + } + + public int getWordCount() { + return wordCount; + } + + public void setWordCount(int wordCount) { + this.wordCount = wordCount; + } + + private int wordCount; + + public Greeting(String text) { + this.text = text; + this.textLength = text.length(); + this.wordCount = text.split(" ").length; + } + + public static void validate(Greeting greeting) { + String text = greeting.text; + + if (text.length() != greeting.textLength) { + throw new Error("Length incorrectly set"); + } + + if (text.split(" ").length != greeting.wordCount) { + throw new Error("Word count incorrectly set"); + } + + } + + public String toJSONString() { + return new JSONObject(this).toString(); + } + +} diff --git a/fabric-chaincode-shim/src/test/java/contract/SampleContract.java b/fabric-chaincode-shim/src/test/java/contract/SampleContract.java new file mode 100644 index 00000000..084fed8c --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/contract/SampleContract.java @@ -0,0 +1,104 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package contract; + +import java.util.List; + +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.annotation.Contact; +import org.hyperledger.fabric.contract.annotation.Contract; +import org.hyperledger.fabric.contract.annotation.Default; +import org.hyperledger.fabric.contract.annotation.Info; +import org.hyperledger.fabric.contract.annotation.License; +import org.hyperledger.fabric.contract.annotation.Transaction; +import org.hyperledger.fabric.shim.ChaincodeException; + +@Contract( + name = "samplecontract", + info = @Info( + contact = @Contact( + email = "fred@example.com" + ), + license = @License( + name = "fred", + url = "http://fred.me" + ), + version = "0.0.1", + title = "samplecontract" + ) +) +@Default() +public class SampleContract implements ContractInterface { + static public int beforeInvoked = 0; + static public int afterInvoked = 0; + static public int doWorkInvoked = 0; + static public int t1Invoked = 0; + static public int i1Invoked = 0; + + @Transaction + public String t5(Context ctx) { + doSomeWork(); + System.out.println("SampleContract::T5 Done"); + return null; + } + + @Transaction(name = "t4") + public String tFour(Context ctx) { + + System.out.println("SampleContract::T4 Done"); + return "Transaction 4"; + } + + @Transaction + public String t3(Context ctx, String exception, String message) { + if ("TransactionException".equals(exception)) { + if (message.isEmpty()) { + throw new ChaincodeException(null, "T3ERR1"); + } else { + throw new ChaincodeException(message, "T3ERR1"); + } + } else { + throw new RuntimeException(message); + } + } + + @Transaction + public String t2(Context ctx) { + + System.out.println("SampleContract::T2 Done"); + return "Transaction 2"; + } + + @Transaction + public void noReturn(Context ctx) { + System.out.println("SampleContract::noReturn done"); + } + + @Transaction + public String t1(Context ctx, String arg1) { + t1Invoked++; + + List args = ctx.getStub().getStringArgs(); + doSomeWork(); + System.out.println("SampleContract::T1 Done"); + return args.get(1); + } + + @Override + public void beforeTransaction(Context ctx) { + beforeInvoked++; + } + + @Override + public void afterTransaction(Context ctx, Object value) { + afterInvoked++; + } + + private void doSomeWork() { + doWorkInvoked++; + } +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java new file mode 100644 index 00000000..a978456a --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java @@ -0,0 +1,51 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Level; +import java.util.logging.LogManager; + +import org.hamcrest.CoreMatchers; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; + +public class LoggerTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + + @Test + public void testFormatError() { + Exception e1 = new Exception("Computer says no"); + Logger l = Logger.getLogger("acme.wibble"); + assertThat(l.formatError(e1), containsString("Computer says no")); + + NullPointerException npe1 = new NullPointerException("Nothing here"); + npe1.initCause(e1); + + assertThat(l.formatError(npe1), containsString("Computer says no")); + assertThat(l.formatError(npe1), containsString("Nothing here")); + + assertThat(l.formatError(null), CoreMatchers.nullValue()); + } + + @Test + public void testGetLogger() { + Logger l = Logger.getLogger(this.getClass()); + l.error("It'll be fine"); + l.error(()-> "It'll be fine, honest"); + l.debug("Well maybe"); + l.debug(()->"Well no."); + } + +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java new file mode 100644 index 00000000..65d675db --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java @@ -0,0 +1,88 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Level; +import java.util.logging.LogManager; + +import org.hamcrest.CoreMatchers; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; + +public class LoggingTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testMapLevel() { + + assertEquals("Error maps", Level.SEVERE, proxyMapLevel( "ERROR")); + assertEquals("Critical maps", Level.SEVERE, proxyMapLevel( "critical")); + assertEquals("Warn maps", Level.WARNING, proxyMapLevel( "WARNING")); + assertEquals("Info maps", Level.INFO, proxyMapLevel( "INFO")); + assertEquals("Config maps", Level.CONFIG, proxyMapLevel( " notice")); + assertEquals("Info maps", Level.INFO, proxyMapLevel( " info")); + assertEquals("Debug maps", Level.FINEST, proxyMapLevel( "debug ")); + assertEquals("Info maps", Level.INFO, proxyMapLevel( "wibble ")); + assertEquals("Info maps", Level.INFO, proxyMapLevel(new Object[] {null})); + } + + public Object proxyMapLevel(Object... args) { + + try { + Method m = Logging.class.getDeclaredMethod("mapLevel", String.class); + m.setAccessible(true); + return m.invoke(null, args); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException e) { + throw new RuntimeException(e); + } + + } + + @Test + public void testFormatError() { + Exception e1 = new Exception("Computer says no"); + + assertThat(Logging.formatError(e1), containsString("Computer says no")); + + NullPointerException npe1 = new NullPointerException("Nothing here"); + npe1.initCause(e1); + + assertThat(Logging.formatError(npe1), containsString("Computer says no")); + assertThat(Logging.formatError(npe1), containsString("Nothing here")); + + assertThat(Logging.formatError(null), CoreMatchers.nullValue()); + } + + @Test + public void testSetLogLevel() { + + java.util.logging.Logger l = java.util.logging.Logger.getLogger("org.hyperledger.fabric.test"); + java.util.logging.Logger another = java.util.logging.Logger.getLogger("acme.wibble"); + + Level anotherLevel = another.getLevel(); + Logging.setLogLevel("debug"); + assertThat(l.getLevel(),CoreMatchers.equalTo(Level.FINEST)); + assertThat(another.getLevel(),CoreMatchers.equalTo(anotherLevel)); + + Logging.setLogLevel("dsomethoig"); + assertThat(l.getLevel(),CoreMatchers.equalTo(Level.INFO)); + assertThat(another.getLevel(),CoreMatchers.equalTo(anotherLevel)); + + Logging.setLogLevel("ERROR"); + assertThat(l.getLevel(),CoreMatchers.equalTo(Level.SEVERE)); + assertThat(another.getLevel(),CoreMatchers.equalTo(anotherLevel)); + + } +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/TestUtil.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/TestUtil.java new file mode 100644 index 00000000..a8f05db8 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/TestUtil.java @@ -0,0 +1,110 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric; + +import java.io.ByteArrayInputStream; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Base64; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; + +public class TestUtil { + public static final String certWithoutAttrs = "MIICXTCCAgSgAwIBAgIUeLy6uQnq8wwyElU/jCKRYz3tJiQwCgYIKoZIzj0EAwIw" + + "eTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh" + + "biBGcmFuY2lzY28xGTAXBgNVBAoTEEludGVybmV0IFdpZGdldHMxDDAKBgNVBAsT" + + "A1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTcwOTA4MDAxNTAwWhcNMTgw" + + "OTA4MDAxNTAwWjBdMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xp" + + "bmExFDASBgNVBAoTC0h5cGVybGVkZ2VyMQ8wDQYDVQQLEwZGYWJyaWMxDjAMBgNV" + + "BAMTBWFkbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFq/90YMuH4tWugHa" + + "oyZtt4Mbwgv6CkBSDfYulVO1CVInw1i/k16DocQ/KSDTeTfgJxrX1Ree1tjpaodG" + + "1wWyM6OBhTCBgjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4E" + + "FgQUhKs/VJ9IWJd+wer6sgsgtZmxZNwwHwYDVR0jBBgwFoAUIUd4i/sLTwYWvpVr" + + "TApzcT8zv/kwIgYDVR0RBBswGYIXQW5pbHMtTWFjQm9vay1Qcm8ubG9jYWwwCgYI" + + "KoZIzj0EAwIDRwAwRAIgCoXaCdU8ZiRKkai0QiXJM/GL5fysLnmG2oZ6XOIdwtsC" + + "IEmCsI8Mhrvx1doTbEOm7kmIrhQwUVDBNXCWX1t3kJVN"; + + public static final String certWithAttrs = "MIIB6TCCAY+gAwIBAgIUHkmY6fRP0ANTvzaBwKCkMZZPUnUwCgYIKoZIzj0EAwIw" + + "GzEZMBcGA1UEAxMQZmFicmljLWNhLXNlcnZlcjAeFw0xNzA5MDgwMzQyMDBaFw0x" + + "ODA5MDgwMzQyMDBaMB4xHDAaBgNVBAMTE015VGVzdFVzZXJXaXRoQXR0cnMwWTAT" + + "BgcqhkjOPQIBBggqhkjOPQMBBwNCAATmB1r3CdWvOOP3opB3DjJnW3CnN8q1ydiR" + + "dzmuA6A2rXKzPIltHvYbbSqISZJubsy8gVL6GYgYXNdu69RzzFF5o4GtMIGqMA4G" + + "A1UdDwEB/wQEAwICBDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTYKLTAvJJK08OM" + + "VGwIhjMQpo2DrjAfBgNVHSMEGDAWgBTEs/52DeLePPx1+65VhgTwu3/2ATAiBgNV" + + "HREEGzAZghdBbmlscy1NYWNCb29rLVByby5sb2NhbDAmBggqAwQFBgcIAQQaeyJh" + + "dHRycyI6eyJhdHRyMSI6InZhbDEifX0wCgYIKoZIzj0EAwIDSAAwRQIhAPuEqWUp" + + "svTTvBqLR5JeQSctJuz3zaqGRqSs2iW+QB3FAiAIP0mGWKcgSGRMMBvaqaLytBYo" + + "9v3hRt1r8j8vN0pMcg=="; + + public static final String certWithLongDNs = "MIICGjCCAcCgAwIBAgIRAIPRwJHVLhHK47XK0BbFZJswCgYIKoZIzj0EAwIwczEL" + + "MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG" + + "cmFuY2lzY28xGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh" + + "Lm9yZzIuZXhhbXBsZS5jb20wHhcNMTcwNjIzMTIzMzE5WhcNMjcwNjIxMTIzMzE5" + + "WjBbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN" + + "U2FuIEZyYW5jaXNjbzEfMB0GA1UEAwwWVXNlcjFAb3JnMi5leGFtcGxlLmNvbTBZ" + + "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBd9SsEiFH1/JIb3qMEPLR2dygokFVKW" + + "eINcB0Ni4TBRkfIWWUJeCANTUY11Pm/+5gs+fBTqBz8M2UzpJDVX7+2jTTBLMA4G" + + "A1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIKfUfvpGproH" + + "cwyFD+0sE3XfJzYNcif0jNwvgOUFZ4AFMAoGCCqGSM49BAMCA0gAMEUCIQC8NIMw" + + "e4ym/QRwCJb5umbONNLSVQuEpnPsJrM/ssBPvgIgQpe2oYa3yO3USro9nBHjpM3L" + + "KsFQrpVnF8O6hoHOYZQ="; + + public static final String certWithMultipleAttributes = "MIIChzCCAi6gAwIBAgIURilAHeqwLu/fNUv8eZoGPRh3H4IwCgYIKoZIzj0EAwIw" + + "czELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh" + + "biBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT" + + "E2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTkwNzMxMTYxNzAwWhcNMjAwNzMwMTYy" + + "MjAwWjAgMQ8wDQYDVQQLEwZjbGllbnQxDTALBgNVBAMTBHRlc3QwWTATBgcqhkjO" + + "PQIBBggqhkjOPQMBBwNCAAR2taQK8w7D3hr3gBxCz+8eV4KSv7pFQfNjDHMMe9J9" + + "LJwcLpVTT5hYiLLRaqQonLBxBE3Ey0FneySvFuBScas3o4HyMIHvMA4GA1UdDwEB" + + "/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQi3mhXS/WzcjBniwAmPdYP" + + "kHqVVzArBgNVHSMEJDAigCC7VXjmSEugjAB/A0S6vfMxLsUIgag9WVNwtwwebnRC" + + "7TCBggYIKgMEBQYHCAEEdnsiYXR0cnMiOnsiYXR0cjEiOiJ2YWwxIiwiZm9vIjoi" + + "YmFyIiwiaGVsbG8iOiJ3b3JsZCIsImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5y" + + "b2xsbWVudElEIjoidGVzdCIsImhmLlR5cGUiOiJjbGllbnQifX0wCgYIKoZIzj0E" + + "AwIDRwAwRAIgQxEFvnZTEsf3CSZmp9IYsxcnEOtVYleOd86LAKtk1wICIH7XOPwW" + + "/RE4Z8WLZzFei/78Oezbx6obOvBxPMsVWRe5"; + + /** + * Function to create a certificate with dummy attributes + * @param attributeValue {String} value to be written to the identity attributes section of the certificate + * @return encodedCert {String} encoded certificate with re-written attributes + */ + public static String createCertWithIdentityAttributes(String attributeValue) throws Exception { + + // Use existing certificate with attributes + byte [] decodedCert = Base64.getDecoder().decode(certWithMultipleAttributes); + // Create a certificate holder and builder + X509CertificateHolder certHolder = new X509CertificateHolder(decodedCert); + X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(certHolder); + + // special OID used by Fabric to save attributes in x.509 certificates + String FABRIC_CERT_ATTR_OID = "1.2.3.4.5.6.7.8.1"; + // Write the new attribute value + byte[] extDataToWrite = attributeValue.getBytes(); + certBuilder.replaceExtension(new ASN1ObjectIdentifier(FABRIC_CERT_ATTR_OID), true, extDataToWrite); + + // Create a privateKey + KeyPairGenerator generator = KeyPairGenerator.getInstance("EC"); + generator.initialize(384); + KeyPair keyPair = generator.generateKeyPair(); + + // Create and build the Content Signer + JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256withECDSA"); + ContentSigner contentSigner = contentSignerBuilder.build(keyPair.getPrivate()); + // Build the Certificate from the certificate builder + X509CertificateHolder builtCert = certBuilder.build(contentSigner); + X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(new ByteArrayInputStream(builtCert.getEncoded())); + String encodedCert = Base64.getEncoder().encodeToString(certificate.getEncoded()); + return encodedCert; + } +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java new file mode 100644 index 00000000..56262405 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java @@ -0,0 +1,290 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract; + +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.google.protobuf.ByteString; + +import org.hyperledger.fabric.TestUtil; +import org.hyperledger.fabric.protos.msp.Identities.SerializedIdentity; +import org.hyperledger.fabric.protos.peer.ChaincodeEventPackage; +import org.hyperledger.fabric.protos.peer.ProposalPackage; +import org.hyperledger.fabric.shim.Chaincode; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.hyperledger.fabric.shim.ledger.CompositeKey; +import org.hyperledger.fabric.shim.ledger.KeyModification; +import org.hyperledger.fabric.shim.ledger.KeyValue; +import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; +import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata; + +public class ChaincodeStubNaiveImpl implements ChaincodeStub { + private List args; + private List argsAsByte; + private Map state; + private Chaincode.Response resp; + private String certificate = TestUtil.certWithoutAttrs; + + public ChaincodeStubNaiveImpl() { + args = new ArrayList<>(); + args.add("func1"); + args.add("param1"); + args.add("param2"); + + state = new HashMap<>(); + state.put("a", ByteString.copyFrom("asdf", StandardCharsets.UTF_8)); + + argsAsByte = null; + + resp = new Chaincode.Response(404, "Wrong cc name", new byte[]{}); + } + + ChaincodeStubNaiveImpl(List args) { + this.args = args; + state = new HashMap<>(); + state.put("a", ByteString.copyFrom("asdf", StandardCharsets.UTF_8)); + + argsAsByte = null; + + resp = new Chaincode.Response(404, "Wrong cc name", new byte[]{}); + } + + + @Override + public List getArgs() { + if (argsAsByte == null) { + argsAsByte = args.stream().map(i -> i.getBytes()).collect(Collectors.toList()); + } + return argsAsByte; + } + + @Override + public List getStringArgs() { + return args; + } + + @Override + public String getFunction() { + return args.get(0); + } + + @Override + public List getParameters() { + return args.subList(1, args.size()); + } + + @Override + public String getTxId() { + return "tx0"; + } + + @Override + public String getChannelId() { + return "ch0"; + } + + @Override + public Chaincode.Response invokeChaincode(String chaincodeName, List args, String channel) { + return resp; + } + + @Override + public byte[] getState(String key) { + return state.get(key).toByteArray(); + } + + @Override + public byte[] getStateValidationParameter(String key) { + return new byte[0]; + } + + @Override + public void putState(String key, byte[] value) { + state.put(key, ByteString.copyFrom(value)); + + } + + @Override + public void setStateValidationParameter(String key, byte[] value) { + + } + + @Override + public void delState(String key) { + state.remove(key); + } + + @Override + public QueryResultsIterator getStateByRange(String startKey, String endKey) { + return null; + } + + @Override + public QueryResultsIteratorWithMetadata getStateByRangeWithPagination(String startKey, String endKey, int pageSize, String bookmark) { + return null; + } + + @Override + public QueryResultsIterator getStateByPartialCompositeKey(String compositeKey) { + return null; + } + + @Override + public QueryResultsIterator getStateByPartialCompositeKey(String objectType, String... attributes) { + return null; + } + + @Override + public QueryResultsIterator getStateByPartialCompositeKey(CompositeKey compositeKey) { + return null; + } + + @Override + public QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination(CompositeKey compositeKey, int pageSize, String bookmark) { + return null; + } + + @Override + public CompositeKey createCompositeKey(String objectType, String... attributes) { + return null; + } + + @Override + public CompositeKey splitCompositeKey(String compositeKey) { + return null; + } + + @Override + public QueryResultsIterator getQueryResult(String query) { + return null; + } + + @Override + public QueryResultsIteratorWithMetadata getQueryResultWithPagination(String query, int pageSize, String bookmark) { + return null; + } + + @Override + public QueryResultsIterator getHistoryForKey(String key) { + return null; + } + + @Override + public byte[] getPrivateData(String collection, String key) { + return new byte[0]; + } + + @Override + public byte[] getPrivateDataHash(String collection, String key) { + return new byte[0]; + } + + @Override + public byte[] getPrivateDataValidationParameter(String collection, String key) { + return new byte[0]; + } + + @Override + public void putPrivateData(String collection, String key, byte[] value) { + + } + + @Override + public void setPrivateDataValidationParameter(String collection, String key, byte[] value) { + + } + + @Override + public void delPrivateData(String collection, String key) { + + } + + @Override + public QueryResultsIterator getPrivateDataByRange(String collection, String startKey, String endKey) { + return null; + } + + @Override + public QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, String compositeKey) { + return null; + } + + @Override + public QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, CompositeKey compositeKey) { + return null; + } + + @Override + public QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, String objectType, String... attributes) { + return null; + } + + @Override + public QueryResultsIterator getPrivateDataQueryResult(String collection, String query) { + return null; + } + + @Override + public void setEvent(String name, byte[] payload) { + + } + + @Override + public ChaincodeEventPackage.ChaincodeEvent getEvent() { + return null; + } + + @Override + public ProposalPackage.SignedProposal getSignedProposal() { + return null; + } + + @Override + public Instant getTxTimestamp() { + return null; + } + + @Override + public byte[] getCreator() { + return buildSerializedIdentity(); + } + + @Override + public Map getTransient() { + return null; + } + + @Override + public byte[] getBinding() { + return new byte[0]; + } + + void setStringArgs(List args){ + this.args = args; + this.argsAsByte = args.stream().map(i -> i.getBytes()).collect(Collectors.toList()); + } + + public byte[] buildSerializedIdentity() { + SerializedIdentity.Builder identity = SerializedIdentity.newBuilder(); + identity.setMspid("testMSPID"); + byte [] decodedCert = Base64.getDecoder().decode(this.certificate); + identity.setIdBytes(ByteString.copyFrom(decodedCert)); + SerializedIdentity builtIdentity = identity.build(); + return builtIdentity.toByteArray(); + } + + // Used by tests to control which serialized identity is returned by buildSerializedIdentity + public void setCertificate(String certificateToTest) { + this.certificate = certificateToTest; + } +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java new file mode 100644 index 00000000..9169ed66 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java @@ -0,0 +1,126 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.math.BigInteger; + +import org.hyperledger.fabric.TestUtil; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class ClientIdentityTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + /** + * Test client identity can be created using certificate without attributes + */ + @Test + public void clientIdentityWithoutAttributes() throws Exception { + ChaincodeStub stub = new ChaincodeStubNaiveImpl(); + ClientIdentity identity = new ClientIdentity(stub); + assertEquals(identity.getMSPID(), "testMSPID"); + assertEquals(identity.getId(), "x509::CN=admin, OU=Fabric, O=Hyperledger, ST=North Carolina, C=US::CN=example.com, OU=WWW, O=Internet Widgets, L=San Francisco, ST=California, C=US"); + assertEquals(identity.getAttributeValue("attr1"), null); + assertEquals(identity.getAttributeValue("val1"), null); + assertEquals(identity.getX509Certificate().getSubjectX500Principal().toString(), "CN=admin, OU=Fabric, O=Hyperledger, ST=North Carolina, C=US"); + assertEquals(identity.getX509Certificate().getSerialNumber(), new BigInteger("689287698446788666856807436918134903862142510628") ); + } + + /** + * Test client identity can be created using certificate with attributes + */ + @Test + public void clientIdentityWithAttributes() throws Exception { + ChaincodeStub stub = new ChaincodeStubNaiveImpl(); + ((ChaincodeStubNaiveImpl) stub).setCertificate(TestUtil.certWithAttrs); + ClientIdentity identity = new ClientIdentity(stub); + assertEquals(identity.getMSPID(), "testMSPID"); + assertEquals(identity.getId(), "x509::CN=MyTestUserWithAttrs::CN=fabric-ca-server"); + assertEquals(identity.getAttributeValue("attr1"), "val1"); + assertEquals(identity.getAttributeValue("val1"), null); + assertEquals(identity.assertAttributeValue("attr1", "val1"), true); + assertEquals(identity.assertAttributeValue("attr1", "val2"), false); + assertEquals(identity.assertAttributeValue("attr2", "val1"), false); + assertEquals(identity.getX509Certificate().getSubjectX500Principal().toString(), "CN=MyTestUserWithAttrs"); + assertEquals(identity.getX509Certificate().getSerialNumber(), new BigInteger("172910998202207082780622887076293058980152824437") ); + } + + /** + * Test client identity can be created using certificate with multiple attributes + */ + @Test + public void clientIdentityWithMultipleAttributes() throws Exception { + ChaincodeStub stub = new ChaincodeStubNaiveImpl(); + ((ChaincodeStubNaiveImpl) stub).setCertificate(TestUtil.certWithMultipleAttributes); + ClientIdentity identity = new ClientIdentity(stub); + assertEquals(identity.getMSPID(), "testMSPID"); + assertEquals(identity.getId(), "x509::CN=test, OU=client::CN=ca.org1.example.com, O=org1.example.com, L=San Francisco, ST=California, C=US"); + assertEquals(identity.getAttributeValue("hello"), "world"); + assertEquals(identity.getAttributeValue("foo"), "bar"); + assertEquals(identity.getAttributeValue("attr1"), "val1"); + assertEquals(identity.getAttributeValue("val1"), null); + assertEquals(identity.assertAttributeValue("hello", "world"), true); + assertEquals(identity.assertAttributeValue("attr1", "val2"), false); + assertEquals(identity.assertAttributeValue("hello", "val1"), false); + assertEquals(identity.getX509Certificate().getSubjectX500Principal().toString(), "CN=test, OU=client"); + assertEquals(identity.getX509Certificate().getSerialNumber(), new BigInteger("400549269877250942864348502164024974865235124098") ); + } + + /** + * Test client identity can be created using certificate with long distinguished name + */ + @Test + public void clientIdentityWithLongDNs() throws Exception { + ChaincodeStub stub = new ChaincodeStubNaiveImpl(); + ((ChaincodeStubNaiveImpl) stub).setCertificate(TestUtil.certWithLongDNs); + ClientIdentity identity = new ClientIdentity(stub); + assertEquals(identity.getMSPID(), "testMSPID"); + assertEquals(identity.getId(), "x509::CN=User1@org2.example.com, L=San Francisco, ST=California, C=US::CN=ca.org2.example.com, O=org2.example.com, L=San Francisco, ST=California, C=US"); + assertEquals(identity.getX509Certificate().getSubjectX500Principal().toString(), "CN=User1@org2.example.com, L=San Francisco, ST=California, C=US"); + assertEquals(identity.getX509Certificate().getSerialNumber(), new BigInteger("175217963267961225716341475631843075227") ); + } + + /** + * Test client identity throws a ContractRuntimeException + * when creating a serialized identity fails + */ + @Test + public void catchInvalidProtocolBufferException() { + thrown.expect(ContractRuntimeException.class); + thrown.expectMessage("Could not create new client identity"); + + ChaincodeStub stub = mock(ChaincodeStub.class); + when(stub.getCreator()).thenReturn("somethingInvalid".getBytes()); + ContextFactory.getInstance().createContext(stub); + + } + + /** + * Test client identity attributes are empty + * when using a certificate with dummy attributes + */ + @Test + public void createClientIdentityWithDummyAttributesCert() throws Exception { + ChaincodeStub stub = new ChaincodeStubNaiveImpl(); + // Create a certificate with rubbish attributes + String certWithDummyAttrs = TestUtil.createCertWithIdentityAttributes("{gsdhrlxhvcilgwoueglfs,djhzxo;vjs.dcx }"); + ((ChaincodeStubNaiveImpl) stub).setCertificate(certWithDummyAttrs); + ClientIdentity identity = new ClientIdentity(stub); + + assertEquals(identity.getMSPID(), "testMSPID"); + assertEquals(identity.getAttributeValue("attr1"), null); + assertEquals(identity.getAttributeValue("val1"), null); + assertEquals(identity.getX509Certificate().getSubjectX500Principal().toString(), "CN=test, OU=client"); + } +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java new file mode 100644 index 00000000..10dbd537 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java @@ -0,0 +1,48 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.sameInstance; +import static org.junit.Assert.assertThat; + +import java.util.Collections; + +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.junit.Test; + +public class ContextFactoryTest { + + @Test + public void getInstance() { + ContextFactory f1 = ContextFactory.getInstance(); + ContextFactory f2 = ContextFactory.getInstance(); + assertThat(f1, sameInstance(f2)); + } + + @Test + public void createContext() { + ChaincodeStub stub = new ChaincodeStubNaiveImpl(); + Context ctx = ContextFactory.getInstance().createContext(stub); + + assertThat(stub.getArgs(), is(equalTo(ctx.getStub().getArgs()))); + assertThat(stub.getStringArgs(), is(equalTo(ctx.getStub().getStringArgs()))); + assertThat(stub.getFunction(), is(equalTo(ctx.getStub().getFunction()))); + assertThat(stub.getParameters(), is(equalTo(ctx.getStub().getParameters()))); + assertThat(stub.getTxId(), is(equalTo(ctx.getStub().getTxId()))); + assertThat(stub.getChannelId(), is(equalTo(ctx.getStub().getChannelId()))); + assertThat(stub.invokeChaincode("cc", Collections.emptyList(), "ch0"), + is(equalTo(ctx.getStub().invokeChaincode("cc", Collections.emptyList(), "ch0")))); + + assertThat(stub.getState("a"), is(equalTo(ctx.getStub().getState("a")))); + ctx.getStub().putState("b", "sdfg".getBytes()); + assertThat(stub.getStringState("b"), is(equalTo(ctx.getStub().getStringState("b")))); + + assertThat(ctx.clientIdentity.getMSPID(), is(equalTo("testMSPID"))); + assertThat(ctx.clientIdentity.getId(), is(equalTo("x509::CN=admin, OU=Fabric, O=Hyperledger, ST=North Carolina, C=US::CN=example.com, OU=WWW, O=Internet Widgets, L=San Francisco, ST=California, C=US"))); + } +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java new file mode 100644 index 00000000..31a8ee17 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java @@ -0,0 +1,37 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract; + +import static org.hamcrest.Matchers.sameInstance; +import static org.junit.Assert.assertThat; + +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.junit.Test; + +public class ContextTest { + + /** + * Test creating a new context returns what we expect + */ + @Test + public void getInstance() { + ChaincodeStub stub = new ChaincodeStubNaiveImpl(); + Context context1 = new Context(stub); + Context context2 = new Context(stub); + assertThat(context1.getStub(), sameInstance(context2.getStub())); + } + + /** + * Test identity created in Context constructor matches getClientIdentity + */ + @Test + public void getSetClientIdentity() { + ChaincodeStub stub = new ChaincodeStubNaiveImpl(); + Context context = ContextFactory.getInstance().createContext(stub); + assertThat(context.getClientIdentity(), sameInstance(context.clientIdentity)); + + } +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java new file mode 100644 index 00000000..27ed7054 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java @@ -0,0 +1,51 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract; + +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import org.hyperledger.fabric.shim.ChaincodeException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class ContractInterfaceTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void createContext() { + assertThat((new ContractInterface() { + }).createContext(new ChaincodeStubNaiveImpl()), is(instanceOf(Context.class))); + } + + @Test + public void unknownTransaction() { + thrown.expect(ChaincodeException.class); + thrown.expectMessage("Undefined contract method called"); + + ContractInterface c = new ContractInterface() { + }; + c.unknownTransaction(c.createContext(new ChaincodeStubNaiveImpl())); + } + + @Test + public void beforeTransaction() { + ContractInterface c = new ContractInterface() { + }; + + c.beforeTransaction(c.createContext(new ChaincodeStubNaiveImpl())); + } + + @Test + public void afterTransaction() { + ContractInterface c = new ContractInterface() { + }; + c.afterTransaction(c.createContext(new ChaincodeStubNaiveImpl()), "ReturnValue"); + } +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java new file mode 100644 index 00000000..2eb0df60 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java @@ -0,0 +1,379 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; + +import org.hyperledger.fabric.contract.annotation.Contract; +import org.hyperledger.fabric.contract.execution.ExecutionFactory; +import org.hyperledger.fabric.contract.execution.InvocationRequest; +import org.hyperledger.fabric.shim.Chaincode; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import contract.SampleContract; + +public class ContractRouterTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testCreateAndScan() { + ContractRouter r = new ContractRouter(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); + r.findAllContracts(); + ChaincodeStub s = new ChaincodeStubNaiveImpl(); + + // Test Transaction routing + List args = new ArrayList<>(); + args.add("samplecontract:t1"); + args.add("asdf"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + InvocationRequest request = ExecutionFactory.getInstance().createRequest(s); + assertThat(request.getNamespace(), is(equalTo(SampleContract.class.getAnnotation(Contract.class).name()))); + assertThat(request.getMethod(), is(equalTo("t1"))); + assertThat(request.getRequestName(), is(equalTo("samplecontract:t1"))); + assertThat(request.getArgs(), is(contains(s.getArgs().get(1)))); + } + + @Test + public void testInit() { + ContractRouter r = new ContractRouter(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); + r.findAllContracts(); + ChaincodeStub s = new ChaincodeStubNaiveImpl(); + + List args = new ArrayList<>(); + args.add("samplecontract:t1"); + args.add("asdf"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + + SampleContract.beforeInvoked = 0; + SampleContract.afterInvoked = 0; + SampleContract.doWorkInvoked = 0; + SampleContract.t1Invoked = 0; + + Chaincode.Response response = r.init(s); + assertThat(response, is(notNullValue())); + assertThat(response.getStatus(), is(Chaincode.Response.Status.SUCCESS)); + assertThat(response.getMessage(), is(nullValue())); + assertThat(response.getStringPayload(), is(equalTo("asdf"))); + assertThat(SampleContract.beforeInvoked, is(1)); + assertThat(SampleContract.afterInvoked, is(1)); + assertThat(SampleContract.doWorkInvoked, is(1)); + assertThat(SampleContract.t1Invoked, is(1)); + } + + /** + * Test invoking two transaction functions in a contract via fully qualified + * name + */ + @Test + public void testInvokeTwoTxnsThatExist() { + ContractRouter r = new ContractRouter(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); + r.findAllContracts(); + System.out.println("-------------testInvokeTwoTxnsThatExist--------------"); + r.getRoutingRegistry().getAllDefinitions().forEach(s -> System.out.println(s)); + System.out.println("---------------------------"); + ChaincodeStub s = new ChaincodeStubNaiveImpl(); + + List args = new ArrayList<>(); + args.add("samplecontract:t1"); + args.add("asdf"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + + SampleContract.beforeInvoked = 0; + SampleContract.afterInvoked = 0; + SampleContract.doWorkInvoked = 0; + SampleContract.t1Invoked = 0; + + Chaincode.Response response = r.invoke(s); + assertThat(response, is(notNullValue())); + assertThat(response.getStatus(), is(Chaincode.Response.Status.SUCCESS)); + assertThat(response.getMessage(), is(nullValue())); + assertThat(response.getStringPayload(), is(equalTo("asdf"))); + assertThat(SampleContract.beforeInvoked, is(1)); + assertThat(SampleContract.afterInvoked, is(1)); + assertThat(SampleContract.doWorkInvoked, is(1)); + assertThat(SampleContract.t1Invoked, is(1)); + + args.clear(); + args.add("samplecontract:t5"); + args.add("asdf"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + + SampleContract.beforeInvoked = 0; + SampleContract.afterInvoked = 0; + SampleContract.doWorkInvoked = 0; + SampleContract.t1Invoked = 0; + + Chaincode.Response secondResponse = r.invoke(s); + assertThat(secondResponse, is(notNullValue())); + assertThat(secondResponse.getStatus(), is(Chaincode.Response.Status.SUCCESS)); + assertThat(secondResponse.getMessage(), is(nullValue())); + assertThat(secondResponse.getStringPayload(), is(nullValue())); + assertThat(SampleContract.beforeInvoked, is(1)); + assertThat(SampleContract.afterInvoked, is(1)); + assertThat(SampleContract.doWorkInvoked, is(1)); + assertThat(SampleContract.t1Invoked, is(0)); + } + + @Test + public void testInvokeTxnWithDefinedName() { + ContractRouter r = new ContractRouter(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); + r.findAllContracts(); + ChaincodeStub s = new ChaincodeStubNaiveImpl(); + + List args = new ArrayList<>(); + args.add("samplecontract:t4"); + args.add("asdf"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + + SampleContract.beforeInvoked = 0; + SampleContract.afterInvoked = 0; + SampleContract.doWorkInvoked = 0; + SampleContract.t1Invoked = 0; + + Chaincode.Response response = r.invoke(s); + assertThat(response, is(notNullValue())); + assertThat(response.getStatus(), is(Chaincode.Response.Status.SUCCESS)); + assertThat(response.getMessage(), is(nullValue())); + assertThat(response.getStringPayload(), is(equalTo("Transaction 4"))); + assertThat(SampleContract.beforeInvoked, is(1)); + assertThat(SampleContract.afterInvoked, is(1)); + assertThat(SampleContract.doWorkInvoked, is(0)); + assertThat(SampleContract.t1Invoked, is(0)); + } + + /** + * Test invoking two transaction functions in a contract via default name + * name + */ + @Test + public void testInvokeTwoTxnsWithDefaultNamespace() { + ContractRouter r = new ContractRouter(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); + r.findAllContracts(); + ChaincodeStub s = new ChaincodeStubNaiveImpl(); + + List args = new ArrayList<>(); + args.add("t1"); + args.add("asdf"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + + SampleContract.beforeInvoked = 0; + SampleContract.afterInvoked = 0; + SampleContract.doWorkInvoked = 0; + SampleContract.t1Invoked = 0; + + Chaincode.Response response = r.invoke(s); + assertThat(response, is(notNullValue())); + assertThat(response.getStatus(), is(Chaincode.Response.Status.SUCCESS)); + assertThat(response.getMessage(), is(nullValue())); + assertThat(response.getStringPayload(), is(equalTo("asdf"))); + assertThat(SampleContract.beforeInvoked, is(1)); + assertThat(SampleContract.afterInvoked, is(1)); + assertThat(SampleContract.doWorkInvoked, is(1)); + assertThat(SampleContract.t1Invoked, is(1)); + + args.clear(); + args.add("t5"); + args.add("asdf"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + + SampleContract.beforeInvoked = 0; + SampleContract.afterInvoked = 0; + SampleContract.doWorkInvoked = 0; + SampleContract.t1Invoked = 0; + + Chaincode.Response secondResponse = r.invoke(s); + assertThat(secondResponse, is(notNullValue())); + assertThat(secondResponse.getStatus(), is(Chaincode.Response.Status.SUCCESS)); + assertThat(secondResponse.getMessage(), is(nullValue())); + assertThat(secondResponse.getStringPayload(), is(nullValue())); + assertThat(SampleContract.beforeInvoked, is(1)); + assertThat(SampleContract.afterInvoked, is(1)); + assertThat(SampleContract.doWorkInvoked, is(1)); + assertThat(SampleContract.t1Invoked, is(0)); + } + + @Test + public void testInvokeTxnWithDefinedNameUsingMethodName() { + ContractRouter r = new ContractRouter(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); + r.findAllContracts(); + ChaincodeStub s = new ChaincodeStubNaiveImpl(); + + List args = new ArrayList<>(); + args.add("samplecontract:tFour"); + args.add("asdf"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + + SampleContract.beforeInvoked = 0; + SampleContract.afterInvoked = 0; + SampleContract.doWorkInvoked = 0; + SampleContract.t1Invoked = 0; + + Chaincode.Response response = r.invoke(s); + assertThat(response, is(notNullValue())); + assertThat(response.getStatus(), is(Chaincode.Response.Status.INTERNAL_SERVER_ERROR)); + assertThat(response.getMessage(), is(equalTo("Undefined contract method called"))); + assertThat(response.getStringPayload(), is(nullValue())); + assertThat(SampleContract.beforeInvoked, is(1)); + assertThat(SampleContract.afterInvoked, is(0)); + assertThat(SampleContract.doWorkInvoked, is(0)); + assertThat(SampleContract.t1Invoked, is(0)); + } + + @Test + public void testInvokeContractThatDoesNotExist() { + ContractRouter r = new ContractRouter(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); + r.findAllContracts(); + ChaincodeStub s = new ChaincodeStubNaiveImpl(); + + List args = new ArrayList<>(); + args.add("thereisnocontract:t1"); + args.add("asdf"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + + SampleContract.beforeInvoked = 0; + SampleContract.afterInvoked = 0; + SampleContract.doWorkInvoked = 0; + SampleContract.t1Invoked = 0; + + Chaincode.Response response = r.invoke(s); + assertThat(response, is(notNullValue())); + assertThat(response.getStatus(), is(Chaincode.Response.Status.INTERNAL_SERVER_ERROR)); + assertThat(response.getMessage(), is(equalTo("Undefined contract called"))); + assertThat(response.getStringPayload(), is(nullValue())); + assertThat(SampleContract.beforeInvoked, is(0)); + assertThat(SampleContract.afterInvoked, is(0)); + assertThat(SampleContract.doWorkInvoked, is(0)); + assertThat(SampleContract.t1Invoked, is(0)); + } + + @Test + public void testInvokeTxnThatDoesNotExist() { + ContractRouter r = new ContractRouter(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); + r.findAllContracts(); + ChaincodeStub s = new ChaincodeStubNaiveImpl(); + + List args = new ArrayList<>(); + args.add("samplecontract:notsupposedtoexist"); + args.add("asdf"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + + SampleContract.beforeInvoked = 0; + SampleContract.afterInvoked = 0; + SampleContract.doWorkInvoked = 0; + SampleContract.t1Invoked = 0; + + Chaincode.Response response = r.invoke(s); + assertThat(response, is(notNullValue())); + assertThat(response.getStatus(), is(Chaincode.Response.Status.INTERNAL_SERVER_ERROR)); + assertThat(response.getMessage(), is(equalTo("Undefined contract method called"))); + assertThat(response.getStringPayload(), is(nullValue())); + assertThat(SampleContract.beforeInvoked, is(1)); + assertThat(SampleContract.afterInvoked, is(0)); + assertThat(SampleContract.doWorkInvoked, is(0)); + assertThat(SampleContract.t1Invoked, is(0)); + } + + @Test + public void testInvokeTxnThatReturnsNullString() { + ContractRouter r = new ContractRouter(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); + r.findAllContracts(); + ChaincodeStub s = new ChaincodeStubNaiveImpl(); + + List args = new ArrayList<>(); + args.add("samplecontract:t5"); + args.add("asdf"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + + SampleContract.beforeInvoked = 0; + SampleContract.afterInvoked = 0; + SampleContract.doWorkInvoked = 0; + SampleContract.t1Invoked = 0; + + Chaincode.Response response = r.invoke(s); + assertThat(response, is(notNullValue())); + assertThat(response.getStatus(), is(Chaincode.Response.Status.SUCCESS)); + assertThat(response.getMessage(), is(nullValue())); + assertThat(response.getStringPayload(), is(nullValue())); + assertThat(SampleContract.beforeInvoked, is(1)); + assertThat(SampleContract.afterInvoked, is(1)); + assertThat(SampleContract.doWorkInvoked, is(1)); + assertThat(SampleContract.t1Invoked, is(0)); + } + + @Test + public void testInvokeTxnThatThrowsAnException() { + ContractRouter r = new ContractRouter(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); + r.findAllContracts(); + ChaincodeStub s = new ChaincodeStubNaiveImpl(); + + List args = new ArrayList<>(); + args.add("samplecontract:t3"); + args.add("RuntimeException"); + args.add("T3 fail!"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + + SampleContract.beforeInvoked = 0; + SampleContract.afterInvoked = 0; + SampleContract.doWorkInvoked = 0; + + Chaincode.Response response = r.invoke(s); + assertThat(response, is(notNullValue())); + assertThat(response.getStatus(), is(Chaincode.Response.Status.INTERNAL_SERVER_ERROR)); + assertThat(response.getMessage(), is(equalTo("Error during contract method execution"))); + assertThat(response.getStringPayload(), is(nullValue())); + assertThat(SampleContract.beforeInvoked, is(1)); + assertThat(SampleContract.afterInvoked, is(0)); + assertThat(SampleContract.doWorkInvoked, is(0)); + } + + @Test + public void testInvokeTxnThatThrowsAChaincodeException() { + ContractRouter r = new ContractRouter(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); + r.findAllContracts(); + ChaincodeStub s = new ChaincodeStubNaiveImpl(); + + List args = new ArrayList<>(); + args.add("samplecontract:t3"); + args.add("TransactionException"); + args.add("T3 fail!"); + ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + + SampleContract.beforeInvoked = 0; + SampleContract.afterInvoked = 0; + SampleContract.doWorkInvoked = 0; + + Chaincode.Response response = r.invoke(s); + assertThat(response, is(notNullValue())); + assertThat(response.getStatus(), is(Chaincode.Response.Status.INTERNAL_SERVER_ERROR)); + assertThat(response.getMessage(), is(equalTo("T3 fail!"))); + assertThat(response.getStringPayload(), is("T3ERR1")); + assertThat(SampleContract.beforeInvoked, is(1)); + assertThat(SampleContract.afterInvoked, is(0)); + assertThat(SampleContract.doWorkInvoked, is(0)); + } + + /** + * Test confirming ContractRuntimeExceptions can be created + */ + @Test + public void createContractRuntimeExceptions() { + ContractRuntimeException cre1 = new ContractRuntimeException("failure"); + new ContractRuntimeException("another failure", cre1); + new ContractRuntimeException(new Exception("cause")); + } +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType.java new file mode 100644 index 00000000..f515e8a6 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType.java @@ -0,0 +1,30 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract; + +import org.hyperledger.fabric.contract.annotation.DataType; +import org.hyperledger.fabric.contract.annotation.Property; + +@DataType +public class MyType { + + @Property() + private String value; + + public MyType setValue(String value) { + this.value = value; + return this; + } + + public String getValue() { + return this.value; + } + + public String toString() { + return "++++ MyType: " + value; + } +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType2.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType2.java new file mode 100644 index 00000000..c8100f0d --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType2.java @@ -0,0 +1,38 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract; + +import org.hyperledger.fabric.contract.annotation.DataType; +import org.hyperledger.fabric.contract.annotation.Property; + +@DataType +public class MyType2 { + + @Property() + private String value; + + @Property(schema = {"title","MrProperty", + "Pattern","[a-z]", + "uniqueItems","false", + "required","true,false", + "enum","a,bee,cee,dee", + "minimum","42"}) + private String constrainedValue; + + public MyType2 setValue(String value) { + this.value = value; + return this; + } + + public String getValue() { + return this.value; + } + + public String toString() { + return "++++ MyType: " + value; + } +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java new file mode 100644 index 00000000..ea8f732c --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java @@ -0,0 +1,106 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +import org.hyperledger.fabric.shim.ChaincodeException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class TransactionExceptionTest { + + class MyTransactionException extends ChaincodeException { + + private static final long serialVersionUID = 1L; + + private int errorCode; + + public MyTransactionException(int errorCode) { + super("MyTransactionException"); + this.errorCode = errorCode; + } + + @Override + public byte[] getPayload() { + String payload = String.format("E%03d", errorCode); + return payload.getBytes(); + } + } + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testNoArgConstructor() { + ChaincodeException e = new ChaincodeException(); + assertThat(e.getMessage(), is(nullValue())); + assertThat(e.getPayload(), is(nullValue())); + } + + @Test + public void testMessageArgConstructor() { + ChaincodeException e = new ChaincodeException("Failure"); + assertThat(e.getMessage(), is("Failure")); + assertThat(e.getPayload(), is(nullValue())); + } + + @Test + public void testCauseArgConstructor() { + ChaincodeException e = new ChaincodeException(new Error("Cause")); + assertThat(e.getMessage(), is("java.lang.Error: Cause")); + assertThat(e.getPayload(), is(nullValue())); + assertThat(e.getCause().getMessage(), is("Cause")); + } + + @Test + public void testMessageAndCauseArgConstructor() { + ChaincodeException e = new ChaincodeException("Failure", new Error("Cause")); + assertThat(e.getMessage(), is("Failure")); + assertThat(e.getPayload(), is(nullValue())); + assertThat(e.getCause().getMessage(), is("Cause")); + } + + @Test + public void testMessageAndPayloadArgConstructor() { + ChaincodeException e = new ChaincodeException("Failure", new byte[] { 'P', 'a', 'y', 'l', 'o', 'a', 'd' }); + assertThat(e.getMessage(), is("Failure")); + assertThat(e.getPayload(), is(new byte[] { 'P', 'a', 'y', 'l', 'o', 'a', 'd' })); + } + + @Test + public void testMessagePayloadAndCauseArgConstructor() { + ChaincodeException e = new ChaincodeException("Failure", new byte[] { 'P', 'a', 'y', 'l', 'o', 'a', 'd' }, new Error("Cause")); + assertThat(e.getMessage(), is("Failure")); + assertThat(e.getPayload(), is(new byte[] { 'P', 'a', 'y', 'l', 'o', 'a', 'd' })); + assertThat(e.getCause().getMessage(), is("Cause")); + } + + @Test + public void testMessageAndStringPayloadArgConstructor() { + ChaincodeException e = new ChaincodeException("Failure", "Payload"); + assertThat(e.getMessage(), is("Failure")); + assertThat(e.getPayload(), is(new byte[] { 'P', 'a', 'y', 'l', 'o', 'a', 'd' })); + } + + @Test + public void testMessageStringPayloadAndCauseArgConstructor() { + ChaincodeException e = new ChaincodeException("Failure", "Payload", new Error("Cause")); + assertThat(e.getMessage(), is("Failure")); + assertThat(e.getPayload(), is(new byte[] { 'P', 'a', 'y', 'l', 'o', 'a', 'd' })); + assertThat(e.getCause().getMessage(), is("Cause")); + } + + @Test + public void testSubclass() { + ChaincodeException e = new MyTransactionException(1); + assertThat(e.getMessage(), is("MyTransactionException")); + assertThat(e.getPayload(), is(new byte[] { 'E', '0', '0', '1' })); + } +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java new file mode 100644 index 00000000..e8b1009a --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java @@ -0,0 +1,94 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.execution; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; + +import org.hyperledger.fabric.contract.ChaincodeStubNaiveImpl; +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.ContractRuntimeException; +import org.hyperledger.fabric.contract.execution.impl.ContractExecutionService; +import org.hyperledger.fabric.contract.routing.TxFunction; +import org.hyperledger.fabric.contract.routing.TypeRegistry; +import org.hyperledger.fabric.contract.routing.impl.TypeRegistryImpl; +import org.hyperledger.fabric.shim.Chaincode.Response; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import contract.SampleContract; + +public class ContractExecutionServiceTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @SuppressWarnings({ "serial" }) + @Test + public void noReturnValue() + throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException { + TypeRegistry typeRegistry = new TypeRegistryImpl(); + + ContractExecutionService ces = new ContractExecutionService(typeRegistry); + + ContractInterface contract = spy(new SampleContract()); + TxFunction txFn = mock(TxFunction.class); + InvocationRequest req = mock(InvocationRequest.class); + TxFunction.Routing routing = mock(TxFunction.Routing.class); + + ChaincodeStub stub = new ChaincodeStubNaiveImpl(); + + when(txFn.getRouting()).thenReturn(routing); + when(req.getArgs()).thenReturn(new ArrayList() { + }); + when(routing.getMethod()).thenReturn(SampleContract.class.getMethod("noReturn", new Class[] { Context.class })); + when(routing.getContractInstance()).thenReturn(contract); + ces.executeRequest(txFn, req, stub); + + verify(contract).beforeTransaction(any()); + + } + + @SuppressWarnings({ "serial" }) + @Test() + public void failureToInvoke() + throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException { + TypeRegistry typeRegistry = new TypeRegistryImpl(); + + ContractExecutionService ces = new ContractExecutionService(typeRegistry); + + spy(new SampleContract()); + TxFunction txFn = mock(TxFunction.class); + InvocationRequest req = mock(InvocationRequest.class); + TxFunction.Routing routing = mock(TxFunction.Routing.class); + + ChaincodeStub stub = mock(ChaincodeStub.class); + + when(txFn.getRouting()).thenReturn(routing); + when(req.getArgs()).thenReturn(new ArrayList() { + }); + + when(routing.getContractInstance()).thenThrow(IllegalAccessException.class); + when(routing.toString()).thenReturn("MockMethodName:MockClassName"); + + thrown.expect(ContractRuntimeException.class); + thrown.expectMessage("Could not execute contract method: MockMethodName:MockClassName"); + + Response resp = ces.executeRequest(txFn, req, stub); + assertThat(resp.getStatusCode(), equalTo(500)); + } + +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java new file mode 100644 index 00000000..82a57f10 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java @@ -0,0 +1,128 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract.execution; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; + +import java.nio.charset.StandardCharsets; + +import org.hyperledger.fabric.contract.MyType; +import org.hyperledger.fabric.contract.metadata.MetadataBuilder; +import org.hyperledger.fabric.contract.metadata.TypeSchema; +import org.hyperledger.fabric.contract.routing.TypeRegistry; +import org.hyperledger.fabric.contract.routing.impl.TypeRegistryImpl; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class JSONTransactionSerializerTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void toBuffer() { + TypeRegistry tr = new TypeRegistryImpl(); + JSONTransactionSerializer serializer = new JSONTransactionSerializer(tr); + + byte[] bytes = serializer.toBuffer("hello world", TypeSchema.typeConvert(String.class)); + assertThat(new String(bytes, StandardCharsets.UTF_8), equalTo("hello world")); + + bytes = serializer.toBuffer(42, TypeSchema.typeConvert(Integer.class)); + assertThat(new String(bytes, StandardCharsets.UTF_8), equalTo("42")); + + bytes = serializer.toBuffer(true, TypeSchema.typeConvert(Boolean.class)); + assertThat(new String(bytes, StandardCharsets.UTF_8), equalTo("true")); + + bytes = serializer.toBuffer(new MyType(), TypeSchema.typeConvert(MyType.class)); + assertThat(new String(bytes, StandardCharsets.UTF_8), equalTo("{}")); + + bytes = serializer.toBuffer(new MyType().setValue("Hello"), TypeSchema.typeConvert(MyType.class)); + assertThat(new String(bytes, StandardCharsets.UTF_8), equalTo("{\"value\":\"Hello\"}")); + + MyType array[] = new MyType[2]; + array[0] = new MyType().setValue("hello"); + array[1] = new MyType().setValue("world"); + bytes = serializer.toBuffer(array, TypeSchema.typeConvert(MyType[].class)); + + byte[] buffer = "[{\"value\":\"hello\"},{\"value\":\"world\"}]".getBytes(StandardCharsets.UTF_8); + + System.out.println(new String(buffer,StandardCharsets.UTF_8)); + System.out.println(new String(bytes,StandardCharsets.UTF_8)); + assertThat(bytes, equalTo(buffer)); + } + + @Test + public void fromBufferObject() { + byte[] buffer = "[{\"value\":\"hello\"},{\"value\":\"world\"}]".getBytes(StandardCharsets.UTF_8); + + TypeRegistry tr = new TypeRegistryImpl(); + tr.addDataType(MyType.class); + + MetadataBuilder.addComponent(tr.getDataType("MyType")); + + JSONTransactionSerializer serializer = new JSONTransactionSerializer(tr); + TypeSchema ts = TypeSchema.typeConvert(MyType[].class); + MyType[] o = (MyType[]) serializer.fromBuffer(buffer, ts); + assertThat(o[0].toString(),equalTo("++++ MyType: hello")); + assertThat(o[1].toString(),equalTo("++++ MyType: world")); + + } + + @Test + public void toBufferPrimitive() { + TypeRegistry tr = new TypeRegistryImpl(); + JSONTransactionSerializer serializer = new JSONTransactionSerializer(tr); + + TypeSchema ts; + Object value; + byte[] buffer; + + ts = TypeSchema.typeConvert(boolean.class); + value = false; + buffer =serializer.toBuffer(value, ts); + assertThat(buffer,equalTo(new byte[] {102, 97, 108, 115, 101})); + assertThat(serializer.fromBuffer(buffer, ts),equalTo(false)); + + ts = TypeSchema.typeConvert(int.class); + value = 1; + buffer =serializer.toBuffer(value, ts); + assertThat(buffer,equalTo(new byte[] {49})); + assertThat(serializer.fromBuffer(buffer, ts),equalTo(1)); + + ts = TypeSchema.typeConvert(long.class); + value = 9192631770l; + buffer =serializer.toBuffer(value, ts); + assertThat(buffer,equalTo(new byte[] {57, 49, 57, 50, 54, 51, 49, 55, 55, 48})); + assertThat(serializer.fromBuffer(buffer, ts),equalTo(9192631770l)); + + ts = TypeSchema.typeConvert(float.class); + float f = 3.1415927F; + buffer =serializer.toBuffer(f, ts); + assertThat(buffer,equalTo(new byte[] {51, 46, 49, 52, 49, 53, 57, 50, 55})); + assertThat(serializer.fromBuffer(buffer, ts),equalTo(3.1415927F)); + + ts = TypeSchema.typeConvert(double.class); + double d = 2.7182818284590452353602874713527; + buffer =serializer.toBuffer(d, ts); + assertThat(buffer,equalTo(new byte[] {50, 46, 55, 49, 56, 50, 56, 49, 56, 50, 56, 52, 53, 57, 48, 52, 53})); + assertThat(serializer.fromBuffer(buffer, ts),equalTo(2.7182818284590452353602874713527)); + } + + @Test + public void fromBufferErrors() { + TypeRegistry tr = new TypeRegistryImpl(); + tr.addDataType(MyType.class); + MetadataBuilder.addComponent(tr.getDataType("MyType")); + JSONTransactionSerializer serializer = new JSONTransactionSerializer(tr); + TypeSchema ts = TypeSchema.typeConvert(MyType[].class); + serializer.toBuffer(null, ts); + } + + + +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java new file mode 100644 index 00000000..c8135872 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java @@ -0,0 +1,77 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.metadata; + +import java.io.InputStream; +import java.io.Serializable; +import java.util.HashMap; + +import org.everit.json.schema.loader.SchemaClient; +import org.everit.json.schema.loader.internal.DefaultSchemaClient; +import org.hyperledger.fabric.contract.ChaincodeStubNaiveImpl; +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.routing.ContractDefinition; +import org.hyperledger.fabric.contract.routing.impl.ContractDefinitionImpl; +import org.hyperledger.fabric.contract.systemcontract.SystemContract; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import contract.SampleContract; + +public class MetadataBuilderTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + String expectedMetadataString = " {\n" + " \"components\": {\"schemas\": {}},\n" + + " \"$schema\": \"https://fabric-shim.github.io/contract-schema.json\",\n" + + " \"contracts\": {\"SampleContract\": {\n" + " \"name\": \"SampleContract\",\n" + + " \"transactions\": [],\n" + " \"info\": {\n" + + " \"license\": {\"name\": \"\"},\n" + " \"description\": \"\",\n" + + " \"termsOfService\": \"\",\n" + " \"title\": \"\",\n" + + " \"version\": \"\",\n" + " \"contact\": {\"email\": \"fred@example.com\"}\n" + + " }\n" + " }},\n" + " \"info\": {\n" + " \"license\": {\"name\": \"\"},\n" + + " \"description\": \"\",\n" + " \"termsOfService\": \"\",\n" + + " \"title\": \"\",\n" + " \"version\": \"\",\n" + + " \"contact\": {\"email\": \"fred@example.com\"}\n" + " }\n" + " }\n" + ""; + + @Before + @After + public void beforeAndAfterEach() { + MetadataBuilder.componentMap = new HashMap(); + MetadataBuilder.contractMap = new HashMap>(); + MetadataBuilder.overallInfoMap = new HashMap(); + MetadataBuilder.schemaClient = new DefaultSchemaClient(); + } + + @Test + public void systemContract() { + + SystemContract system = new SystemContract(); + ChaincodeStub stub = new ChaincodeStubNaiveImpl(); + // TODO: Assert something about the returned metadata + system.getMetadata(new Context(stub)); + } + + @Test + public void defaultSchemasNotLoadedFromNetwork() { + ContractDefinition contractDefinition = new ContractDefinitionImpl(SampleContract.class); + MetadataBuilder.addContract(contractDefinition); + MetadataBuilder.schemaClient = new SchemaClient(){ + + @Override + public InputStream get(String uri) { + throw new RuntimeException("Refusing to load schema: " + uri); + } + + }; + MetadataBuilder.validate(); + } + +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java new file mode 100644 index 00000000..d8b1b3bc --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java @@ -0,0 +1,199 @@ + +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.metadata; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; + +import org.hyperledger.fabric.contract.annotation.DataType; +import org.hyperledger.fabric.contract.routing.DataTypeDefinition; +import org.hyperledger.fabric.contract.routing.TypeRegistry; +import org.hyperledger.fabric.contract.routing.impl.DataTypeDefinitionImpl; +import org.hyperledger.fabric.contract.routing.impl.TypeRegistryImpl; +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class TypeSchemaTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void beforeEach() { + } + + @Test + public void putIfNotNull() { + TypeSchema ts = new TypeSchema(); + + ts.putIfNotNull("Key", "value"); + String nullstr = null; + ts.putIfNotNull("Key", nullstr); + + assertThat(ts.get("Key"), equalTo("value")); + ts.putIfNotNull("Key", ""); + + assertThat(ts.get("Key"), equalTo("value")); + } + + @Test + public void getType() { + TypeSchema ts = new TypeSchema(); + ts.put("type", "MyType"); + assertThat(ts.getType(), equalTo("MyType")); + + TypeSchema wrapper = new TypeSchema(); + wrapper.put("schema", ts); + assertThat(wrapper.getType(), equalTo("MyType")); + } + + @Test + public void getFormat() { + TypeSchema ts = new TypeSchema(); + ts.put("format", "MyFormat"); + assertThat(ts.getFormat(), equalTo("MyFormat")); + + TypeSchema wrapper = new TypeSchema(); + wrapper.put("schema", ts); + assertThat(wrapper.getFormat(), equalTo("MyFormat")); + } + + @Test + public void getRef() { + TypeSchema ts = new TypeSchema(); + ts.put("$ref", "#/ref/to/MyType"); + assertThat(ts.getRef(), equalTo("#/ref/to/MyType")); + + TypeSchema wrapper = new TypeSchema(); + wrapper.put("schema", ts); + assertThat(wrapper.getRef(), equalTo("#/ref/to/MyType")); + } + + @Test + public void getItems() { + TypeSchema ts1 = new TypeSchema(); + + TypeSchema ts = new TypeSchema(); + ts.put("items", ts1); + assertThat(ts.getItems(), equalTo(ts1)); + + TypeSchema wrapper = new TypeSchema(); + wrapper.put("schema", ts); + assertThat(wrapper.getItems(), equalTo(ts1)); + } + + @DataType + class MyType { + } + + @Test + public void getTypeClass() { + TypeSchema ts = new TypeSchema(); + + ts.put("type", "string"); + TypeRegistry mockRegistry = new TypeRegistryImpl(); + assertThat(ts.getTypeClass(mockRegistry), equalTo(String.class)); + + ts.put("type", "integer"); + assertThat(ts.getTypeClass(mockRegistry), equalTo(int.class)); + + ts.put("type", "boolean"); + assertThat(ts.getTypeClass(mockRegistry), equalTo(boolean.class)); + + ts.put("type", null); + ts.put("$ref", "#/ref/to/MyType"); + + mockRegistry.addDataType(MyType.class); + assertThat(ts.getTypeClass(mockRegistry), equalTo(MyType.class)); + + TypeSchema array = new TypeSchema(); + array.put("type", "array"); + array.put("items", ts); + assertThat(array.getTypeClass(mockRegistry), equalTo(MyType[].class)); + + } + + @Test + public void TypeConvertPrimitives() { + TypeSchema rts; + + String[] array = new String[] {}; + rts = TypeSchema.typeConvert(array.getClass()); + assertThat(rts.getType(), equalTo("array")); + + rts = TypeSchema.typeConvert(int.class); + assertThat(rts.getType(), equalTo("integer")); + + rts = TypeSchema.typeConvert(long.class); + assertThat(rts.getType(), equalTo("integer")); + + rts = TypeSchema.typeConvert(float.class); + assertThat(rts.getType(), equalTo("number")); + + rts = TypeSchema.typeConvert(double.class); + assertThat(rts.getType(), equalTo("number")); + + rts = TypeSchema.typeConvert(byte.class); + assertThat(rts.getType(), equalTo("integer")); + + rts = TypeSchema.typeConvert(short.class); + assertThat(rts.getType(), equalTo("integer")); + + rts = TypeSchema.typeConvert(boolean.class); + assertThat(rts.getType(), equalTo("boolean")); + + } + + @Test + public void TypeConvertObjects() { + TypeSchema rts; + rts = TypeSchema.typeConvert(String.class); + assertThat(rts.getType(), equalTo("string")); + + String[] array = new String[] {}; + rts = TypeSchema.typeConvert(array.getClass()); + assertThat(rts.getType(), equalTo("array")); + + rts = TypeSchema.typeConvert(Integer.class); + assertThat(rts.getType(), equalTo("integer")); + + rts = TypeSchema.typeConvert(Long.class); + assertThat(rts.getType(), equalTo("integer")); + + rts = TypeSchema.typeConvert(Float.class); + assertThat(rts.getType(), equalTo("number")); + + rts = TypeSchema.typeConvert(Double.class); + assertThat(rts.getType(), equalTo("number")); + + rts = TypeSchema.typeConvert(Byte.class); + assertThat(rts.getType(), equalTo("integer")); + + rts = TypeSchema.typeConvert(Short.class); + assertThat(rts.getType(), equalTo("integer")); + + rts = TypeSchema.typeConvert(Boolean.class); + assertThat(rts.getType(), equalTo("boolean")); + + rts = TypeSchema.typeConvert(MyType.class); + assertThat(rts.getRef(), equalTo("#/components/schemas/TypeSchemaTest$MyType")); + } + + @Test + public void validate() { + + TypeSchema ts = TypeSchema.typeConvert(org.hyperledger.fabric.contract.MyType.class); + DataTypeDefinition dtd = new DataTypeDefinitionImpl(org.hyperledger.fabric.contract.MyType.class); + + MetadataBuilder.addComponent(dtd); + JSONObject json = new JSONObject(); + ts.validate(json); + + } +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java new file mode 100644 index 00000000..c4d707be --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java @@ -0,0 +1,101 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertThat; + +import java.lang.reflect.Method; +import java.security.Permission; + +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.ContractRuntimeException; +import org.hyperledger.fabric.contract.annotation.Contract; +import org.hyperledger.fabric.contract.routing.impl.ContractDefinitionImpl; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import contract.SampleContract; +import org.hyperledger.fabric.contract.annotation.Info; + +public class ContractDefinitionTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void beforeEach() { + } + + @Test + public void constructor() throws NoSuchMethodException, SecurityException { + + ContractDefinition cf = new ContractDefinitionImpl(SampleContract.class); + assertThat(cf.toString(), startsWith("samplecontract:")); + } + + @Contract(name = "", info = @Info()) + public class FailureTestObject { + + } + + public boolean fail; + public int step = 1; + + @Test + public void unknownRoute() { + + SecurityManager tmp = new SecurityManager() { + int count = 0; + + @Override + public void checkPackageAccess(String pkg) { + + if (pkg.startsWith("org.hyperledger.fabric.contract")) { + if (count >= step) { + throw new SecurityException("Sorry I can't do that"); + } + count++; + } + super.checkPackageAccess(pkg); + } + + @Override + public void checkPermission(Permission perm) { + return; + } + }; + + try { + ContractDefinition cf = new ContractDefinitionImpl(SampleContract.class); + System.setSecurityManager(tmp); + this.fail = true; + + cf.getUnknownRoute(); + } catch (Exception e) { + assertThat(e.getMessage(), equalTo("Failure to find unknownTransation method")); + } finally { + System.setSecurityManager(null); + } + } + + @Test + public void duplicateTransaction() throws NoSuchMethodException, SecurityException { + ContractDefinition cf = new ContractDefinitionImpl(SampleContract.class); + + ContractInterface contract = new SampleContract(); + Method m = contract.getClass().getMethod("t2", new Class[] { Context.class }); + + thrown.expect(ContractRuntimeException.class); + thrown.expectMessage("Duplicate transaction method t2"); + + cf.addTxFunction(m); + cf.addTxFunction(m); + } +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java new file mode 100644 index 00000000..279d38fc --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java @@ -0,0 +1,57 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasKey; +import static org.junit.Assert.assertThat; + +import java.util.Map; + +import org.hyperledger.fabric.contract.MyType2; +import org.hyperledger.fabric.contract.routing.impl.DataTypeDefinitionImpl; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class DataTypeDefinitionTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void beforeEach() { + } + + @Test + public void constructor() { + DataTypeDefinitionImpl dtd = new DataTypeDefinitionImpl(MyType2.class); + assertThat(dtd.getTypeClass(), equalTo(MyType2.class)); + assertThat(dtd.getName(), equalTo("org.hyperledger.fabric.contract.MyType2")); + assertThat(dtd.getSimpleName(), equalTo("MyType2")); + + Map properties = dtd.getProperties(); + assertThat(properties.size(), equalTo(2)); + assertThat(properties, hasKey("value")); + assertThat(properties, hasKey("constrainedValue")); + + PropertyDefinition pd = properties.get("constrainedValue"); + Map ts = pd.getSchema(); + + assertThat(ts, hasEntry("title", "MrProperty")); + assertThat(ts, hasEntry("Pattern", "[a-z]")); + assertThat(ts, hasEntry("uniqueItems", false)); + assertThat(ts, hasEntry("required", new String[] {"true","false"})); + assertThat(ts, hasEntry("enum", new String[] {"a","bee","cee","dee"})); + assertThat(ts, hasEntry("minimum", 42)); + + + } + + + +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java new file mode 100644 index 00000000..7813bbe8 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java @@ -0,0 +1,37 @@ + +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; + +import java.lang.reflect.Parameter; + +import org.hyperledger.fabric.contract.metadata.TypeSchema; +import org.hyperledger.fabric.contract.routing.impl.ParameterDefinitionImpl; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class ParameterDefinitionTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void beforeEach() { + } + + @Test + public void constructor() throws NoSuchMethodException, SecurityException { + Parameter params[] = String.class.getMethod("concat", String.class).getParameters(); + ParameterDefinition pd = new ParameterDefinitionImpl("test",String.class, new TypeSchema(),params[0]); + assertThat(pd.toString(),equalTo("test-class java.lang.String-{}-java.lang.String arg0")); + assertThat(pd.getTypeClass(), equalTo(String.class)); + assertThat(pd.getParameter(), equalTo(params[0])); + } +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java new file mode 100644 index 00000000..8f6d678d --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java @@ -0,0 +1,40 @@ + +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; + +import java.lang.reflect.Field; + +import org.hyperledger.fabric.contract.metadata.TypeSchema; +import org.hyperledger.fabric.contract.routing.impl.PropertyDefinitionImpl; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class PropertyDefinitionTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void beforeEach() { + } + + @Test + public void constructor() throws NoSuchMethodException, SecurityException { + Field props[] = String.class.getFields(); + TypeSchema ts = new TypeSchema(); + PropertyDefinition pd = new PropertyDefinitionImpl("test", String.class, ts, props[0]); + + assertThat(pd.getTypeClass(), equalTo(String.class)); + assertThat(pd.getField(), equalTo(props[0])); + assertThat(pd.getSchema(), equalTo(ts)); + assertThat(pd.getName(), equalTo("test")); + }; +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java new file mode 100644 index 00000000..1a43ef16 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java @@ -0,0 +1,99 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.ContractRuntimeException; +import org.hyperledger.fabric.contract.annotation.Property; +import org.hyperledger.fabric.contract.annotation.Transaction; +import org.hyperledger.fabric.contract.metadata.TypeSchema; +import org.hyperledger.fabric.contract.routing.impl.TxFunctionImpl; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class TxFunctionTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + class TestObject implements ContractInterface { + + @Transaction() + public void testMethod1(Context ctx) { + + } + + @Transaction() + public void testMethod2(Context ctx, @Property(schema = { "a", "b" }) int arg) { + + } + + @Transaction() + public void wibble(String arg1) { + + } + } + + @Before + public void beforeEach() { + } + + @Test + public void constructor() throws NoSuchMethodException, SecurityException { + TestObject test = new TestObject(); + ContractDefinition cd = mock(ContractDefinition.class); + + TxFunction txfn = new TxFunctionImpl(test.getClass().getMethod("testMethod1", new Class[] { Context.class }), + cd); + String name = txfn.getName(); + assertEquals(name, "testMethod1"); + + assertThat(txfn.toString(), startsWith("testMethod1")); + } + + @Test + public void property() throws NoSuchMethodException, SecurityException { + TestObject test = new TestObject(); + ContractDefinition cd = mock(ContractDefinition.class); + + TxFunction txfn = new TxFunctionImpl( + test.getClass().getMethod("testMethod2", new Class[] { Context.class, int.class }), cd); + String name = txfn.getName(); + assertEquals(name, "testMethod2"); + + assertThat(txfn.toString(), startsWith("testMethod2")); + assertFalse(txfn.isUnknownTx()); + txfn.setUnknownTx(true); + assertTrue(txfn.isUnknownTx()); + + TypeSchema ts = new TypeSchema(); + txfn.setReturnSchema(ts); + TypeSchema rts = txfn.getReturnSchema(); + System.out.println(ts); + assertEquals(ts, rts); + + } + + @Test + public void invaldtxfn() throws NoSuchMethodException, SecurityException { + TestObject test = new TestObject(); + ContractDefinition cd = mock(ContractDefinition.class); + + thrown.expect(ContractRuntimeException.class); + new TxFunctionImpl(test.getClass().getMethod("wibble", new Class[] { String.class }), cd); + + } + +} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java new file mode 100644 index 00000000..b86a16b6 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java @@ -0,0 +1,59 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.routing; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; + +import java.util.Collection; + +import org.hyperledger.fabric.contract.routing.impl.DataTypeDefinitionImpl; +import org.hyperledger.fabric.contract.routing.impl.TypeRegistryImpl; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class TypeRegistryTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void beforeEach() { + } + + @Test + public void addDataType() { + TypeRegistryImpl tr = new TypeRegistryImpl(); + tr.addDataType(String.class); + + DataTypeDefinition drt = tr.getDataType("String"); + assertThat(drt.getName(), equalTo("java.lang.String")); + } + + @Test + public void addDataTypeDefinition() { + DataTypeDefinitionImpl dtd = new DataTypeDefinitionImpl(String.class); + TypeRegistryImpl tr = new TypeRegistryImpl(); + tr.addDataType(dtd); + + DataTypeDefinition drt = tr.getDataType("java.lang.String"); + assertThat(drt.getName(), equalTo("java.lang.String")); + } + + @Test + public void getAllDataTypes() { + + TypeRegistryImpl tr = new TypeRegistryImpl(); + tr.addDataType(String.class); + tr.addDataType(Integer.class); + tr.addDataType(Float.class); + + Collection c = tr.getAllDataTypes(); + assertThat(c.size(), equalTo(3)); + } + +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePath.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePath.java new file mode 100644 index 00000000..99c385c3 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePath.java @@ -0,0 +1,91 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.simplepath; + +import static org.hamcrest.Matchers.is; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.READY; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.REGISTER; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.TRANSACTION; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.hyperledger.fabric.contract.ContractRouter; +import org.hyperledger.fabric.protos.peer.Chaincode; +import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeInput.Builder; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage; +import org.hyperledger.fabric.protos.peer.ProposalResponsePackage; +import org.hyperledger.fabric.protos.peer.ProposalResponsePackage.Response; +import org.hyperledger.fabric.shim.mock.peer.ChaincodeMockPeer; +import org.hyperledger.fabric.shim.mock.peer.RegisterStep; +import org.hyperledger.fabric.shim.mock.peer.ScenarioStep; +import org.hyperledger.fabric.shim.utils.MessageUtil; +import org.junit.After; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.EnvironmentVariables; +import org.junit.rules.ExpectedException; + +import com.google.protobuf.ByteString; + +public class ContractSimplePath { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Rule + public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + + ChaincodeMockPeer server; + + @After + public void afterTest() throws Exception { + if (server != null) { + server.stop(); + server = null; + } + } + + /** + * Test starting the contract logic + * + * @throws Exception + */ + @Test + public void testContract() throws Exception { + + List scenario = new ArrayList<>(); + scenario.add(new RegisterStep()); + setLogLevel("DEBUG"); + server = ChaincodeMockPeer.startServer(scenario); + ContractRouter.main(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); + + ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); + + assertThat(server.getLastMessageSend().getType(), is(READY)); + assertThat(server.getLastMessageRcvd().getType(), is(REGISTER)); + } + + public ChaincodeMessage newInvokeFn(String args[]) { + Builder invokePayload = Chaincode.ChaincodeInput.newBuilder(); + for (String arg : args) { + invokePayload.addArgs(ByteString.copyFromUtf8(arg)); + } + + return MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0", invokePayload.build().toByteString(), null); + } + + public String getLastReturnString() throws Exception { + Response resp = ProposalResponsePackage.Response.parseFrom(server.getLastMessageRcvd().getPayload()); + return (resp.getPayload().toStringUtf8()); + } + + public void setLogLevel(String logLevel) { + environmentVariables.set("CORE_CHAINCODE_LOGGING_SHIM", logLevel); + environmentVariables.set("CORE_CHAINCODE_LOGGING_LEVEL", logLevel); + } +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/MetricsTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/MetricsTest.java new file mode 100644 index 00000000..9e873fd2 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/MetricsTest.java @@ -0,0 +1,83 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.metrics; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Properties; + +import org.hyperledger.fabric.metrics.impl.DefaultProvider; +import org.hyperledger.fabric.metrics.impl.NullProvider; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class MetricsTest { + + static class TestProvider implements MetricsProvider { + + public TestProvider() { + + } + + @Override + public void setTaskMetricsCollector(TaskMetricsCollector taskService) { + } + + @Override + public void initialize(Properties props) { + } + + } + + @Nested + @DisplayName("Metrics initialize") + class Initalize { + + @Test + public void metricsDisabled() { + MetricsProvider provider = Metrics.initialize(new Properties()); + assertThat(provider).isExactlyInstanceOf(NullProvider.class); + } + + @Test + public void metricsEnabledUnkownProvider() { + Properties props = new Properties(); + props.put("CHAINCODE_METRICS_PROVIDER", "org.example.metrics.provider"); + props.put("CHAINCODE_METRICS_ENABLED", "true"); + + assertThrows(RuntimeException.class, () -> { + MetricsProvider provider = Metrics.initialize(props); + }, "Unable to start metrics"); + } + + @Test + public void metricsNoProvider() { + Properties props = new Properties(); + props.put("CHAINCODE_METRICS_ENABLED", "true"); + + MetricsProvider provider = Metrics.initialize(props); + assertTrue(provider instanceof DefaultProvider); + + } + + @Test + public void metricsValid() { + Properties props = new Properties(); + props.put("CHAINCODE_METRICS_PROVIDER", MetricsTest.TestProvider.class.getName()); + props.put("CHAINCODE_METRICS_ENABLED", "true"); + MetricsProvider provider = Metrics.initialize(props); + + assertThat(provider).isExactlyInstanceOf(MetricsTest.TestProvider.class); + } + + } + + + +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/impl/DefaultProviderTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/impl/DefaultProviderTest.java new file mode 100644 index 00000000..eae1829d --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/impl/DefaultProviderTest.java @@ -0,0 +1,88 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.metrics.impl; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Properties; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import org.hyperledger.fabric.metrics.MetricsProvider; +import org.hyperledger.fabric.metrics.TaskMetricsCollector; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +public class DefaultProviderTest { + + @Test + public void allMethods() { + MetricsProvider provider = new DefaultProvider(); + provider.setTaskMetricsCollector(new TaskMetricsCollector() { + + @Override + public int getPoolSize() { + return 0; + } + + @Override + public int getMaximumPoolSize() { + return 0; + } + + @Override + public int getLargestPoolSize() { + return 0; + } + + @Override + public int getCurrentTaskCount() { + return 0; + } + + @Override + public int getCurrentQueueCount() { + return 0; + } + + @Override + public int getCorePoolSize() { + return 0; + } + + @Override + public int getActiveCount() { + // TODO Auto-generated method stub + return 0; + } + }); + + Logger perfLogger = LogManager.getLogManager().getLogger("org.hyperledger.Performance"); + perfLogger.setLevel(Level.ALL); + + Handler mockHandler = Mockito.mock(Handler.class); + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(LogRecord.class); + perfLogger.addHandler(mockHandler); + + provider.initialize(new Properties()); + ((DefaultProvider)provider).logMetrics(); + try { + Thread.sleep(6000); + } catch (InterruptedException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + Mockito.verify(mockHandler,Mockito.atLeast(1)).publish(argumentCaptor.capture()) ; + LogRecord lr = argumentCaptor.getValue(); + String message = lr.getMessage(); + assertThat(message).contains("{ \"active_count\":0 , \"pool_size\":0 , \"core_pool_size\":0 , \"current_task_count\":0 , \"current_queue_depth\":0 " ); + + } + +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java index 3d08a3fc..ce7eb2ad 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java @@ -6,19 +6,30 @@ package org.hyperledger.fabric.shim; -import io.grpc.netty.NettyChannelBuilder; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.charset.Charset; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.Logger; + import org.hamcrest.Matchers; import org.hyperledger.fabric.shim.chaincode.EmptyChaincode; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.EnvironmentVariables; import org.junit.rules.ExpectedException; -import java.nio.charset.Charset; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static org.junit.Assert.*; +import io.grpc.netty.NettyChannelBuilder; public class ChaincodeBaseTest { @Rule @@ -27,76 +38,130 @@ public class ChaincodeBaseTest { @Rule public ExpectedException thrown = ExpectedException.none(); + @Test + public void testMapLevel() { + ChaincodeBase cb = new EmptyChaincode(); + assertEquals("Error maps", Level.SEVERE, proxyMapLevel(cb, "ERROR")); + assertEquals("Critical maps", Level.SEVERE, proxyMapLevel(cb, "critical")); + assertEquals("Warn maps", Level.WARNING, proxyMapLevel(cb, "WARNING")); + assertEquals("Info maps", Level.INFO, proxyMapLevel(cb, "INFO")); + assertEquals("Config maps", Level.CONFIG, proxyMapLevel(cb, " notice")); + assertEquals("Info maps", Level.INFO, proxyMapLevel(cb, " info")); + assertEquals("Debug maps", Level.FINEST, proxyMapLevel(cb, "debug ")); + assertEquals("Info maps", Level.INFO, proxyMapLevel(cb, "wibble ")); + } + + public Object proxyMapLevel(Object obj, Object... args) { + + try { + Method m = ChaincodeBase.class.getDeclaredMethod("mapLevel", String.class); + m.setAccessible(true); + return m.invoke(obj, args); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException e) { + throw new RuntimeException(e); + } + + } + @Test public void testNewSuccessResponseEmpty() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newSuccessResponse(); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); + org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse(); + assertEquals("Response status is incorrect", response.getStatus(), + org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); assertNull("Response message in not null", response.getMessage()); assertNull("Response payload in not null", response.getPayload()); } @Test public void testNewSuccessResponseWithMessage() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newSuccessResponse("Simple message"); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); + org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse("Simple message"); + assertEquals("Response status is incorrect", response.getStatus(), + org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); assertEquals("Response message in not correct", "Simple message", response.getMessage()); assertNull("Response payload in not null", response.getPayload()); } @Test public void testNewSuccessResponseWithPayload() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newSuccessResponse("Simple payload".getBytes(Charset.defaultCharset())); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); + org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils + .newSuccessResponse("Simple payload".getBytes(Charset.defaultCharset())); + assertEquals("Response status is incorrect", response.getStatus(), + org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); assertNull("Response message in not null", response.getMessage()); - assertArrayEquals("Response payload in not null", response.getPayload(), "Simple payload".getBytes(Charset.defaultCharset())); + assertArrayEquals("Response payload in not null", response.getPayload(), + "Simple payload".getBytes(Charset.defaultCharset())); } @Test public void testNewSuccessResponseWithMessageAndPayload() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newSuccessResponse("Simple message", "Simple payload".getBytes(Charset.defaultCharset())); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); + org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse("Simple message", + "Simple payload".getBytes(Charset.defaultCharset())); + assertEquals("Response status is incorrect", response.getStatus(), + org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); assertEquals("Response message in not correct", "Simple message", response.getMessage()); - assertArrayEquals("Response payload in not null", response.getPayload(), "Simple payload".getBytes(Charset.defaultCharset())); + assertArrayEquals("Response payload in not null", response.getPayload(), + "Simple payload".getBytes(Charset.defaultCharset())); } @Test public void testNewErrorResponseEmpty() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newErrorResponse(); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse(); + assertEquals("Response status is incorrect", response.getStatus(), + org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); assertNull("Response message in not null", response.getMessage()); assertNull("Response payload in not null", response.getPayload()); } @Test public void testNewErrorResponseWithMessage() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newErrorResponse("Simple message"); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse("Simple message"); + assertEquals("Response status is incorrect", response.getStatus(), + org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); assertEquals("Response message in not correct", "Simple message", response.getMessage()); assertNull("Response payload in not null", response.getPayload()); } @Test public void testNewErrorResponseWithPayload() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newErrorResponse("Simple payload".getBytes(Charset.defaultCharset())); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils + .newErrorResponse("Simple payload".getBytes(Charset.defaultCharset())); + assertEquals("Response status is incorrect", response.getStatus(), + org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); assertNull("Response message in not null", response.getMessage()); - assertArrayEquals("Response payload in not null", response.getPayload(), "Simple payload".getBytes(Charset.defaultCharset())); + assertArrayEquals("Response payload in not null", response.getPayload(), + "Simple payload".getBytes(Charset.defaultCharset())); } @Test public void testNewErrorResponseWithMessageAndPayload() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newErrorResponse("Simple message", "Simple payload".getBytes(Charset.defaultCharset())); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse("Simple message", + "Simple payload".getBytes(Charset.defaultCharset())); + assertEquals("Response status is incorrect", response.getStatus(), + org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); assertEquals("Response message in not correct", "Simple message", response.getMessage()); - assertArrayEquals("Response payload in not null", response.getPayload(), "Simple payload".getBytes(Charset.defaultCharset())); + assertArrayEquals("Response payload in not null", response.getPayload(), + "Simple payload".getBytes(Charset.defaultCharset())); } @Test public void testNewErrorResponseWithException() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newErrorResponse(new Exception("Simple exception")); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); - assertEquals("Response message in not correct", "Simple exception", response.getMessage()); - assertNotNull("Response payload in null", response.getPayload()); + org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils + .newErrorResponse(new Exception("Simple exception")); + assertEquals("Response status is incorrect", response.getStatus(), + org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + assertEquals("Response message is not correct", "Unexpected error", response.getMessage()); + assertNull("Response payload is not null", response.getPayload()); + } + + @Test + public void testNewErrorResponseWithChaincodeException() { + org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils + .newErrorResponse(new ChaincodeException("Chaincode exception")); + assertEquals("Response status is incorrect", response.getStatus(), + org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + assertEquals("Response message is not correct", "Chaincode exception", response.getMessage()); + assertNull("Response payload is not null", response.getPayload()); } @Test @@ -133,7 +198,7 @@ public void testOptions() throws Exception { fail("Wrong arguments"); } - cb.processCommandLineOptions(new String[]{"-i", "mycc1", "--peerAddress", "localhost.org:7053"}); + cb.processCommandLineOptions(new String[] { "-i", "mycc1", "--peerAddress", "localhost.org:7053" }); assertEquals("CCId incorrect", cb.getId(), "mycc1"); assertEquals("Host incorrect", cb.getHost(), "localhost.org"); assertEquals("Port incorrect", cb.getPort(), 7053); @@ -144,7 +209,7 @@ public void testOptions() throws Exception { fail("Wrong arguments"); } - cb.processCommandLineOptions(new String[]{"-i", "mycc1", "--peerAddress", "localhost1.org.7054"}); + cb.processCommandLineOptions(new String[] { "-i", "mycc1", "--peerAddress", "localhost1.org.7054" }); assertEquals("Host incorrect", cb.getHost(), "localhost.org"); assertEquals("Port incorrect", cb.getPort(), 7053); } @@ -181,6 +246,7 @@ public void testUnsetOptionClientKeyPath() { } @Test + @Ignore public void testNewChannelBuilder() throws Exception { ChaincodeBase cb = new EmptyChaincode(); @@ -198,32 +264,37 @@ public void testNewChannelBuilder() throws Exception { @Test public void testInitializeLogging() { - ChaincodeBase cb = new EmptyChaincode(); - + ChaincodeBase cb = new EmptyChaincode(); cb.processEnvironmentOptions(); cb.initializeLogging(); - assertEquals("Wrong log level for org.hyperledger.fabric.shim ", Level.INFO, Logger.getLogger("org.hyperledger.fabric.shim").getLevel()); - assertEquals("Wrong log level for " + cb.getClass().getPackage().getName(), Level.INFO, Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()); - setLogLevelForChaincode(environmentVariables, cb, "WRONG", "WRONG"); - assertEquals("Wrong log level for org.hyperledger.fabric.shim ", Level.INFO, Logger.getLogger("org.hyperledger.fabric.shim").getLevel()); - assertEquals("Wrong log level for " + cb.getClass().getPackage().getName(), Level.INFO, Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()); + assertTrue("Wrong log level for org.hyperledger.fabric.shim ", + Logger.getLogger("org.hyperledger.fabric.shim").isLoggable(Level.INFO)); + + setLogLevelForChaincode(environmentVariables, cb, "WRONG SO LOG AT INFO"); + assertTrue("Wrong log level for org.hyperledger.fabric.shim ", + Logger.getLogger("org.hyperledger.fabric.shim").isLoggable(Level.INFO)); + + setLogLevelForChaincode(environmentVariables, cb, "NOTICE"); + assertTrue("Wrong log level for org.hyperledger.fabric.shim ", + Logger.getLogger("org.hyperledger.fabric.shim").isLoggable(Level.CONFIG)); - setLogLevelForChaincode(environmentVariables, cb, "DEBUG", "NOTICE"); - assertEquals("Wrong log level for org.hyperledger.fabric.shim ", Level.FINEST, Logger.getLogger("org.hyperledger.fabric.shim").getLevel()); - assertEquals("Wrong log level for " + cb.getClass().getPackage().getName(), Level.CONFIG, Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()); + setLogLevelForChaincode(environmentVariables, cb, "WARNING"); + assertTrue("Wrong log level for org.hyperledger.fabric.shim ", + Logger.getLogger("org.hyperledger.fabric.shim").isLoggable(Level.WARNING)); - setLogLevelForChaincode(environmentVariables, cb, "INFO", "WARNING"); - assertEquals("Wrong log level for org.hyperledger.fabric.shim ", Level.INFO, Logger.getLogger("org.hyperledger.fabric.shim").getLevel()); - assertEquals("Wrong log level for " + cb.getClass().getPackage().getName(), Level.WARNING, Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()); + setLogLevelForChaincode(environmentVariables, cb, "ERROR"); + assertTrue("Wrong log level for org.hyperledger.fabric.shim ", + Logger.getLogger("org.hyperledger.fabric.shim").isLoggable(Level.SEVERE)); - setLogLevelForChaincode(environmentVariables, cb, "CRITICAL", "ERROR"); - assertEquals("Wrong log level for org.hyperledger.fabric.shim ", Level.SEVERE, Logger.getLogger("org.hyperledger.fabric.shim").getLevel()); - assertEquals("Wrong log level for " + cb.getClass().getPackage().getName(), Level.SEVERE, Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()); + setLogLevelForChaincode(environmentVariables, cb, "DEBUG"); + assertTrue("Wrong log level for org.hyperledger.fabric.shim ", + Logger.getLogger("org.hyperledger.fabric.shim").isLoggable(Level.FINE)); } - public static void setLogLevelForChaincode(EnvironmentVariables environmentVariables, ChaincodeBase cb, String shimLevel, String chaincodeLelev) { - environmentVariables.set(ChaincodeBase.CORE_CHAINCODE_LOGGING_SHIM, shimLevel); + public static void setLogLevelForChaincode(EnvironmentVariables environmentVariables, ChaincodeBase cb, + String chaincodeLelev) { + environmentVariables.set(ChaincodeBase.CORE_CHAINCODE_LOGGING_LEVEL, chaincodeLelev); cb.processEnvironmentOptions(); cb.initializeLogging(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeStubTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeStubTest.java new file mode 100644 index 00000000..46087d91 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeStubTest.java @@ -0,0 +1,296 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.shim; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.hyperledger.fabric.protos.peer.ChaincodeEventPackage.ChaincodeEvent; +import org.hyperledger.fabric.protos.peer.ProposalPackage.SignedProposal; +import org.hyperledger.fabric.shim.Chaincode.Response; +import org.hyperledger.fabric.shim.ledger.CompositeKey; +import org.hyperledger.fabric.shim.ledger.KeyModification; +import org.hyperledger.fabric.shim.ledger.KeyValue; +import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; +import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata; +import org.junit.jupiter.api.Test; + +public class ChaincodeStubTest { + + class FakeStub implements ChaincodeStub { + + @Override + public List getArgs() { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getStringArgs() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getFunction() { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getParameters() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getTxId() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getChannelId() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Response invokeChaincode(String chaincodeName, List args, String channel) { + // TODO Auto-generated method stub + return null; + } + + @Override + public byte[] getState(String key) { + return key.getBytes(); + } + + @Override + public byte[] getStateValidationParameter(String key) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void putState(String key, byte[] value) { + // TODO Auto-generated method stub + + } + + @Override + public void setStateValidationParameter(String key, byte[] value) { + // TODO Auto-generated method stub + + } + + @Override + public void delState(String key) { + // TODO Auto-generated method stub + + } + + @Override + public QueryResultsIterator getStateByRange(String startKey, String endKey) { + // TODO Auto-generated method stub + return null; + } + + @Override + public QueryResultsIteratorWithMetadata getStateByRangeWithPagination(String startKey, String endKey, + int pageSize, String bookmark) { + // TODO Auto-generated method stub + return null; + } + + @Override + public QueryResultsIterator getStateByPartialCompositeKey(String compositeKey) { + // TODO Auto-generated method stub + return null; + } + + @Override + public QueryResultsIterator getStateByPartialCompositeKey(String objectType, String... attributes) { + // TODO Auto-generated method stub + return null; + } + + @Override + public QueryResultsIterator getStateByPartialCompositeKey(CompositeKey compositeKey) { + // TODO Auto-generated method stub + return null; + } + + @Override + public QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination( + CompositeKey compositeKey, int pageSize, String bookmark) { + // TODO Auto-generated method stub + return null; + } + + @Override + public CompositeKey createCompositeKey(String objectType, String... attributes) { + // TODO Auto-generated method stub + return null; + } + + @Override + public CompositeKey splitCompositeKey(String compositeKey) { + // TODO Auto-generated method stub + return null; + } + + @Override + public QueryResultsIterator getQueryResult(String query) { + // TODO Auto-generated method stub + return null; + } + + @Override + public QueryResultsIteratorWithMetadata getQueryResultWithPagination(String query, int pageSize, + String bookmark) { + // TODO Auto-generated method stub + return null; + } + + @Override + public QueryResultsIterator getHistoryForKey(String key) { + // TODO Auto-generated method stub + return null; + } + + @Override + public byte[] getPrivateData(String collection, String key) { + return collection.getBytes(); + } + + @Override + public byte[] getPrivateDataHash(String collection, String key) { + // TODO Auto-generated method stub + return null; + } + + @Override + public byte[] getPrivateDataValidationParameter(String collection, String key) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void putPrivateData(String collection, String key, byte[] value) { + // TODO Auto-generated method stub + + } + + @Override + public void setPrivateDataValidationParameter(String collection, String key, byte[] value) { + // TODO Auto-generated method stub + + } + + @Override + public void delPrivateData(String collection, String key) { + // TODO Auto-generated method stub + + } + + @Override + public QueryResultsIterator getPrivateDataByRange(String collection, String startKey, String endKey) { + // TODO Auto-generated method stub + return null; + } + + @Override + public QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, + String compositeKey) { + // TODO Auto-generated method stub + return null; + } + + @Override + public QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, + CompositeKey compositeKey) { + // TODO Auto-generated method stub + return null; + } + + @Override + public QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, String objectType, + String... attributes) { + // TODO Auto-generated method stub + return null; + } + + @Override + public QueryResultsIterator getPrivateDataQueryResult(String collection, String query) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setEvent(String name, byte[] payload) { + // TODO Auto-generated method stub + + } + + @Override + public ChaincodeEvent getEvent() { + // TODO Auto-generated method stub + return null; + } + + @Override + public SignedProposal getSignedProposal() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Instant getTxTimestamp() { + // TODO Auto-generated method stub + return null; + } + + @Override + public byte[] getCreator() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map getTransient() { + // TODO Auto-generated method stub + return null; + } + + @Override + public byte[] getBinding() { + // TODO Auto-generated method stub + return null; + } + + } + + + @Test + public void testDefaultMethods() { + ChaincodeStub stub = new FakeStub(); + String chaincodeName = "ACME_SHIPPING"; + + stub.invokeChaincode(chaincodeName, new ArrayList()); + stub.invokeChaincodeWithStringArgs(chaincodeName, new ArrayList(),"channel"); + stub.invokeChaincodeWithStringArgs(chaincodeName, new ArrayList()); + stub.invokeChaincodeWithStringArgs(chaincodeName, "anvil","tnt"); + + stub.getStringState("key"); + stub.putPrivateData("collection", "key", "value"); + stub.getPrivateDataUTF8("collection", "key"); + stub.putStringState("key", "value"); + } + +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/chaincode/EmptyChaincode.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/chaincode/EmptyChaincode.java index 346ecada..61fe47ee 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/chaincode/EmptyChaincode.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/chaincode/EmptyChaincode.java @@ -7,15 +7,16 @@ import org.hyperledger.fabric.shim.ChaincodeBase; import org.hyperledger.fabric.shim.ChaincodeStub; +import org.hyperledger.fabric.shim.ResponseUtils; public class EmptyChaincode extends ChaincodeBase { @Override public Response init(ChaincodeStub stub) { - return newSuccessResponse(); + return ResponseUtils.newSuccessResponse(); } @Override public Response invoke(ChaincodeStub stub) { - return newSuccessResponse(); + return ResponseUtils.newSuccessResponse(); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java index 2fdfc2c0..e0f5beb1 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java @@ -5,39 +5,62 @@ */ package org.hyperledger.fabric.shim.fvt; +import static org.hamcrest.Matchers.is; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.COMPLETED; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.ERROR; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.INIT; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.READY; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.REGISTER; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.RESPONSE; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.TRANSACTION; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + import com.google.protobuf.ByteString; + import org.hyperledger.fabric.protos.peer.Chaincode; import org.hyperledger.fabric.protos.peer.ChaincodeShim; import org.hyperledger.fabric.protos.peer.ProposalResponsePackage; import org.hyperledger.fabric.shim.ChaincodeBase; import org.hyperledger.fabric.shim.ChaincodeStub; +import org.hyperledger.fabric.shim.ResponseUtils; import org.hyperledger.fabric.shim.chaincode.EmptyChaincode; import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement; import org.hyperledger.fabric.shim.ext.sbe.impl.StateBasedEndorsementFactory; import org.hyperledger.fabric.shim.ledger.KeyModification; import org.hyperledger.fabric.shim.ledger.KeyValue; import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; -import org.hyperledger.fabric.shim.mock.peer.*; +import org.hyperledger.fabric.shim.mock.peer.ChaincodeMockPeer; +import org.hyperledger.fabric.shim.mock.peer.CompleteStep; +import org.hyperledger.fabric.shim.mock.peer.DelValueStep; +import org.hyperledger.fabric.shim.mock.peer.ErrorResponseStep; +import org.hyperledger.fabric.shim.mock.peer.GetHistoryForKeyStep; +import org.hyperledger.fabric.shim.mock.peer.GetQueryResultStep; +import org.hyperledger.fabric.shim.mock.peer.GetStateByRangeStep; +import org.hyperledger.fabric.shim.mock.peer.GetStateMetadata; +import org.hyperledger.fabric.shim.mock.peer.GetValueStep; +import org.hyperledger.fabric.shim.mock.peer.InvokeChaincodeStep; +import org.hyperledger.fabric.shim.mock.peer.PutStateMetadata; +import org.hyperledger.fabric.shim.mock.peer.PutValueStep; +import org.hyperledger.fabric.shim.mock.peer.QueryCloseStep; +import org.hyperledger.fabric.shim.mock.peer.QueryNextStep; +import org.hyperledger.fabric.shim.mock.peer.RegisterStep; +import org.hyperledger.fabric.shim.mock.peer.ScenarioStep; import org.hyperledger.fabric.shim.utils.MessageUtil; -import org.hyperledger.fabric.shim.utils.TimeoutUtil; import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.EnvironmentVariables; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static org.hamcrest.Matchers.is; -import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.*; -import static org.junit.Assert.*; - public class ChaincodeFVTest { @Rule @@ -64,7 +87,7 @@ public void testRegister() throws Exception { cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"}); - checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(READY)); assertThat(server.getLastMessageRcvd().getType(), is(REGISTER)); @@ -75,12 +98,12 @@ public void testRegisterAndEmptyInit() throws Exception { ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(ChaincodeStub stub) { - return newSuccessResponse(); + return ResponseUtils.newSuccessResponse(); } @Override public Response invoke(ChaincodeStub stub) { - return newSuccessResponse(); + return ResponseUtils.newSuccessResponse(); } }; @@ -94,10 +117,10 @@ public Response invoke(ChaincodeStub stub) { server = ChaincodeMockPeer.startServer(scenario); cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"}); - checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); server.send(initMsg); - checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(INIT)); assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); @@ -111,7 +134,7 @@ public Response init(ChaincodeStub stub) { assertThat(stub.getFunction(), is("init")); assertThat(stub.getArgs().size(), is(3)); stub.putState("a", ByteString.copyFromUtf8("100").toByteArray()); - return newSuccessResponse("OK response1"); + return ResponseUtils.newSuccessResponse("OK response1"); } @Override @@ -120,10 +143,10 @@ public Response invoke(ChaincodeStub stub) { assertThat(stub.getArgs().size(), is(3)); String aKey = stub.getStringArgs().get(1); assertThat(aKey, is("a")); - String aVal = stub.getStringState(aKey); + stub.getStringState(aKey); stub.putState(aKey, ByteString.copyFromUtf8("120").toByteArray()); stub.delState("delKey"); - return newSuccessResponse("OK response2"); + return ResponseUtils.newSuccessResponse("OK response2"); } }; @@ -147,10 +170,10 @@ public Response invoke(ChaincodeStub stub) { server = ChaincodeMockPeer.startServer(scenario); cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"}); - checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); server.send(initMsg); - checkScenarioStepEnded(server, 3, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 3, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(RESPONSE)); assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); @@ -166,7 +189,7 @@ public Response invoke(ChaincodeStub stub) { server.send(invokeMsg); - checkScenarioStepEnded(server, 7, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 7, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(RESPONSE)); assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); assertThat(ProposalResponsePackage.Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2")); @@ -177,7 +200,7 @@ public void testStateValidationParameter() throws Exception { ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(ChaincodeStub stub) { - return newSuccessResponse("OK response1"); + return ResponseUtils.newSuccessResponse("OK response1"); } @Override @@ -187,7 +210,7 @@ public Response invoke(ChaincodeStub stub) { StateBasedEndorsement stateBasedEndorsement = StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(epBytes); assertThat(stateBasedEndorsement.listOrgs().size(), is(2)); stub.setStateValidationParameter(aKey, stateBasedEndorsement.policy()); - return newSuccessResponse("OK response2"); + return ResponseUtils.newSuccessResponse("OK response2"); } }; @@ -212,10 +235,10 @@ public Response invoke(ChaincodeStub stub) { server = ChaincodeMockPeer.startServer(scenario); cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"}); - checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); server.send(initMsg); - checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(INIT)); assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); @@ -230,7 +253,7 @@ public Response invoke(ChaincodeStub stub) { server.send(invokeMsg); - checkScenarioStepEnded(server, 5, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 5, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(RESPONSE)); assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); assertThat(ProposalResponsePackage.Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2")); @@ -241,7 +264,7 @@ public void testInvokeRangeQ() throws Exception { ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(ChaincodeStub stub) { - return newSuccessResponse("OK response1"); + return ResponseUtils.newSuccessResponse("OK response1"); } @Override @@ -261,7 +284,7 @@ public Response invoke(ChaincodeStub stub) { } catch (Exception e) { fail("No exception expected"); } - return newSuccessResponse("OK response2"); + return ResponseUtils.newSuccessResponse("OK response2"); } }; @@ -292,22 +315,22 @@ public Response invoke(ChaincodeStub stub) { server = ChaincodeMockPeer.startServer(scenario); cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"}); - checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); server.send(initMsg); - checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); server.send(invokeMsg); - checkScenarioStepEnded(server, 5, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 5, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(RESPONSE)); assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); assertThat(ProposalResponsePackage.Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2")); server.send(invokeMsg); - checkScenarioStepEnded(server, 9, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 9, 10000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(RESPONSE)); assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); assertThat(ProposalResponsePackage.Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2")); @@ -318,7 +341,7 @@ public void testGetQueryResult() throws Exception { ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(ChaincodeStub stub) { - return newSuccessResponse("OK response1"); + return ResponseUtils.newSuccessResponse("OK response1"); } @Override @@ -335,7 +358,7 @@ public Response invoke(ChaincodeStub stub) { } catch (Exception e) { fail("No exception expected"); } - return newSuccessResponse("OK response2"); + return ResponseUtils.newSuccessResponse("OK response2"); } }; @@ -365,21 +388,21 @@ public Response invoke(ChaincodeStub stub) { server = ChaincodeMockPeer.startServer(scenario); cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"}); - checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); server.send(initMsg); - checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); server.send(invokeMsg); - checkScenarioStepEnded(server, 5, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 5, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(RESPONSE)); assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); assertThat(ProposalResponsePackage.Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2")); server.send(invokeMsg); - checkScenarioStepEnded(server, 9, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 9, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(RESPONSE)); assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); assertThat(ProposalResponsePackage.Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2")); @@ -390,7 +413,7 @@ public void testGetHistoryForKey() throws Exception { ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(ChaincodeStub stub) { - return newSuccessResponse("OK response1"); + return ResponseUtils.newSuccessResponse("OK response1"); } @Override @@ -407,7 +430,7 @@ public Response invoke(ChaincodeStub stub) { } catch (Exception e) { fail("No exception expected"); } - return newSuccessResponse("OK response2"); + return ResponseUtils.newSuccessResponse("OK response2"); } }; @@ -433,14 +456,14 @@ public Response invoke(ChaincodeStub stub) { server = ChaincodeMockPeer.startServer(scenario); cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"}); - checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); server.send(initMsg); - checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); server.send(invokeMsg); - checkScenarioStepEnded(server, 5, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 5, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(RESPONSE)); assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); assertThat(ProposalResponsePackage.Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2")); @@ -452,13 +475,13 @@ public void testInvokeChaincode() throws Exception { ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(ChaincodeStub stub) { - return newSuccessResponse("OK response1"); + return ResponseUtils.newSuccessResponse("OK response1"); } @Override public Response invoke(ChaincodeStub stub) { - Response response = stub.invokeChaincode("anotherChaincode", Collections.EMPTY_LIST); - return newSuccessResponse("OK response2"); + stub.invokeChaincode("anotherChaincode", Collections.emptyList()); + return ResponseUtils.newSuccessResponse("OK response2"); } }; @@ -482,14 +505,14 @@ public Response invoke(ChaincodeStub stub) { server = ChaincodeMockPeer.startServer(scenario); cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"}); - checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); server.send(initMsg); - checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); server.send(invokeMsg); - checkScenarioStepEnded(server, 4, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 4, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(RESPONSE)); assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); } @@ -499,12 +522,12 @@ public void testErrorInitInvoke() throws Exception { ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(ChaincodeStub stub) { - return newErrorResponse("Wrong response1"); + return ResponseUtils.newErrorResponse("Wrong response1"); } @Override public Response invoke(ChaincodeStub stub) { - return newErrorResponse("Wrong response2"); + return ResponseUtils.newErrorResponse("Wrong response2"); } }; @@ -520,10 +543,10 @@ public Response invoke(ChaincodeStub stub) { server = ChaincodeMockPeer.startServer(scenario); cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"}); - checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); server.send(initMsg); - checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(INIT)); assertThat(server.getLastMessageRcvd().getType(), is(ERROR)); @@ -535,7 +558,7 @@ public Response invoke(ChaincodeStub stub) { server.send(invokeMsg); - checkScenarioStepEnded(server, 3, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 3, 5000, TimeUnit.MILLISECONDS); assertThat(server.getLastMessageSend().getType(), is(TRANSACTION)); assertThat(server.getLastMessageRcvd().getType(), is(ERROR)); assertThat(server.getLastMessageRcvd().getPayload().toStringUtf8(), is("Wrong response2")); @@ -550,12 +573,12 @@ public Response init(ChaincodeStub stub) { Thread.sleep(10); } catch (InterruptedException e) { } - return newSuccessResponse(); + return ResponseUtils.newSuccessResponse(); } @Override public Response invoke(ChaincodeStub stub) { - return newSuccessResponse(); + return ResponseUtils.newSuccessResponse(); } }; @@ -570,45 +593,12 @@ public Response invoke(ChaincodeStub stub) { server = ChaincodeMockPeer.startServer(scenario); cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"}); - checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); + ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); server.send(initMsg); server.stop(); server = null; } - @Test - public void testChaincodeLogLevel() throws Exception { - ChaincodeBase cb = new EmptyChaincode(); - - List scenario = new ArrayList<>(); - scenario.add(new RegisterStep()); - scenario.add(new CompleteStep()); - - setLogLevel("DEBUG"); - server = ChaincodeMockPeer.startServer(scenario); - - cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"}); - - assertEquals("Wrong debug level for " + cb.getClass().getPackage().getName(), Level.FINEST, Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()); - - } - - public static void checkScenarioStepEnded(final ChaincodeMockPeer s, final int step, final int timeout, final TimeUnit units) throws Exception { - try { - TimeoutUtil.runWithTimeout(new Thread(() -> { - while (true) { - if (s.getLastExecutedStep() == step) return; - try { - Thread.sleep(1); - } catch (InterruptedException e) { - } - } - }), timeout, units); - } catch (TimeoutException e) { - fail("Got timeout, step " + step + " not finished"); - } - } - public void setLogLevel(String logLevel) { environmentVariables.set("CORE_CHAINCODE_LOGGING_SHIM", logLevel); environmentVariables.set("CORE_CHAINCODE_LOGGING_LEVEL", logLevel); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/helper/ChannelTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/helper/ChannelTest.java deleted file mode 100644 index 559d454b..00000000 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/helper/ChannelTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ -package org.hyperledger.fabric.shim.helper; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static org.junit.Assert.*; - -public class ChannelTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - Channel testChannel = new Channel<>(); - - @Test - public void testChannel() throws InterruptedException { - testChannel.clear(); - testChannel.add(1); - testChannel.add(2); - assertEquals("Wrong item come out the channel", (long) 1, (long) testChannel.take()); - testChannel.close(); - thrown.expect(InterruptedException.class); - testChannel.take(); - thrown.expect(IllegalStateException.class); - testChannel.add(1); - } - -} \ No newline at end of file diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactoryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactoryTest.java new file mode 100644 index 00000000..4ba23c07 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactoryTest.java @@ -0,0 +1,94 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.shim.impl; + +import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeID; +import org.hyperledger.fabric.protos.peer.ChaincodeEventPackage.ChaincodeEvent; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type; +import org.hyperledger.fabric.shim.Chaincode.Response; +import org.hyperledger.fabric.shim.ResponseUtils; +import org.junit.jupiter.api.Test; + +import com.google.protobuf.ByteString; + +class ChaincodeMessageFactoryTest { + + private String txId = "txid"; + private String key = "key"; + private String channelId = "channelid"; + private String collection = "collectionId"; + private ByteString value = ByteString.copyFromUtf8("Hello");; + private String metakey = "metakey"; + private Throwable throwable = new Throwable(); + private String message ="message"; + private ChaincodeEvent event; + private Response response = ResponseUtils.newSuccessResponse();; + private ByteString payload = ByteString.copyFromUtf8("Hello"); + private ChaincodeID chaincodeId =ChaincodeID.newBuilder().setName("test").build(); + private Type type = ChaincodeMessage.Type.COMPLETED; + + @Test + void testNewGetPrivateDataHashEventMessage() { + ChaincodeMessageFactory.newGetPrivateDataHashEventMessage(channelId, txId, collection, key); + } + + @Test + void testNewGetStateEventMessage() { + ChaincodeMessageFactory.newGetStateEventMessage(channelId, txId, collection, key); + } + + @Test + void testNewGetStateMetadataEventMessage() { + ChaincodeMessageFactory.newGetStateMetadataEventMessage(channelId, txId, collection, key); + } + + @Test + void testNewPutStateEventMessage() { + ChaincodeMessageFactory.newPutStateEventMessage(channelId, txId, collection, key, value); + } + + @Test + void testNewPutStateMatadateEventMessage() { + ChaincodeMessageFactory.newPutStateMatadateEventMessage(channelId, txId, collection, key, metakey, value); + } + + @Test + void testNewDeleteStateEventMessage() { + ChaincodeMessageFactory.newDeleteStateEventMessage(channelId, txId, collection, key); + } + + @Test + void testNewErrorEventMessage() { + ChaincodeMessageFactory.newErrorEventMessage(channelId, txId, message); + ChaincodeMessageFactory.newErrorEventMessage(channelId, txId, throwable); + ChaincodeMessageFactory.newErrorEventMessage(channelId, txId, message, event); + } + + @Test + void testNewCompletedEventMessage() { + + ChaincodeMessageFactory.newCompletedEventMessage(channelId, txId, response, event); + } + + @Test + void testNewInvokeChaincodeMessage() { + ChaincodeMessageFactory.newInvokeChaincodeMessage(channelId, txId, payload); + } + + @Test + void testNewRegisterChaincodeMessage() { + ChaincodeMessageFactory.newRegisterChaincodeMessage(chaincodeId); + } + + @Test + void testNewEventMessageTypeStringStringByteString() { + ChaincodeMessageFactory.newEventMessage(type, channelId, txId, payload); + ChaincodeMessageFactory.newEventMessage(type, channelId, txId, payload, event); + } + +} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeStubImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeStubImplTest.java deleted file mode 100644 index 2635edc2..00000000 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeStubImplTest.java +++ /dev/null @@ -1,910 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ -package org.hyperledger.fabric.shim.impl; - -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Timestamp; -import org.hamcrest.Matchers; -import org.hyperledger.fabric.protos.common.Common.ChannelHeader; -import org.hyperledger.fabric.protos.common.Common.Header; -import org.hyperledger.fabric.protos.common.Common.SignatureHeader; -import org.hyperledger.fabric.protos.ledger.queryresult.KvQueryResult; -import org.hyperledger.fabric.protos.ledger.queryresult.KvQueryResult.KV; -import org.hyperledger.fabric.protos.peer.ChaincodeEventPackage.ChaincodeEvent; -import org.hyperledger.fabric.protos.peer.ChaincodeShim; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryResponse; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryResultBytes; -import org.hyperledger.fabric.protos.peer.ProposalPackage.ChaincodeProposalPayload; -import org.hyperledger.fabric.protos.peer.ProposalPackage.Proposal; -import org.hyperledger.fabric.protos.peer.ProposalPackage.SignedProposal; -import org.hyperledger.fabric.protos.peer.TransactionPackage; -import org.hyperledger.fabric.shim.Chaincode; -import org.hyperledger.fabric.shim.Chaincode.Response.Status; -import org.hyperledger.fabric.shim.ledger.CompositeKey; -import org.hyperledger.fabric.shim.ledger.KeyValue; -import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; -import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mock; -import org.mockito.internal.matchers.Null; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; -import org.mockito.quality.Strictness; -import org.mockito.stubbing.OngoingStubbing; - -import javax.xml.bind.DatatypeConverter; -import java.time.Instant; -import java.util.*; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; -import static org.hamcrest.Matchers.contains; -import static org.hyperledger.fabric.protos.common.Common.HeaderType.ENDORSER_TRANSACTION_VALUE; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; - -public class ChaincodeStubImplTest { - - private static final String TEST_COLLECTION = "testcoll"; - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Rule - public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); - - @Mock - private Handler handler; - - @Test - public void testGetArgs() { - List args = Arrays.asList( - ByteString.copyFromUtf8("arg0"), - ByteString.copyFromUtf8("arg1"), - ByteString.copyFromUtf8("arg2")); - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, args, null); - assertThat(stub.getArgs(), contains(args.stream().map(ByteString::toByteArray).toArray())); - } - - @Test - public void testGetStringArgs() { - List args = Arrays.asList( - ByteString.copyFromUtf8("arg0"), - ByteString.copyFromUtf8("arg1"), - ByteString.copyFromUtf8("arg2")); - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, args, null); - assertThat(stub.getStringArgs(), contains(args.stream().map(ByteString::toStringUtf8).toArray())); - } - - @Test - public void testGetFunction() { - List args = Arrays.asList( - ByteString.copyFromUtf8("function"), - ByteString.copyFromUtf8("arg0"), - ByteString.copyFromUtf8("arg1")); - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, args, null); - assertThat(stub.getFunction(), is("function")); - } - - @Test - public void testGetParameters() { - List args = Arrays.asList( - ByteString.copyFromUtf8("function"), - ByteString.copyFromUtf8("arg0"), - ByteString.copyFromUtf8("arg1")); - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, args, null); - assertThat(stub.getParameters(), contains("arg0", "arg1")); - } - - @Test - public void testSetGetEvent() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final byte[] payload = new byte[]{0x10, 0x20, 0x20}; - final String eventName = "event_name"; - stub.setEvent(eventName, payload); - ChaincodeEvent event = stub.getEvent(); - assertThat(event, hasProperty("eventName", equalTo(eventName))); - assertThat(event, hasProperty("payload", equalTo(ByteString.copyFrom(payload)))); - - stub.setEvent(eventName, null); - event = stub.getEvent(); - assertNotNull(event); - assertThat(event, hasProperty("eventName", equalTo(eventName))); - assertThat(event, hasProperty("payload", equalTo(ByteString.copyFrom(new byte[0])))); - } - - @Test - public void testSetEventEmptyName() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - thrown.expect(Matchers.isA(IllegalArgumentException.class)); - stub.setEvent("", new byte[0]); - } - - @Test - public void testSetEventNullName() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - thrown.expect(Matchers.isA(IllegalArgumentException.class)); - stub.setEvent(null, new byte[0]); - } - - @Test - public void testGetTxId() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - assertThat(stub.getTxId(), is("txId")); - } - - @Test - public void testGetState() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final byte[] value = new byte[]{0x10, 0x20, 0x30}; - when(handler.getState("myc", "txId", "", "key")).thenReturn(ByteString.copyFrom(value)); - assertThat(stub.getState("key"), is(value)); - } - - @Test - public void testGetStateValidationParameter() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final byte[] value = new byte[]{0x10, 0x20, 0x30}; - Map metaMap = new HashMap<>(); - metaMap.put(TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString(), ByteString.copyFrom(value)); - when(handler.getStateMetadata("myc", "txId", "", "key")).thenReturn(metaMap); - assertThat(stub.getStateValidationParameter("key"), is(value)); - - when(handler.getStateMetadata("myc", "txId", "", "key2")).thenReturn(new HashMap<>()); - assertThat(stub.getStateValidationParameter("key2"), is(nullValue())); - - } - - @Test - public void testGetStringState() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final String value = "TEST"; - when(handler.getState("myc", "txId", "", "key")).thenReturn(ByteString.copyFromUtf8(value)); - assertThat(stub.getStringState("key"), is(value)); - } - - @Test - public void testPutState() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final byte[] value = new byte[]{0x10, 0x20, 0x30}; - stub.putState("key", value); - verify(handler).putState("myc", "txId", "", "key", ByteString.copyFrom(value)); - try { - stub.putState(null, value); - Assert.fail("Null key check fails"); - } catch (NullPointerException e) { - } - - try { - stub.putState("", value); - Assert.fail("Empty key check fails"); - } catch (IllegalArgumentException e) { - } - } - - @Test - public void testSetStateValidationParameter() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final byte[] value = new byte[]{0x10, 0x20, 0x30}; - stub.setStateValidationParameter("key", value); - verify(handler).putStateMetadata("myc", "txId", "", "key", TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString(), ByteString.copyFrom(value)); - try { - stub.setStateValidationParameter(null, value); - Assert.fail("Null key check fails"); - } catch (NullPointerException e) { - } - - try { - stub.setStateValidationParameter("", value); - Assert.fail("Empty key check fails"); - } catch (IllegalArgumentException e) { - } - } - - @Test - public void testPutStringState() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final String value = "TEST"; - stub.putStringState("key", value); - verify(handler).putState("myc", "txId", "", "key", ByteString.copyFromUtf8(value)); - } - - @Test - public void testDelState() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - stub.delState("key"); - verify(handler).deleteState("myc", "txId", "", "key"); - } - - @Test - public void testGetStateByRange() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final String startKey = "START"; - final String endKey = "END"; - KV[] keyValues = prepareKeyValuePairs(2); - final QueryResponse value = prepareQueryResponseForRange(startKey, endKey, keyValues, false); - when(handler.getStateByRange("myc", "txId", "", startKey, endKey, null)).thenReturn(value); - QueryResultsIterator queryResultsIterator = stub.getStateByRange(startKey, endKey); - assertThat(queryResultsIterator, contains(Arrays.stream(keyValues).map(KeyValueImpl::new).toArray())); - } - - @Test - public void testGetStateByRangeWithPagination() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final String startKey = "START"; - final String endKey = "END"; - KV[] keyValues = prepareKeyValuePairs(2); - final QueryResponse value = prepareQueryResponseForRange(startKey, endKey, keyValues, true); - - ChaincodeShim.QueryMetadata queryMetadata = ChaincodeShim.QueryMetadata.newBuilder() - .setBookmark("aaaa") - .setPageSize(1) - .build(); - - when(handler.getStateByRange("myc", "txId", "", startKey, endKey, queryMetadata.toByteString())).thenReturn(value); - QueryResultsIteratorWithMetadata queryResultsIterator = stub.getStateByRangeWithPagination(startKey, endKey, 1, "aaaa"); - assertThat(queryResultsIterator, contains(Arrays.stream(keyValues).map(KeyValueImpl::new).toArray())); - assertThat(queryResultsIterator.getMetadata().getFetchedRecordsCount(), is(2)); - assertThat(queryResultsIterator.getMetadata().getBookmark(), is("bbbb")); - } - - private KV[] prepareKeyValuePairs(int count) { - final KV[] keyValue = new KV[count]; - for(int i = 0; i < count; i++) { - keyValue[i] = KV.newBuilder() - .setKey("Key" + i) - .setValue(ByteString.copyFromUtf8("Value of Key" + i)) - .build(); - } - return keyValue; - } - - private QueryResponse prepareQueryResponseForRange(String startKey, String endKey, KV[] keyValues, boolean createMetadata) { - QueryResponse.Builder builder = QueryResponse.newBuilder() - .setHasMore(false); - Arrays.stream(keyValues).forEach(kv -> builder.addResults(QueryResultBytes.newBuilder().setResultBytes(kv.toByteString()))); - if (createMetadata) { - ChaincodeShim.QueryResponseMetadata qrm = ChaincodeShim.QueryResponseMetadata.newBuilder() - .setBookmark("bbbb") - .setFetchedRecordsCount(2) - .build(); - builder.setMetadata(qrm.toByteString()); - } - return builder.build(); - } - - @Test - public void testGetStateByPartialCompositeKey() { - - ChaincodeStubImpl stub = prepareStubAndMockHandler(); - - stub.getStateByPartialCompositeKey("KEY"); - String key = new CompositeKey("KEY").toString(); - verify(handler).getStateByRange("myc", "txId", "", key, key + "\udbff\udfff", null); - - stub.getStateByPartialCompositeKey(""); - key = new CompositeKey("").toString(); - verify(handler).getStateByRange("myc", "txId", "", key, key + "\udbff\udfff", null); - } - - @Test - public void testGetStateByPartialCompositeKey_withAttributesAsString() { - - ChaincodeStubImpl stub = prepareStubAndMockHandler(); - CompositeKey cKey = new CompositeKey("KEY", "attr1", "attr2"); - stub.getStateByPartialCompositeKey(cKey.toString()); - verify(handler).getStateByRange("myc", "txId", "", cKey.toString(), cKey.toString() + "\udbff\udfff", null); - - } - - @Test - public void testGetStateByPartialCompositeKey_withAttributesWithSplittedParams() { - - ChaincodeStubImpl stub = prepareStubAndMockHandler(); - CompositeKey cKey = new CompositeKey("KEY", "attr1", "attr2", "attr3"); - stub.getStateByPartialCompositeKey("KEY", "attr1", "attr2", "attr3"); - verify(handler).getStateByRange("myc", "txId", "", cKey.toString(), cKey.toString() + "\udbff\udfff", null); - - } - - @Test - public void testGetStateByPartialCompositeKey_withCompositeKey() { - - ChaincodeStubImpl stub = prepareStubAndMockHandler(); - - CompositeKey key = new CompositeKey("KEY"); - stub.getStateByPartialCompositeKey(key); - verify(handler).getStateByRange("myc", "txId", "", key.toString(), key.toString() + "\udbff\udfff", null); - - key = new CompositeKey(""); - stub.getStateByPartialCompositeKey(key); - verify(handler).getStateByRange("myc", "txId", "", key.toString(), key.toString() + "\udbff\udfff", null); - } - - @Test - public void testGetStateByPartialCompositeKeyWithPagination() { - ChaincodeShim.QueryMetadata queryMetadata = ChaincodeShim.QueryMetadata.newBuilder() - .setBookmark("aaaa") - .setPageSize(1) - .build(); - - ChaincodeStubImpl stub = prepareStubAndMockHandler(true, queryMetadata.toByteString()); - - CompositeKey key = new CompositeKey("KEY"); - QueryResultsIteratorWithMetadata queryResultsIterator = stub.getStateByPartialCompositeKeyWithPagination(key, 1, "aaaa"); - verify(handler).getStateByRange("myc", "txId", "", key.toString(), key.toString() + "\udbff\udfff", queryMetadata.toByteString()); - assertThat(queryResultsIterator.getMetadata().getFetchedRecordsCount(), is(2)); - assertThat(queryResultsIterator.getMetadata().getBookmark(), is("bbbb")); - - - key = new CompositeKey(""); - queryResultsIterator = stub.getStateByPartialCompositeKeyWithPagination(key,1, "aaaa"); - verify(handler).getStateByRange("myc", "txId", "", key.toString(), key.toString() + "\udbff\udfff", queryMetadata.toByteString()); - assertThat(queryResultsIterator.getMetadata().getFetchedRecordsCount(), is(2)); - assertThat(queryResultsIterator.getMetadata().getBookmark(), is("bbbb")); - } - - private ChaincodeStubImpl prepareStubAndMockHandler() { - return prepareStubAndMockHandler(false, null); - } - - private ChaincodeStubImpl prepareStubAndMockHandler(boolean createMetadata, ByteString metadata) { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final KV[] keyValues = prepareKeyValuePairs(2); - - QueryResponse.Builder builder = QueryResponse.newBuilder() - .setHasMore(false); - Arrays.stream(keyValues).forEach(kv -> builder.addResults(QueryResultBytes.newBuilder().setResultBytes(kv.toByteString()))); - if (createMetadata) { - ChaincodeShim.QueryResponseMetadata qrm = ChaincodeShim.QueryResponseMetadata.newBuilder() - .setBookmark("bbbb") - .setFetchedRecordsCount(2) - .build(); - builder.setMetadata(qrm.toByteString()); - } - final QueryResponse value = builder.build(); - when(handler.getStateByRange(anyString(), anyString(), anyString(), anyString(), anyString(), eq(metadata))).thenReturn(value); - - return stub; - } - - @Test - public void testCreateCompositeKey() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final CompositeKey key = stub.createCompositeKey("abc", "def", "ghi", "jkl", "mno"); - assertThat(key, hasProperty("objectType", equalTo("abc"))); - assertThat(key, hasProperty("attributes", hasSize(4))); - assertThat(key, Matchers.hasToString(equalTo("\u0000abc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000"))); - } - - @Test - public void testSplitCompositeKey() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final CompositeKey key = stub.splitCompositeKey("\u0000abc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000"); - assertThat(key, hasProperty("objectType", equalTo("abc"))); - assertThat(key, hasProperty("attributes", contains("def", "ghi", "jkl", "mno"))); - assertThat(key, Matchers.hasToString(equalTo("\u0000abc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000"))); - } - - @Test - public void testGetQueryResult() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final KV[] keyValues = new KV[]{ - KV.newBuilder() - .setKey("A") - .setValue(ByteString.copyFromUtf8("Value of A")) - .build(), - KV.newBuilder() - .setKey("B") - .setValue(ByteString.copyFromUtf8("Value of B")) - .build() - }; - final QueryResponse value = QueryResponse.newBuilder() - .setHasMore(false) - .addResults(QueryResultBytes.newBuilder().setResultBytes(keyValues[0].toByteString())) - .addResults(QueryResultBytes.newBuilder().setResultBytes(keyValues[1].toByteString())) - .build(); - when(handler.getQueryResult("myc", "txId", "", "QUERY", null)).thenReturn(value); - assertThat(stub.getQueryResult("QUERY"), contains(Arrays.stream(keyValues).map(KeyValueImpl::new).toArray())); - } - - @Test(expected = InvalidProtocolBufferException.class) - public void testGetQueryResultWithException() throws Throwable { - final String txId = "txId", query = "QUERY", channelId = "myc"; - final ChaincodeStubImpl stub = new ChaincodeStubImpl(channelId, txId, handler, Collections.emptyList(), null); - final QueryResponse value = QueryResponse.newBuilder() - .setHasMore(false) - .addResults(QueryResultBytes.newBuilder().setResultBytes(ByteString.copyFromUtf8("exception"))) - .build(); - when(handler.getQueryResult(channelId, txId, "", query, null)).thenReturn(value); - try { - stub.getQueryResult(query).iterator().next(); - } catch (RuntimeException e) { - throw e.getCause(); - } - } - - @Test - public void testGetHistoryForKey() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final KvQueryResult.KeyModification[] keyModifications = new KvQueryResult.KeyModification[]{ - KvQueryResult.KeyModification.newBuilder() - .setTxId("tx0") - .setTimestamp(Timestamp.getDefaultInstance()) - .setValue(ByteString.copyFromUtf8("Value A")) - .build(), - KvQueryResult.KeyModification.newBuilder() - .setTxId("tx1") - .setTimestamp(Timestamp.getDefaultInstance()) - .setValue(ByteString.copyFromUtf8("Value B")) - .build() - }; - final QueryResponse value = QueryResponse.newBuilder() - .setHasMore(false) - .addResults(QueryResultBytes.newBuilder().setResultBytes(keyModifications[0].toByteString())) - .addResults(QueryResultBytes.newBuilder().setResultBytes(keyModifications[1].toByteString())) - .build(); - when(handler.getHistoryForKey("myc", "txId", "KEY")).thenReturn(value); - assertThat(stub.getHistoryForKey("KEY"), contains(Arrays.stream(keyModifications).map(KeyModificationImpl::new).toArray())); - } - - @Test - public void testGetPrivateData() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final byte[] value = new byte[]{0x10, 0x20, 0x30}; - when(handler.getState("myc", "txId", "testcoll", "key")).thenReturn(ByteString.copyFrom(value)); - assertThat(stub.getPrivateData("testcoll", "key"), is(value)); - try { - stub.getPrivateData(null, "key"); - Assert.fail("Null collection check fails"); - } catch (NullPointerException e) { - } - try { - stub.getPrivateData("", "key"); - Assert.fail("Empty collection check fails"); - } catch (IllegalArgumentException e) { - } - } - - @Test - public void testGetStringPrivateData() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final String value = "TEST"; - when(handler.getState("myc", "txId", "testcoll", "key")).thenReturn(ByteString.copyFromUtf8(value)); - assertThat(stub.getPrivateDataUTF8("testcoll", "key"), is(value)); - } - - @Test - public void testGetPrivateDataValidationParameter() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final byte[] value = new byte[]{0x10, 0x20, 0x30}; - Map metaMap = new HashMap<>(); - metaMap.put(TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString(), ByteString.copyFrom(value)); - when(handler.getStateMetadata("myc", "txId", "testcoll", "key")).thenReturn(metaMap); - assertThat(stub.getPrivateDataValidationParameter("testcoll", "key"), is(value)); - - when(handler.getStateMetadata("myc", "txId", "testcoll", "key2")).thenReturn(new HashMap<>()); - assertThat(stub.getPrivateDataValidationParameter("testcoll", "key2"), is(nullValue())); - - try { - stub.getPrivateDataValidationParameter(null, "key"); - Assert.fail("Null collection check fails"); - } catch (NullPointerException e) { - } - try { - stub.getPrivateDataValidationParameter("", "key"); - Assert.fail("Empty collection check fails"); - } catch (IllegalArgumentException e) { - } - } - - @Test - public void testPutPrivateData() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final byte[] value = new byte[]{0x10, 0x20, 0x30}; - stub.putPrivateData("testcoll", "key", value); - verify(handler).putState("myc", "txId", "testcoll", "key", ByteString.copyFrom(value)); - try { - stub.putPrivateData(null, "key", value); - Assert.fail("Null collection check fails"); - } catch (NullPointerException e) { - } - try { - stub.putPrivateData("", "key", value); - Assert.fail("Empty collection check fails"); - } catch (IllegalArgumentException e) { - } - try { - stub.putPrivateData("testcoll", null, value); - Assert.fail("Null key check fails"); - } catch (NullPointerException e) { - } - try { - stub.putPrivateData("testcoll", "", value); - Assert.fail("Empty key check fails"); - } catch (IllegalArgumentException e) { - } - } - - @Test - public void testPutStringPrivateData() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final String value = "TEST"; - stub.putPrivateData("testcoll", "key", value); - verify(handler).putState("myc", "txId", "testcoll", "key", ByteString.copyFromUtf8(value)); - } - - @Test - public void testSetPrivateDataValidationParameter() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final byte[] value = new byte[]{0x10, 0x20, 0x30}; - stub.setPrivateDataValidationParameter("testcoll", "key", value); - verify(handler).putStateMetadata("myc", "txId", "testcoll", "key", TransactionPackage.MetaDataKeys.VALIDATION_PARAMETER.toString(), ByteString.copyFrom(value)); - try { - stub.setPrivateDataValidationParameter(null, "key", value); - Assert.fail("Null collection check fails"); - } catch (NullPointerException e) { - } - try { - stub.setPrivateDataValidationParameter("", "key", value); - Assert.fail("Empty collection check fails"); - } catch (IllegalArgumentException e) { - } - try { - stub.setPrivateDataValidationParameter("testcoll", null, value); - Assert.fail("Null key check fails"); - } catch (NullPointerException e) { - } - try { - stub.setPrivateDataValidationParameter("testcoll", "", value); - Assert.fail("Empty key check fails"); - } catch (IllegalArgumentException e) { - } - } - - @Test - public void testDelPrivateState() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - stub.delPrivateData("testcoll", "key"); - verify(handler).deleteState("myc", "txId", "testcoll", "key"); - try { - stub.delPrivateData(null, "key"); - Assert.fail("Null collection check fails"); - } catch (NullPointerException e) { - } - try { - stub.delPrivateData("", "key"); - Assert.fail("Empty collection check fails"); - } catch (IllegalArgumentException e) { - } - } - - @Test - public void testGetPrivateDataByRange() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final String startKey = "START"; - final String endKey = "END"; - final KV[] keyValues = new KV[]{ - KV.newBuilder() - .setKey("A") - .setValue(ByteString.copyFromUtf8("Value of A")) - .build(), - KV.newBuilder() - .setKey("B") - .setValue(ByteString.copyFromUtf8("Value of B")) - .build() - }; - final QueryResponse value = QueryResponse.newBuilder() - .setHasMore(false) - .addResults(QueryResultBytes.newBuilder().setResultBytes(keyValues[0].toByteString())) - .addResults(QueryResultBytes.newBuilder().setResultBytes(keyValues[1].toByteString())) - .build(); - when(handler.getStateByRange("myc", "txId", "testcoll", startKey, endKey, null)).thenReturn(value); - assertThat(stub.getPrivateDataByRange("testcoll", startKey, endKey), contains(Arrays.stream(keyValues).map(KeyValueImpl::new).toArray())); - - try { - stub.getPrivateDataByRange(null, startKey, endKey); - Assert.fail("Null collection check fails"); - } catch (NullPointerException e) { - } - try { - stub.getPrivateDataByRange("", startKey, endKey); - Assert.fail("Empty collection check fails"); - } catch (IllegalArgumentException e) { - } - } - - @Test - public void testGetPrivateDataByPartialCompositeKey() { - final ChaincodeStubImpl stub = prepareStubAndMockHandler(); - - CompositeKey key = new CompositeKey("KEY"); - stub.getPrivateDataByPartialCompositeKey(TEST_COLLECTION, "KEY"); - verify(handler).getStateByRange("myc", "txId", TEST_COLLECTION, key.toString(), key.toString() + "\udbff\udfff", null); - - key = new CompositeKey(""); - stub.getPrivateDataByPartialCompositeKey(TEST_COLLECTION, (String) null); - stub.getPrivateDataByPartialCompositeKey(TEST_COLLECTION, ""); - verify(handler, times(2)).getStateByRange("myc", "txId", TEST_COLLECTION, key.toString(), key.toString() + "\udbff\udfff", null); - } - - @Test - public void testGetPrivateDataByPartialCompositeKey_withAttributesAsString() { - - ChaincodeStubImpl stub = prepareStubAndMockHandler(); - CompositeKey cKey = new CompositeKey("KEY", "attr1", "attr2"); - stub.getPrivateDataByPartialCompositeKey(TEST_COLLECTION, cKey.toString()); - - verify(handler).getStateByRange("myc", "txId", TEST_COLLECTION, cKey.toString(), cKey.toString() + "\udbff\udfff", null); - } - - @Test - public void testGetPrivateDataByPartialCompositeKey_withAttributesWithSplittedParams() { - - ChaincodeStubImpl stub = prepareStubAndMockHandler(); - CompositeKey cKey = new CompositeKey("KEY", "attr1", "attr2", "attr3"); - stub.getPrivateDataByPartialCompositeKey(TEST_COLLECTION, "KEY", "attr1", "attr2", "attr3"); - verify(handler).getStateByRange("myc", "txId", TEST_COLLECTION, cKey.toString(), cKey.toString() + "\udbff\udfff", null); - - } - - @Test - public void testGetPrivateDataByPartialCompositeKey_withCompositeKey() { - - ChaincodeStubImpl stub = prepareStubAndMockHandler(); - - CompositeKey key = new CompositeKey("KEY"); - stub.getPrivateDataByPartialCompositeKey(TEST_COLLECTION, key); - verify(handler).getStateByRange("myc", "txId", TEST_COLLECTION, key.toString(), key.toString() + "\udbff\udfff", null); - - key = new CompositeKey(""); - stub.getPrivateDataByPartialCompositeKey(TEST_COLLECTION, key); - verify(handler).getStateByRange("myc", "txId", TEST_COLLECTION, key.toString(), key.toString() + "\udbff\udfff", null); - } - - @Test - public void testGetPrivateDataQueryResult() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final KV[] keyValues = new KV[]{ - KV.newBuilder() - .setKey("A") - .setValue(ByteString.copyFromUtf8("Value of A")) - .build(), - KV.newBuilder() - .setKey("B") - .setValue(ByteString.copyFromUtf8("Value of B")) - .build() - }; - final QueryResponse value = QueryResponse.newBuilder() - .setHasMore(false) - .addResults(QueryResultBytes.newBuilder().setResultBytes(keyValues[0].toByteString())) - .addResults(QueryResultBytes.newBuilder().setResultBytes(keyValues[1].toByteString())) - .build(); - when(handler.getQueryResult("myc", "txId", "testcoll", "QUERY", null)).thenReturn(value); - assertThat(stub.getPrivateDataQueryResult("testcoll", "QUERY"), contains(Arrays.stream(keyValues).map(KeyValueImpl::new).toArray())); - - try { - stub.getPrivateDataQueryResult(null, "QUERY"); - Assert.fail("Null collection check fails"); - } catch (NullPointerException e) { - } - try { - stub.getPrivateDataQueryResult("", "QUERY"); - Assert.fail("Empty collection check fails"); - } catch (IllegalArgumentException e) { - } - - } - - @Test(expected = InvalidProtocolBufferException.class) - public void testGetPrivateDataQueryResultWithException() throws Throwable { - final String txId = "txId", query = "QUERY", channelId = "myc"; - final ChaincodeStubImpl stub = new ChaincodeStubImpl(channelId, txId, handler, Collections.emptyList(), null); - final QueryResponse value = QueryResponse.newBuilder() - .setHasMore(false) - .addResults(QueryResultBytes.newBuilder().setResultBytes(ByteString.copyFromUtf8("exception"))) - .build(); - when(handler.getQueryResult(channelId, txId, "testcoll", query, null)).thenReturn(value); - try { - stub.getPrivateDataQueryResult("testcoll", query).iterator().next(); - } catch (RuntimeException e) { - throw e.getCause(); - } - } - - @Test(expected = InvalidProtocolBufferException.class) - public void testGetHistoryForKeyWithException() throws Throwable { - final String txId = "txId", key = "KEY", channelId = "myc"; - final ChaincodeStubImpl stub = new ChaincodeStubImpl(channelId, txId, handler, Collections.emptyList(), null); - final QueryResponse value = QueryResponse.newBuilder() - .setHasMore(false) - .addResults(QueryResultBytes.newBuilder().setResultBytes(ByteString.copyFromUtf8("exception"))) - .build(); - when(handler.getHistoryForKey(channelId, txId, key)).thenReturn(value); - try { - stub.getHistoryForKey(key).iterator().next(); - } catch (RuntimeException e) { - throw e.getCause(); - } - } - - @Test - public void testInvokeChaincode() { - final String txId = "txId", chaincodeName = "CHAINCODE_ID", channel = "CHAINCODE_CHANNEL"; - final ChaincodeStubImpl stub = new ChaincodeStubImpl(channel, txId, handler, Collections.emptyList(), null); - final Chaincode.Response expectedResponse = new Chaincode.Response(Status.SUCCESS, "MESSAGE", "PAYLOAD".getBytes(UTF_8)); - when(handler.invokeChaincode(channel, txId, chaincodeName, Collections.emptyList())).thenReturn(expectedResponse); - assertThat(stub.invokeChaincode(chaincodeName, Collections.emptyList()), is(expectedResponse)); - - when(handler.invokeChaincode(eq(channel), eq(txId), eq(chaincodeName + "/" + channel), anyList())).thenReturn(expectedResponse); - assertThat(stub.invokeChaincode(chaincodeName, Collections.emptyList(), channel), is(expectedResponse)); - } - - @Test - public void testInvokeChaincodeWithStringArgs() { - final String txId = "txId", chaincodeName = "CHAINCODE_ID", channel = "CHAINCODE_CHANNEL"; - final ChaincodeStubImpl stub = new ChaincodeStubImpl(channel, txId, handler, Collections.emptyList(), null); - final Chaincode.Response expectedResponse = new Chaincode.Response(Status.SUCCESS, "MESSAGE", "PAYLOAD".getBytes(UTF_8)); - when(handler.invokeChaincode(channel, txId, chaincodeName, Collections.emptyList())).thenReturn(expectedResponse); - assertThat(stub.invokeChaincodeWithStringArgs(chaincodeName), is(expectedResponse)); - - when(handler.invokeChaincode(channel, txId, chaincodeName, Collections.emptyList())).thenReturn(expectedResponse); - assertThat(stub.invokeChaincodeWithStringArgs(chaincodeName, Collections.emptyList()), is(expectedResponse)); - - when(handler.invokeChaincode(eq(channel), eq(txId), eq(chaincodeName + "/" + channel), anyList())).thenReturn(expectedResponse); - assertThat(stub.invokeChaincodeWithStringArgs(chaincodeName, Collections.emptyList(), channel), is(expectedResponse)); - } - - @Test - public void testGetSignedProposal() { - final SignedProposal signedProposal = SignedProposal.newBuilder() - .setProposalBytes(Proposal.newBuilder() - .setHeader(Header.newBuilder() - .setChannelHeader(ChannelHeader.newBuilder() - .setType(ENDORSER_TRANSACTION_VALUE) - .setTimestamp(Timestamp.getDefaultInstance()) - .build().toByteString() - ) - .build().toByteString() - ) - .build().toByteString() - ).build(); - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), signedProposal); - assertThat(stub.getSignedProposal(), is(signedProposal)); - } - - @Test - public void testGetSignedProposalWithEmptyProposal() { - final SignedProposal signedProposal = SignedProposal.newBuilder().setProposalBytes(ByteString.EMPTY).build(); - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), signedProposal); - assertThat(stub.getSignedProposal(), is(signedProposal)); - } - - @Test - public void testGetTxTimestamp() { - final Instant instant = Instant.now(); - final Timestamp timestamp = Timestamp.newBuilder().setSeconds(instant.getEpochSecond()).setNanos(instant.getNano()).build(); - final SignedProposal signedProposal = SignedProposal.newBuilder() - .setProposalBytes(Proposal.newBuilder() - .setHeader(Header.newBuilder() - .setChannelHeader(ChannelHeader.newBuilder() - .setType(ENDORSER_TRANSACTION_VALUE) - .setTimestamp(timestamp) - .build().toByteString() - ) - .build().toByteString() - ) - .build().toByteString() - ).build(); - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txid", handler, new ArrayList<>(), signedProposal); - assertThat(stub.getTxTimestamp(), is(instant)); - } - - @Test - public void testGetTxTimestampNullSignedProposal() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txid", handler, new ArrayList<>(), null); - assertThat(stub.getTxTimestamp(), is(nullValue())); - } - - @Test - public void testGetTxTimestampEmptySignedProposal() { - final SignedProposal signedProposal = SignedProposal.newBuilder().setProposalBytes(ByteString.EMPTY).build(); - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txid", handler, new ArrayList<>(), signedProposal); - assertThat(stub.getTxTimestamp(), is(nullValue())); - } - - @Test - public void testGetCreator() { - final Instant instant = Instant.now(); - final byte[] creator = "CREATOR".getBytes(UTF_8); - final Timestamp timestamp = Timestamp.newBuilder().setSeconds(instant.getEpochSecond()).setNanos(instant.getNano()).build(); - final SignedProposal signedProposal = SignedProposal.newBuilder() - .setProposalBytes(Proposal.newBuilder() - .setHeader(Header.newBuilder() - .setChannelHeader(ChannelHeader.newBuilder() - .setType(ENDORSER_TRANSACTION_VALUE) - .setTimestamp(timestamp) - .build().toByteString() - ) - .setSignatureHeader(SignatureHeader.newBuilder() - .setCreator(ByteString.copyFrom(creator)) - .build().toByteString() - ) - .build().toByteString() - ) - .build().toByteString() - ).build(); - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txid", handler, new ArrayList<>(), signedProposal); - assertThat(stub.getCreator(), is(creator)); - } - - @Test - public void testGetTransient() { - final SignedProposal signedProposal = SignedProposal.newBuilder() - .setProposalBytes(Proposal.newBuilder() - .setHeader(Header.newBuilder() - .setChannelHeader(ChannelHeader.newBuilder() - .setType(ENDORSER_TRANSACTION_VALUE) - .setTimestamp(Timestamp.getDefaultInstance()) - .build().toByteString() - ) - .build().toByteString() - ) - .setPayload(ChaincodeProposalPayload.newBuilder() - .putTransientMap("key0", ByteString.copyFromUtf8("value0")) - .putTransientMap("key1", ByteString.copyFromUtf8("value1")) - .build().toByteString() - ) - .build().toByteString() - ).build(); - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txid", handler, new ArrayList<>(), signedProposal); - assertThat(stub.getTransient(), allOf( - hasEntry("key0", "value0".getBytes(UTF_8)), - hasEntry("key1", "value1".getBytes(UTF_8)) - )); - } - - @Test - public void testGetBinding() { - final byte[] expectedDigest = DatatypeConverter.parseHexBinary("5093dd4f4277e964da8f4afbde0a9674d17f2a6a5961f0670fc21ae9b67f2983"); - final SignedProposal signedProposal = SignedProposal.newBuilder() - .setProposalBytes(Proposal.newBuilder() - .setHeader(Header.newBuilder() - .setChannelHeader(ChannelHeader.newBuilder() - .setType(ENDORSER_TRANSACTION_VALUE) - .setTimestamp(Timestamp.getDefaultInstance()) - .setEpoch(10) - .build().toByteString() - ) - .setSignatureHeader(SignatureHeader.newBuilder() - .setNonce(ByteString.copyFromUtf8("nonce")) - .setCreator(ByteString.copyFromUtf8("creator")) - .build().toByteString() - ) - .build().toByteString() - ) - .build().toByteString() - ).build(); - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txid", handler, new ArrayList<>(), signedProposal); - assertThat(stub.getBinding(), is(expectedDigest)); - } - - @Test - public void testGetBindingEmptyProposal() { - final SignedProposal signedProposal = SignedProposal.newBuilder().setProposalBytes(ByteString.EMPTY).build(); - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txid", handler, new ArrayList<>(), signedProposal); - assertThat(stub.getBinding(), is((byte[]) null)); - } -} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/HandlerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/HandlerTest.java deleted file mode 100644 index 31f7ff6d..00000000 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/HandlerTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ -package org.hyperledger.fabric.shim.impl; - -import com.google.protobuf.ByteString; -import org.hyperledger.fabric.protos.peer.Chaincode; -import org.hyperledger.fabric.protos.peer.ChaincodeShim; -import org.hyperledger.fabric.shim.ChaincodeBase; -import org.hyperledger.fabric.shim.ChaincodeBaseTest; -import org.hyperledger.fabric.shim.chaincode.EmptyChaincode; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.EnvironmentVariables; -import org.junit.rules.ExpectedException; - - -public class HandlerTest { - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Rule - public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); - - @Test - public void testHandlerStates() { - ChaincodeBase cb = new EmptyChaincode(); - ChaincodeBaseTest.setLogLevelForChaincode(environmentVariables, cb, "DEBUG", "DEBUG"); - - Chaincode.ChaincodeID chaincodeId = Chaincode.ChaincodeID.newBuilder().setName("mycc").build(); - Handler handler = new Handler(chaincodeId, cb); - - ChaincodeShim.ChaincodeMessage msgReg = ChaincodeShim.ChaincodeMessage.newBuilder() - .setType(ChaincodeShim.ChaincodeMessage.Type.REGISTERED) - .build(); - // Correct message - handler.onChaincodeMessage(msgReg); - Assert.assertEquals("Not correct handler state", Handler.CCState.ESTABLISHED, handler.getState()); - - ChaincodeShim.ChaincodeMessage msgReady = ChaincodeShim.ChaincodeMessage.newBuilder() - .setType(ChaincodeShim.ChaincodeMessage.Type.READY) - .build(); - // Correct message - handler.onChaincodeMessage(msgReady); - Assert.assertEquals("Not correct handler state", Handler.CCState.READY, handler.getState()); - - handler = new Handler(chaincodeId, cb); - // Incorrect message - handler.onChaincodeMessage(msgReady); - Assert.assertEquals("Not correct handler state", Handler.CCState.CREATED, handler.getState()); - // Correct message - handler.onChaincodeMessage(msgReg); - Assert.assertEquals("Not correct handler state", Handler.CCState.ESTABLISHED, handler.getState()); - // Incorrect message - handler.onChaincodeMessage(msgReg); - Assert.assertEquals("Not correct handler state", Handler.CCState.ESTABLISHED, handler.getState()); - handler.onChaincodeMessage(msgReady); - Assert.assertEquals("Not correct handler state", Handler.CCState.READY, handler.getState()); - - // Unrelated message, do nothing - ChaincodeShim.ChaincodeMessage unkonwnMessage = ChaincodeShim.ChaincodeMessage.newBuilder() - .setType(ChaincodeShim.ChaincodeMessage.Type.PUT_STATE) - .setChannelId("mychannel") - .setTxid("q") - .setPayload(ByteString.copyFromUtf8("")) - .build(); - - handler.onChaincodeMessage(unkonwnMessage); - Assert.assertEquals("Not correct handler state", Handler.CCState.READY, handler.getState()); - - // KEEPALIVE message, do nothing - ChaincodeShim.ChaincodeMessage keepAliveMessage = ChaincodeShim.ChaincodeMessage.newBuilder() - .setType(ChaincodeShim.ChaincodeMessage.Type.KEEPALIVE) - .setChannelId("mychannel") - .setTxid("q") - .setPayload(ByteString.copyFromUtf8("")) - .build(); - handler.onChaincodeMessage(keepAliveMessage); - Assert.assertEquals("Not correct handler state", Handler.CCState.READY, handler.getState()); - - ChaincodeShim.ChaincodeMessage errorMsg = ChaincodeShim.ChaincodeMessage.newBuilder() - .setType(ChaincodeShim.ChaincodeMessage.Type.ERROR) - .setChannelId("mychannel") - .setTxid("q") - .setPayload(ByteString.copyFromUtf8("")) - .build(); - // Error message, except exception, no open communication - thrown.expect(IllegalStateException.class); - handler.onChaincodeMessage(errorMsg); - Assert.assertEquals("Not correct handler state", Handler.CCState.READY, handler.getState()); - - } -} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java index 6a39600a..6cd3c2dd 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java @@ -26,7 +26,7 @@ public class QueryResultsIteratorWithMetadataImplTest { @Test public void getMetadata() { - QueryResultsIteratorWithMetadataImpl testIter = new QueryResultsIteratorWithMetadataImpl<>(null, "", "", prepareQueryResopnse(), queryResultBytesToKv); + QueryResultsIteratorWithMetadataImpl testIter = new QueryResultsIteratorWithMetadataImpl<>(null, "", "", prepareQueryResopnse().toByteString(), queryResultBytesToKv); assertThat(testIter.getMetadata().getBookmark(), is("asdf")); assertThat(testIter.getMetadata().getFetchedRecordsCount(), is(2)); } @@ -34,7 +34,7 @@ public void getMetadata() { @Test public void getInvalidMetadata() { try { - new QueryResultsIteratorWithMetadataImpl<>(null, "", "", prepareQueryResopnseWrongMeta(), queryResultBytesToKv); + new QueryResultsIteratorWithMetadataImpl<>(null, "", "", prepareQueryResopnseWrongMeta().toByteString(), queryResultBytesToKv); fail(); } catch (RuntimeException e) { } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java index e1b67b34..6ca60379 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java @@ -11,9 +11,14 @@ import io.grpc.stub.StreamObserver; import org.hyperledger.fabric.protos.peer.ChaincodeShim; import org.hyperledger.fabric.protos.peer.ChaincodeSupportGrpc; +import org.hyperledger.fabric.shim.utils.TimeoutUtil; + +import static org.junit.Assert.fail; import java.io.IOException; import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.logging.Logger; /** @@ -179,4 +184,20 @@ public void onCompleted() { } } + public static void checkScenarioStepEnded(final ChaincodeMockPeer s, final int step, final int timeout, final TimeUnit units) throws Exception { + try { + TimeoutUtil.runWithTimeout(new Thread(() -> { + while (true) { + if (s.getLastExecutedStep() == step) return; + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + } + }), timeout, units); + } catch (TimeoutException e) { + fail("Got timeout, step " + step + " not finished"); + } + } + } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/CompleteStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/CompleteStep.java index d4ebce51..5296b678 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/CompleteStep.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/CompleteStep.java @@ -22,6 +22,6 @@ public boolean expected(ChaincodeShim.ChaincodeMessage msg) { @Override public List next() { - return Collections.EMPTY_LIST; + return Collections.emptyList(); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ErrorResponseStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ErrorResponseStep.java index 74845ffb..afe74bd4 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ErrorResponseStep.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ErrorResponseStep.java @@ -21,6 +21,6 @@ public boolean expected(ChaincodeShim.ChaincodeMessage msg) { @Override public List next() { - return Collections.EMPTY_LIST; + return Collections.emptyList(); } } diff --git a/fabric-contract-example/gradle/.gitignore b/fabric-contract-example/gradle/.gitignore new file mode 100644 index 00000000..25f5f86a --- /dev/null +++ b/fabric-contract-example/gradle/.gitignore @@ -0,0 +1,3 @@ +.gradle/ +build/ +bin/ \ No newline at end of file diff --git a/fabric-contract-example/gradle/.yo-rc.json b/fabric-contract-example/gradle/.yo-rc.json new file mode 100644 index 00000000..e4b1ae2a --- /dev/null +++ b/fabric-contract-example/gradle/.yo-rc.json @@ -0,0 +1,7 @@ +{ + "generator-fabric": { + "promptValues": { + "subgenerator": "contract" + } + } +} \ No newline at end of file diff --git a/fabric-contract-example/gradle/README.md b/fabric-contract-example/gradle/README.md new file mode 100644 index 00000000..08eae0f2 --- /dev/null +++ b/fabric-contract-example/gradle/README.md @@ -0,0 +1,10 @@ +This example needs to use gradle4.6 please install this first + +eg using sdkman + +`sdk install gradle 4.6` + + +and then add the wrapper code before building + +`gradle wrapper` \ No newline at end of file diff --git a/fabric-contract-example/gradle/build.gradle b/fabric-contract-example/gradle/build.gradle new file mode 100644 index 00000000..bbdfc56c --- /dev/null +++ b/fabric-contract-example/gradle/build.gradle @@ -0,0 +1,50 @@ +plugins { + id 'com.github.johnrengelman.shadow' version '2.0.3' + id 'java' +} + +version '0.0.1' + +sourceCompatibility = 1.8 + +repositories { + mavenLocal() + mavenCentral() + maven { + url "https://www.jitpack.io" + } + maven { + url "https://hyperledger.jfrog.io/hyperledger/fabric-maven" + } + +} + +dependencies { + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.8' + compile group: 'org.json', name: 'json', version: '20180813' + testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2' + testImplementation 'org.assertj:assertj-core:3.11.1' + testImplementation 'org.mockito:mockito-core:2.+' +} + +shadowJar { + baseName = 'chaincode' + version = null + classifier = null + + manifest { + attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter' + } +} + +test { + useJUnitPlatform() + testLogging { + events "passed", "skipped", "failed" + } +} + + +tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" << "-parameters" +} diff --git a/fabric-contract-example/gradle/src/main/java/org/example/MyAsset.java b/fabric-contract-example/gradle/src/main/java/org/example/MyAsset.java new file mode 100644 index 00000000..f4431088 --- /dev/null +++ b/fabric-contract-example/gradle/src/main/java/org/example/MyAsset.java @@ -0,0 +1,39 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.example; + +import org.hyperledger.fabric.contract.annotation.Contract; +import org.hyperledger.fabric.contract.annotation.DataType; +import org.hyperledger.fabric.contract.annotation.Property; +import org.json.JSONObject; + +@DataType() +public class MyAsset { + + @Property() + private String value; + + public MyAsset(){ + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String toJSONString() { + return new JSONObject(this).toString(); + } + + public static MyAsset fromJSONString(String json) { + String value = new JSONObject(json).getString("value"); + MyAsset asset = new MyAsset(); + asset.setValue(value); + return asset; + } +} diff --git a/fabric-contract-example/gradle/src/main/java/org/example/MyAssetContract.java b/fabric-contract-example/gradle/src/main/java/org/example/MyAssetContract.java new file mode 100644 index 00000000..8a44258e --- /dev/null +++ b/fabric-contract-example/gradle/src/main/java/org/example/MyAssetContract.java @@ -0,0 +1,81 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ +package org.example; + +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.annotation.Contract; +import org.hyperledger.fabric.contract.annotation.Default; +import org.hyperledger.fabric.contract.annotation.Transaction; + +import io.swagger.v3.oas.annotations.info.Contact; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.info.License; +import static java.nio.charset.StandardCharsets.UTF_8; + +@Contract(name = "MyAssetContract", + info = @Info(title = "MyAsset contract", + description = "Very basic Java Contract example", + version = "0.0.1", + license = + @License(name = "SPDX-License-Identifier: Apache-2.0", + url = ""), + contact = @Contact(email = "MyAssetContract@example.com", + name = "MyAssetContract", + url = "http://MyAssetContract.me"))) +@Default +public class MyAssetContract implements ContractInterface { + public MyAssetContract() { + + } + @Transaction() + public boolean myAssetExists(Context ctx, String myAssetId) { + byte[] buffer = ctx.getStub().getState(myAssetId); + return (buffer != null && buffer.length > 0); + } + + @Transaction() + public void createMyAsset(Context ctx, String myAssetId, String value) { + boolean exists = myAssetExists(ctx,myAssetId); + if (exists) { + throw new RuntimeException("The asset "+myAssetId+" already exists"); + } + MyAsset asset = new MyAsset(); + asset.setValue(value); + ctx.getStub().putState(myAssetId, asset.toJSONString().getBytes(UTF_8)); + } + + @Transaction() + public MyAsset readMyAsset(Context ctx, String myAssetId) { + boolean exists = myAssetExists(ctx,myAssetId); + if (!exists) { + throw new RuntimeException("The asset "+myAssetId+" does not exist"); + } + + MyAsset newAsset = MyAsset.fromJSONString(new String(ctx.getStub().getState(myAssetId),UTF_8)); + return newAsset; + } + + @Transaction() + public void updateMyAsset(Context ctx, String myAssetId, String newValue) { + boolean exists = myAssetExists(ctx,myAssetId); + if (!exists) { + throw new RuntimeException("The asset "+myAssetId+" does not exist"); + } + MyAsset asset = new MyAsset(); + asset.setValue(newValue); + + ctx.getStub().putState(myAssetId, asset.toJSONString().getBytes(UTF_8)); + } + + @Transaction() + public void deleteMyAsset(Context ctx, String myAssetId) { + boolean exists = myAssetExists(ctx,myAssetId); + if (!exists) { + throw new RuntimeException("The asset "+myAssetId+" does not exist"); + } + ctx.getStub().delState(myAssetId); + } + +} \ No newline at end of file diff --git a/fabric-contract-example/gradle/src/test/java/org/example/MyAssetContractTest.java b/fabric-contract-example/gradle/src/test/java/org/example/MyAssetContractTest.java new file mode 100644 index 00000000..4dd4b52b --- /dev/null +++ b/fabric-contract-example/gradle/src/test/java/org/example/MyAssetContractTest.java @@ -0,0 +1,174 @@ +/* + * SPDX-License-Identifier: Apache License 2.0 + */ + +package org.example; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.nio.charset.StandardCharsets; + +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + + +public final class MyAssetContractTest { + + @Nested + class AssetExists { + @Test + public void noProperAsset() { + + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + when(stub.getState("10001")).thenReturn(new byte[] {}); + boolean result = contract.myAssetExists(ctx,"10001"); + + assertFalse(result); + } + + @Test + public void assetExists() { + + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + when(stub.getState("10001")).thenReturn(new byte[] {42}); + boolean result = contract.myAssetExists(ctx,"10001"); + + assertTrue(result); + + } + + @Test + public void noKey() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + when(stub.getState("10002")).thenReturn(null); + boolean result = contract.myAssetExists(ctx,"10002"); + + assertFalse(result); + + } + + } + + @Nested + class AssetCreates { + + @Test + public void newAssetCreate() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + String json = "{\"value\":\"TheAsset\"}"; + + contract.createMyAsset(ctx, "10001", "TheAsset"); + + verify(stub).putState("10001", json.getBytes(UTF_8)); + } + + @Test + public void alreadyExists() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + when(stub.getState("10002")).thenReturn(new byte[] { 42 }); + + Exception thrown = assertThrows(RuntimeException.class, () -> { + contract.createMyAsset(ctx, "10002", "TheAsset"); + }); + + assertEquals(thrown.getMessage(), "The asset 10002 already exists"); + + } + + } + + @Test + public void assetRead() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + MyAsset asset = new MyAsset(); + asset.setValue("Valuable"); + + String json = asset.toJSONString(); + when(stub.getState("10001")).thenReturn(json.getBytes(StandardCharsets.UTF_8)); + + MyAsset returnedAsset = contract.readMyAsset(ctx, "10001"); + assertEquals(returnedAsset.getValue(), asset.getValue()); + } + + @Nested + class AssetUpdates { + @Test + public void updateExisting() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + when(stub.getState("10001")).thenReturn(new byte[] { 42 }); + + contract.updateMyAsset(ctx, "10001", "updates"); + + String json = "{\"value\":\"updates\"}"; + verify(stub).putState("10001", json.getBytes(UTF_8)); + } + + @Test + public void updateMissing() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + when(stub.getState("10001")).thenReturn(null); + + Exception thrown = assertThrows(RuntimeException.class, () -> { + contract.updateMyAsset(ctx, "10001", "TheAsset"); + }); + + assertEquals(thrown.getMessage(), "The asset 10001 does not exist"); + } + + } + + @Test + public void assetDelete() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + when(stub.getState("10001")).thenReturn(null); + + Exception thrown = assertThrows(RuntimeException.class, () -> { + contract.deleteMyAsset(ctx, "10001"); + }); + + assertEquals(thrown.getMessage(), "The asset 10001 does not exist"); + } + +} \ No newline at end of file diff --git a/fabric-contract-example/maven/.gitignore b/fabric-contract-example/maven/.gitignore new file mode 100644 index 00000000..1de56593 --- /dev/null +++ b/fabric-contract-example/maven/.gitignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/fabric-contract-example/maven/pom.xml b/fabric-contract-example/maven/pom.xml new file mode 100644 index 00000000..3e976b60 --- /dev/null +++ b/fabric-contract-example/maven/pom.xml @@ -0,0 +1,158 @@ + + 4.0.0 + MyAssetContract + MyAssetContract + 1.0-SNAPSHOT + + + + 1.8 + UTF-8 + UTF-8 + + + 1.4.8 + + + 1.0.13 + 1.7.5 + + + 5.3.0-RC1 + 1.3.0-RC1 + + + + + + jitpack.io + https://www.jitpack.io + + + artifactory + https://hyperledger.jfrog.io/hyperledger/fabric-maven + + + + + + + + org.hyperledger.fabric-chaincode-java + fabric-chaincode-shim + ${fabric-chaincode-java.version} + compile + + + + org.hyperledger.fabric-chaincode-java + fabric-chaincode-protos + ${fabric-chaincode-java.version} + compile + + + + + + + + org.slf4j + slf4j-api + ${slf4j.version} + compile + + + ch.qos.logback + logback-classic + ${logback.version} + runtime + + + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + compile + + + org.junit.jupiter + junit-jupiter-params + ${junit.jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + + org.mockito + mockito-core + 2.10.0 + + + + + org.json + json + 20180813 + + + + + src + + + + maven-surefire-plugin + 2.22.0 + + + maven-compiler-plugin + 3.1 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.1.0 + + + package + + shade + + + chaincode + + + chaincode.example.SimpleChaincode + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + + + + diff --git a/fabric-contract-example/maven/src/main/java/org/example/MyAsset.java b/fabric-contract-example/maven/src/main/java/org/example/MyAsset.java new file mode 100644 index 00000000..f4431088 --- /dev/null +++ b/fabric-contract-example/maven/src/main/java/org/example/MyAsset.java @@ -0,0 +1,39 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.example; + +import org.hyperledger.fabric.contract.annotation.Contract; +import org.hyperledger.fabric.contract.annotation.DataType; +import org.hyperledger.fabric.contract.annotation.Property; +import org.json.JSONObject; + +@DataType() +public class MyAsset { + + @Property() + private String value; + + public MyAsset(){ + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String toJSONString() { + return new JSONObject(this).toString(); + } + + public static MyAsset fromJSONString(String json) { + String value = new JSONObject(json).getString("value"); + MyAsset asset = new MyAsset(); + asset.setValue(value); + return asset; + } +} diff --git a/fabric-contract-example/maven/src/main/java/org/example/MyAssetContract.java b/fabric-contract-example/maven/src/main/java/org/example/MyAssetContract.java new file mode 100644 index 00000000..a0bfa8fb --- /dev/null +++ b/fabric-contract-example/maven/src/main/java/org/example/MyAssetContract.java @@ -0,0 +1,81 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ +package org.example; + +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.ContractInterface; +import org.hyperledger.fabric.contract.annotation.Contract; +import org.hyperledger.fabric.contract.annotation.Default; +import org.hyperledger.fabric.contract.annotation.Transaction; + +import org.hyperledger.fabric.contract.annotation.Contact; +import org.hyperledger.fabric.contract.annotation.Info; +import org.hyperledger.fabric.contract.annotation.License; +import static java.nio.charset.StandardCharsets.UTF_8; + +@Contract(name = "MyAssetContract", + info = @Info(title = "MyAsset contract", + description = "Very basic Java Contract example", + version = "0.0.1", + license = + @License(name = "SPDX-License-Identifier: Apache-2.0", + url = ""), + contact = @Contact(email = "MyAssetContract@example.com", + name = "MyAssetContract", + url = "http://MyAssetContract.me"))) +@Default +public class MyAssetContract implements ContractInterface { + public MyAssetContract() { + + } + @Transaction() + public boolean myAssetExists(Context ctx, String myAssetId) { + byte[] buffer = ctx.getStub().getState(myAssetId); + return (buffer != null && buffer.length > 0); + } + + @Transaction() + public void createMyAsset(Context ctx, String myAssetId, String value) { + boolean exists = myAssetExists(ctx,myAssetId); + if (exists) { + throw new RuntimeException("The asset "+myAssetId+" already exists"); + } + MyAsset asset = new MyAsset(); + asset.setValue(value); + ctx.getStub().putState(myAssetId, asset.toJSONString().getBytes(UTF_8)); + } + + @Transaction() + public MyAsset readMyAsset(Context ctx, String myAssetId) { + boolean exists = myAssetExists(ctx,myAssetId); + if (!exists) { + throw new RuntimeException("The asset "+myAssetId+" does not exist"); + } + + MyAsset newAsset = MyAsset.fromJSONString(new String(ctx.getStub().getState(myAssetId),UTF_8)); + return newAsset; + } + + @Transaction() + public void updateMyAsset(Context ctx, String myAssetId, String newValue) { + boolean exists = myAssetExists(ctx,myAssetId); + if (!exists) { + throw new RuntimeException("The asset "+myAssetId+" does not exist"); + } + MyAsset asset = new MyAsset(); + asset.setValue(newValue); + + ctx.getStub().putState(myAssetId, asset.toJSONString().getBytes(UTF_8)); + } + + @Transaction() + public void deleteMyAsset(Context ctx, String myAssetId) { + boolean exists = myAssetExists(ctx,myAssetId); + if (!exists) { + throw new RuntimeException("The asset "+myAssetId+" does not exist"); + } + ctx.getStub().delState(myAssetId); + } + +} \ No newline at end of file diff --git a/fabric-contract-example/maven/src/test/java/org/example/MyAssetContractTest.java b/fabric-contract-example/maven/src/test/java/org/example/MyAssetContractTest.java new file mode 100644 index 00000000..4dd4b52b --- /dev/null +++ b/fabric-contract-example/maven/src/test/java/org/example/MyAssetContractTest.java @@ -0,0 +1,174 @@ +/* + * SPDX-License-Identifier: Apache License 2.0 + */ + +package org.example; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.nio.charset.StandardCharsets; + +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + + +public final class MyAssetContractTest { + + @Nested + class AssetExists { + @Test + public void noProperAsset() { + + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + when(stub.getState("10001")).thenReturn(new byte[] {}); + boolean result = contract.myAssetExists(ctx,"10001"); + + assertFalse(result); + } + + @Test + public void assetExists() { + + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + when(stub.getState("10001")).thenReturn(new byte[] {42}); + boolean result = contract.myAssetExists(ctx,"10001"); + + assertTrue(result); + + } + + @Test + public void noKey() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + when(stub.getState("10002")).thenReturn(null); + boolean result = contract.myAssetExists(ctx,"10002"); + + assertFalse(result); + + } + + } + + @Nested + class AssetCreates { + + @Test + public void newAssetCreate() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + String json = "{\"value\":\"TheAsset\"}"; + + contract.createMyAsset(ctx, "10001", "TheAsset"); + + verify(stub).putState("10001", json.getBytes(UTF_8)); + } + + @Test + public void alreadyExists() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + when(stub.getState("10002")).thenReturn(new byte[] { 42 }); + + Exception thrown = assertThrows(RuntimeException.class, () -> { + contract.createMyAsset(ctx, "10002", "TheAsset"); + }); + + assertEquals(thrown.getMessage(), "The asset 10002 already exists"); + + } + + } + + @Test + public void assetRead() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + MyAsset asset = new MyAsset(); + asset.setValue("Valuable"); + + String json = asset.toJSONString(); + when(stub.getState("10001")).thenReturn(json.getBytes(StandardCharsets.UTF_8)); + + MyAsset returnedAsset = contract.readMyAsset(ctx, "10001"); + assertEquals(returnedAsset.getValue(), asset.getValue()); + } + + @Nested + class AssetUpdates { + @Test + public void updateExisting() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + when(stub.getState("10001")).thenReturn(new byte[] { 42 }); + + contract.updateMyAsset(ctx, "10001", "updates"); + + String json = "{\"value\":\"updates\"}"; + verify(stub).putState("10001", json.getBytes(UTF_8)); + } + + @Test + public void updateMissing() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + + when(stub.getState("10001")).thenReturn(null); + + Exception thrown = assertThrows(RuntimeException.class, () -> { + contract.updateMyAsset(ctx, "10001", "TheAsset"); + }); + + assertEquals(thrown.getMessage(), "The asset 10001 does not exist"); + } + + } + + @Test + public void assetDelete() { + MyAssetContract contract = new MyAssetContract(); + Context ctx = mock(Context.class); + ChaincodeStub stub = mock(ChaincodeStub.class); + when(ctx.getStub()).thenReturn(stub); + when(stub.getState("10001")).thenReturn(null); + + Exception thrown = assertThrows(RuntimeException.class, () -> { + contract.deleteMyAsset(ctx, "10001"); + }); + + assertEquals(thrown.getMessage(), "The asset 10001 does not exist"); + } + +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 66d6614a..1987d35d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/release_notes/v1.4.2.txt b/release_notes/v1.4.2.txt new file mode 100644 index 00000000..280a894c --- /dev/null +++ b/release_notes/v1.4.2.txt @@ -0,0 +1,33 @@ +v1.4.2 July 18, 2019 +---------------------------- + +Release Notes +------------- +This release contains a preview of the updated Contract programming model. This is the same as +that released within Node.js earlier in 2019. The method of operation is the same +as with the Node.js version, tailored to Java language idioms. + +Future releases will build on this preview; please experiement with this and provide feedback. +(RocketChat and JIRA) + +For more information on the Contract Programming Model please +see See https://hyperledger-fabric.readthedocs.io/en/developapps/developing_applications.html + + +baseimage version: 0.4.15 +Java version: openjdk version "1.8.0_181" + +Known Vulnerabilities +--------------------- +none + +Resolved Vulnerabilities +------------------------ +none + +Known Issues & Workarounds +-------------------------- +none +Change Log +---------- +https://github.com/hyperledger/fabric-chaincode-java/blob/release-1.4/CHANGELOG.md#v141 \ No newline at end of file diff --git a/release_notes/v1.4.3.txt b/release_notes/v1.4.3.txt new file mode 100644 index 00000000..dc505a47 --- /dev/null +++ b/release_notes/v1.4.3.txt @@ -0,0 +1,34 @@ +v1.4.3 July 31, 2019 +---------------------------- + +Release Notes +------------- +This is a bug fix release for some contract issue on top the previous v1.4.2 release. + +When chaincode is rebuilt when building the docker container, the tests phases will not +be run; this took noteable extra time for the more complex contracts. + +Future releases will build on this preview; please experiement with this and provide feedback. +(RocketChat and JIRA) + +For more information on the Contract Programming Model please +see https://hyperledger-fabric.readthedocs.io/en/developapps/developing_applications.html + + +baseimage version: 0.4.15 +Java version: openjdk version "1.8.0_181" + +Known Vulnerabilities +--------------------- +none + +Resolved Vulnerabilities +------------------------ +none + +Known Issues & Workarounds +-------------------------- +none +Change Log +---------- +https://github.com/hyperledger/fabric-chaincode-java/blob/release-1.4/CHANGELOG.md#v143 \ No newline at end of file diff --git a/release_notes/v1.4.4.txt b/release_notes/v1.4.4.txt new file mode 100644 index 00000000..5f38432c --- /dev/null +++ b/release_notes/v1.4.4.txt @@ -0,0 +1,31 @@ +v1.4.4 11 November 2019 +---------------------------- + +Release Notes +------------- + +The Contract Programming model was introduced with v1.4.3; this release has fixes +upong the original version that improvde stability and performance. + +This version should be used in real scenarios. + +For more information on the Contract Programming Model please +see https://hyperledger-fabric.readthedocs.io/en/developapps/developing_applications.html + +baseimage version: 0.4.15 +Java version: openjdk version "1.8.0_181" + +Known Vulnerabilities +--------------------- +none + +Resolved Vulnerabilities +------------------------ +none + +Known Issues & Workarounds +-------------------------- +none +Change Log +---------- +https://github.com/hyperledger/fabric-chaincode-java/blob/release-1.4/CHANGELOG.md#v144 \ No newline at end of file diff --git a/release_notes/v1.4.5.txt b/release_notes/v1.4.5.txt new file mode 100644 index 00000000..e603bf6e --- /dev/null +++ b/release_notes/v1.4.5.txt @@ -0,0 +1,33 @@ +v1.4.5 16 January 2020 +---------------------------- + +Release Notes +------------- + +The work in this release has been primarily the move to github, Azure Pipelines +and artifactory + +The main fix is to correct set the default values of the internal thread pools +(https://jira.hyperledger.org/browse/FAB-17100) + + +For more information on the Contract Programming Model please +see https://hyperledger-fabric.readthedocs.io/en/developapps/developing_applications.html + +baseimage version: 0.4.15 +Java version: openjdk version "1.8.0_181" + +Known Vulnerabilities +--------------------- +none + +Resolved Vulnerabilities +------------------------ +none + +Known Issues & Workarounds +-------------------------- +none +Change Log +---------- +https://github.com/hyperledger/fabric-chaincode-java/blob/release-1.4/CHANGELOG.md#v145 \ No newline at end of file diff --git a/release_notes/v1.4.6.txt b/release_notes/v1.4.6.txt new file mode 100644 index 00000000..3771b8e0 --- /dev/null +++ b/release_notes/v1.4.6.txt @@ -0,0 +1,27 @@ +v1.4.6 04 March 2020 +---------------------------- + +Release Notes +------------- + +This release includes changes to tolerate the use of Java 11. +It does not update default JVM used, but backports fixes from v2.0. + + +baseimage version: 0.4.15 +Java version: openjdk version "1.8.0_181" + +Known Vulnerabilities +--------------------- +none + +Resolved Vulnerabilities +------------------------ +none + +Known Issues & Workarounds +-------------------------- +none +Change Log +---------- +https://github.com/hyperledger/fabric-chaincode-java/blob/release-1.4/CHANGELOG.md#v146 \ No newline at end of file diff --git a/release_notes/v1.4.7.txt b/release_notes/v1.4.7.txt new file mode 100644 index 00000000..7c4ac3ca --- /dev/null +++ b/release_notes/v1.4.7.txt @@ -0,0 +1,22 @@ +v1.4.7 08 October 2020 + -------------------------- + + Release Notes + ------------- + This is a bug fix release. + + Known Vulnerabilities + --------------------- + none + + Resolved Vulnerabilities + ------------------------ + none + + Known Issues & Workarounds + -------------------------- + none + + Change Log + ---------- + https://github.com/hyperledger/fabric-chaincode-java/blob/release-1.4/CHANGELOG.md#v147 \ No newline at end of file diff --git a/release_notes/v1.4.8.txt b/release_notes/v1.4.8.txt new file mode 100644 index 00000000..d540a552 --- /dev/null +++ b/release_notes/v1.4.8.txt @@ -0,0 +1,22 @@ +v1.4.8 04 November 2020 + -------------------------- + + Release Notes + ------------- + This is a bug fix release. + + Known Vulnerabilities + --------------------- + none + + Resolved Vulnerabilities + ------------------------ + none + + Known Issues & Workarounds + -------------------------- + none + + Change Log + ---------- + https://github.com/hyperledger/fabric-chaincode-java/blob/release-1.4/CHANGELOG.md#v148 \ No newline at end of file diff --git a/scripts/changelog.sh b/scripts/changelog.sh index 1ea8328e..b74634c4 100755 --- a/scripts/changelog.sh +++ b/scripts/changelog.sh @@ -4,11 +4,19 @@ # # SPDX-License-Identifier: Apache-2.0 # +set -ev +PREVIOUS_TAG=$1 +NEW_VERSION=$2 -echo "## $2\n$(date)" >> CHANGELOG.new +: ${PREVIOUS_TAG:?} +: ${NEW_VERSION:?} + +echo "## ${NEW_VERSION}" >> CHANGELOG.new +echo "$(date)" >> CHANGELOG.new echo "" >> CHANGELOG.new -git log $1..HEAD --oneline | grep -v Merge | sed -e "s/\[\(FAB-[0-9]*\)\]/\[\1\](https:\/\/jira.hyperledger.org\/browse\/\1\)/" -e "s/ \(FAB-[0-9]*\)/ \[\1\](https:\/\/jira.hyperledger.org\/browse\/\1\)/" -e "s/\([0-9|a-z]*\)/* \[\1\](https:\/\/github.com\/hyperledger\/fabric-chaincode-java\/commit\/\1)/" >> CHANGELOG.new +git log ${PREVIOUS_TAG}..HEAD --oneline | grep -v Merge | sed -e "s/\[\{0,1\}\(FAB[^0-9]*-[0-9]*\)\]\{0,1\}/\[\1\](https:\/\/jira.hyperledger.org\/browse\/\1\)/" -e "s/\([0-9|a-z]*\)/* \[\1\](https:\/\/github.com\/hyperledger\/fabric-chaincode-java\/commit\/\1)/" >> CHANGELOG.new echo "" >> CHANGELOG.new cat CHANGELOG.md >> CHANGELOG.new mv -f CHANGELOG.new CHANGELOG.md + diff --git a/scripts/gittag.sh b/scripts/gittag.sh new file mode 100755 index 00000000..1c408980 --- /dev/null +++ b/scripts/gittag.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Exit on first error, print all commands. +set -e +set -o pipefail +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" + +# release name +RELEASE=release-1.4 + +function abort { + echo "!! Exiting shell script" + echo "!!" "$1" + exit -1 +} + +# Run printVersionName task in the root directory, grab the first line and remove anything after the version number +VERSION=$(cd ../ && ./gradlew -q printVersionName | gsed -n 1p | gsed -r "s/-.*//") + +echo New version string will be v${VERSION} + +# do the release notes for this new version exist? +if [[ -f "${DIR}/release_notes/v${VERSION}.txt" ]]; then + echo "Release notes exist, hope they make sense!" +else + abort "No releases notes under the file ${DIR}/release_notes/v${NEW_VERSION}.txt exist"; +fi + +git checkout "${RELEASE}" +git pull +git tag -a "v${VERSION}" `git log -n 1 --pretty=oneline | head -c7` -F release_notes/"v${VERSION}".txt +git push origin v${VERSION} HEAD:refs/heads/${RELEASE} \ No newline at end of file diff --git a/scripts/multiarch.sh b/scripts/multiarch.sh deleted file mode 100755 index f3eb4587..00000000 --- a/scripts/multiarch.sh +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/sh -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# -# This script publishes the fabric docker images to hyperledger dockerhub and nexus3 repositories. -# when publishing the images to dockerhub the values for NS_PULL & NS_PUSH variables set to default values. -# when publishing the images to nexus3 repository the values for NS_PULL & NS_PUSH variables set like below -# NS_PULL=nexus3.hyperledger.org:10001/hyperledger & NS_PUSH=nexus3.hyperledger.org:10002/hyperledger -# since nexus has separate port numbers to pull and push the images to nexus3. - -usage() { - echo "Usage: $0 " - echo " and credentials for the repository" - echo "ENV:" - echo " NS_PULL=$NS_PULL" - echo " NS_PUSH=$NS_PUSH" - echo " VERSION=$VERSION" - echo " TWO_DIGIT_VERSION=$TWO_DIGIT_VERSION" - exit 1 -} - -missing() { - echo "Error: some image(s) missing from registry" - echo "ENV:" - echo " NS_PULL=$NS_PULL" - echo " NS_PUSH=$NS_PUSH" - echo " VERSION=$VERSION" - echo " TWO_DIGIT_VERSION=$TWO_DIGIT_VERSION" - exit 1 -} - -failed() { - echo "Error: multiarch manifest push failed" - echo "ENV:" - echo " NS_PULL=$NS_PULL" - echo " NS_PUSH=$NS_PUSH" - echo " VERSION=$VERSION" - echo " TWO_DIGIT_VERSION=$TWO_DIGIT_VERSION" - exit 1 -} - -USER=${1:-nobody} -PASSWORD=${2:-nohow} -NS_PULL=${NS_PULL:-hyperledger} -NS_PUSH=${NS_PUSH:-hyperledger} -VERSION=${BASE_VERSION:-1.4.1} -TWO_DIGIT_VERSION=${TWO_DIGIT_VERSION:-1.4} - -if [ "$#" -ne 2 ]; then - usage -fi - -# verify that manifest-tool is installed and found on PATH -which manifest-tool -if [ "$?" -ne 0 ]; then - echo "manifest-tool not installed or not found on PATH" - exit 1 -fi - -IMAGES="fabric-javaenv" - -# check that all images have been published -for image in ${IMAGES}; do - docker pull ${NS_PULL}/${image}:amd64-${VERSION} || missing -done - -# push the multiarch manifest and tag with $VERSION,$TWO_DIGIT_VERSION and latest tag -for image in ${IMAGES}; do - manifest-tool --username ${USER} --password ${PASSWORD} push from-args\ - --platforms linux/amd64 --template "${NS_PULL}/${image}:ARCH-${VERSION}"\ - --target "${NS_PUSH}/${image}:${VERSION}" - manifest-tool --username ${USER} --password ${PASSWORD} push from-args\ - --platforms linux/amd64 --template "${NS_PULL}/${image}:ARCH-${VERSION}"\ - --target "${NS_PUSH}/${image}:latest" - manifest-tool --username ${USER} --password ${PASSWORD} push from-args\ - --platforms linux/amd64 --template "${NS_PULL}/${image}:ARCH-${VERSION}"\ - --target "${NS_PUSH}/${image}:${TWO_DIGIT_VERSION}" -done - -# test that manifest is working as expected -for image in ${IMAGES}; do - docker pull ${NS_PULL}/${image}:${VERSION} || failed - docker pull ${NS_PULL}/${image}:${TWO_DIGIT_VERSION} || failed - docker pull ${NS_PULL}/${image}:latest || failed -done - -echo "Successfully pushed multiarch manifest" -exit 0 diff --git a/scripts/preparenext.sh b/scripts/preparenext.sh new file mode 100755 index 00000000..37e7c81f --- /dev/null +++ b/scripts/preparenext.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Exit on first error, print all commands. +set -e +set -o pipefail +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" + +function abort { + echo "!! Exiting shell script" + echo "!!" "$1" + exit -1 +} + +VERSION=$(cat build.gradle | sed -n "s/version = '\(.*\)'/\1/p") +VERSION=${VERSION// } +echo Version is :${VERSION}: + +NEW_VERSION=$(npx semver --increment "${VERSION}" )-SNAPSHOT +echo New version is :${NEW_VERSION}: + + +# Remove the snapshot from the main build.gradle +for GRADLE_FILE in "${DIR}/fabric-chaincode-example-sbe/build.gradle" "${DIR}/fabric-contract-example/gradle/build.gradle" "${DIR}/fabric-chaincode-example-gradle/build.gradle" "${DIR}/fabric-chaincode-example-sacc/build.gradle" +do + sed -i "s/\(.*fabric-chaincode-shim.*version:\).*/\1 '${NEW_VERSION}'" "${GRADLE_FILE}" +done + +for MAVEN_FILE in "${DIR}/fabric-chaincode-example-maven/pom.xml" "${DIR}/fabric-contract-example/maven/pom.xml" +do + sed -i "s/\(.*\)<\/fabric-chaincode-java.version>/${NEW_VERSION}<\/fabric-chaincode-java.version>/" "${MAVEN_FILE}" +done + +sed -i "s/version = '.*'/version = '${NEW_VERSION}'/" build.gradle + +echo "...done" + + + diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 00000000..66813470 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Exit on first error, print all commands. +set -e +set -o pipefail +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" + +function abort { + echo "!! Exiting shell script" + echo "!!" "$1" + exit -1 +} + +VERSION=$(cat build.gradle | sed -n "s/version = '\(.*\)-SNAPSHOT'/\1/p") +VERSION=${VERSION// } +echo Version is :${VERSION}: + +# Remove the snapshot from the main build.gradle +for GRADLE_FILE in "${DIR}/build.gradle" "${DIR}/fabric-chaincode-example-sbe/build.gradle" "${DIR}/fabric-contract-example/gradle/build.gradle" "${DIR}/fabric-chaincode-example-gradle/build.gradle" "${DIR}/fabric-chaincode-example-sacc/build.gradle" +do + sed -i "s/version:\(.*\)-SNAPSHOT/version:\1/" "${GRADLE_FILE}" +done + +for MAVEN_FILE in "${DIR}/build.gradle" "${DIR}/fabric-chaincode-example-maven/pom.xml" "${DIR}/fabric-contract-example/maven/pom.xml" +do + sed -i "s/\(.*\)-SNAPSHOT/\1/" "${MAVEN_FILE}" +done + +if [[ -f "${DIR}/release_notes/v${VERSION}.txt" ]]; then + echo "Release notes exist, hope they make sense!" +else + abort "No releases notes under the file ${DIR}/release_notes/v${VERSION// }.txt exist"; +fi + +OLD_VERSION=$(cat ./CHANGELOG.md | sed -n 1p | sed -n -e "s/.*v\(.*\)/\1/p") +OLD_VERSION=${OLD_VERSION// } +echo Previous version is v${OLD_VERSION} + +echo "Writing change log... [v${OLD_VERSION} -> v${VERSION}]" +"${DIR}/scripts/changelog.sh" "v${OLD_VERSION}" "v${VERSION}" +echo "...done" + + +