From 605bebe86939f5ff70777f1e492a93839e5a611a Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Wed, 3 Jul 2019 17:29:26 +0100 Subject: [PATCH 01/61] [FAB-13753] Contract Support Change-Id: Ia15fd8c6f92979a5dcc8c18180aa1f099af9b796 Signed-off-by: Matthew B. White --- MAINTAINERS.md | 1 + build.gradle | 8 +- fabric-chaincode-docker/build.gradle | 3 + fabric-chaincode-docker/build.sh | 14 +- fabric-chaincode-example-gradle/build.gradle | 1 + fabric-chaincode-example-maven/pom.xml | 7 + .../bin/.gitignore | 1 + fabric-chaincode-protos/bin/.gitignore | 1 + fabric-chaincode-shim/bin/.gitignore | 2 + fabric-chaincode-shim/build.gradle | 37 +- .../java/org/hyperledger/fabric/Logger.java | 70 ++++ .../hyperledger/fabric/contract/Context.java | 51 +++ .../fabric/contract/ContextFactory.java | 30 ++ .../fabric/contract/ContractInterface.java | 102 +++++ .../fabric/contract/ContractRouter.java | 150 ++++++++ .../contract/ContractRuntimeException.java | 37 ++ .../fabric/contract/annotation/Contract.java | 48 +++ .../fabric/contract/annotation/DataType.java | 30 ++ .../fabric/contract/annotation/Default.java | 21 ++ .../fabric/contract/annotation/Property.java | 45 +++ .../contract/annotation/Transaction.java | 44 +++ .../contract/execution/ExecutionFactory.java | 35 ++ .../contract/execution/ExecutionService.java | 20 + .../contract/execution/InvocationRequest.java | 21 ++ .../execution/JSONTransactionSerializer.java | 185 +++++++++ .../impl/ContractExecutionService.java | 100 +++++ .../impl/ContractInvocationRequest.java | 66 ++++ .../contract/metadata/MetadataBuilder.java | 246 ++++++++++++ .../fabric/contract/metadata/TypeSchema.java | 215 +++++++++++ .../contract/routing/ContractDefinition.java | 84 +++++ .../contract/routing/DataTypeDefinition.java | 19 + .../contract/routing/ParameterDefinition.java | 22 ++ .../contract/routing/PropertyDefinition.java | 22 ++ .../contract/routing/RoutingRegistry.java | 69 ++++ .../contract/routing/TransactionType.java | 12 + .../fabric/contract/routing/TxFunction.java | 47 +++ .../fabric/contract/routing/TypeRegistry.java | 20 + .../routing/impl/ContractDefinitionImpl.java | 128 +++++++ .../routing/impl/DataTypeDefinitionImpl.java | 107 ++++++ .../routing/impl/ParameterDefinitionImpl.java | 50 +++ .../routing/impl/PropertyDefinitionImpl.java | 48 +++ .../routing/impl/RoutingRegistryImpl.java | 194 ++++++++++ .../contract/routing/impl/TxFunctionImpl.java | 204 ++++++++++ .../routing/impl/TypeRegistryImpl.java | 52 +++ .../systemcontract/SystemContract.java | 29 ++ .../hyperledger/fabric/shim/Chaincode.java | 2 +- .../fabric/shim/ChaincodeBase.java | 139 ++++--- .../fabric/shim/ChaincodeException.java | 137 +++++++ .../fabric/shim/ChaincodeStub.java | 20 +- .../fabric/shim/ResponseUtils.java | 64 ++++ .../shim/ext/sbe/StateBasedEndorsement.java | 2 +- .../impl/StateBasedEndorsementFactory.java | 2 +- .../fabric/shim/helper/Channel.java | 1 + .../src/main/resources/contract-schema.json | 352 ++++++++++++++++++ .../java/ChaincodeWithoutPackageTest.java | 2 +- .../java/EmptyChaincodeWithoutPackage.java | 5 +- .../src/test/java/contract/Greeting.java | 72 ++++ .../test/java/contract/SampleContract.java | 91 +++++ .../contract/ChaincodeStubNaiveImpl.java | 262 +++++++++++++ .../fabric/contract/ContextFactoryTest.java | 45 +++ .../contract/ContractInterfaceTest.java | 51 +++ .../fabric/contract/ContractRouterTest.java | 271 ++++++++++++++ .../hyperledger/fabric/contract/MyType.java | 30 ++ .../hyperledger/fabric/contract/MyType2.java | 38 ++ .../contract/TransactionExceptionTest.java | 106 ++++++ .../ContractExecutionServiceTest.java | 93 +++++ .../JSONTransactionSerializerTest.java | 128 +++++++ .../metadata/MetadataBuilderTest.java | 50 +++ .../contract/metadata/TypeSchemaTest.java | 199 ++++++++++ .../routing/ContractDefinitionTest.java | 101 +++++ .../routing/DataTypeDefinitionTest.java | 57 +++ .../routing/ParameterDefinitionTest.java | 37 ++ .../routing/PropertyDefinitionTest.java | 40 ++ .../contract/routing/TxFunctionTest.java | 99 +++++ .../contract/routing/TypeRegistryTest.java | 59 +++ .../simplepath/ContractSimplePath.java | 187 ++++++++++ .../fabric/shim/ChaincodeBaseTest.java | 50 ++- .../fabric/shim/chaincode/EmptyChaincode.java | 5 +- .../fabric/shim/fvt/ChaincodeFVTest.java | 110 +++--- .../shim/mock/peer/ChaincodeMockPeer.java | 21 ++ .../fabric/shim/mock/peer/CompleteStep.java | 2 +- .../shim/mock/peer/ErrorResponseStep.java | 2 +- 82 files changed, 5471 insertions(+), 159 deletions(-) create mode 100644 fabric-chaincode-integration-test/bin/.gitignore create mode 100644 fabric-chaincode-protos/bin/.gitignore create mode 100644 fabric-chaincode-shim/bin/.gitignore create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/Context.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContextFactory.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractInterface.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRuntimeException.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contract.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/DataType.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Default.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Property.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Transaction.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionFactory.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionService.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/InvocationRequest.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractExecutionService.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ContractDefinition.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/DataTypeDefinition.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ParameterDefinition.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/PropertyDefinition.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/RoutingRegistry.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TransactionType.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TxFunction.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TypeRegistry.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ParameterDefinitionImpl.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/PropertyDefinitionImpl.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TypeRegistryImpl.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeException.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java create mode 100644 fabric-chaincode-shim/src/main/resources/contract-schema.json create mode 100644 fabric-chaincode-shim/src/test/java/contract/Greeting.java create mode 100644 fabric-chaincode-shim/src/test/java/contract/SampleContract.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType2.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePath.java 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/build.gradle b/build.gradle index 9e462690..5ea8356d 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,8 @@ allprojects { mavenLocal() jcenter() maven { url "https://oss.sonatype.org/content/repositories/snapshots" } + maven { url 'https://jitpack.io' } + mavenCentral() } } @@ -34,5 +36,9 @@ subprojects { testCompile 'org.mockito:mockito-core:2.23.0' testCompile 'com.github.stefanbirkner:system-rules:1.17.0' } -} + + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" + } + } diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index 82b6f6c6..b50cf851 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -6,7 +6,10 @@ buildscript { repositories { + mavenLocal() jcenter() + maven { url "https://oss.sonatype.org/content/repositories/snapshots" } + maven { url 'https://jitpack.io' } mavenCentral() } dependencies { diff --git a/fabric-chaincode-docker/build.sh b/fabric-chaincode-docker/build.sh index 67f8a745..2405d798 100644 --- a/fabric-chaincode-docker/build.sh +++ b/fabric-chaincode-docker/build.sh @@ -73,6 +73,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..c2212ac4 100644 --- a/fabric-chaincode-example-gradle/build.gradle +++ b/fabric-chaincode-example-gradle/build.gradle @@ -11,6 +11,7 @@ sourceCompatibility = 1.8 repositories { mavenLocal() mavenCentral() + maven { url 'https://jitpack.io' } } dependencies { diff --git a/fabric-chaincode-example-maven/pom.xml b/fabric-chaincode-example-maven/pom.xml index 9e6016f3..6f574c18 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -22,6 +22,13 @@ 4.11 + + + + jitpack.io + https://jitpack.io + + diff --git a/fabric-chaincode-integration-test/bin/.gitignore b/fabric-chaincode-integration-test/bin/.gitignore new file mode 100644 index 00000000..19337860 --- /dev/null +++ b/fabric-chaincode-integration-test/bin/.gitignore @@ -0,0 +1 @@ +/test/ diff --git a/fabric-chaincode-protos/bin/.gitignore b/fabric-chaincode-protos/bin/.gitignore new file mode 100644 index 00000000..ddf9c656 --- /dev/null +++ b/fabric-chaincode-protos/bin/.gitignore @@ -0,0 +1 @@ +/main/ diff --git a/fabric-chaincode-shim/bin/.gitignore b/fabric-chaincode-shim/bin/.gitignore new file mode 100644 index 00000000..7eed456b --- /dev/null +++ b/fabric-chaincode-shim/bin/.gitignore @@ -0,0 +1,2 @@ +/main/ +/test/ diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 20b0de87..5456c205 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -11,11 +11,20 @@ plugins { id 'signing' } +tasks.withType(org.gradle.api.tasks.testing.Test) { + systemProperty 'CORE_CHAINCODE_LOGGING_LEVEL', 'DEBUG' +} + + 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 'org.reflections:reflections:0.9.11' + 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' } sourceSets { @@ -62,7 +71,13 @@ 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.execution.impl.ContractInvocationRequest', + 'org.hyperledger.fabric.contract.routing.TransactionType', + 'org.hyperledger.fabric.contract.metadata.MetadataBuilder'] limit { minimum = 0.86 } @@ -71,9 +86,14 @@ 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.shim.impl.Handler', + 'org.hyperledger.fabric.contract.metadata.MetadataBuilder'] limit { - minimum = 0.79 + minimum = 0.71 } } } @@ -93,6 +113,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 +133,7 @@ task licenseCheck { missing.add(file) } } + } } } @@ -140,7 +162,14 @@ task licenseCheck { javadoc { failOnError = false - excludes = ['org/hyperledger/fabric/shim/impl/**', + 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/shim/impl/**', 'org/hyperledger/fabric/shim/helper/**', 'org/hyperledger/fabric/shim/ChaincodeBase.java'] source = sourceSets.main.allJava 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..e9d2b9e6 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java @@ -0,0 +1,70 @@ +/* +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 + * + */ +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); + } + + public void debug(Supplier msgSupplier) { + log(Level.FINEST, msgSupplier); + } + + 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; + } + + public void error(String message) { + log(Level.SEVERE, message); + } + + public void error(Supplier msgSupplier) { + log(Level.SEVERE, msgSupplier); + } + + 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(); + } + +} 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..8cc1085d --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/Context.java @@ -0,0 +1,51 @@ +/* +Copyright IBM Corp., DTCC All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract; + +import org.hyperledger.fabric.shim.ChaincodeStub; + +/** + * + * 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; + + /** + * Constructor + * @param stub Instance of the {@link ChaincodeStub} to use + */ + public Context(ChaincodeStub stub) { + this.stub = stub; + } + + /** + * + * @return ChaincodeStub instance to use + */ + public ChaincodeStub getStub() { + return this.stub; + } +} 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..42a5be12 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java @@ -0,0 +1,150 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package org.hyperledger.fabric.contract; + +import org.hyperledger.fabric.Logger; +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.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); + + super.validateOptions(); + logger.debug("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"); + logger.error(() -> logger.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.debug(() -> "Namespace is " + request); + ContractDefinition contract = registry.getContract(request.getNamespace()); + return contract.getUnkownRoute(); + } + } + + /** + * Main method to start the contract based chaincode + * + */ + public static void main(String[] args) { + + 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(); + + } + + 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/Contract.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contract.java new file mode 100644 index 00000000..1641f42f --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contract.java @@ -0,0 +1,48 @@ +/* +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 io.swagger.v3.oas.annotations.info.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 + *

+ * The Info object can be supplied to provide additional information about the + * contract; the format of this uses the OpenAPI v3 specification of info + * {@link io.swagger.v3.oas.annotations.info.Info} + * + */ +@Retention(RUNTIME) +@Target(ElementType.TYPE) +public @interface Contract { + + /** + * The Info object can be supplied to provide additional information about the + * contract; the format of this uses the OpenAPI v3 Info format + * + * + * @return OpenAPI v3 specification of info + * {@link io.swagger.v3.oas.annotations.info.Info} + */ + Info 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/Property.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Property.java new file mode 100644 index 00000000..02006ab0 --- /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 paratemers 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 friendlyness = 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..3f966e29 --- /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 funcitons are called in client SDKs by the combination of

 [contractname]:[transactioname] 
+ * Unless specified other wise, the contract name is the class name (without package) and the transactio + * 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..052afde3 --- /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..f4f591fc --- /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 org.hyperledger.fabric.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 TypeRegistry typeRegistry; + + /** + * Create a new serialiser and maintain a reference to the TypeRegistry + * + * @param typeRegistry + */ + public JSONTransactionSerializer(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(Object value, TypeSchema ts) { + logger.debug(() -> "Schema to convert is " + ts); + byte[] buffer = null; + if (value != null) { + String type = ts.getType(); + if (type != null) { + switch (type) { + case "array": + 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 { + 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(byte[] buffer, TypeSchema ts) { + try { + String stringData = new String(buffer, StandardCharsets.UTF_8); + Object value = null; + + value = _convert(stringData, ts); + + return value; + } catch (InstantiationException | IllegalAccessException e) { + ContractRuntimeException cre = new ContractRuntimeException(e); + throw cre; + } + } + + /* + * Internal method to do the conversion + */ + private Object _convert(String stringData, TypeSchema ts) + throws IllegalArgumentException, IllegalAccessException, InstantiationException { + logger.debug(() -> "Schema to convert is " + ts); + String type = ts.getType(); + String format = null; + Object value = null; + if (type == null) { + type = "object"; + String ref = ts.getRef(); + format = ref.substring(ref.lastIndexOf("/") + 1); + } + + if (type.contentEquals("string")) { + value = stringData; + } else if (type.contentEquals("integer")) { + String intFormat = ts.getFormat(); + if (intFormat.contentEquals("int32")) { + value = Integer.parseInt(stringData); + } else { + value = Long.parseLong(stringData); + } + } else if (type.contentEquals("number")) { + 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")) { + JSONArray jsonArray = new JSONArray(stringData); + TypeSchema itemSchema = ts.getItems(); + 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(String format, String jsonString, TypeSchema ts) { + + 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); + } + + JSONObject json = new JSONObject(jsonString); + // request validation of the type may throw an exception if validation fails + ts.validate(json); + + try { + Map fields = dtd.getProperties(); + for (Iterator iterator = fields.values().iterator(); iterator.hasNext();) { + PropertyDefinition prop = iterator.next(); + + Field f = prop.getField(); + f.setAccessible(true); + 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..3308cb3e --- /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 org.hyperledger.fabric.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.debug(() -> "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 arguement + 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..1ff6f721 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java @@ -0,0 +1,246 @@ +/* +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.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.stream.Collectors; + +import org.everit.json.schema.Schema; +import org.everit.json.schema.ValidationException; +import org.everit.json.schema.loader.SchemaLoader; +import org.hyperledger.fabric.Logger; +import org.hyperledger.fabric.contract.annotation.Contract; +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; + +import io.swagger.v3.oas.annotations.info.Info; + +/** + * 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); + + @SuppressWarnings("serial") + static class MetadataMap extends HashMap { + + V putIfNotNull(K key, 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(); + + /** + * Validation method + * + * @throws ValidationException if the metadata is not valid + */ + public static void validate() { + logger.info("Running schema test validation"); + try (InputStream inputStream = MetadataBuilder.class.getClassLoader() + .getResourceAsStream("contract-schema.json")) { + JSONObject rawSchema = new JSONObject(new JSONTokener(inputStream)); + Schema schema = SchemaLoader.load(rawSchema); + schema.validate(metadata()); + + } catch (IOException e) { + throw new RuntimeException(e); + } catch (ValidationException e) { + logger.error(e.getMessage()); + e.getCausingExceptions().stream().map(ValidationException::getMessage).forEach(logger::info); + logger.error(debugString()); + throw e; + } + + } + + /** + * Setup the metadata from the found contracts + */ + public static void initialize(RoutingRegistry registry, TypeRegistry typeRegistry) { + Collection contractDefinitions = registry.getAllDefinitions(); + contractDefinitions.forEach(MetadataBuilder::addContract); + + 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 scehma created"); + MetadataBuilder.validate(); + + } + + /** + * Adds a component/ complex data-type + */ + public static void addComponent(DataTypeDefinition datatype) { + + Map component = new HashMap<>(); + + component.put("$id", datatype.getName()); + component.put("type", "object"); + component.put("additionalProperties", false); + + 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(ContractDefinition contractDefinition) { + + String key = contractDefinition.getName(); + + Contract annotation = contractDefinition.getAnnotation(); + + Info info = annotation.info(); + 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()); + + HashMap contract = new HashMap(); + contract.put("name", key); + contract.put("transactions", new ArrayList()); + contract.put("info", infoMap); + + contractMap.put(key, contract); + boolean defaultContract = true; + if (defaultContract) { + overallInfoMap.putAll(infoMap); + } + + 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(TxFunction txFunction, String contractName) { + TypeSchema transaction = new TypeSchema(); + TypeSchema returnSchema = txFunction.getReturnSchema(); + if (returnSchema != null) { + transaction.put("returns", returnSchema); + } + + ArrayList tags = new ArrayList(); + tags.add(txFunction.getType()); + + Map contract = contractMap.get(contractName); + @SuppressWarnings("unchecked") + List txs = (ArrayList) contract.get("transactions"); + + ArrayList paramsList = new ArrayList(); + txFunction.getParamsList().forEach(pd -> { + 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() { + 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)); + + 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..3eaba75b --- /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 org.everit.json.schema.Schema; +import org.everit.json.schema.ValidationException; +import org.everit.json.schema.loader.SchemaLoader; +import org.hyperledger.fabric.Logger; +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/routing/ContractDefinition.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ContractDefinition.java new file mode 100644 index 00000000..6099a10a --- /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 unkown + * + */ +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 returned + * @return TxFunction that represent 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 getUnkownRoute(); + + /** + * @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..c274b1d8 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java @@ -0,0 +1,128 @@ +/* +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 org.hyperledger.fabric.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.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); + + private Map txFunctions = new HashMap<>(); + private String name; + private boolean isDefault; + private Class contractClz; + private Contract contractAnnotation; + private TxFunction unknownTx; + + public ContractDefinitionImpl(Class cl) { + + Contract annotation = cl.getAnnotation(Contract.class); + logger.debug(() -> "Class Contract Annodation: " + annotation); + + 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 { + Method m = cl.getMethod("unknownTransaction", new Class[] { Context.class }); + unknownTx = new TxFunctionImpl(m, this); + unknownTx.setUnknownTx(true); + } catch (NoSuchMethodException | SecurityException e) { + ContractRuntimeException cre = new ContractRuntimeException("Failure to find unknownTranction method", e); + logger.severe(() -> logger.formatError(cre)); + throw cre; + } + + logger.info(() -> "Found class: " + cl.getCanonicalName()); + logger.debug(() -> "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(Method m) { + logger.debug(() -> "Adding method " + m.getName()); + TxFunction txFn = new TxFunctionImpl(m, this); + TxFunction previousTxnFn = txFunctions.put(txFn.getName(), txFn); + if (previousTxnFn != null) { + String message = String.format("Duplicate transaction method %s", previousTxnFn.getName()); + ContractRuntimeException cre = new ContractRuntimeException(message); + logger.severe(() -> logger.formatError(cre)); + throw cre; + } + return txFn; + } + + @Override + public boolean isDefault() { + return isDefault; + } + + @Override + public TxFunction getTxFunction(String method) { + return txFunctions.get(method); + } + + @Override + public boolean hasTxFunction(String method) { + return txFunctions.containsKey(method); + } + + @Override + public TxFunction getUnkownRoute() { + 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..c397cbc9 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java @@ -0,0 +1,107 @@ +/* +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.ArrayList; +import java.util.HashMap; +import java.util.List; +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..d65ef9cf --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java @@ -0,0 +1,194 @@ +/* +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.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.hyperledger.fabric.Logger; +import org.hyperledger.fabric.contract.ContractInterface; +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 org.reflections.Reflections; +import org.reflections.util.ClasspathHelper; +import org.reflections.util.ConfigurationBuilder; + +/** + * 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); + + private Map contracts = new HashMap<>(); + + /* + * (non-Javadoc) + * + * @see + * org.hyperledger.fabric.contract.routing.RoutingRegistry#addNewContract(java. + * lang.Class) + */ + @Override + public ContractDefinition addNewContract(Class clz) { + logger.debug(() -> "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.debug(() -> "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(InvocationRequest request) { + if (contracts.containsKey(request.getNamespace())) { + 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(InvocationRequest request) { + TxFunction txFunction = contracts.get(request.getNamespace()).getTxFunction(request.getMethod()); + return txFunction.getRouting(); + } + + @Override + public TxFunction getTxFn(InvocationRequest request) { + 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(String namespace) { + return contracts.get(namespace); + } + + /* + * (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() + */ + @Override + public void findAndSetContracts(TypeRegistry typeRegistry) { + ArrayList urls = new ArrayList<>(); + ClassLoader[] classloaders = { getClass().getClassLoader(), Thread.currentThread().getContextClassLoader() }; + for (int i = 0; i < classloaders.length; i++) { + if (classloaders[i] instanceof URLClassLoader) { + urls.addAll(Arrays.asList(((URLClassLoader) classloaders[i]).getURLs())); + } else { + throw new RuntimeException("classLoader is not an instanceof URLClassLoader"); + } + } + + ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); + configurationBuilder.addUrls(urls); + configurationBuilder.addUrls(ClasspathHelper.forJavaClassPath()); + Reflections ref = new Reflections(configurationBuilder); + + logger.info("Searching chaincode class in urls: " + urls); + + // set to ensure that we don't scan the same class twice + Set seenClass = new HashSet<>(); + + // loop over all the classes that have the Contract annotation + for (Class cl : ref.getTypesAnnotatedWith(Contract.class)) { + logger.info("Found class: " + cl.getCanonicalName()); + if (ContractInterface.class.isAssignableFrom(cl)) { + logger.debug("Inheritance ok"); + String className = cl.getCanonicalName(); + + if (!seenClass.contains(className)) { + ContractDefinition contract = addNewContract((Class) cl); + + logger.debug("Searching annotated methods"); + for (Method m : cl.getMethods()) { + if (m.getAnnotation(Transaction.class) != null) { + logger.debug("Found annotated method " + m.getName()); + + contract.addTxFunction(m); + + } + } + + seenClass.add(className); + } + } else { + logger.debug("Class is not assignabled from Contract"); + } + } + + // now need to look for the data types have been set with the + logger.info("Looking for the data types"); + Set> czs = ref.getTypesAnnotatedWith(DataType.class); + logger.info("found " + czs.size()); + czs.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..796c85db --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java @@ -0,0 +1,204 @@ +/* +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 org.hyperledger.fabric.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); + + private Method method; + private String name; + private TransactionType type; + private Routing routing; + private TypeSchema returnSchema; + private List paramsList = new ArrayList<>(); + private boolean isUnknownTx; + + public class RoutingImpl implements Routing { + + Method method; + Class clazz; + + public RoutingImpl(Method method, 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(Method m, ContractDefinition contract) { + + this.method = m; + if (m.getAnnotation(Transaction.class) != null) { + logger.debug("Found Transaction method: " + m.getName()); + if (m.getAnnotation(Transaction.class).submit()) { + this.type = TransactionType.INVOKE; + } else { + this.type = TransactionType.QUERY; + } + + 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 + 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 (java.lang.reflect.Parameter parameter : params) { + TypeSchema paramMap = new TypeSchema(); + TypeSchema schema = TypeSchema.typeConvert(parameter.getType()); + + Property annotation = parameter.getAnnotation(org.hyperledger.fabric.contract.annotation.Property.class); + if (annotation != null) { + 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); + 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(TypeSchema returnSchema) { + this.returnSchema = returnSchema; + } + + @Override + public List getParamsList() { + return paramsList; + } + + public void setParamsList(ArrayList paramsList) { + this.paramsList = paramsList; + } + + @Override + public TypeSchema getReturnSchema() { + return returnSchema; + } + + @Override + public void setParameterDefinitions(List list) { + this.paramsList = list; + + } + + @Override + public boolean isUnknownTx() { + return isUnknownTx; + } + + @Override + public void setUnknownTx(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..1a45e5c9 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java @@ -0,0 +1,29 @@ +/* +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.metadata.MetadataBuilder; + +import io.swagger.v3.oas.annotations.info.Info; + +@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/shim/Chaincode.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java index 1c7e152f..57060072 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 @@ -70,7 +70,7 @@ public byte[] getPayload() { } public String getStringPayload() { - return new String(payload, UTF_8); + return (payload==null) ? null : new String(payload, UTF_8); } /** 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..8493f071 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 @@ -6,36 +6,40 @@ 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 static java.util.logging.Level.ALL; -import java.io.*; -import java.nio.charset.StandardCharsets; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.security.Security; import java.util.Base64; +import java.util.Collections; +import java.util.List; 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.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.hyperledger.fabric.contract.ContractRouter; +import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeID; +import org.hyperledger.fabric.shim.impl.ChaincodeSupportStream; +import org.hyperledger.fabric.shim.impl.Handler; + +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 { @@ -84,21 +88,28 @@ public void start(String[] args) { processCommandLineOptions(args); initializeLogging(); 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); + connectToPeer(); } catch (Exception e) { logger.fatal("Chaincode could not start", 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"); + protected void connectToPeer() throws IOException { + 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); + } + + + protected void initializeLogging() { + System.setProperty("java.util.logging.SimpleFormatter.format","%1$tH:%1$tM:%1$tS:%1$tL %4$-7.7s %2$-80.80s %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) @@ -108,11 +119,17 @@ public synchronized String format(LogRecord record) { .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"); - } + } + }); } + + + + rootLogger.info("Updated all handlers the format"); // 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); @@ -125,11 +142,19 @@ public synchronized String format(LogRecord record) { // set logging level of shim logger Level shimLogLevel = mapLevel(System.getenv(CORE_CHAINCODE_LOGGING_SHIM)); Logger.getLogger(ChaincodeBase.class.getPackage().getName()).setLevel(shimLogLevel); + Logger.getLogger(ContractRouter.class.getPackage().getName()).setLevel(chaincodeLogLevel); + + List loggers = Collections.list(LogManager.getLogManager().getLoggerNames()); + loggers.forEach(x -> { + Logger l = LogManager.getLogManager().getLogger((String) x); + //TODO: err what is the code supposed to do? + }); + } private Level mapLevel(String level) { if (level != null) { - switch (level) { + switch (level.toUpperCase().trim()) { case "CRITICAL": case "ERROR": return Level.SEVERE; @@ -146,7 +171,7 @@ private Level mapLevel(String level) { 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)); } @@ -163,7 +188,7 @@ void validateOptions() { } } - void processCommandLineOptions(String[] args) { + protected void processCommandLineOptions(String[] args) { 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"); @@ -199,12 +224,14 @@ void processCommandLineOptions(String[] args) { 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); } @@ -229,9 +256,9 @@ void processEnvironmentOptions() { 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); } ManagedChannelBuilder newChannelBuilder() throws IOException { @@ -248,8 +275,8 @@ ManagedChannelBuilder newChannelBuilder() throws IOException { } SslContext createSSLContext() throws IOException { - byte ckb[] = Files.readAllBytes(Paths.get(this.tlsClientKeyPath)); - byte ccb[] = Files.readAllBytes(Paths.get(this.tlsClientCertPath)); + byte[] ckb = Files.readAllBytes(Paths.get(this.tlsClientKeyPath)); + byte[] ccb = Files.readAllBytes(Paths.get(this.tlsClientCertPath)); return GrpcSslContexts.forClient() .trustManager(new File(this.tlsClientRootCertPath)) @@ -259,47 +286,49 @@ SslContext createSSLContext() throws IOException { .build(); } + @Deprecated protected static Response newSuccessResponse(String message, byte[] payload) { - return new Response(SUCCESS, message, payload); + return ResponseUtils.newSuccessResponse(message, payload); } + @Deprecated protected static Response newSuccessResponse() { - return newSuccessResponse(null, null); + return ResponseUtils.newSuccessResponse(); } + @Deprecated protected static Response newSuccessResponse(String message) { - return newSuccessResponse(message, null); + return ResponseUtils.newSuccessResponse(message); } + @Deprecated protected static Response newSuccessResponse(byte[] payload) { - return newSuccessResponse(null, payload); + return ResponseUtils.newSuccessResponse(payload); } + @Deprecated protected static Response newErrorResponse(String message, byte[] payload) { - return new Response(INTERNAL_SERVER_ERROR, message, payload); + return ResponseUtils.newErrorResponse(message, payload); } + @Deprecated protected static Response newErrorResponse() { - return newErrorResponse(null, null); + return ResponseUtils.newErrorResponse(); } + @Deprecated protected static Response newErrorResponse(String message) { - return newErrorResponse(message, null); + return ResponseUtils.newErrorResponse(message); } + @Deprecated protected static Response newErrorResponse(byte[] payload) { - return newErrorResponse(null, payload); + return ResponseUtils.newErrorResponse(payload); } + @Deprecated 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); + return ResponseUtils.newErrorResponse(throwable); } String getHost() { 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..ea90c1a0 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 @@ -21,7 +21,9 @@ 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 +199,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 +240,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 +272,7 @@ public interface ChaincodeStub { * @param compositeKey * @param pageSize * @param bookmark - * @return + * @return QueryIterator */ QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination(CompositeKey compositeKey, int pageSize, String bookmark); @@ -323,7 +325,7 @@ public interface ChaincodeStub { * @param query * @param pageSize * @param bookmark - * @return + * @return QueryIterator */ QueryResultsIteratorWithMetadata getQueryResultWithPagination(String query, int pageSize, String bookmark); @@ -362,7 +364,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 +483,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..2581e12f --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java @@ -0,0 +1,64 @@ +/* +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 org.hyperledger.fabric.Logger; + +public class ResponseUtils { + + private static Logger logger = Logger.getLogger(ResponseUtils.class.getName()); + + public static Chaincode.Response newSuccessResponse(String message, byte[] payload) { + return new Chaincode.Response(SUCCESS, message, payload); + } + + public static Chaincode.Response newSuccessResponse() { + return newSuccessResponse(null, null); + } + + public static Chaincode.Response newSuccessResponse(String message) { + return newSuccessResponse(message, null); + } + + public static Chaincode.Response newSuccessResponse(byte[] payload) { + return newSuccessResponse(null, payload); + } + + public static Chaincode.Response newErrorResponse(String message, 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(String message) { + return newErrorResponse(message, null); + } + + public static Chaincode.Response newErrorResponse(byte[] payload) { + return newErrorResponse(null, payload); + } + + public static Chaincode.Response newErrorResponse(Throwable throwable) { + // Responses should not include internals like stack trace but make sure it gets logged + logger.error(() -> logger.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..75c9fdaa 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 @@ -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 index c44220db..b91aa795 100644 --- 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 @@ -10,6 +10,7 @@ import java.util.HashSet; import java.util.concurrent.LinkedBlockingQueue; +@SuppressWarnings("serial") public class Channel extends LinkedBlockingQueue implements Closeable { private boolean closed = false; 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/test/java/ChaincodeWithoutPackageTest.java b/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java index 1dafcc2d..56dbdcd1 100644 --- a/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java +++ b/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java @@ -48,7 +48,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..49446792 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/contract/Greeting.java @@ -0,0 +1,72 @@ +/* +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; + + private String notPartOfExternalContract; + + 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..276d5f05 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/contract/SampleContract.java @@ -0,0 +1,91 @@ +/* +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.Contract; +import org.hyperledger.fabric.contract.annotation.Default; +import org.hyperledger.fabric.contract.annotation.Transaction; +import org.hyperledger.fabric.shim.ChaincodeException; + +import io.swagger.v3.oas.annotations.info.Contact; +import io.swagger.v3.oas.annotations.info.Info; + +@Contract(name = "samplecontract", info = @Info(contact = @Contact(email = "fred@example.com"))) +@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/contract/ChaincodeStubNaiveImpl.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java new file mode 100644 index 00000000..f8879892 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java @@ -0,0 +1,262 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract; + +import com.google.protobuf.ByteString; +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.*; + +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class ChaincodeStubNaiveImpl implements ChaincodeStub { + private List args; + private List argsAsByte; + private Map state; + private Chaincode.Response resp; + + 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[] 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 new byte[0]; + } + + @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()); + } +} 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..72a4d2a9 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java @@ -0,0 +1,45 @@ +/* +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")))); + } +} \ 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..7ab39f6e --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java @@ -0,0 +1,271 @@ +/* +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 + public void testInvokeTxnThatExists() { + 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.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)); + } + + @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 + 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 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 + public void exceptions() { + ContractRuntimeException cre1 = new ContractRuntimeException("failure"); + ContractRuntimeException cre2 = new ContractRuntimeException("another failure", cre1); + ContractRuntimeException cre3 = 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..b9bd831d --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java @@ -0,0 +1,93 @@ +/* +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.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("rawtypes") + @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 = mock(ChaincodeStub.class); + + 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("rawtypes") + @Test() + public void failureToInvoke() + 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 = 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..9aaa83b2 --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java @@ -0,0 +1,50 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package org.hyperledger.fabric.contract.metadata; + +import java.io.Serializable; +import java.util.HashMap; + +import org.hyperledger.fabric.contract.Context; +import org.hyperledger.fabric.contract.systemcontract.SystemContract; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class MetadataBuilderTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + String expectedJSON = " {\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 + public void beforeEach() { + MetadataBuilder.componentMap = new HashMap(); + MetadataBuilder.contractMap = new HashMap>(); + MetadataBuilder.overallInfoMap = new HashMap(); + } + + @Test + public void systemContract() { + + // access the system contract to extract the metadata + SystemContract system = new SystemContract(); + String metadatacompressed = system.getMetadata(new Context(null)); + + } + +} \ 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..200a917b --- /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 io.swagger.v3.oas.annotations.info.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 unkownRoute() { + + 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.getUnkownRoute(); + } catch (Exception e) { + assertThat(e.getMessage(), equalTo("Failure to find unknownTranction 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..12a64ac6 --- /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); + TxFunction txfn = 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..455a90ed --- /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.*; +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..a6df5bed --- /dev/null +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePath.java @@ -0,0 +1,187 @@ +/* +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.COMPLETED; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.ERROR; +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; +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.CompleteStep; +import org.hyperledger.fabric.shim.mock.peer.ErrorResponseStep; +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)); + } + + /** + * Test executing two transaction functions in a contract via fully qualified + * name + * + * @throws Exception + */ + @Test + public void main() throws Exception { + + List scenario = new ArrayList<>(); + scenario.add(new RegisterStep()); + scenario.add(new CompleteStep()); + scenario.add(new CompleteStep()); + + 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); + + ChaincodeShim.ChaincodeMessage initMsg = newInvokeFn(new String[] { "samplecontract:t2" }); + server.send(initMsg); + ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); + assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); + assertThat(getLastReturnString(), is("Transaction 2")); + + ChaincodeShim.ChaincodeMessage invokeMsg = newInvokeFn(new String[] { "samplecontract:t1", "a" }); + server.send(invokeMsg); + ChaincodeMockPeer.checkScenarioStepEnded(server, 3, 5000, TimeUnit.MILLISECONDS); + assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); + assertThat(getLastReturnString(), is("a")); + } + + /** + * Test executing two transaction functions in a contract via default name + * + * @throws Exception + */ + @Test + public void defaultNamespace() throws Exception { + + List scenario = new ArrayList<>(); + scenario.add(new RegisterStep()); + scenario.add(new CompleteStep()); + scenario.add(new CompleteStep()); + + 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); + + ChaincodeShim.ChaincodeMessage initMsg = newInvokeFn(new String[] { "t2" }); + server.send(initMsg); + ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); + assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); + assertThat(getLastReturnString(), is("Transaction 2")); + + ChaincodeShim.ChaincodeMessage invokeMsg = newInvokeFn(new String[] { "t1", "a" }); + server.send(invokeMsg); + ChaincodeMockPeer.checkScenarioStepEnded(server, 3, 5000, TimeUnit.MILLISECONDS); + assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); + assertThat(getLastReturnString(), is("a")); + } + + /** + * Test executing two a function that does not exist + * + * @throws Exception + */ + @Test + public void unkownFn() throws Exception { + + List scenario = new ArrayList<>(); + scenario.add(new RegisterStep()); + scenario.add(new ErrorResponseStep()); + + 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); + + ChaincodeShim.ChaincodeMessage initMsg = newInvokeFn(new String[] { "samplecontract:wibble" }); + server.send(initMsg); + ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); + assertThat(server.getLastMessageRcvd().getType(), is(ERROR)); + assertThat(server.getLastMessageRcvd().getPayload().toStringUtf8(), is("Undefined contract method called")); + + } + + 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/shim/ChaincodeBaseTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java index 3d08a3fc..beeb7a6a 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,26 @@ 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.nio.charset.Charset; +import java.util.logging.Level; +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 @@ -29,7 +36,7 @@ public class ChaincodeBaseTest { @Test public void testNewSuccessResponseEmpty() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newSuccessResponse(); + 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()); @@ -37,7 +44,7 @@ public void testNewSuccessResponseEmpty() { @Test public void testNewSuccessResponseWithMessage() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newSuccessResponse("Simple message"); + 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()); @@ -45,7 +52,7 @@ public void testNewSuccessResponseWithMessage() { @Test public void testNewSuccessResponseWithPayload() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newSuccessResponse("Simple payload".getBytes(Charset.defaultCharset())); + 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())); @@ -53,7 +60,7 @@ public void testNewSuccessResponseWithPayload() { @Test public void testNewSuccessResponseWithMessageAndPayload() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newSuccessResponse("Simple message", "Simple payload".getBytes(Charset.defaultCharset())); + 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())); @@ -61,7 +68,7 @@ public void testNewSuccessResponseWithMessageAndPayload() { @Test public void testNewErrorResponseEmpty() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newErrorResponse(); + 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()); @@ -69,7 +76,7 @@ public void testNewErrorResponseEmpty() { @Test public void testNewErrorResponseWithMessage() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newErrorResponse("Simple message"); + 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()); @@ -77,7 +84,7 @@ public void testNewErrorResponseWithMessage() { @Test public void testNewErrorResponseWithPayload() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newErrorResponse("Simple payload".getBytes(Charset.defaultCharset())); + 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())); @@ -85,7 +92,7 @@ public void testNewErrorResponseWithPayload() { @Test public void testNewErrorResponseWithMessageAndPayload() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newErrorResponse("Simple message", "Simple payload".getBytes(Charset.defaultCharset())); + 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())); @@ -93,10 +100,18 @@ public void testNewErrorResponseWithMessageAndPayload() { @Test public void testNewErrorResponseWithException() { - org.hyperledger.fabric.shim.Chaincode.Response response = ChaincodeBase.newErrorResponse(new Exception("Simple exception")); + 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 in not correct", "Simple exception", response.getMessage()); - assertNotNull("Response payload in null", response.getPayload()); + assertEquals("Response message is not correct", "Chaincode exception", response.getMessage()); + assertNull("Response payload is not null", response.getPayload()); } @Test @@ -181,6 +196,7 @@ public void testUnsetOptionClientKeyPath() { } @Test + @Ignore public void testNewChannelBuilder() throws Exception { ChaincodeBase cb = new EmptyChaincode(); 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..d549257d 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 @@ -11,6 +11,7 @@ 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; @@ -24,6 +25,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.EnvironmentVariables; +import org.mockito.Mock; import java.util.ArrayList; import java.util.Collections; @@ -64,7 +66,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 +77,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 +96,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 +113,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 @@ -123,7 +125,7 @@ public Response invoke(ChaincodeStub stub) { String aVal = stub.getStringState(aKey); stub.putState(aKey, ByteString.copyFromUtf8("120").toByteArray()); stub.delState("delKey"); - return newSuccessResponse("OK response2"); + return ResponseUtils.newSuccessResponse("OK response2"); } }; @@ -147,10 +149,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 +168,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 +179,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 +189,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 +214,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 +232,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 +243,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 +263,7 @@ public Response invoke(ChaincodeStub stub) { } catch (Exception e) { fail("No exception expected"); } - return newSuccessResponse("OK response2"); + return ResponseUtils.newSuccessResponse("OK response2"); } }; @@ -292,22 +294,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, 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")); @@ -318,7 +320,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 +337,7 @@ public Response invoke(ChaincodeStub stub) { } catch (Exception e) { fail("No exception expected"); } - return newSuccessResponse("OK response2"); + return ResponseUtils.newSuccessResponse("OK response2"); } }; @@ -365,21 +367,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 +392,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 +409,7 @@ public Response invoke(ChaincodeStub stub) { } catch (Exception e) { fail("No exception expected"); } - return newSuccessResponse("OK response2"); + return ResponseUtils.newSuccessResponse("OK response2"); } }; @@ -433,14 +435,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 +454,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"); + Response response = stub.invokeChaincode("anotherChaincode", Collections.emptyList()); + return ResponseUtils.newSuccessResponse("OK response2"); } }; @@ -482,14 +484,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 +501,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 +522,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 +537,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 +552,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,7 +572,7 @@ 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; @@ -593,22 +595,6 @@ public void testChaincodeLogLevel() throws Exception { } - 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/mock/peer/ChaincodeMockPeer.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java index e1b67b34..3c1f5356 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(1); + } 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(); } } From ea32146ab11e0eab89097d9dfa005753ea648997 Mon Sep 17 00:00:00 2001 From: heatherlp Date: Thu, 11 Jul 2019 11:49:24 +0100 Subject: [PATCH 02/61] [FAB-15883] Removed swagger annotations - added contact, info and license annotation files - added .vscode folder to .gitignore - fixed some typos Signed-off-by: heatherlp Change-Id: I45bcff4a3b8cd98b65a3f3766cfbb9d4712e7902 --- .gitignore | 3 +- fabric-chaincode-shim/build.gradle | 4 +- .../fabric/contract/annotation/Contact.java | 30 +++++++++++ .../fabric/contract/annotation/Contract.java | 15 ++---- .../fabric/contract/annotation/Info.java | 51 +++++++++++++++++++ .../fabric/contract/annotation/License.java | 28 ++++++++++ .../fabric/contract/annotation/Property.java | 4 +- .../contract/annotation/Transaction.java | 6 +-- .../contract/metadata/MetadataBuilder.java | 2 +- .../routing/impl/ContractDefinitionImpl.java | 4 +- .../systemcontract/SystemContract.java | 3 +- .../test/java/contract/SampleContract.java | 19 +++++-- .../routing/ContractDefinitionTest.java | 4 +- 13 files changed, 143 insertions(+), 30 deletions(-) create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contact.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Info.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/License.java diff --git a/.gitignore b/.gitignore index 5bee9ce6..9495ade8 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,5 @@ nbdist/ .nb-gradle/ local-config.yaml -gradle.properties \ No newline at end of file +gradle.properties +.vscode/ \ No newline at end of file diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 5456c205..a537ec04 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -19,8 +19,8 @@ tasks.withType(org.gradle.api.tasks.testing.Test) { 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 'org.bouncycastle:bcpkix-jdk15on:1.60' + compile 'org.bouncycastle:bcprov-jdk15on:1.60' compile 'org.reflections:reflections:0.9.11' implementation 'com.github.everit-org.json-schema:org.everit.json.schema:1.11.1' compile 'io.swagger.core.v3:swagger-annotations:2.0.0' 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 index 1641f42f..d964fe4d 100644 --- 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 @@ -12,17 +12,12 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; -import io.swagger.v3.oas.annotations.info.Info; +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 - *

- * The Info object can be supplied to provide additional information about the - * contract; the format of this uses the OpenAPI v3 specification of info - * {@link io.swagger.v3.oas.annotations.info.Info} - * */ @Retention(RUNTIME) @Target(ElementType.TYPE) @@ -30,13 +25,11 @@ /** * The Info object can be supplied to provide additional information about the - * contract; the format of this uses the OpenAPI v3 Info format + * contract, including title, description, version and license * - * - * @return OpenAPI v3 specification of info - * {@link io.swagger.v3.oas.annotations.info.Info} + * @return Info object */ - Info info(); + Info info() default @Info(); /** * Normally the name of the class is used to refer to the contract (name without package). 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 index 02006ab0..323d1dc2 100644 --- 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 @@ -13,7 +13,7 @@ /** * Field and parameter level annotation defining a property of the class - * (identified by {@link DataType}) Can also be used on the paratemers of + * (identified by {@link DataType}) Can also be used on the parameters of * transaction functions *

* Example of using this annotation @@ -26,7 +26,7 @@ * * // How friendly is this on a scale of 1-5, 1 being formal, 5 being familar * @Property(schema = { "minimum", "1", "maximum", "5" }) - * private int friendlyness = 1; + * private int friendliness = 1; * * */ 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 index 3f966e29..661ca977 100644 --- 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 @@ -16,8 +16,8 @@ * Method level annotation indicating the method to be a callable transaction * function. *

- * These funcitons are called in client SDKs by the combination of

 [contractname]:[transactioname] 
- * Unless specified other wise, the contract name is the class name (without package) and the transactio + * 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) @@ -25,7 +25,7 @@ public @interface Transaction { /** * TRUE indicates that this function is intended to be called with the 'submit' - * semantics. + * semantics * * FALSE indicates that this is intended to be called with the evaluate * semantics 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 index 1ff6f721..189f2a43 100644 --- 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 @@ -31,7 +31,7 @@ import org.json.JSONObject; import org.json.JSONTokener; -import io.swagger.v3.oas.annotations.info.Info; +import org.hyperledger.fabric.contract.annotation.Info; /** * Builder to assist in production of the metadata 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 index c274b1d8..851540ed 100644 --- 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 @@ -39,7 +39,7 @@ public class ContractDefinitionImpl implements ContractDefinition { public ContractDefinitionImpl(Class cl) { Contract annotation = cl.getAnnotation(Contract.class); - logger.debug(() -> "Class Contract Annodation: " + annotation); + logger.debug(() -> "Class Contract Annotation: " + annotation); String annotationName = annotation.name(); @@ -58,7 +58,7 @@ public ContractDefinitionImpl(Class cl) { unknownTx = new TxFunctionImpl(m, this); unknownTx.setUnknownTx(true); } catch (NoSuchMethodException | SecurityException e) { - ContractRuntimeException cre = new ContractRuntimeException("Failure to find unknownTranction method", e); + ContractRuntimeException cre = new ContractRuntimeException("Failure to find unknownTransaction method", e); logger.severe(() -> logger.formatError(cre)); throw cre; } 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 index 1a45e5c9..fbdca9c5 100644 --- 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 @@ -9,10 +9,9 @@ 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; -import io.swagger.v3.oas.annotations.info.Info; - @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 { diff --git a/fabric-chaincode-shim/src/test/java/contract/SampleContract.java b/fabric-chaincode-shim/src/test/java/contract/SampleContract.java index 276d5f05..a869c1c1 100644 --- a/fabric-chaincode-shim/src/test/java/contract/SampleContract.java +++ b/fabric-chaincode-shim/src/test/java/contract/SampleContract.java @@ -12,12 +12,23 @@ 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 org.hyperledger.fabric.shim.ChaincodeException; -import io.swagger.v3.oas.annotations.info.Contact; -import io.swagger.v3.oas.annotations.info.Info; - -@Contract(name = "samplecontract", info = @Info(contact = @Contact(email = "fred@example.com"))) +@Contract( + name = "samplecontract", + info = @Info( + contact = @Contact( + email = "fred@example.com" + ), + license = @License( + name = "fred", + url = "http://fred.me" + ) + ) +) @Default() public class SampleContract implements ContractInterface { static public int beforeInvoked = 0; 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 index 200a917b..786a51bd 100644 --- 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 @@ -23,7 +23,7 @@ import org.junit.rules.ExpectedException; import contract.SampleContract; -import io.swagger.v3.oas.annotations.info.Info; +import org.hyperledger.fabric.contract.annotation.Info; public class ContractDefinitionTest { @Rule @@ -79,7 +79,7 @@ public void checkPermission(Permission perm) { cf.getUnkownRoute(); } catch (Exception e) { - assertThat(e.getMessage(), equalTo("Failure to find unknownTranction method")); + assertThat(e.getMessage(), equalTo("Failure to find unknownTransation method")); } finally { System.setSecurityManager(null); } From 7f1e772be7b2785ba5bfc40c3a7c7662576f230c Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Mon, 15 Jul 2019 16:11:24 +0100 Subject: [PATCH 03/61] [FAB-15213] In-repo examples, readme update - add directory for basic contract examples based on the generator used by VSCode - Additional words in markdown readmes etc - remove gradle jar as the jenkins script forbade this Change-Id: Icfa3427e30107b64eae58c1808074f5941ec95b6 Signed-off-by: Matthew B. White --- CODE_OF_CONDUCT.md | 3 +- CONTRACT_TUTORIAL.md | 98 ++++++++++ CONTRIBUTING.md | 51 +++++ FAQ.md | 40 ---- README.md | 28 +-- fabric-chaincode-example-maven/pom.xml | 4 + fabric-contract-example/gradle/.gitignore | 3 + fabric-contract-example/gradle/.yo-rc.json | 7 + fabric-contract-example/gradle/README.md | 10 + fabric-contract-example/gradle/build.gradle | 50 +++++ .../src/main/java/org/example/MyAsset.java | 39 ++++ .../java/org/example/MyAssetContract.java | 81 ++++++++ .../java/org/example/MyAssetContractTest.java | 174 ++++++++++++++++++ fabric-contract-example/maven/.gitignore | 1 + fabric-contract-example/maven/pom.xml | 158 ++++++++++++++++ .../src/main/java/org/example/MyAsset.java | 39 ++++ .../java/org/example/MyAssetContract.java | 81 ++++++++ .../java/org/example/MyAssetContractTest.java | 174 ++++++++++++++++++ 18 files changed, 981 insertions(+), 60 deletions(-) create mode 100644 CONTRACT_TUTORIAL.md delete mode 100644 FAQ.md create mode 100644 fabric-contract-example/gradle/.gitignore create mode 100644 fabric-contract-example/gradle/.yo-rc.json create mode 100644 fabric-contract-example/gradle/README.md create mode 100644 fabric-contract-example/gradle/build.gradle create mode 100644 fabric-contract-example/gradle/src/main/java/org/example/MyAsset.java create mode 100644 fabric-contract-example/gradle/src/main/java/org/example/MyAssetContract.java create mode 100644 fabric-contract-example/gradle/src/test/java/org/example/MyAssetContractTest.java create mode 100644 fabric-contract-example/maven/.gitignore create mode 100644 fabric-contract-example/maven/pom.xml create mode 100644 fabric-contract-example/maven/src/main/java/org/example/MyAsset.java create mode 100644 fabric-contract-example/maven/src/main/java/org/example/MyAssetContract.java create mode 100644 fabric-contract-example/maven/src/test/java/org/example/MyAssetContractTest.java 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/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..32838a06 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,6 +7,57 @@ 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. +## Folder structure + +The "fabric-chaincode-protos" folder contains the protobuf definition files used by +Java shim to communicate with Fabric peer. + +The "fabric-chaincode-shim" folder contains the java shim classes that define Java +chaincode API and way to communicate with Fabric peer. + +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. + +#### 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' +} +``` + ## Code of Conduct Guidelines See our [Code of Conduct Guidelines](../blob/master/CODE_OF_CONDUCT.md). 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/README.md b/README.md index b3299590..6ffd7acb 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,19 @@ -# Hyperledger Fabric Shim for Java chaincode +# Hyperledger Fabric - Java Contract and Chaincode -This is a Java based implementation of Hyprledger Fabric chaincode shim APIs, which enables development of chaincodes using Java language. +This is a Java implementation of Hyperledger Fabric chaincode shim APIs and contract programming model. This enables development of using Java language or other JVM based languages -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 `__. +## 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. +Application developers interested in developing smart contracts should read the [introductory tutorial](CONTRACT_TUTORIAL.md) and for a full scenario visit the +[Commercial Paper](https://hyperledger-fabric.readthedocs.io/en/latest/tutorial/commercial_paper.html) tutorial. -This project creates `fabric-chaincode-protos` and `fabric-chaincode-shim` jar -files for developers consumption and the `hyperledger/fabric-javaenv` docker image -to run Java chaincode. +We recommend using the IBM Blockchain Platform [VSCode extension](https://marketplace.visualstudio.com/items?itemName=IBMBlockchain.ibm-blockchain-platform) to assist you in developing smart contracts. The extension is able to create sample contracts for you, an example of such a contract is in the [fabric-contract-example](./fabric-contract-example) directory; there are folders for using both gradle and maven. -## Folder structure +In addition, this has reference to other tutorials to get you started -The "fabric-chaincode-protos" folder contains the protobuf definition files used by -Java shim to communicate with Fabric peer. +## Contributors -The "fabric-chaincode-shim" folder contains the java shim classes that define Java -chaincode API and way to communicate with Fabric peer. +Contributors or early adopters who need to be able to build and test recent builds, should reference the [contributing](CONTRIBUTING.md) guide. -The "fabric-chaincode-docker" folder contains instructions to the build -`hyperledger/fabric-javaenv` docker image. +This project creates `fabric-chaincode-protos` and `fabric-chaincode-shim` jar files for developers consumption and the `hyperledger/fabric-javaenv` docker image to run the Java chaincode and contracts. -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 diff --git a/fabric-chaincode-example-maven/pom.xml b/fabric-chaincode-example-maven/pom.xml index 6f574c18..1907c14c 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -27,6 +27,10 @@ jitpack.io https://jitpack.io + + + nexus + https://nexus.hyperledger.org/content/repositories/snapshots/ 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..6b1471a7 --- /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://jitpack.io' + } + maven { + url "https://nexus.hyperledger.org/content/repositories/snapshots/" + } + +} + +dependencies { + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.2-SNAPSHOT' + 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..f06a064d --- /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.2-SNAPSHOT + + + 1.0.13 + 1.7.5 + + + 5.3.0-RC1 + 1.3.0-RC1 + + + + + + jitpack.io + https://jitpack.io + + + nexus + https://nexus.hyperledger.org/content/repositories/snapshots/ + + + + + + + + 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..8a44258e --- /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 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/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 From eeeb0795050413ecc88116545803fad1a778c667 Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Thu, 18 Jul 2019 10:55:13 +0100 Subject: [PATCH 04/61] [FAB-16003] 1.4.2 Java Release Big update in this release is the preview of the Contract Programming Model Change-Id: I389d256d4db35becc2a389792b3295a395bbbc3a Signed-off-by: Matthew B. White --- CHANGELOG.md | 10 +++++ build.gradle | 2 +- fabric-chaincode-example-gradle/build.gradle | 2 +- fabric-chaincode-example-maven/pom.xml | 2 +- fabric-chaincode-example-sacc/build.gradle | 2 +- fabric-chaincode-example-sbe/build.gradle | 4 +- fabric-contract-example/gradle/build.gradle | 2 +- fabric-contract-example/maven/pom.xml | 2 +- release_notes/v1.4.2.txt | 33 ++++++++++++++++ scripts/release.sh | 41 ++++++++++++++++++++ 10 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 release_notes/v1.4.2.txt create mode 100755 scripts/release.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index bb3a9e93..77f6e7dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## v 1.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/build.gradle b/build.gradle index 5ea8356d..befd4eda 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ subprojects { apply plugin: 'maven' group = 'org.hyperledger.fabric-chaincode-java' - version = '1.4.2-SNAPSHOT' + version = '1.4.2' sourceCompatibility = 1.8 targetCompatibility = 1.8 diff --git a/fabric-chaincode-example-gradle/build.gradle b/fabric-chaincode-example-gradle/build.gradle index c2212ac4..0fbf58e8 100644 --- a/fabric-chaincode-example-gradle/build.gradle +++ b/fabric-chaincode-example-gradle/build.gradle @@ -15,7 +15,7 @@ repositories { } 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.2' 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 1907c14c..a956cdde 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.2 1.0.13 diff --git a/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-example-sacc/build.gradle index ebf9947f..00070bc7 100644 --- a/fabric-chaincode-example-sacc/build.gradle +++ b/fabric-chaincode-example-sacc/build.gradle @@ -14,7 +14,7 @@ repositories { } 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.2' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-example-sbe/build.gradle b/fabric-chaincode-example-sbe/build.gradle index f55eadf4..561c62c4 100644 --- a/fabric-chaincode-example-sbe/build.gradle +++ b/fabric-chaincode-example-sbe/build.gradle @@ -4,7 +4,7 @@ plugins { } group 'org.hyperledger.fabric-chaincode-java' -version '1.0-SNAPSHOT' +version '1.0' sourceCompatibility = 1.8 @@ -14,7 +14,7 @@ repositories { } 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.2' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-contract-example/gradle/build.gradle b/fabric-contract-example/gradle/build.gradle index 6b1471a7..8de5460e 100644 --- a/fabric-contract-example/gradle/build.gradle +++ b/fabric-contract-example/gradle/build.gradle @@ -20,7 +20,7 @@ repositories { } 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.2' 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' diff --git a/fabric-contract-example/maven/pom.xml b/fabric-contract-example/maven/pom.xml index f06a064d..71151fba 100644 --- a/fabric-contract-example/maven/pom.xml +++ b/fabric-contract-example/maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.2-SNAPSHOT + 1.4.2 1.0.13 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/scripts/release.sh b/scripts/release.sh new file mode 100755 index 00000000..3bcc4a7e --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# 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") +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") +echo Previous version is v${OLD_VERSION} + +echo "Writing change log..." +"${DIR}/scripts/changelog.sh" "v${OLD_VERSION}" "v${VERSION}" +echo "...done" + + + From 614b14b8ec6033f265ea1728157df160a8ed7e84 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 22 Jul 2019 14:27:44 +0100 Subject: [PATCH 05/61] [FAB-15929] Add getPrivateDataHash support Change-Id: Ifbf6ed4cbefca7b0cbb5146b4bfc0c42878e2018 Signed-off-by: James Taylor --- fabric-chaincode-protos/build.gradle | 6 +- .../fabric/protos/common/Common.java | 703 +- .../fabric/protos/peer/ChaincodeShim.java | 72 +- .../fabric/protos/peer/ProposalPackage.java | 307 +- .../fabric/protos/token/Expectations.java | 2584 ++++ .../fabric/protos/token/Transaction.java | 10167 ++++++++++++++++ .../src/main/protos/common/common.proto | 12 +- .../src/main/protos/peer/chaincode_shim.proto | 1 + .../src/main/protos/peer/proposal.proto | 7 +- .../src/main/protos/token/expectations.proto | 40 + .../src/main/protos/token/transaction.proto | 158 + .../fabric/shim/ChaincodeStub.java | 24 +- .../fabric/shim/impl/ChaincodeStubImpl.java | 43 +- .../hyperledger/fabric/shim/impl/Handler.java | 71 +- .../contract/ChaincodeStubNaiveImpl.java | 24 +- .../shim/impl/ChaincodeStubImplTest.java | 70 +- 16 files changed, 14155 insertions(+), 134 deletions(-) create mode 100644 fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/token/Expectations.java create mode 100644 fabric-chaincode-protos/src/main/java/org/hyperledger/fabric/protos/token/Transaction.java create mode 100644 fabric-chaincode-protos/src/main/protos/token/expectations.proto create mode 100644 fabric-chaincode-protos/src/main/protos/token/transaction.proto diff --git a/fabric-chaincode-protos/build.gradle b/fabric-chaincode-protos/build.gradle index 3f2f98e9..32560fb3 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 { 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/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java index ea90c1a0..7594cbcb 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,18 +6,22 @@ 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 { @@ -357,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 + */ + byte[] getPrivateDataHash(String collection, String key); + /** * Retrieves the key-level endorsement * policy for the private data specified by key. Note that this introduces 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/ChaincodeStubImpl.java index cb536a03..1d4f59c5 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/ChaincodeStubImpl.java @@ -6,9 +6,19 @@ 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 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.protos.common.Common; import org.hyperledger.fabric.protos.common.Common.ChannelHeader; import org.hyperledger.fabric.protos.common.Common.Header; @@ -25,20 +35,15 @@ import org.hyperledger.fabric.protos.peer.TransactionPackage; import org.hyperledger.fabric.shim.Chaincode.Response; import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.shim.ledger.*; +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 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 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 { @@ -349,6 +354,12 @@ public byte[] getPrivateData(String collection, String key) { return handler.getState(channelId, txId, collection, key).toByteArray(); } + @Override + public byte[] getPrivateDataHash(String collection, String key) { + validateCollection(collection); + return handler.getPrivateDataHash(channelId, txId, collection, key).toByteArray(); + } + @Override public byte[] getPrivateDataValidationParameter(String collection, String key) { validateCollection(collection); 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 index 6a4749ec..9929d2d9 100644 --- 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 @@ -6,32 +6,62 @@ package org.hyperledger.fabric.shim.impl; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.util.JsonFormat; +import static java.lang.String.format; +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_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; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.GET_STATE_BY_RANGE; +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.KEEPALIVE; +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.QUERY_STATE_CLOSE; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.QUERY_STATE_NEXT; +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.REGISTERED; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.RESPONSE; + +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 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.ChaincodeMessage.Type; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.DelState; +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.GetStateMetadata; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.PutState; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.PutStateMetadata; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryResponse; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryStateClose; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryStateNext; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.StateMetadata; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.StateMetadataResult; 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.*; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; public class Handler { @@ -316,6 +346,10 @@ ByteString getState(String channelId, String txId, String collection, String key return invokeChaincodeSupport(newGetStateEventMessage(channelId, txId, collection, key)); } + ByteString getPrivateDataHash(String channelId, String txId, String collection, String key) { + return invokeChaincodeSupport(newGetPrivateDataHashEventMessage(channelId, txId, collection, key)); + } + Map getStateMetadata(String channelId, String txId, String collection, String key) { ByteString payload = invokeChaincodeSupport(newGetStateMetadataEventMessage(channelId, txId, collection, key)); try { @@ -484,6 +518,13 @@ private static Chaincode.Response newErrorChaincodeResponse(String message) { return new Chaincode.Response(Chaincode.Response.Status.INTERNAL_SERVER_ERROR, message, null); } + private 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()); + } + 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) 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 index f8879892..36685084 100644 --- 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 @@ -5,13 +5,6 @@ */ package org.hyperledger.fabric.contract; -import com.google.protobuf.ByteString; -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.*; - import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.ArrayList; @@ -20,6 +13,18 @@ import java.util.Map; import java.util.stream.Collectors; +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; + +import com.google.protobuf.ByteString; + public class ChaincodeStubNaiveImpl implements ChaincodeStub { private List args; private List argsAsByte; @@ -175,6 +180,11 @@ 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]; 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 index 2635edc2..fe068397 100644 --- 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 @@ -5,9 +5,35 @@ */ package org.hyperledger.fabric.shim.impl; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Timestamp; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasProperty; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.hyperledger.fabric.protos.common.Common.HeaderType.ENDORSER_TRANSACTION_VALUE; +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.DatatypeConverter; + import org.hamcrest.Matchers; import org.hyperledger.fabric.protos.common.Common.ChannelHeader; import org.hyperledger.fabric.protos.common.Common.Header; @@ -33,27 +59,13 @@ 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.*; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Timestamp; public class ChaincodeStubImplTest { @@ -478,6 +490,24 @@ public void testGetPrivateData() { } } + @Test + public void testGetPrivateDataHash() { + final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); + final byte[] value = new byte[]{0x10, 0x20, 0x30}; + when(handler.getPrivateDataHash("myc", "txId", "testcoll", "key")).thenReturn(ByteString.copyFrom(value)); + assertThat(stub.getPrivateDataHash("testcoll", "key"), is(value)); + try { + stub.getPrivateDataHash(null, "key"); + Assert.fail("Null collection check fails"); + } catch (NullPointerException e) { + } + try { + stub.getPrivateDataHash("", "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); From 601eade750cca8e7ea9bfbd7e4a1e1db12b1ec03 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Tue, 30 Jul 2019 13:33:32 +0100 Subject: [PATCH 06/61] [FAB-16091] Handle invalid contract name Change-Id: I4897e11686199edf4db7df974a59f2dcd20af132 Signed-off-by: James Taylor --- .../routing/impl/RoutingRegistryImpl.java | 9 ++++++- .../fabric/contract/ContractRouterTest.java | 27 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) 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 index d65ef9cf..7103c08e 100644 --- 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 @@ -18,6 +18,7 @@ import org.hyperledger.fabric.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; @@ -113,7 +114,13 @@ public TxFunction getTxFn(InvocationRequest request) { */ @Override public ContractDefinition getContract(String namespace) { - return contracts.get(namespace); + ContractDefinition contract = contracts.get(namespace); + + if (contract == null) { + throw new ContractRuntimeException("Undefined contract called"); + } + + return contract; } /* 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 index 7ab39f6e..7bdd932a 100644 --- 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 @@ -156,6 +156,33 @@ public void testInvokeTxnWithDefinedNameUsingMethodName() { 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" }); From 8ae8b6ff971df8f468394d71f805e7bd8bbb12db Mon Sep 17 00:00:00 2001 From: vijaypunugubati Date: Tue, 30 Jul 2019 11:12:19 -0400 Subject: [PATCH 07/61] Prepare for next release 1.4.3-SNAPSHOT #FAB-16004 done Signed-off-by: vijaypunugubati Change-Id: I351c50bee92522ae3937257ee58f87592c40d45d --- build.gradle | 2 +- fabric-chaincode-example-gradle/build.gradle | 2 +- fabric-chaincode-example-maven/pom.xml | 2 +- fabric-chaincode-example-sacc/build.gradle | 2 +- fabric-chaincode-example-sbe/build.gradle | 2 +- fabric-contract-example/gradle/build.gradle | 2 +- fabric-contract-example/maven/pom.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index befd4eda..6befb2ea 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ subprojects { apply plugin: 'maven' group = 'org.hyperledger.fabric-chaincode-java' - version = '1.4.2' + version = '1.4.3-SNAPSHOT' sourceCompatibility = 1.8 targetCompatibility = 1.8 diff --git a/fabric-chaincode-example-gradle/build.gradle b/fabric-chaincode-example-gradle/build.gradle index 0fbf58e8..4cb749ed 100644 --- a/fabric-chaincode-example-gradle/build.gradle +++ b/fabric-chaincode-example-gradle/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.2' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3-SNAPSHOT' 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 a956cdde..52e986eb 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.2 + 1.4.3-SNAPSHOT 1.0.13 diff --git a/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-example-sacc/build.gradle index 00070bc7..711ec3a8 100644 --- a/fabric-chaincode-example-sacc/build.gradle +++ b/fabric-chaincode-example-sacc/build.gradle @@ -14,7 +14,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.2' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3-SNAPSHOT' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-example-sbe/build.gradle b/fabric-chaincode-example-sbe/build.gradle index 561c62c4..a348b4b0 100644 --- a/fabric-chaincode-example-sbe/build.gradle +++ b/fabric-chaincode-example-sbe/build.gradle @@ -14,7 +14,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.2' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3-SNAPSHOT' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-contract-example/gradle/build.gradle b/fabric-contract-example/gradle/build.gradle index 8de5460e..10bcbef8 100644 --- a/fabric-contract-example/gradle/build.gradle +++ b/fabric-contract-example/gradle/build.gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.2' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3-SNAPSHOT' 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' diff --git a/fabric-contract-example/maven/pom.xml b/fabric-contract-example/maven/pom.xml index 71151fba..df33771e 100644 --- a/fabric-contract-example/maven/pom.xml +++ b/fabric-contract-example/maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.2 + 1.4.3-SNAPSHOT 1.0.13 From 34612584d88c00cda87fe38719342463f13d855f Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Tue, 30 Jul 2019 14:59:46 +0100 Subject: [PATCH 08/61] [FAB-16136] Do not run tests in chaincode container Set the gradle and maven rebuilds of the Java code when creating the chaincode container to not do the tests. These would have been run before deployment by the deverlopers. Doing so in Java slows down deployment quite a bit. Change-Id: Id3ffc2dc9a36c11c7cfe7f41e98aaeb234c478ad Signed-off-by: Matthew B. White --- fabric-chaincode-docker/build.sh | 4 ++-- .../maven/src/main/java/org/example/MyAssetContract.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fabric-chaincode-docker/build.sh b/fabric-chaincode-docker/build.sh index 2405d798..3341495b 100644 --- a/fabric-chaincode-docker/build.sh +++ b/fabric-chaincode-docker/build.sh @@ -3,7 +3,7 @@ buildGradle() { cd "$1" > /dev/null echo "Gradle build" - gradle build shadowJar + gradle build shadowJar -x test retval=$? if [ $retval -ne 0 ]; then exit $retval @@ -19,7 +19,7 @@ buildGradle() { buildMaven() { cd "$1" > /dev/null echo "Maven build" - mvn compile package + mvn compile package -DskipTests -Dmaven.test.skip=true retval=$? if [ $retval -ne 0 ]; then exit $retval 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 index 8a44258e..a0bfa8fb 100644 --- a/fabric-contract-example/maven/src/main/java/org/example/MyAssetContract.java +++ b/fabric-contract-example/maven/src/main/java/org/example/MyAssetContract.java @@ -9,9 +9,9 @@ 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 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", From 0242f5305a57cff1524df5a497fbeab9f2948b56 Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Wed, 31 Jul 2019 11:25:21 +0100 Subject: [PATCH 09/61] [FAB-16148] Chaincode/Contract v1.4.3 Change-Id: I98eebd7d3ff24718344d21f173c73ea7cc8ae7ed Signed-off-by: Matthew B. White --- CHANGELOG.md | 10 +++++- build.gradle | 2 +- fabric-chaincode-example-gradle/build.gradle | 2 +- fabric-chaincode-example-maven/pom.xml | 2 +- fabric-chaincode-example-sacc/build.gradle | 2 +- fabric-chaincode-example-sbe/build.gradle | 2 +- fabric-contract-example/gradle/build.gradle | 2 +- fabric-contract-example/maven/pom.xml | 2 +- release_notes/v1.4.3.txt | 34 ++++++++++++++++++ scripts/gittag.sh | 37 ++++++++++++++++++++ scripts/release.sh | 12 +++++-- 11 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 release_notes/v1.4.3.txt create mode 100644 scripts/gittag.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 77f6e7dc..0f6d9b85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,12 @@ -## v 1.4.2 +## 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 diff --git a/build.gradle b/build.gradle index 6befb2ea..694117b8 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ subprojects { apply plugin: 'maven' group = 'org.hyperledger.fabric-chaincode-java' - version = '1.4.3-SNAPSHOT' + version = '1.4.3' sourceCompatibility = 1.8 targetCompatibility = 1.8 diff --git a/fabric-chaincode-example-gradle/build.gradle b/fabric-chaincode-example-gradle/build.gradle index 4cb749ed..e79e497f 100644 --- a/fabric-chaincode-example-gradle/build.gradle +++ b/fabric-chaincode-example-gradle/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3-SNAPSHOT' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3' 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 52e986eb..8c31a127 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.3-SNAPSHOT + 1.4.3 1.0.13 diff --git a/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-example-sacc/build.gradle index 711ec3a8..b1ea8a32 100644 --- a/fabric-chaincode-example-sacc/build.gradle +++ b/fabric-chaincode-example-sacc/build.gradle @@ -14,7 +14,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3-SNAPSHOT' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-example-sbe/build.gradle b/fabric-chaincode-example-sbe/build.gradle index a348b4b0..90588200 100644 --- a/fabric-chaincode-example-sbe/build.gradle +++ b/fabric-chaincode-example-sbe/build.gradle @@ -14,7 +14,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3-SNAPSHOT' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-contract-example/gradle/build.gradle b/fabric-contract-example/gradle/build.gradle index 10bcbef8..10322e3c 100644 --- a/fabric-contract-example/gradle/build.gradle +++ b/fabric-contract-example/gradle/build.gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3-SNAPSHOT' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3' 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' diff --git a/fabric-contract-example/maven/pom.xml b/fabric-contract-example/maven/pom.xml index df33771e..e7afc70f 100644 --- a/fabric-contract-example/maven/pom.xml +++ b/fabric-contract-example/maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.3-SNAPSHOT + 1.4.3 1.0.13 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/scripts/gittag.sh b/scripts/gittag.sh new file mode 100644 index 00000000..96621715 --- /dev/null +++ b/scripts/gittag.sh @@ -0,0 +1,37 @@ +#!/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 +} + +VERSION=$(jq '.version' ${DIR}/package.json | sed -r "s/\"([0-9]?[0-9]\.[0-9]?[0-9]\.[0-9]?[0-9]).*/\1/") + +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/release.sh b/scripts/release.sh index 3bcc4a7e..66813470 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -1,4 +1,8 @@ #!/bin/bash +# +# SPDX-License-Identifier: Apache-2.0 +# + # Exit on first error, print all commands. set -e set -o pipefail @@ -11,7 +15,8 @@ function abort { } VERSION=$(cat build.gradle | sed -n "s/version = '\(.*\)-SNAPSHOT'/\1/p") -echo Version is ${VERSION} +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" @@ -24,16 +29,17 @@ do sed -i "s/\(.*\)-SNAPSHOT/\1/" "${MAVEN_FILE}" done -if [[ -f "${DIR}/release_notes/v${VERSION// }.txt" ]]; then +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..." +echo "Writing change log... [v${OLD_VERSION} -> v${VERSION}]" "${DIR}/scripts/changelog.sh" "v${OLD_VERSION}" "v${VERSION}" echo "...done" From 43dbff354527ea6a523c5380508ac12b41df160e Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Fri, 2 Aug 2019 09:23:02 +0100 Subject: [PATCH 10/61] Prepare next version Prepare next version Add scripts/preparenext.sh to help automate this Change-Id: I63f44ac16e9f571a6454eae877582a0bf0f46149 Signed-off-by: Matthew B. White --- build.gradle | 2 +- fabric-chaincode-example-gradle/build.gradle | 2 +- fabric-chaincode-example-maven/pom.xml | 2 +- fabric-chaincode-example-sacc/build.gradle | 2 +- fabric-chaincode-example-sbe/build.gradle | 2 +- fabric-contract-example/gradle/build.gradle | 2 +- fabric-contract-example/maven/pom.xml | 2 +- scripts/preparenext.sh | 41 ++++++++++++++++++++ 8 files changed, 48 insertions(+), 7 deletions(-) create mode 100755 scripts/preparenext.sh diff --git a/build.gradle b/build.gradle index 694117b8..f4ebaee5 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ subprojects { apply plugin: 'maven' group = 'org.hyperledger.fabric-chaincode-java' - version = '1.4.3' + version = '1.4.4-SNAPSHOT' sourceCompatibility = 1.8 targetCompatibility = 1.8 diff --git a/fabric-chaincode-example-gradle/build.gradle b/fabric-chaincode-example-gradle/build.gradle index e79e497f..c143d517 100644 --- a/fabric-chaincode-example-gradle/build.gradle +++ b/fabric-chaincode-example-gradle/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4-SNAPSHOT' 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 8c31a127..1d743bd5 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.3 + 1.4.4-SNAPSHOT 1.0.13 diff --git a/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-example-sacc/build.gradle index b1ea8a32..af0b2f34 100644 --- a/fabric-chaincode-example-sacc/build.gradle +++ b/fabric-chaincode-example-sacc/build.gradle @@ -14,7 +14,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4-SNAPSHOT' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-example-sbe/build.gradle b/fabric-chaincode-example-sbe/build.gradle index 90588200..2d6d4f73 100644 --- a/fabric-chaincode-example-sbe/build.gradle +++ b/fabric-chaincode-example-sbe/build.gradle @@ -14,7 +14,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4-SNAPSHOT' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-contract-example/gradle/build.gradle b/fabric-contract-example/gradle/build.gradle index 10322e3c..029a9cae 100644 --- a/fabric-contract-example/gradle/build.gradle +++ b/fabric-contract-example/gradle/build.gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.3' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4-SNAPSHOT' 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' diff --git a/fabric-contract-example/maven/pom.xml b/fabric-contract-example/maven/pom.xml index e7afc70f..7a867cb1 100644 --- a/fabric-contract-example/maven/pom.xml +++ b/fabric-contract-example/maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.3 + 1.4.4-SNAPSHOT 1.0.13 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" + + + From b54e0d4ba4d3f304687ce827fb3ceb8c466da94b Mon Sep 17 00:00:00 2001 From: heatherlp Date: Wed, 7 Aug 2019 16:41:52 +0100 Subject: [PATCH 11/61] [FABN-1320] Fix git_tag.sh - so that it parses the build.gradle version - also specify a version and add a task to print it in the root level build.gradle Signed-off-by: heatherlp Change-Id: I1448b063592d4d8c1943920375e4bd4069b0e40d --- build.gradle | 15 +++++++++++---- scripts/gittag.sh | 6 ++---- 2 files changed, 13 insertions(+), 8 deletions(-) mode change 100644 => 100755 scripts/gittag.sh diff --git a/build.gradle b/build.gradle index f4ebaee5..25d70882 100644 --- a/build.gradle +++ b/build.gradle @@ -7,6 +7,8 @@ apply plugin: 'idea' apply plugin: 'eclipse-wtp' +version = '1.4.4-SNAPSHOT' + allprojects { repositories { mavenLocal() @@ -22,7 +24,7 @@ subprojects { apply plugin: 'maven' group = 'org.hyperledger.fabric-chaincode-java' - version = '1.4.4-SNAPSHOT' + version = rootProject.version sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -38,7 +40,12 @@ subprojects { } - tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" - } + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" } + +} + +task printVersionName() { + println rootProject.version +} diff --git a/scripts/gittag.sh b/scripts/gittag.sh old mode 100644 new mode 100755 index 96621715..1c408980 --- a/scripts/gittag.sh +++ b/scripts/gittag.sh @@ -17,7 +17,8 @@ function abort { exit -1 } -VERSION=$(jq '.version' ${DIR}/package.json | sed -r "s/\"([0-9]?[0-9]\.[0-9]?[0-9]\.[0-9]?[0-9]).*/\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} @@ -28,9 +29,6 @@ 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 From 55c29f95973dcdf2933f4f5feb3d61af44d37a5e Mon Sep 17 00:00:00 2001 From: heatherlp Date: Thu, 18 Jul 2019 11:10:49 +0100 Subject: [PATCH 12/61] [FAB-15895] Added client identity to context - Created a test utility file for storing certificate strings - Moved tests from ContractSimplePath to ContractRouterTest - Tidied up some imports - Fixed some typos and warnings Signed-off-by: heatherlp Change-Id: Iee2512ca4078a6487f6711eb5eae0be5b82acd30 --- .../fabric/shim/integration/Utils.java | 72 ++++++-- fabric-chaincode-shim/build.gradle | 4 +- .../fabric/contract/ClientIdentity.java | 169 ++++++++++++++++++ .../hyperledger/fabric/contract/Context.java | 19 ++ .../fabric/contract/ContractRouter.java | 2 +- .../contract/execution/ExecutionService.java | 2 +- .../contract/metadata/MetadataBuilder.java | 5 +- .../contract/routing/ContractDefinition.java | 8 +- .../routing/impl/ContractDefinitionImpl.java | 2 +- .../java/ChaincodeWithoutPackageTest.java | 19 +- .../test/java/contract/SampleContract.java | 8 +- .../java/org/hyperledger/fabric/TestUtil.java | 110 ++++++++++++ .../contract/ChaincodeStubNaiveImpl.java | 26 ++- .../fabric/contract/ClientIdentityTest.java | 126 +++++++++++++ .../fabric/contract/ContextFactoryTest.java | 3 + .../fabric/contract/ContextTest.java | 37 ++++ .../fabric/contract/ContractRouterTest.java | 86 ++++++++- .../ContractExecutionServiceTest.java | 5 +- .../metadata/MetadataBuilderTest.java | 10 +- .../routing/ContractDefinitionTest.java | 4 +- .../simplepath/ContractSimplePath.java | 97 +--------- .../fabric/shim/fvt/ChaincodeFVTest.java | 57 ++++-- .../shim/impl/ChaincodeStubImplTest.java | 4 +- 23 files changed, 702 insertions(+), 173 deletions(-) create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/TestUtil.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java 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 index fea47893..1d77134f 100644 --- 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 @@ -5,7 +5,42 @@ */ package org.hyperleder.fabric.shim.integration; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.spec.InvalidKeySpecException; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + 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; @@ -18,25 +53,28 @@ 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.hyperledger.fabric.sdk.BlockEvent; +import org.hyperledger.fabric.sdk.ChaincodeCollectionConfiguration; +import org.hyperledger.fabric.sdk.ChaincodeEndorsementPolicy; +import org.hyperledger.fabric.sdk.ChaincodeID; +import org.hyperledger.fabric.sdk.Channel; +import org.hyperledger.fabric.sdk.Enrollment; +import org.hyperledger.fabric.sdk.HFClient; +import org.hyperledger.fabric.sdk.InstallProposalRequest; +import org.hyperledger.fabric.sdk.InstantiateProposalRequest; +import org.hyperledger.fabric.sdk.Orderer; +import org.hyperledger.fabric.sdk.Peer; +import org.hyperledger.fabric.sdk.ProposalResponse; +import org.hyperledger.fabric.sdk.TransactionProposalRequest; +import org.hyperledger.fabric.sdk.TransactionRequest; +import org.hyperledger.fabric.sdk.User; +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.exception.ProposalException; +import org.hyperledger.fabric.sdk.exception.TransactionException; 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) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index a537ec04..13340b4b 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -19,8 +19,8 @@ tasks.withType(org.gradle.api.tasks.testing.Test) { dependencies { compile project(':fabric-chaincode-protos') compile 'io.netty:netty-tcnative-boringssl-static:2.0.7.Final' - compile 'org.bouncycastle:bcpkix-jdk15on:1.60' - compile 'org.bouncycastle:bcprov-jdk15on:1.60' + compile 'org.bouncycastle:bcpkix-jdk15on:1.62' + compile 'org.bouncycastle:bcprov-jdk15on:1.62' compile 'org.reflections:reflections:0.9.11' implementation 'com.github.everit-org.json-schema:org.everit.json.schema:1.11.1' compile 'io.swagger.core.v3:swagger-annotations:2.0.0' 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..ce4d7b4b --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java @@ -0,0 +1,169 @@ +/* +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 org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DEROctetString; +import org.hyperledger.fabric.Logger; +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 String mspId; + private X509Certificate cert; + private Map attrs; + private 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(ChaincodeStub stub) throws CertificateException, JSONException, IOException { + final byte[] signingId = stub.getCreator(); + + // Create a Serialized Identity protobuf + 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(byte[] extensionValue) throws IOException { + + Map attrMap = new HashMap(); + + // Create ASN1InputStream from extensionValue + try ( ByteArrayInputStream inStream = new ByteArrayInputStream(extensionValue); + ASN1InputStream asn1InputStream = new ASN1InputStream(inStream)) { + + // Read the DER object + ASN1Primitive derObject = asn1InputStream.readObject(); + if (derObject instanceof DEROctetString) + { + DEROctetString derOctetString = (DEROctetString) derObject; + + // Create attributeString from octets and create JSON object + String attributeString = new String(derOctetString.getOctets(), UTF_8); + final JSONObject extJSON = new JSONObject(attributeString); + final JSONObject attrs = extJSON.getJSONObject("attrs"); + + Iterator keys = attrs.keys(); + while(keys.hasNext()) { + String key = keys.next(); + // Populate map with attributes and values + attrMap.put(key, attrs.getString(key)); + } + } + } catch (JSONException error) { + // creating a JSON object failed + // decoded extensionValue is not a string containing JSON + logger.error(() -> logger.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(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(String attrName, 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; + } +} \ No newline at end of file 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 index 8cc1085d..561c9ae4 100644 --- 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 @@ -6,7 +6,11 @@ package org.hyperledger.fabric.contract; +import java.io.IOException; +import java.security.cert.CertificateException; + import org.hyperledger.fabric.shim.ChaincodeStub; +import org.json.JSONException; /** * @@ -32,13 +36,20 @@ */ 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); + } } /** @@ -48,4 +59,12 @@ public Context(ChaincodeStub stub) { 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/ContractRouter.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java index 42a5be12..0338731c 100644 --- 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 @@ -116,7 +116,7 @@ TxFunction getRouting(InvocationRequest request) { } else { logger.debug(() -> "Namespace is " + request); ContractDefinition contract = registry.getContract(request.getNamespace()); - return contract.getUnkownRoute(); + return contract.getUnknownRoute(); } } 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 index 052afde3..e55a3a92 100644 --- 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 @@ -12,7 +12,7 @@ import org.hyperledger.fabric.shim.ChaincodeStub; /** - * Service that executes {@link InvocationRequest} (wrapped INit/Invoke + extra data) using routing information {@link Routing} + * Service that executes {@link InvocationRequest} (wrapped Init/Invoke + extra data) using routing information {@link Routing} */ public interface ExecutionService { 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 index 189f2a43..2fec80ef 100644 --- 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 @@ -22,6 +22,7 @@ import org.everit.json.schema.loader.SchemaLoader; import org.hyperledger.fabric.Logger; 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; @@ -31,8 +32,6 @@ import org.json.JSONObject; import org.json.JSONTokener; -import org.hyperledger.fabric.contract.annotation.Info; - /** * Builder to assist in production of the metadata *

@@ -99,7 +98,7 @@ public static void initialize(RoutingRegistry registry, TypeRegistry typeRegistr // 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 scehma created"); + logger.info("Validating schema created"); MetadataBuilder.validate(); } 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 index 6099a10a..d74354b2 100644 --- 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 @@ -24,7 +24,7 @@ * 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 unkown + * itself, and the routing for any tx function that is unknown * */ public interface ContractDefinition { @@ -59,8 +59,8 @@ public interface ContractDefinition { /** * - * @param method name to returned - * @return TxFunction that represent this requested method + * @param method name to be returned + * @return TxFunction that represents this requested method */ TxFunction getTxFunction(String method); @@ -75,7 +75,7 @@ public interface ContractDefinition { * @return The TxFunction to be used for this contract in case of unknown * request */ - TxFunction getUnkownRoute(); + TxFunction getUnknownRoute(); /** * @return Underlying raw annotation 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 index 851540ed..f0635200 100644 --- 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 @@ -112,7 +112,7 @@ public boolean hasTxFunction(String method) { } @Override - public TxFunction getUnkownRoute() { + public TxFunction getUnknownRoute() { return unknownTx; } diff --git a/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java b/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java index 56dbdcd1..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(); diff --git a/fabric-chaincode-shim/src/test/java/contract/SampleContract.java b/fabric-chaincode-shim/src/test/java/contract/SampleContract.java index a869c1c1..084fed8c 100644 --- a/fabric-chaincode-shim/src/test/java/contract/SampleContract.java +++ b/fabric-chaincode-shim/src/test/java/contract/SampleContract.java @@ -9,12 +9,12 @@ 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.Transaction; -import org.hyperledger.fabric.contract.annotation.Contact; 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( @@ -26,7 +26,9 @@ license = @License( name = "fred", url = "http://fred.me" - ) + ), + version = "0.0.1", + title = "samplecontract" ) ) @Default() 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 index 36685084..56262405 100644 --- 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 @@ -8,11 +8,16 @@ 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; @@ -23,15 +28,14 @@ import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata; -import com.google.protobuf.ByteString; - public class ChaincodeStubNaiveImpl implements ChaincodeStub { private List args; private List argsAsByte; private Map state; private Chaincode.Response resp; + private String certificate = TestUtil.certWithoutAttrs; - ChaincodeStubNaiveImpl() { + public ChaincodeStubNaiveImpl() { args = new ArrayList<>(); args.add("func1"); args.add("param1"); @@ -252,7 +256,7 @@ public Instant getTxTimestamp() { @Override public byte[] getCreator() { - return new byte[0]; + return buildSerializedIdentity(); } @Override @@ -269,4 +273,18 @@ 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 index 72a4d2a9..10dbd537 100644 --- 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 @@ -41,5 +41,8 @@ public void createContext() { 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/ContractRouterTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java index 7bdd932a..ec426e9e 100644 --- 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 @@ -75,8 +75,12 @@ public void testInit() { assertThat(SampleContract.t1Invoked, is(1)); } + /** + * Test invoking two transaction functions in a contract via fully qualified + * name + */ @Test - public void testInvokeTxnThatExists() { + public void testInvokeTwoTxnsThatExist() { ContractRouter r = new ContractRouter(new String[] { "-a", "127.0.0.1:7052", "-i", "testId" }); r.findAllContracts(); ChaincodeStub s = new ChaincodeStubNaiveImpl(); @@ -100,6 +104,26 @@ public void testInvokeTxnThatExists() { 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 @@ -129,6 +153,57 @@ public void testInvokeTxnWithDefinedName() { 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" }); @@ -289,10 +364,13 @@ public void testInvokeTxnThatThrowsAChaincodeException() { assertThat(SampleContract.doWorkInvoked, is(0)); } + /** + * Test confirming ContractRuntimeExceptions can be created + */ @Test - public void exceptions() { + public void createContractRuntimeExceptions() { ContractRuntimeException cre1 = new ContractRuntimeException("failure"); - ContractRuntimeException cre2 = new ContractRuntimeException("another failure", cre1); - ContractRuntimeException cre3 = new ContractRuntimeException(new Exception("cause")); + new ContractRuntimeException("another failure", cre1); + new ContractRuntimeException(new Exception("cause")); } } 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 index b9bd831d..8a75fba7 100644 --- 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 @@ -16,6 +16,7 @@ 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; @@ -48,7 +49,7 @@ public void noReturnValue() InvocationRequest req = mock(InvocationRequest.class); TxFunction.Routing routing = mock(TxFunction.Routing.class); - ChaincodeStub stub = mock(ChaincodeStub.class); + ChaincodeStub stub = new ChaincodeStubNaiveImpl(); when(txFn.getRouting()).thenReturn(routing); when(req.getArgs()).thenReturn(new ArrayList() { @@ -69,7 +70,7 @@ public void failureToInvoke() ContractExecutionService ces = new ContractExecutionService(typeRegistry); - ContractInterface contract = spy(new SampleContract()); + spy(new SampleContract()); TxFunction txFn = mock(TxFunction.class); InvocationRequest req = mock(InvocationRequest.class); TxFunction.Routing routing = mock(TxFunction.Routing.class); 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 index 9aaa83b2..3a6cc264 100644 --- 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 @@ -8,8 +8,10 @@ import java.io.Serializable; import java.util.HashMap; +import org.hyperledger.fabric.contract.ChaincodeStubNaiveImpl; import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.contract.systemcontract.SystemContract; +import org.hyperledger.fabric.shim.ChaincodeStub; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -19,7 +21,7 @@ public class MetadataBuilderTest { @Rule public ExpectedException thrown = ExpectedException.none(); - String expectedJSON = " {\n" + " \"components\": {\"schemas\": {}},\n" + 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" @@ -41,10 +43,10 @@ public void beforeEach() { @Test public void systemContract() { - // access the system contract to extract the metadata SystemContract system = new SystemContract(); - String metadatacompressed = system.getMetadata(new Context(null)); - + ChaincodeStub stub = new ChaincodeStubNaiveImpl(); + // TODO: Assert something about the returned metadata + String metadataCompressed = system.getMetadata(new Context(stub)); } } \ No newline at end of file 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 index 786a51bd..c4d707be 100644 --- 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 @@ -49,7 +49,7 @@ public class FailureTestObject { public int step = 1; @Test - public void unkownRoute() { + public void unknownRoute() { SecurityManager tmp = new SecurityManager() { int count = 0; @@ -77,7 +77,7 @@ public void checkPermission(Permission perm) { System.setSecurityManager(tmp); this.fail = true; - cf.getUnkownRoute(); + cf.getUnknownRoute(); } catch (Exception e) { assertThat(e.getMessage(), equalTo("Failure to find unknownTransation method")); } finally { 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 index a6df5bed..dd407aab 100644 --- 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 @@ -7,7 +7,6 @@ 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.READY; import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.REGISTER; import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.TRANSACTION; @@ -17,6 +16,8 @@ import java.util.List; import java.util.concurrent.TimeUnit; +import com.google.protobuf.ByteString; + import org.hyperledger.fabric.contract.ContractRouter; import org.hyperledger.fabric.protos.peer.Chaincode; import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeInput.Builder; @@ -26,7 +27,6 @@ import org.hyperledger.fabric.protos.peer.ProposalResponsePackage.Response; import org.hyperledger.fabric.shim.mock.peer.ChaincodeMockPeer; import org.hyperledger.fabric.shim.mock.peer.CompleteStep; -import org.hyperledger.fabric.shim.mock.peer.ErrorResponseStep; import org.hyperledger.fabric.shim.mock.peer.RegisterStep; import org.hyperledger.fabric.shim.mock.peer.ScenarioStep; import org.hyperledger.fabric.shim.utils.MessageUtil; @@ -36,8 +36,6 @@ 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(); @@ -75,97 +73,6 @@ public void testContract() throws Exception { assertThat(server.getLastMessageRcvd().getType(), is(REGISTER)); } - /** - * Test executing two transaction functions in a contract via fully qualified - * name - * - * @throws Exception - */ - @Test - public void main() throws Exception { - - List scenario = new ArrayList<>(); - scenario.add(new RegisterStep()); - scenario.add(new CompleteStep()); - scenario.add(new CompleteStep()); - - 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); - - ChaincodeShim.ChaincodeMessage initMsg = newInvokeFn(new String[] { "samplecontract:t2" }); - server.send(initMsg); - ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); - assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); - assertThat(getLastReturnString(), is("Transaction 2")); - - ChaincodeShim.ChaincodeMessage invokeMsg = newInvokeFn(new String[] { "samplecontract:t1", "a" }); - server.send(invokeMsg); - ChaincodeMockPeer.checkScenarioStepEnded(server, 3, 5000, TimeUnit.MILLISECONDS); - assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); - assertThat(getLastReturnString(), is("a")); - } - - /** - * Test executing two transaction functions in a contract via default name - * - * @throws Exception - */ - @Test - public void defaultNamespace() throws Exception { - - List scenario = new ArrayList<>(); - scenario.add(new RegisterStep()); - scenario.add(new CompleteStep()); - scenario.add(new CompleteStep()); - - 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); - - ChaincodeShim.ChaincodeMessage initMsg = newInvokeFn(new String[] { "t2" }); - server.send(initMsg); - ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); - assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); - assertThat(getLastReturnString(), is("Transaction 2")); - - ChaincodeShim.ChaincodeMessage invokeMsg = newInvokeFn(new String[] { "t1", "a" }); - server.send(invokeMsg); - ChaincodeMockPeer.checkScenarioStepEnded(server, 3, 5000, TimeUnit.MILLISECONDS); - assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); - assertThat(getLastReturnString(), is("a")); - } - - /** - * Test executing two a function that does not exist - * - * @throws Exception - */ - @Test - public void unkownFn() throws Exception { - - List scenario = new ArrayList<>(); - scenario.add(new RegisterStep()); - scenario.add(new ErrorResponseStep()); - - 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); - - ChaincodeShim.ChaincodeMessage initMsg = newInvokeFn(new String[] { "samplecontract:wibble" }); - server.send(initMsg); - ChaincodeMockPeer.checkScenarioStepEnded(server, 2, 5000, TimeUnit.MILLISECONDS); - assertThat(server.getLastMessageRcvd().getType(), is(ERROR)); - assertThat(server.getLastMessageRcvd().getPayload().toStringUtf8(), is("Undefined contract method called")); - - } - public ChaincodeMessage newInvokeFn(String args[]) { Builder invokePayload = Chaincode.ChaincodeInput.newBuilder(); for (String arg : args) { 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 d549257d..c8ed7683 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,7 +5,28 @@ */ 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; @@ -18,27 +39,27 @@ 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 org.mockito.Mock; - -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 { @@ -122,7 +143,7 @@ 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 ResponseUtils.newSuccessResponse("OK response2"); @@ -459,7 +480,7 @@ public Response init(ChaincodeStub stub) { @Override public Response invoke(ChaincodeStub stub) { - Response response = stub.invokeChaincode("anotherChaincode", Collections.emptyList()); + stub.invokeChaincode("anotherChaincode", Collections.emptyList()); return ResponseUtils.newSuccessResponse("OK response2"); } }; 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 index fe068397..dda43314 100644 --- 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 @@ -322,7 +322,7 @@ public void testGetStateByPartialCompositeKey_withAttributesAsString() { } @Test - public void testGetStateByPartialCompositeKey_withAttributesWithSplittedParams() { + public void testGetStateByPartialCompositeKey_withAttributesWithSplitParams() { ChaincodeStubImpl stub = prepareStubAndMockHandler(); CompositeKey cKey = new CompositeKey("KEY", "attr1", "attr2", "attr3"); @@ -681,7 +681,7 @@ public void testGetPrivateDataByPartialCompositeKey_withAttributesAsString() { } @Test - public void testGetPrivateDataByPartialCompositeKey_withAttributesWithSplittedParams() { + public void testGetPrivateDataByPartialCompositeKey_withAttributesWithSplitParams() { ChaincodeStubImpl stub = prepareStubAndMockHandler(); CompositeKey cKey = new CompositeKey("KEY", "attr1", "attr2", "attr3"); From bd59b349ad163ed04ac0ac0029427651d1a9fcf8 Mon Sep 17 00:00:00 2001 From: Simon Stone Date: Thu, 8 Aug 2019 12:52:24 +0100 Subject: [PATCH 13/61] [FAB-16217] Do not load JSON Schema schema from network Currently, the JSON Schema schema (http://json-schema.org/draft-04/schema) is loaded from the network every time the Java chaincode starts. This has been seen to cause delays/hangs in the CI system, and we should avoid it if possible. This CR adds the JSON Schema schema to the chaincode resources, and uses that copy (instead of the network copy) to validate any contract schemas. Signed-off-by: Simon Stone Change-Id: Ic559fb5f1a07f86bcd4d2eb2003c791e71abc701 (cherry picked from commit 4371d072c2566a2becaea6dfc8422d2d76261a30) --- .../contract/metadata/MetadataBuilder.java | 21 ++- .../json-schema-draft-04-schema.json | 149 ++++++++++++++++++ .../metadata/MetadataBuilderTest.java | 27 +++- 3 files changed, 192 insertions(+), 5 deletions(-) create mode 100644 fabric-chaincode-shim/src/main/resources/json-schema-draft-04-schema.json 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 index 2fec80ef..3fa51687 100644 --- 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 @@ -8,6 +8,7 @@ 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; @@ -19,7 +20,9 @@ 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.Logger; import org.hyperledger.fabric.contract.annotation.Contract; import org.hyperledger.fabric.contract.annotation.Info; @@ -61,6 +64,9 @@ V putIfNotNull(K key, V value) { 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 * @@ -68,10 +74,17 @@ V putIfNotNull(K key, V value) { */ public static void validate() { logger.info("Running schema test validation"); - try (InputStream inputStream = MetadataBuilder.class.getClassLoader() - .getResourceAsStream("contract-schema.json")) { - JSONObject rawSchema = new JSONObject(new JSONTokener(inputStream)); - Schema schema = SchemaLoader.load(rawSchema); + ClassLoader cl = MetadataBuilder.class.getClassLoader(); + try (InputStream contractSchemaInputStream = cl.getResourceAsStream("contract-schema.json"); + InputStream jsonSchemaInputStream = cl.getResourceAsStream("json-schema-draft-04-schema.json")) { + JSONObject rawContractSchema = new JSONObject(new JSONTokener(contractSchemaInputStream)); + JSONObject rawJsonSchema = new JSONObject(new JSONTokener(jsonSchemaInputStream)); + SchemaLoader schemaLoader = SchemaLoader.builder() + .schemaClient(schemaClient) + .schemaJson(rawContractSchema) + .registerSchemaByURI(URI.create("http://json-schema.org/draft-04/schema"), rawJsonSchema) + .build(); + Schema schema = schemaLoader.load().build(); schema.validate(metadata()); } catch (IOException e) { 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/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java index 3a6cc264..04f967ad 100644 --- 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 @@ -5,18 +5,26 @@ */ 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(); @@ -34,10 +42,12 @@ public class MetadataBuilderTest { + " \"contact\": {\"email\": \"fred@example.com\"}\n" + " }\n" + " }\n" + ""; @Before - public void beforeEach() { + @After + public void beforeAndAfterEach() { MetadataBuilder.componentMap = new HashMap(); MetadataBuilder.contractMap = new HashMap>(); MetadataBuilder.overallInfoMap = new HashMap(); + MetadataBuilder.schemaClient = new DefaultSchemaClient(); } @Test @@ -49,4 +59,19 @@ public void systemContract() { String metadataCompressed = 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 From 8cca4bb4a90806bb6d3877dffb812643b6cebc19 Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Mon, 19 Aug 2019 13:58:59 +0100 Subject: [PATCH 14/61] [FAB-16315] Unrequired lock Change-Id: Ifc885b6e702a4722a8f5296c97e1c1a44f98d8c5 Signed-off-by: Matthew B. White --- .../hyperledger/fabric/shim/impl/Handler.java | 49 +------------------ 1 file changed, 2 insertions(+), 47 deletions(-) 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 index 9929d2d9..4f5ad102 100644 --- 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 @@ -67,7 +67,6 @@ 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; @@ -236,28 +235,6 @@ private synchronized void releaseResponseChannelForTx(String channelId, String t } } - /** - * 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 * @@ -270,9 +247,6 @@ private void handleInit(ChaincodeMessage message) { // 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()); @@ -294,9 +268,6 @@ private void handleInit(ChaincodeMessage message) { } 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(); } @@ -309,9 +280,6 @@ private void handleTransaction(ChaincodeMessage message) { // 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()); @@ -334,9 +302,6 @@ private void handleTransaction(ChaincodeMessage message) { } 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(); } @@ -363,28 +328,18 @@ Map getStateMetadata(String channelId, String txId, String c } } - 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) { + 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))); + logger.fine(format("[%-8.8s] Inside putstate (\"%s\":\"%s\":\"%s\")", txId, collection, key, value)); } - 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)); } From 1db31c94471ef764e65757decb1f007923640222 Mon Sep 17 00:00:00 2001 From: Ry Jones Date: Wed, 25 Sep 2019 10:18:37 -0700 Subject: [PATCH 15/61] [IN-68] Add default GitHub SECURITY policy this file must exist on the default branch Signed-off-by: Ry Jones Change-Id: I8a172ea9a8f0e4ffbdd7b789fe879cac489a76b6 (cherry picked from commit af3dec089f15de4100167d1e8f25dfec137a7e87) --- SECURITY.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 SECURITY.md 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). + From b58f11dbc4dd721e1b97079d836cf691f8738e6e Mon Sep 17 00:00:00 2001 From: vijaypunugubati Date: Wed, 2 Oct 2019 10:03:57 -0400 Subject: [PATCH 16/61] FAB-16680 Fix cloudflare error on jitpack.io Fixing error on fabric-chaincode-java builds to get dependencies from jitpack.io in 1.4 branch Signed-off-by: vijaypunugubati Change-Id: Iaccb2b7db4852d58719aeb481d61192f1fd5f74b --- build.gradle | 2 +- fabric-chaincode-docker/build.gradle | 2 +- fabric-chaincode-example-gradle/build.gradle | 2 +- fabric-contract-example/gradle/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 25d70882..49e7eadd 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ allprojects { mavenLocal() jcenter() maven { url "https://oss.sonatype.org/content/repositories/snapshots" } - maven { url 'https://jitpack.io' } + maven { url "https://www.jitpack.io" } mavenCentral() } } diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index b50cf851..bdeb0101 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -9,7 +9,7 @@ buildscript { mavenLocal() jcenter() maven { url "https://oss.sonatype.org/content/repositories/snapshots" } - maven { url 'https://jitpack.io' } + maven { url "https://www.jitpack.io" } mavenCentral() } dependencies { diff --git a/fabric-chaincode-example-gradle/build.gradle b/fabric-chaincode-example-gradle/build.gradle index c143d517..befed338 100644 --- a/fabric-chaincode-example-gradle/build.gradle +++ b/fabric-chaincode-example-gradle/build.gradle @@ -11,7 +11,7 @@ sourceCompatibility = 1.8 repositories { mavenLocal() mavenCentral() - maven { url 'https://jitpack.io' } + maven { url "https://www.jitpack.io" } } dependencies { diff --git a/fabric-contract-example/gradle/build.gradle b/fabric-contract-example/gradle/build.gradle index 029a9cae..21087a62 100644 --- a/fabric-contract-example/gradle/build.gradle +++ b/fabric-contract-example/gradle/build.gradle @@ -11,7 +11,7 @@ repositories { mavenLocal() mavenCentral() maven { - url 'https://jitpack.io' + url "https://www.jitpack.io" } maven { url "https://nexus.hyperledger.org/content/repositories/snapshots/" From 388802e990def4368c1775a71c83b425f0982196 Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Thu, 3 Oct 2019 09:16:52 +0100 Subject: [PATCH 17/61] [FAB-16745] Remove SDK from integration tests - Remove the use of the SDK to setup fabric - Use the script.sh in the cli container for the channel, and cc install etc. - Use Java ProcessBuilder to then issue peer exec/peer chaincode invoke calls in the cli container - This change is remove dependency on the SDK and focus on the tests that do exist - Will move to Cucumber in due course Change-Id: I0a6529a0bf3e324e432622f8ada35a2d2ec18829 Signed-off-by: Matthew B. White --- .gitignore | 7 +- .../fabric/example/EndorsementCC.java | 9 + .../build.gradle | 15 + .../fabric/shim/integration/Command.java | 119 ++++ .../fabric/shim/integration/Docker.java | 77 +++ .../shim/integration/DockerCompose.java | 74 +++ .../fabric/shim/integration/Peer.java | 169 +++++ .../shim/integration/SACCIntegrationTest.java | 123 ++-- .../integration/SBECCIntegrationTest.java | 226 ++++--- .../fabric/shim/integration/Utils.java | 615 ------------------ .../base/docker-compose-base.yaml | 2 +- .../first-network/base/peer-base.yaml | 5 +- .../first-network/docker-compose-cli.yaml | 9 +- .../scripts/collection_config.json | 9 + .../first-network/scripts/script-sbe.sh | 37 ++ .../resources/first-network/scripts/script.sh | 25 +- .../resources/first-network/scripts/utils.sh | 37 +- 17 files changed, 762 insertions(+), 796 deletions(-) create mode 100644 fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Command.java create mode 100644 fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Docker.java create mode 100644 fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/DockerCompose.java create mode 100644 fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Peer.java delete mode 100644 fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Utils.java create mode 100644 fabric-chaincode-integration-test/src/test/resources/first-network/scripts/collection_config.json create mode 100755 fabric-chaincode-integration-test/src/test/resources/first-network/scripts/script-sbe.sh diff --git a/.gitignore b/.gitignore index 9495ade8..5a44b8f7 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,9 @@ nbdist/ local-config.yaml gradle.properties -.vscode/ \ No newline at end of file +.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/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..8103fcf3 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,16 @@ public Response getVal(ChaincodeStub stub) { } if ("pub".equals(parameters.get(0))) { + _logger.info(stub.getState("pub")); return newSuccessResponse(stub.getState("pub")); } else if ("priv".equals(parameters.get(0))) { + _logger.info("get privateData" +stub.getPrivateData("col", "priv")); return newSuccessResponse(stub.getPrivateData("col", "priv")); } 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..8876e3cc 100644 --- a/fabric-chaincode-integration-test/build.gradle +++ b/fabric-chaincode-integration-test/build.gradle @@ -3,7 +3,22 @@ dependencies { testCompile 'org.testcontainers:testcontainers:1.7.1' testCompile 'org.hyperledger.fabric-sdk-java:fabric-sdk-java:1.4.1' 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" + + } + } \ No newline at end of file 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/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..559c7ccc 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 @@ -5,86 +5,79 @@ */ package org.hyperleder.fabric.shim.integration; -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.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 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.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.Test; +/** + * 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(); - } - - @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()); + // 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); - Channel myChannel = Utils.getMyChannelFirstNetwork(client); - List peers = myChannel.getPeers().stream().filter(peer -> peer.getName().indexOf("peer0.org1") != -1).collect(Collectors.toList()); + // create the docker-compose command + DockerComposeBuilder composebuilder = DockerCompose.newBuilder() + .file("src/test/resources/first-network/docker-compose-cli.yaml"); - InstallProposalRequest installProposalRequest = generateSACCInstallRequest(client); - Utils.sendInstallProposals(client, installProposalRequest, peers); + // close down anything running... + composebuilder.duplicate().down().build().run(); - // Instantiating chaincode - InstantiateProposalRequest instantiateProposalRequest = generateSACCInstantiateRequest(client); - Utils.sendInstantiateProposal("javacc", instantiateProposalRequest, myChannel, peers, myChannel.getOrderers()); + // ...and bring up + DockerCompose compose = composebuilder.up().detach().build(); + compose.run(); - 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); - } - - static public InstallProposalRequest generateSACCInstallRequest(HFClient client) throws IOException, InvalidArgumentException { - return Utils.generateInstallRequest(client, "javacc", "1.0", "../fabric-chaincode-example-sacc"); + // 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(); } - 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"); - } - - static public TransactionProposalRequest generateSACCInvokeRequest(HFClient client, String key, String value) { - return Utils.generateTransactionRequest(client, "javacc", "1.0", "set", key, value); - } + @Test + public void TestSACCChaincodeInstallInstantiateInvokeQuery() { + + // 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("javacc").channel("mychannel"); + Result r; + String text; + // 2019-10-02 13:05:59.812 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 004 Chaincode invoke successful. result: status:200 message:"200" + + r = coreBuilder.duplicate().argsTx(new String[] { "set", "b", "200" }).build().run(); + text = r.stderr.stream() + .filter(line -> line.matches(".*chaincodeInvokeOrQuery.*")) + .collect(Collectors.joining(System.lineSeparator())); + assertThat(text, containsString("result: status:200 message:\"200\"")); + + r = coreBuilder.duplicate().argsTx(new String[] { "get", "a" }).build().run(); + text = r.stderr.stream() + .filter(line -> line.matches(".*chaincodeInvokeOrQuery.*")) + .collect(Collectors.joining(System.lineSeparator())); + assertThat(text, containsString("result: status:200 message:\"100\"")); + + r = coreBuilder.duplicate().argsTx(new String[] { "get", "b" }).build().run(); + text = r.stderr.stream() + .filter(line -> line.matches(".*chaincodeInvokeOrQuery.*")) + .collect(Collectors.joining(System.lineSeparator())); + assertThat(text, containsString("result: status:200 message:\"200\"")); - 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..db72ec4c 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,184 @@ */ 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(); + + // Call the inbuilt script to install/instantiate + DockerBuilder dockerBuilder = new Docker.DockerBuilder(); + Docker docker = dockerBuilder.exec().container("cli").script("./scripts/script-sbe.sh").build(); + docker.run(); + } + + 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; - // Create client and set default crypto suite - System.out.println("Creating client"); - final HFClient client = HFClient.createNewInstance(); - client.setCryptoSuite(crypto); + String text; - client.setUserContext(Utils.getAdminUserOrg1TLS()); + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "foo" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - Channel myChannel = Utils.getMyChannelFirstNetwork(client); + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200 payload:\"foo\"")); - 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[] { "addorgs", mode, "Org1MSP" }).build().run(true); + text = filter(r.stderr); + assertThat(text, 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[] { "listorgs", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200 payload:\"[\\\"Org1MSP\\\"]\" ")); - 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, "val1" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - RunSBE(client, myChannel, "pub"); - RunSBE(client, myChannel, "priv"); + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200 payload:\"val1\"")); - } + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val2" }).build().run(true); + text = filter(r.stderr); + assertThat(text, 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()); + 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.org1") != -1).collect(Collectors.toList()), Matchers.is(200), Matchers.anything(), Matchers.is(ByteString.copyFrom("foo", 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, "addorgs", mode, "Org1MSP"); - 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[] { "listorgs", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200 payload:\"[\\\"Org2MSP\\\",\\\"Org1MSP\\\"]\"")); - 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, "val3" }).build().run(true); + assertThat(filter(r.stderr), 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); + assertThat(filter(r.stderr), containsString("result: status:200 payload:\"val3\"")); - 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[] { "setval", mode, "val4" }).build().run(true); + assertThat(filter(r.stderr), 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[] { "getval", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200 payload:\"val4\"")); - 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[] { "delorgs", mode, "Org1MSP" }).build().run(true); + assertThat(filter(r.stderr), 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[] { "listorgs", mode }).build().run(true); + text = filter(r.stderr); + assertThat(filter(r.stderr), containsString("result: status:200 payload:\"[\\\"Org2MSP\\\"]\"")); - 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)))); + } - 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); - 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))); + @Test + public void RunSBE_priv() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, IOException, ProposalException, InvalidArgumentException { + String mode = "priv"; - 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()); + // 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; - 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))); + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "foo" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - 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[] { "getval", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200 payload:\"foo\"")); - 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[] { "addorgs", mode, "Org1MSP" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - 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[] { "listorgs", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200 payload:\"[\\\"Org1MSP\\\"]\"")); - 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[] { "setval", mode, "val1" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - } + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200 payload:\"val1\"")); - 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[] { "setval", mode, "val2" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); - 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[]{}); - } + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200 payload:\"val2\"")); + + r = coreBuilder.duplicate().argsTx(new String[] { "addorgs", mode, "Org2MSP" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); + + r = coreBuilder.duplicate().argsTx(new String[] { "listorgs", mode }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200 payload:\"[\\\"Org2MSP\\\",\\\"Org1MSP\\\"]\"")); + + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val3" }).build().run(true); + text = filter(r.stderr); + assertThat(text, containsString("result: status:200")); + + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200 payload:\"val3\"")); + + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val4" }).build().run(true); + assertThat(filter(r.stderr),text, containsString("result: status:200")); + + 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")); + + r = coreBuilder.duplicate().argsTx(new String[] { "listorgs", mode }).build().run(true); + assertThat(filter(r.stderr), containsString("result: status:200 payload:\"[\\\"Org2MSP\\\"]\"")); - 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 1d77134f..00000000 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/Utils.java +++ /dev/null @@ -1,615 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ -package org.hyperleder.fabric.shim.integration; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -import java.io.BufferedOutputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.Security; -import java.security.spec.InvalidKeySpecException; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; - -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.BlockEvent; -import org.hyperledger.fabric.sdk.ChaincodeCollectionConfiguration; -import org.hyperledger.fabric.sdk.ChaincodeEndorsementPolicy; -import org.hyperledger.fabric.sdk.ChaincodeID; -import org.hyperledger.fabric.sdk.Channel; -import org.hyperledger.fabric.sdk.Enrollment; -import org.hyperledger.fabric.sdk.HFClient; -import org.hyperledger.fabric.sdk.InstallProposalRequest; -import org.hyperledger.fabric.sdk.InstantiateProposalRequest; -import org.hyperledger.fabric.sdk.Orderer; -import org.hyperledger.fabric.sdk.Peer; -import org.hyperledger.fabric.sdk.ProposalResponse; -import org.hyperledger.fabric.sdk.TransactionProposalRequest; -import org.hyperledger.fabric.sdk.TransactionRequest; -import org.hyperledger.fabric.sdk.User; -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.exception.ProposalException; -import org.hyperledger.fabric.sdk.exception.TransactionException; -import org.testcontainers.DockerClientFactory; - -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..54dcde48 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 @@ -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..4062ad62 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 @@ -14,9 +14,8 @@ services: # 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 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..65c1cea3 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 @@ -65,23 +65,24 @@ services: 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 + - ./../../../../../fabric-chaincode-example-sacc:/opt/gopath/src/github.com/hyperledger/fabric/peer/chaincodes/sacc + - ./../../../../../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..4356063a 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 @@ -16,22 +16,12 @@ TIMEOUT="$4" VERBOSE="$5" : ${CHANNEL_NAME:="mychannel"} : ${DELAY:="3"} -: ${LANGUAGE:="golang"} +: ${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,15 @@ 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 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" +instantiateChaincode 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..dc8b0bc1 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,6 +128,34 @@ installChaincode() { echo } +instantiateChaincodeSBE() { + 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 "$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":["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 ${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 @@ -139,17 +167,18 @@ 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 javacc -l ${LANGUAGE} -v ${VERSION} -c '{"Args":["init","a","100","b","200"]}' -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 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 javacc -l ${LANGUAGE} -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&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 } @@ -304,7 +333,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 From 5f6d88d49e1d9e9d3a90b741b4d7ab444ad9f731 Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Fri, 4 Oct 2019 13:23:08 +0100 Subject: [PATCH 18/61] [FAB-16711] azure pipelines Change-Id: I75d8936659f5350278196fefe67db6275ae62870 Signed-off-by: Matthew B. White --- ci/azure-pipelines.yml | 70 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 ci/azure-pipelines.yml diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml new file mode 100644 index 00000000..d60162c4 --- /dev/null +++ b/ci/azure-pipelines.yml @@ -0,0 +1,70 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +# fabric-chaincode-java azure pipeline configuration. +# +trigger: + branches: + include: + - 'master' + - '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: + component: fabric-chaincode-node + pipeline: ci + +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 + - task: Gradle@2 + inputs: + workingDirectory: '' + gradleWrapperFile: 'gradlew' + gradleOptions: '-Xmx3072m' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.8' + jdkArchitectureOption: 'x64' + 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' + - stage: Publish_tag + condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags')) + jobs: + - job: update_version + steps: + - script: | + env | sort + echo "Update the version number" + echo "Make sure release notes are present" + echo "Make sure change history is present" + - job: npm_publish + steps: + - script: | + echo "Setup .npmrc" + echo "Use pipeline secret to login" + echo "publish" + - job: jsdoc_publish + steps: + - script: | + echo "checkout docs branch" + echo "checking" \ No newline at end of file From f6c007aa2fcfd3116349adfafda2a10edf5af119 Mon Sep 17 00:00:00 2001 From: David Enyeart Date: Sun, 6 Oct 2019 13:05:27 -0400 Subject: [PATCH 19/61] fabric-chaincode-java update to baseimage 0.4.16 Change-Id: Iaeb651289a77b9720aa2a0acdab19023556f1599 Signed-off-by: David Enyeart --- fabric-chaincode-docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index befc80d7..8c52cfca 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 RUN apt-get update RUN apt-get install zip -y RUN curl -s "https://get.sdkman.io" | bash From f0a1784d38561f8cfbea66a8f9a7033d2ace47f7 Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Fri, 11 Oct 2019 15:36:36 +0100 Subject: [PATCH 20/61] [FAB-16817] manifest classpath Add in the manifest classpath for searching Change-Id: I90172a366b4a8725979e783f572082bd68a1b8c9 Signed-off-by: Matthew B. White --- .../fabric/contract/routing/impl/RoutingRegistryImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 index 7103c08e..dae8686f 100644 --- 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 @@ -156,9 +156,10 @@ public void findAndSetContracts(TypeRegistry typeRegistry) { ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); configurationBuilder.addUrls(urls); configurationBuilder.addUrls(ClasspathHelper.forJavaClassPath()); + configurationBuilder.addUrls(ClasspathHelper.forManifest()); Reflections ref = new Reflections(configurationBuilder); - logger.info("Searching chaincode class in urls: " + urls); + logger.info("Searching chaincode class in urls: " + configurationBuilder.getUrls()); // set to ensure that we don't scan the same class twice Set seenClass = new HashSet<>(); From a4938e86d9b8041dbe62e9deea9d888b6d45160f Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Wed, 16 Oct 2019 13:16:14 +0100 Subject: [PATCH 21/61] [FAB-16845] Correct Logging Signed-off-by: Matthew B. White Change-Id: I40419ce25b8cb7da17b34c8c09914ec5b78d50ce --- build.gradle | 3 +- fabric-chaincode-docker/build.gradle | 1 - fabric-chaincode-example-maven/pom.xml | 2 +- fabric-chaincode-example-sacc/build.gradle | 1 + .../fabric/example/SimpleAsset.java | 2 +- fabric-chaincode-example-sbe/build.gradle | 1 + .../build.gradle | 4 +- .../resources/first-network/scripts/script.sh | 2 +- .../resources/first-network/scripts/utils.sh | 4 +- fabric-chaincode-protos/build.gradle | 6 +- fabric-chaincode-shim/build.gradle | 21 +- .../java/org/hyperledger/fabric/Logger.java | 70 ------ .../java/org/hyperledger/fabric/Logging.java | 37 +++ .../fabric/contract/ClientIdentity.java | 109 +++++---- .../fabric/contract/ContractRouter.java | 16 +- .../execution/JSONTransactionSerializer.java | 56 ++--- .../impl/ContractExecutionService.java | 5 +- .../contract/metadata/MetadataBuilder.java | 81 ++++--- .../fabric/contract/metadata/TypeSchema.java | 4 +- .../routing/impl/ContractDefinitionImpl.java | 48 ++-- .../routing/impl/DataTypeDefinitionImpl.java | 2 - .../routing/impl/RoutingRegistryImpl.java | 62 ++--- .../contract/routing/impl/TxFunctionImpl.java | 41 ++-- .../hyperledger/fabric/shim/Chaincode.java | 31 +-- .../fabric/shim/ChaincodeBase.java | 216 ++++++++++-------- .../fabric/shim/ResponseUtils.java | 23 +- .../fabric/contract/ContractRouterTest.java | 3 + .../fabric/shim/ChaincodeBaseTest.java | 129 ++++++++--- .../fabric/shim/fvt/ChaincodeFVTest.java | 17 -- .../fabric/shim/impl/HandlerTest.java | 5 +- fabric-contract-example/maven/pom.xml | 2 +- 31 files changed, 540 insertions(+), 464 deletions(-) delete mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java diff --git a/build.gradle b/build.gradle index 49e7eadd..72ba7d2e 100644 --- a/build.gradle +++ b/build.gradle @@ -11,11 +11,10 @@ version = '1.4.4-SNAPSHOT' allprojects { repositories { + mavenCentral() mavenLocal() jcenter() - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } maven { url "https://www.jitpack.io" } - mavenCentral() } } diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index bdeb0101..1426563d 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -8,7 +8,6 @@ buildscript { repositories { mavenLocal() jcenter() - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } maven { url "https://www.jitpack.io" } mavenCentral() } diff --git a/fabric-chaincode-example-maven/pom.xml b/fabric-chaincode-example-maven/pom.xml index 1d743bd5..9926719e 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -26,7 +26,7 @@ jitpack.io - https://jitpack.io + https://www.jitpack.io nexus diff --git a/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-example-sacc/build.gradle index af0b2f34..c9ac43a3 100644 --- a/fabric-chaincode-example-sacc/build.gradle +++ b/fabric-chaincode-example-sacc/build.gradle @@ -11,6 +11,7 @@ sourceCompatibility = 1.8 repositories { mavenLocal() mavenCentral() + maven { url "https://www.jitpack.io" } } dependencies { 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..f869832a 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,7 +24,7 @@ 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 diff --git a/fabric-chaincode-example-sbe/build.gradle b/fabric-chaincode-example-sbe/build.gradle index 2d6d4f73..ac7a4270 100644 --- a/fabric-chaincode-example-sbe/build.gradle +++ b/fabric-chaincode-example-sbe/build.gradle @@ -11,6 +11,7 @@ sourceCompatibility = 1.8 repositories { mavenLocal() mavenCentral() + maven { url "https://www.jitpack.io" } } dependencies { diff --git a/fabric-chaincode-integration-test/build.gradle b/fabric-chaincode-integration-test/build.gradle index 8876e3cc..4e56f61e 100644 --- a/fabric-chaincode-integration-test/build.gradle +++ b/fabric-chaincode-integration-test/build.gradle @@ -1,7 +1,7 @@ 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.4' compile project(':fabric-chaincode-shim') implementation group: 'org.json', name: 'json', version: '20180813' } @@ -21,4 +21,4 @@ build.dependsOn project(':fabric-chaincode-docker').buildImage exceptionFormat "full" } - } \ No newline at end of file + } 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 4356063a..ce98f3d2 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,7 +15,7 @@ LANGUAGE="$3" TIMEOUT="$4" VERBOSE="$5" : ${CHANNEL_NAME:="mychannel"} -: ${DELAY:="3"} +: ${DELAY:="10"} : ${LANGUAGE:="java"} : ${TIMEOUT:="10"} : ${VERBOSE:="false"} 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 dc8b0bc1..4dd4190f 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 @@ -167,12 +167,12 @@ 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 javacc -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 javacc -l ${LANGUAGE} -v ${VERSION} -c '{"Args":["init","a","100"]}' -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 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 javacc -l ${LANGUAGE} -v 1.0 -c '{"Args":["init","a","100"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt res=$? set +x fi diff --git a/fabric-chaincode-protos/build.gradle b/fabric-chaincode-protos/build.gradle index 32560fb3..7b49c2c8 100644 --- a/fabric-chaincode-protos/build.gradle +++ b/fabric-chaincode-protos/build.gradle @@ -49,9 +49,9 @@ 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' } protobuf { diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 13340b4b..5e8a4ab4 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -15,10 +15,24 @@ 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 '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 'org.reflections:reflections:0.9.11' @@ -58,6 +72,9 @@ jacoco { } jacocoTestReport { + reports { + xml.enabled true + } afterEvaluate { classDirectories = files(classDirectories.files.collect { fileTree(dir: it, exclude: 'org/hyperledger/fabric/protos/**') @@ -249,6 +266,8 @@ uploadArchives { } } + + task sourcesJar(type: Jar) { classifier = 'sources' from sourceSets.main.allSource 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 deleted file mode 100644 index e9d2b9e6..00000000 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java +++ /dev/null @@ -1,70 +0,0 @@ -/* -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 - * - */ -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); - } - - public void debug(Supplier msgSupplier) { - log(Level.FINEST, msgSupplier); - } - - 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; - } - - public void error(String message) { - log(Level.SEVERE, message); - } - - public void error(Supplier msgSupplier) { - log(Level.SEVERE, msgSupplier); - } - - 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(); - } - -} 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..1d796861 --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java @@ -0,0 +1,37 @@ +/* +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.logging.Logger; + +/** + * Logger class to use throughout the Contract Implementation + * + */ +public class Logging { + + public static final String PERFLOGGER = "org.hyperledger.Performance"; + + public static String formatError(final Throwable throwable) { + if (throwable == null) { + return null; + } + final StringWriter buffer = new StringWriter(); + buffer.append(throwable.getMessage()); + throwable.printStackTrace(new PrintWriter(buffer)); + + final Throwable cause = throwable.getCause(); + if (cause != null) { + buffer.append(".. caused by .."); + buffer.append(Logging.formatError(cause)); + } + + return buffer.toString(); + + } +} 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 index ce4d7b4b..f9c53d3f 100644 --- 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 @@ -16,11 +16,12 @@ 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.Logger; +import org.hyperledger.fabric.Logging; import org.hyperledger.fabric.protos.msp.Identities.SerializedIdentity; import org.hyperledger.fabric.shim.ChaincodeStub; import org.json.JSONException; @@ -28,31 +29,33 @@ /** * 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. + * 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 String mspId; - private X509Certificate cert; + private final String mspId; + private final X509Certificate cert; private Map attrs; - private String id; + 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(ChaincodeStub stub) throws CertificateException, JSONException, IOException { + public ClientIdentity(final ChaincodeStub stub) throws CertificateException, JSONException, IOException { final byte[] signingId = stub.getCreator(); // Create a Serialized Identity protobuf - SerializedIdentity si = SerializedIdentity.parseFrom(signingId); + 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)); + final X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X509") + .generateCertificate(new ByteArrayInputStream(idBytes)); this.cert = cert; this.attrs = new HashMap(); @@ -65,9 +68,11 @@ public ClientIdentity(ChaincodeStub stub) throws CertificateException, JSONExcep // 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. + * 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() { @@ -76,6 +81,7 @@ public String getId() { /** * getMSPID returns the MSP ID of the invoking identity. + * * @return {String} */ public String getMSPID() { @@ -84,55 +90,59 @@ public String getMSPID() { /** * 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 + * + * @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(byte[] extensionValue) throws IOException { + private Map parseAttributes(final byte[] extensionValue) throws IOException { - Map attrMap = new HashMap(); + final Map attrMap = new HashMap(); // Create ASN1InputStream from extensionValue - try ( ByteArrayInputStream inStream = new ByteArrayInputStream(extensionValue); - ASN1InputStream asn1InputStream = new ASN1InputStream(inStream)) { + try (ByteArrayInputStream inStream = new ByteArrayInputStream(extensionValue); + ASN1InputStream asn1InputStream = new ASN1InputStream(inStream)) { // Read the DER object - ASN1Primitive derObject = asn1InputStream.readObject(); - if (derObject instanceof DEROctetString) - { - DEROctetString derOctetString = (DEROctetString) derObject; + final ASN1Primitive derObject = asn1InputStream.readObject(); + if (derObject instanceof DEROctetString) { + final DEROctetString derOctetString = (DEROctetString) derObject; // Create attributeString from octets and create JSON object - String attributeString = new String(derOctetString.getOctets(), UTF_8); + final String attributeString = new String(derOctetString.getOctets(), UTF_8); final JSONObject extJSON = new JSONObject(attributeString); final JSONObject attrs = extJSON.getJSONObject("attrs"); - Iterator keys = attrs.keys(); - while(keys.hasNext()) { - String key = keys.next(); + 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 (JSONException error) { + } catch (final JSONException error) { // creating a JSON object failed // decoded extensionValue is not a string containing JSON - logger.error(() -> logger.formatError(error)); + 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. + * 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. + * 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(String attrName) { + public String getAttributeValue(final String attrName) { if (this.attrs.containsKey(attrName)) { return this.attrs.get(attrName); } else { @@ -141,15 +151,18 @@ public String getAttributeValue(String attrName) { } /** - * 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) + * 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. + * @return {boolean} True if the invoking identity possesses the attribute and + * the attribute value matches the expected value. Otherwise, returns + * false. */ - public boolean assertAttributeValue(String attrName, String attrValue) { + public boolean assertAttributeValue(final String attrName, final String attrValue) { if (!this.attrs.containsKey(attrName)) { return false; } else { @@ -158,12 +171,14 @@ public boolean assertAttributeValue(String attrName, String attrValue) { } /** - * 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). + * 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; } -} \ No newline at end of file +} 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 index 0338731c..fb0ead77 100644 --- 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 @@ -5,8 +5,8 @@ */ package org.hyperledger.fabric.contract; - -import org.hyperledger.fabric.Logger; +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; @@ -46,7 +46,7 @@ public ContractRouter(String[] args) { super.processCommandLineOptions(args); super.validateOptions(); - logger.debug("ContractRouter"); + logger.fine("ContractRouter"); registry = new RoutingRegistryImpl(); typeRegistry = new TypeRegistryImpl(); executor = ExecutionFactory.getInstance().createExecutionService(typeRegistry); @@ -69,8 +69,8 @@ void startRouting() { try { super.connectToPeer(); } catch (Exception e) { - ContractRuntimeException cre = new ContractRuntimeException("Unable to start routing"); - logger.error(() -> logger.formatError(cre)); + ContractRuntimeException cre = new ContractRuntimeException("Unable to start routing",e); + logger.severe(() -> Logging.formatError(cre)); throw cre; } } @@ -114,7 +114,7 @@ TxFunction getRouting(InvocationRequest request) { if (registry.containsRoute(request)) { return registry.getTxFn(request); } else { - logger.debug(() -> "Namespace is " + request); + logger.fine(() -> "Namespace is " + request); ContractDefinition contract = registry.getContract(request.getNamespace()); return contract.getUnknownRoute(); } @@ -126,6 +126,8 @@ TxFunction getRouting(InvocationRequest request) { */ public static void main(String[] args) { + logger.info("Starting ContractRouter..."); + ContractRouter cfc = new ContractRouter(args); cfc.findAllContracts(); @@ -137,7 +139,7 @@ public static void main(String[] args) { // 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() { 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 index f4f591fc..3ada8f92 100644 --- 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 @@ -13,8 +13,8 @@ import java.nio.charset.StandardCharsets; import java.util.Iterator; import java.util.Map; +import java.util.logging.Logger; -import org.hyperledger.fabric.Logger; import org.hyperledger.fabric.contract.ContractRuntimeException; import org.hyperledger.fabric.contract.metadata.TypeSchema; import org.hyperledger.fabric.contract.routing.DataTypeDefinition; @@ -29,14 +29,14 @@ */ public class JSONTransactionSerializer { private static Logger logger = Logger.getLogger(JSONTransactionSerializer.class.getName()); - private TypeRegistry typeRegistry; + private final TypeRegistry typeRegistry; /** * Create a new serialiser and maintain a reference to the TypeRegistry * * @param typeRegistry */ - public JSONTransactionSerializer(TypeRegistry typeRegistry) { + public JSONTransactionSerializer(final TypeRegistry typeRegistry) { this.typeRegistry = typeRegistry; } @@ -45,17 +45,17 @@ public JSONTransactionSerializer(TypeRegistry typeRegistry) { * * @param value * @param ts - * @return Byte buffer + * @return Byte buffer */ - public byte[] toBuffer(Object value, TypeSchema ts) { - logger.debug(() -> "Schema to convert is " + ts); + public byte[] toBuffer(final Object value, final TypeSchema ts) { + logger.fine(() -> "Schema to convert is " + ts); byte[] buffer = null; if (value != null) { - String type = ts.getType(); + final String type = ts.getType(); if (type != null) { switch (type) { case "array": - JSONArray array = new JSONArray(value); + final JSONArray array = new JSONArray(value); buffer = array.toString().getBytes(UTF_8); break; case "string": @@ -68,7 +68,7 @@ public byte[] toBuffer(Object value, TypeSchema ts) { buffer = (value).toString().getBytes(UTF_8); } } else { - JSONObject obj = new JSONObject(value); + final JSONObject obj = new JSONObject(value); buffer = obj.toString().getBytes(UTF_8); } } @@ -86,16 +86,16 @@ public byte[] toBuffer(Object value, TypeSchema ts) { * @throws InstantiationException * @throws IllegalAccessException */ - public Object fromBuffer(byte[] buffer, TypeSchema ts) { + public Object fromBuffer(final byte[] buffer, final TypeSchema ts) { try { - String stringData = new String(buffer, StandardCharsets.UTF_8); + final String stringData = new String(buffer, StandardCharsets.UTF_8); Object value = null; value = _convert(stringData, ts); return value; } catch (InstantiationException | IllegalAccessException e) { - ContractRuntimeException cre = new ContractRuntimeException(e); + final ContractRuntimeException cre = new ContractRuntimeException(e); throw cre; } } @@ -103,29 +103,29 @@ public Object fromBuffer(byte[] buffer, TypeSchema ts) { /* * Internal method to do the conversion */ - private Object _convert(String stringData, TypeSchema ts) + private Object _convert(final String stringData, final TypeSchema ts) throws IllegalArgumentException, IllegalAccessException, InstantiationException { - logger.debug(() -> "Schema to convert is " + ts); + logger.fine(() -> "Schema to convert is " + ts); String type = ts.getType(); String format = null; Object value = null; if (type == null) { type = "object"; - String ref = ts.getRef(); + final String ref = ts.getRef(); format = ref.substring(ref.lastIndexOf("/") + 1); } if (type.contentEquals("string")) { value = stringData; } else if (type.contentEquals("integer")) { - String intFormat = ts.getFormat(); + final String intFormat = ts.getFormat(); if (intFormat.contentEquals("int32")) { value = Integer.parseInt(stringData); } else { value = Long.parseLong(stringData); } } else if (type.contentEquals("number")) { - String numFormat = ts.getFormat(); + final String numFormat = ts.getFormat(); if (numFormat.contentEquals("float")) { value = Float.parseFloat(stringData); } else { @@ -136,9 +136,9 @@ private Object _convert(String stringData, TypeSchema ts) } else if (type.contentEquals("object")) { value = createComponentInstance(format, stringData, ts); } else if (type.contentEquals("array")) { - JSONArray jsonArray = new JSONArray(stringData); - TypeSchema itemSchema = ts.getItems(); - Object[] data = (Object[]) Array.newInstance(itemSchema.getTypeClass(this.typeRegistry), + 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); @@ -149,9 +149,9 @@ private Object _convert(String stringData, TypeSchema ts) return value; } - Object createComponentInstance(String format, String jsonString, TypeSchema ts) { + Object createComponentInstance(final String format, final String jsonString, final TypeSchema ts) { - DataTypeDefinition dtd = this.typeRegistry.getDataType(format); + final DataTypeDefinition dtd = this.typeRegistry.getDataType(format); Object obj; try { obj = dtd.getTypeClass().newInstance(); @@ -159,18 +159,18 @@ Object createComponentInstance(String format, String jsonString, TypeSchema ts) throw new ContractRuntimeException("Unable to to create new instance of type", e1); } - JSONObject json = new JSONObject(jsonString); + final JSONObject json = new JSONObject(jsonString); // request validation of the type may throw an exception if validation fails ts.validate(json); try { - Map fields = dtd.getProperties(); - for (Iterator iterator = fields.values().iterator(); iterator.hasNext();) { - PropertyDefinition prop = iterator.next(); + final Map fields = dtd.getProperties(); + for (final Iterator iterator = fields.values().iterator(); iterator.hasNext();) { + final PropertyDefinition prop = iterator.next(); - Field f = prop.getField(); + final Field f = prop.getField(); f.setAccessible(true); - Object newValue = _convert(json.get(prop.getName()).toString(), prop.getSchema()); + final Object newValue = _convert(json.get(prop.getName()).toString(), prop.getSchema()); f.set(obj, newValue); 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 index 3308cb3e..175fc1e9 100644 --- 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 @@ -11,8 +11,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.logging.Logger; -import org.hyperledger.fabric.Logger; +import org.hyperledger.fabric.Logging; import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.ContractRuntimeException; @@ -42,7 +43,7 @@ public ContractExecutionService(TypeRegistry typeRegistry) { @Override public Chaincode.Response executeRequest(TxFunction txFn, InvocationRequest req, ChaincodeStub stub) { - logger.debug(() -> "Routing Request" + txFn); + logger.fine(() -> "Routing Request" + txFn); TxFunction.Routing rd = txFn.getRouting(); Chaincode.Response response; 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 index 3fa51687..c006131b 100644 --- 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 @@ -16,6 +16,7 @@ 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; @@ -23,7 +24,7 @@ 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.Logger; +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; @@ -43,12 +44,12 @@ * process to and from metadata json to the internal data structure */ public class MetadataBuilder { - private static Logger logger = Logger.getLogger(MetadataBuilder.class); + private static Logger logger = Logger.getLogger(MetadataBuilder.class.getName()); @SuppressWarnings("serial") static class MetadataMap extends HashMap { - V putIfNotNull(K key, V value) { + V putIfNotNull(final K key, final V value) { logger.info(key + " " + value); if (value != null && !value.toString().isEmpty()) { return put(key, value); @@ -74,25 +75,23 @@ V putIfNotNull(K key, V value) { */ public static void validate() { logger.info("Running schema test validation"); - ClassLoader cl = MetadataBuilder.class.getClassLoader(); + final ClassLoader cl = MetadataBuilder.class.getClassLoader(); try (InputStream contractSchemaInputStream = cl.getResourceAsStream("contract-schema.json"); - InputStream jsonSchemaInputStream = cl.getResourceAsStream("json-schema-draft-04-schema.json")) { - JSONObject rawContractSchema = new JSONObject(new JSONTokener(contractSchemaInputStream)); - JSONObject rawJsonSchema = new JSONObject(new JSONTokener(jsonSchemaInputStream)); - SchemaLoader schemaLoader = SchemaLoader.builder() - .schemaClient(schemaClient) - .schemaJson(rawContractSchema) - .registerSchemaByURI(URI.create("http://json-schema.org/draft-04/schema"), rawJsonSchema) - .build(); - Schema schema = schemaLoader.load().build(); + 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 (IOException e) { + } catch (final IOException e) { throw new RuntimeException(e); - } catch (ValidationException e) { - logger.error(e.getMessage()); + } catch (final ValidationException e) { + logger.severe(Logging.formatError(e)); e.getCausingExceptions().stream().map(ValidationException::getMessage).forEach(logger::info); - logger.error(debugString()); + logger.severe(debugString()); throw e; } @@ -101,11 +100,11 @@ public static void validate() { /** * Setup the metadata from the found contracts */ - public static void initialize(RoutingRegistry registry, TypeRegistry typeRegistry) { - Collection contractDefinitions = registry.getAllDefinitions(); + public static void initialize(final RoutingRegistry registry, final TypeRegistry typeRegistry) { + final Collection contractDefinitions = registry.getAllDefinitions(); contractDefinitions.forEach(MetadataBuilder::addContract); - Collection dataTypes = typeRegistry.getAllDataTypes(); + final Collection dataTypes = typeRegistry.getAllDataTypes(); dataTypes.forEach(MetadataBuilder::addComponent); // need to validate that the metadata that has been created is really valid @@ -119,15 +118,15 @@ public static void initialize(RoutingRegistry registry, TypeRegistry typeRegistr /** * Adds a component/ complex data-type */ - public static void addComponent(DataTypeDefinition datatype) { + public static void addComponent(final DataTypeDefinition datatype) { - Map component = new HashMap<>(); + final Map component = new HashMap<>(); component.put("$id", datatype.getName()); component.put("type", "object"); component.put("additionalProperties", false); - Map propertiesMap = datatype.getProperties().entrySet().stream() + final Map propertiesMap = datatype.getProperties().entrySet().stream() .collect(Collectors.toMap(Entry::getKey, e -> (e.getValue().getSchema()))); component.put("properties", propertiesMap); @@ -141,14 +140,14 @@ public static void addComponent(DataTypeDefinition datatype) { * @return the key that the contract class is referred to in the meteadata */ @SuppressWarnings("serial") - public static String addContract(ContractDefinition contractDefinition) { + public static String addContract(final ContractDefinition contractDefinition) { - String key = contractDefinition.getName(); + final String key = contractDefinition.getName(); - Contract annotation = contractDefinition.getAnnotation(); + final Contract annotation = contractDefinition.getAnnotation(); - Info info = annotation.info(); - HashMap infoMap = new HashMap(); + 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()); @@ -167,18 +166,18 @@ public static String addContract(ContractDefinition contractDefinition) { }); infoMap.put("version", info.version()); - HashMap contract = new HashMap(); + final HashMap contract = new HashMap(); contract.put("name", key); contract.put("transactions", new ArrayList()); contract.put("info", infoMap); contractMap.put(key, contract); - boolean defaultContract = true; + final boolean defaultContract = true; if (defaultContract) { overallInfoMap.putAll(infoMap); } - Collection fns = contractDefinition.getTxFunctions(); + final Collection fns = contractDefinition.getTxFunctions(); fns.forEach(txFn -> { MetadataBuilder.addTransaction(txFn, key); }); @@ -192,23 +191,23 @@ public static String addContract(ContractDefinition contractDefinition) { * @param txFunction Object representing the transaction function * @param contractName Name of the contract that this function belongs to */ - public static void addTransaction(TxFunction txFunction, String contractName) { - TypeSchema transaction = new TypeSchema(); - TypeSchema returnSchema = txFunction.getReturnSchema(); + 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); } - ArrayList tags = new ArrayList(); + final ArrayList tags = new ArrayList(); tags.add(txFunction.getType()); - Map contract = contractMap.get(contractName); + final Map contract = contractMap.get(contractName); @SuppressWarnings("unchecked") - List txs = (ArrayList) contract.get("transactions"); + final List txs = (ArrayList) contract.get("transactions"); - ArrayList paramsList = new ArrayList(); + final ArrayList paramsList = new ArrayList(); txFunction.getParamsList().forEach(pd -> { - TypeSchema paramMap = pd.getSchema(); + final TypeSchema paramMap = pd.getSchema(); paramMap.put("name", pd.getName()); paramsList.add(paramMap); }); @@ -241,14 +240,14 @@ public static String debugString() { * */ private static JSONObject metadata() { - HashMap metadata = new HashMap(); + 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)); - JSONObject joMetadata = new JSONObject(metadata); + final JSONObject joMetadata = new JSONObject(metadata); return joMetadata; } 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 index 3eaba75b..93668711 100644 --- 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 @@ -9,11 +9,11 @@ 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.Logger; import org.hyperledger.fabric.contract.ContractRuntimeException; import org.hyperledger.fabric.contract.routing.TypeRegistry; import org.json.JSONObject; @@ -192,7 +192,7 @@ public void validate(JSONObject obj) { JSONObject schemaJSON; if (this.containsKey("schema")) { - schemaJSON = new JSONObject((Map) this.get("schema")); + schemaJSON = new JSONObject((Map) this.get("schema")); } else { schemaJSON = new JSONObject(this); } 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 index f0635200..597f2751 100644 --- 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 @@ -9,8 +9,9 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.logging.Logger; -import org.hyperledger.fabric.Logger; +import org.hyperledger.fabric.Logging; import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.ContractRuntimeException; @@ -27,21 +28,21 @@ * */ public class ContractDefinitionImpl implements ContractDefinition { - private static Logger logger = Logger.getLogger(ContractDefinitionImpl.class); + private static Logger logger = Logger.getLogger(ContractDefinitionImpl.class.getName()); - private Map txFunctions = new HashMap<>(); + private final Map txFunctions = new HashMap<>(); private String name; - private boolean isDefault; - private Class contractClz; - private Contract contractAnnotation; + private final boolean isDefault; + private final Class contractClz; + private final Contract contractAnnotation; private TxFunction unknownTx; - public ContractDefinitionImpl(Class cl) { + public ContractDefinitionImpl(final Class cl) { - Contract annotation = cl.getAnnotation(Contract.class); - logger.debug(() -> "Class Contract Annotation: " + annotation); + final Contract annotation = cl.getAnnotation(Contract.class); + logger.fine(() -> "Class Contract Annotation: " + annotation); - String annotationName = annotation.name(); + final String annotationName = annotation.name(); if (annotationName == null || annotationName.isEmpty()) { this.name = cl.getSimpleName(); @@ -54,17 +55,18 @@ public ContractDefinitionImpl(Class cl) { contractClz = cl; try { - Method m = cl.getMethod("unknownTransaction", new Class[] { Context.class }); + final Method m = cl.getMethod("unknownTransaction", new Class[] { Context.class }); unknownTx = new TxFunctionImpl(m, this); unknownTx.setUnknownTx(true); } catch (NoSuchMethodException | SecurityException e) { - ContractRuntimeException cre = new ContractRuntimeException("Failure to find unknownTransaction method", e); - logger.severe(() -> logger.formatError(cre)); + 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.debug(() -> "Namespace: " + this.name); + logger.fine(() -> "Namespace: " + this.name); } @Override @@ -83,14 +85,14 @@ public Class getContractImpl() { } @Override - public TxFunction addTxFunction(Method m) { - logger.debug(() -> "Adding method " + m.getName()); - TxFunction txFn = new TxFunctionImpl(m, this); - TxFunction previousTxnFn = txFunctions.put(txFn.getName(), txFn); + 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) { - String message = String.format("Duplicate transaction method %s", previousTxnFn.getName()); - ContractRuntimeException cre = new ContractRuntimeException(message); - logger.severe(() -> logger.formatError(cre)); + 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; @@ -102,12 +104,12 @@ public boolean isDefault() { } @Override - public TxFunction getTxFunction(String method) { + public TxFunction getTxFunction(final String method) { return txFunctions.get(method); } @Override - public boolean hasTxFunction(String method) { + public boolean hasTxFunction(final String method) { return txFunctions.containsKey(method); } 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 index c397cbc9..2ed7d81a 100644 --- 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 @@ -6,9 +6,7 @@ package org.hyperledger.fabric.contract.routing.impl; import java.lang.reflect.Field; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.stream.Stream; 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 index dae8686f..ccccff32 100644 --- 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 @@ -15,8 +15,8 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.logging.Logger; -import org.hyperledger.fabric.Logger; import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.ContractRuntimeException; import org.hyperledger.fabric.contract.annotation.Contract; @@ -41,9 +41,9 @@ * */ public class RoutingRegistryImpl implements RoutingRegistry { - private static Logger logger = Logger.getLogger(RoutingRegistryImpl.class); + private static Logger logger = Logger.getLogger(RoutingRegistryImpl.class.getName()); - private Map contracts = new HashMap<>(); + private final Map contracts = new HashMap<>(); /* * (non-Javadoc) @@ -53,8 +53,8 @@ public class RoutingRegistryImpl implements RoutingRegistry { * lang.Class) */ @Override - public ContractDefinition addNewContract(Class clz) { - logger.debug(() -> "Adding new Contract Class " + clz.getCanonicalName()); + public ContractDefinition addNewContract(final Class clz) { + logger.fine(() -> "Adding new Contract Class " + clz.getCanonicalName()); ContractDefinition contract; contract = new ContractDefinitionImpl(clz); @@ -64,7 +64,7 @@ public ContractDefinition addNewContract(Class clz) { contracts.put(InvocationRequest.DEFAULT_NAMESPACE, contract); } - logger.debug(() -> "Put new contract in under name " + contract.getName()); + logger.fine(() -> "Put new contract in under name " + contract.getName()); return contract; } @@ -76,9 +76,9 @@ public ContractDefinition addNewContract(Class clz) { * hyperledger.fabric.contract.execution.InvocationRequest) */ @Override - public boolean containsRoute(InvocationRequest request) { + public boolean containsRoute(final InvocationRequest request) { if (contracts.containsKey(request.getNamespace())) { - ContractDefinition cd = contracts.get(request.getNamespace()); + final ContractDefinition cd = contracts.get(request.getNamespace()); if (cd.hasTxFunction(request.getMethod())) { return true; @@ -94,14 +94,14 @@ public boolean containsRoute(InvocationRequest request) { * hyperledger.fabric.contract.execution.InvocationRequest) */ @Override - public TxFunction.Routing getRoute(InvocationRequest request) { - TxFunction txFunction = contracts.get(request.getNamespace()).getTxFunction(request.getMethod()); + public TxFunction.Routing getRoute(final InvocationRequest request) { + final TxFunction txFunction = contracts.get(request.getNamespace()).getTxFunction(request.getMethod()); return txFunction.getRouting(); } @Override - public TxFunction getTxFn(InvocationRequest request) { - TxFunction txFunction = contracts.get(request.getNamespace()).getTxFunction(request.getMethod()); + public TxFunction getTxFn(final InvocationRequest request) { + final TxFunction txFunction = contracts.get(request.getNamespace()).getTxFunction(request.getMethod()); return txFunction; } @@ -113,8 +113,8 @@ public TxFunction getTxFn(InvocationRequest request) { * .String) */ @Override - public ContractDefinition getContract(String namespace) { - ContractDefinition contract = contracts.get(namespace); + public ContractDefinition getContract(final String namespace) { + final ContractDefinition contract = contracts.get(namespace); if (contract == null) { throw new ContractRuntimeException("Undefined contract called"); @@ -141,10 +141,12 @@ public Collection getAllDefinitions() { * @see * org.hyperledger.fabric.contract.routing.RoutingRegistry#findAndSetContracts() */ + @SuppressWarnings("unchecked") @Override - public void findAndSetContracts(TypeRegistry typeRegistry) { - ArrayList urls = new ArrayList<>(); - ClassLoader[] classloaders = { getClass().getClassLoader(), Thread.currentThread().getContextClassLoader() }; + public void findAndSetContracts(final TypeRegistry typeRegistry) { + final ArrayList urls = new ArrayList<>(); + final ClassLoader[] classloaders = { getClass().getClassLoader(), + Thread.currentThread().getContextClassLoader() }; for (int i = 0; i < classloaders.length; i++) { if (classloaders[i] instanceof URLClassLoader) { urls.addAll(Arrays.asList(((URLClassLoader) classloaders[i]).getURLs())); @@ -153,31 +155,31 @@ public void findAndSetContracts(TypeRegistry typeRegistry) { } } - ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); + final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); configurationBuilder.addUrls(urls); configurationBuilder.addUrls(ClasspathHelper.forJavaClassPath()); - configurationBuilder.addUrls(ClasspathHelper.forManifest()); - Reflections ref = new Reflections(configurationBuilder); + configurationBuilder.addUrls(ClasspathHelper.forManifest()); + final Reflections ref = new Reflections(configurationBuilder); logger.info("Searching chaincode class in urls: " + configurationBuilder.getUrls()); // set to ensure that we don't scan the same class twice - Set seenClass = new HashSet<>(); + final Set seenClass = new HashSet<>(); // loop over all the classes that have the Contract annotation - for (Class cl : ref.getTypesAnnotatedWith(Contract.class)) { + for (final Class cl : ref.getTypesAnnotatedWith(Contract.class)) { logger.info("Found class: " + cl.getCanonicalName()); if (ContractInterface.class.isAssignableFrom(cl)) { - logger.debug("Inheritance ok"); - String className = cl.getCanonicalName(); + logger.fine("Inheritance ok"); + final String className = cl.getCanonicalName(); if (!seenClass.contains(className)) { - ContractDefinition contract = addNewContract((Class) cl); + final ContractDefinition contract = addNewContract((Class) cl); - logger.debug("Searching annotated methods"); - for (Method m : cl.getMethods()) { + logger.fine("Searching annotated methods"); + for (final Method m : cl.getMethods()) { if (m.getAnnotation(Transaction.class) != null) { - logger.debug("Found annotated method " + m.getName()); + logger.fine("Found annotated method " + m.getName()); contract.addTxFunction(m); @@ -187,13 +189,13 @@ public void findAndSetContracts(TypeRegistry typeRegistry) { seenClass.add(className); } } else { - logger.debug("Class is not assignabled from Contract"); + logger.fine("Class is not assignabled from Contract"); } } // now need to look for the data types have been set with the logger.info("Looking for the data types"); - Set> czs = ref.getTypesAnnotatedWith(DataType.class); + final Set> czs = ref.getTypesAnnotatedWith(DataType.class); logger.info("found " + czs.size()); czs.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 index 796c85db..bcd0f56e 100644 --- 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 @@ -9,8 +9,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.logging.Logger; -import org.hyperledger.fabric.Logger; import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.ContractRuntimeException; @@ -23,12 +23,12 @@ import org.hyperledger.fabric.contract.routing.TxFunction; public class TxFunctionImpl implements TxFunction { - private static Logger logger = Logger.getLogger(TxFunctionImpl.class); + private static Logger logger = Logger.getLogger(TxFunctionImpl.class.getName()); - private Method method; + private final Method method; private String name; private TransactionType type; - private Routing routing; + private final Routing routing; private TypeSchema returnSchema; private List paramsList = new ArrayList<>(); private boolean isUnknownTx; @@ -38,7 +38,7 @@ public class RoutingImpl implements Routing { Method method; Class clazz; - public RoutingImpl(Method method, Class clazz) { + public RoutingImpl(final Method method, final Class clazz) { this.method = method; this.clazz = clazz; } @@ -72,18 +72,18 @@ public String toString() { * @param m Reflect method object * @param contract ContractDefinition this is part of */ - public TxFunctionImpl(Method m, ContractDefinition contract) { + public TxFunctionImpl(final Method m, final ContractDefinition contract) { this.method = m; if (m.getAnnotation(Transaction.class) != null) { - logger.debug("Found Transaction method: " + m.getName()); + logger.fine("Found Transaction method: " + m.getName()); if (m.getAnnotation(Transaction.class).submit()) { this.type = TransactionType.INVOKE; } else { this.type = TransactionType.QUERY; } - String txnName = m.getAnnotation(Transaction.class).name(); + final String txnName = m.getAnnotation(Transaction.class).name(); if (!txnName.isEmpty()) { this.name = txnName; } @@ -99,7 +99,7 @@ public TxFunctionImpl(Method m, ContractDefinition contract) { this.returnSchema = TypeSchema.typeConvert(m.getReturnType()); // parameter processing - List params = new ArrayList( + final List params = new ArrayList( Arrays.asList(method.getParameters())); // validate the first one is a context object @@ -116,13 +116,14 @@ public TxFunctionImpl(Method m, ContractDefinition contract) { // here encapsulating the change. eg use an annotation to define where the // context goes - for (java.lang.reflect.Parameter parameter : params) { - TypeSchema paramMap = new TypeSchema(); - TypeSchema schema = TypeSchema.typeConvert(parameter.getType()); + for (final java.lang.reflect.Parameter parameter : params) { + final TypeSchema paramMap = new TypeSchema(); + final TypeSchema schema = TypeSchema.typeConvert(parameter.getType()); - Property annotation = parameter.getAnnotation(org.hyperledger.fabric.contract.annotation.Property.class); + final Property annotation = parameter + .getAnnotation(org.hyperledger.fabric.contract.annotation.Property.class); if (annotation != null) { - String[] userSupplied = annotation.schema(); + final String[] userSupplied = annotation.schema(); for (int i = 0; i < userSupplied.length; i += 2) { schema.put(userSupplied[i], userSupplied[i + 1]); } @@ -130,8 +131,8 @@ public TxFunctionImpl(Method m, ContractDefinition contract) { paramMap.put("name", parameter.getName()); paramMap.put("schema", schema); - ParameterDefinition pd = new ParameterDefinitionImpl(parameter.getName(), parameter.getClass(), paramMap, - parameter); + final ParameterDefinition pd = new ParameterDefinitionImpl(parameter.getName(), parameter.getClass(), + paramMap, parameter); paramsList.add(pd); } } @@ -167,7 +168,7 @@ public String toString() { } @Override - public void setReturnSchema(TypeSchema returnSchema) { + public void setReturnSchema(final TypeSchema returnSchema) { this.returnSchema = returnSchema; } @@ -176,7 +177,7 @@ public List getParamsList() { return paramsList; } - public void setParamsList(ArrayList paramsList) { + public void setParamsList(final ArrayList paramsList) { this.paramsList = paramsList; } @@ -186,7 +187,7 @@ public TypeSchema getReturnSchema() { } @Override - public void setParameterDefinitions(List list) { + public void setParameterDefinitions(final List list) { this.paramsList = list; } @@ -197,7 +198,7 @@ public boolean isUnknownTx() { } @Override - public void setUnknownTx(boolean unknown) { + public void setUnknownTx(final boolean unknown) { this.isUnknownTx = unknown; } 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 57060072..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 (payload==null) ? null : 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 8493f071..8e7f52f0 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 @@ -7,30 +7,31 @@ package org.hyperledger.fabric.shim; import static java.lang.String.format; -import static java.util.logging.Level.ALL; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +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.List; +import java.util.Date; +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 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.contract.ContractRouter; +import org.hyperledger.fabric.Logging; import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeID; import org.hyperledger.fabric.shim.impl.ChaincodeSupportStream; import org.hyperledger.fabric.shim.impl.Handler; @@ -52,7 +53,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; @@ -72,6 +73,7 @@ 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 Level logLevel; static { Security.addProvider(new BouncyCastleProvider()); @@ -82,90 +84,99 @@ public abstract class ChaincodeBase implements Chaincode { * * @param args command line arguments */ - public void start(String[] args) { + public void start(final String[] args) { try { processEnvironmentOptions(); processCommandLineOptions(args); initializeLogging(); validateOptions(); connectToPeer(); - } catch (Exception e) { - logger.fatal("Chaincode could not start", e); + } catch (final Exception e) { + logger.severe("Chaincode could not start"); + logger.severe(Logging.formatError(e)); + throw new RuntimeException(e); } } - protected void connectToPeer() throws IOException { + protected void connectToPeer() throws IOException { 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); } - protected void initializeLogging() { - System.setProperty("java.util.logging.SimpleFormatter.format","%1$tH:%1$tM:%1$tS:%1$tL %4$-7.7s %2$-80.80s %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"); - } - - }); - } + final LogManager logManager = LogManager.getLogManager(); + final Formatter f = new Formatter() { - rootLogger.info("Updated all handlers the format"); - // 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); - } + 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"; - // set logging level of shim logger - Level shimLogLevel = mapLevel(System.getenv(CORE_CHAINCODE_LOGGING_SHIM)); - Logger.getLogger(ChaincodeBase.class.getPackage().getName()).setLevel(shimLogLevel); - Logger.getLogger(ContractRouter.class.getPackage().getName()).setLevel(chaincodeLogLevel); + @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(); + } + 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); - List loggers = Collections.list(LogManager.getLogManager().getLoggerNames()); - loggers.forEach(x -> { - Logger l = LogManager.getLogManager().getLogger((String) x); - //TODO: err what is the code supposed to do? - }); + } + }; + + 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.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; + 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; @@ -173,29 +184,34 @@ private Level mapLevel(String level) { 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)); } } } - protected 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')) { @@ -203,21 +219,22 @@ protected 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("<<<<<<<<<<<<>>>>>>>>>>>"); @@ -231,18 +248,19 @@ protected void processCommandLineOptions(String[] args) { 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)); @@ -252,6 +270,14 @@ protected 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); @@ -259,11 +285,13 @@ protected void processEnvironmentOptions() { 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); } ManagedChannelBuilder newChannelBuilder() throws IOException { 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); @@ -275,19 +303,17 @@ ManagedChannelBuilder newChannelBuilder() throws IOException { } 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(); } @Deprecated - protected static Response newSuccessResponse(String message, byte[] payload) { + protected static Response newSuccessResponse(final String message, final byte[] payload) { return ResponseUtils.newSuccessResponse(message, payload); } @@ -297,17 +323,17 @@ protected static Response newSuccessResponse() { } @Deprecated - protected static Response newSuccessResponse(String message) { + protected static Response newSuccessResponse(final String message) { return ResponseUtils.newSuccessResponse(message); } @Deprecated - protected static Response newSuccessResponse(byte[] payload) { + protected static Response newSuccessResponse(final byte[] payload) { return ResponseUtils.newSuccessResponse(payload); } @Deprecated - protected static Response newErrorResponse(String message, byte[] payload) { + protected static Response newErrorResponse(final String message, final byte[] payload) { return ResponseUtils.newErrorResponse(message, payload); } @@ -317,17 +343,17 @@ protected static Response newErrorResponse() { } @Deprecated - protected static Response newErrorResponse(String message) { + protected static Response newErrorResponse(final String message) { return ResponseUtils.newErrorResponse(message); } @Deprecated - protected static Response newErrorResponse(byte[] payload) { + protected static Response newErrorResponse(final byte[] payload) { return ResponseUtils.newErrorResponse(payload); } @Deprecated - protected static Response newErrorResponse(Throwable throwable) { + protected static Response newErrorResponse(final Throwable throwable) { return ResponseUtils.newErrorResponse(throwable); } 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 index 2581e12f..eb67fd00 100644 --- 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 @@ -8,13 +8,15 @@ import static org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR; import static org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS; -import org.hyperledger.fabric.Logger; +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(String message, byte[] payload) { + public static Chaincode.Response newSuccessResponse(final String message, final byte[] payload) { return new Chaincode.Response(SUCCESS, message, payload); } @@ -22,15 +24,15 @@ public static Chaincode.Response newSuccessResponse() { return newSuccessResponse(null, null); } - public static Chaincode.Response newSuccessResponse(String message) { + public static Chaincode.Response newSuccessResponse(final String message) { return newSuccessResponse(message, null); } - public static Chaincode.Response newSuccessResponse(byte[] payload) { + public static Chaincode.Response newSuccessResponse(final byte[] payload) { return newSuccessResponse(null, payload); } - public static Chaincode.Response newErrorResponse(String message, byte[] payload) { + public static Chaincode.Response newErrorResponse(final String message, final byte[] payload) { return new Chaincode.Response(INTERNAL_SERVER_ERROR, message, payload); } @@ -38,17 +40,18 @@ public static Chaincode.Response newErrorResponse() { return newErrorResponse(null, null); } - public static Chaincode.Response newErrorResponse(String message) { + public static Chaincode.Response newErrorResponse(final String message) { return newErrorResponse(message, null); } - public static Chaincode.Response newErrorResponse(byte[] payload) { + public static Chaincode.Response newErrorResponse(final byte[] payload) { return newErrorResponse(null, payload); } - public static Chaincode.Response newErrorResponse(Throwable throwable) { - // Responses should not include internals like stack trace but make sure it gets logged - logger.error(() -> logger.formatError(throwable)); + 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; 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 index ec426e9e..2eb0df60 100644 --- 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 @@ -83,6 +83,9 @@ public void testInit() { 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<>(); 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 beeb7a6a..bc03bb39 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 @@ -13,6 +13,8 @@ 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.Level; import java.util.logging.Logger; @@ -34,10 +36,37 @@ 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 = ResponseUtils.newSuccessResponse(); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); + 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()); } @@ -45,31 +74,39 @@ public void testNewSuccessResponseEmpty() { @Test public void testNewSuccessResponseWithMessage() { 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 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 = ResponseUtils.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 = ResponseUtils.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 = ResponseUtils.newErrorResponse(); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + 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()); } @@ -77,39 +114,50 @@ public void testNewErrorResponseEmpty() { @Test public void testNewErrorResponseWithMessage() { 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 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 = ResponseUtils.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 = 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); + 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 = ResponseUtils.newErrorResponse(new Exception("Simple exception")); - 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(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); + 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()); } @@ -214,32 +262,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/fvt/ChaincodeFVTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java index c8ed7683..9817b11b 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 @@ -599,23 +599,6 @@ public Response invoke(ChaincodeStub stub) { 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 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/impl/HandlerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/HandlerTest.java index 31f7ff6d..baa3b3f6 100644 --- 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 @@ -5,7 +5,6 @@ */ 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; @@ -17,6 +16,8 @@ import org.junit.contrib.java.lang.system.EnvironmentVariables; import org.junit.rules.ExpectedException; +import com.google.protobuf.ByteString; + public class HandlerTest { @@ -29,7 +30,7 @@ public class HandlerTest { @Test public void testHandlerStates() { ChaincodeBase cb = new EmptyChaincode(); - ChaincodeBaseTest.setLogLevelForChaincode(environmentVariables, cb, "DEBUG", "DEBUG"); + ChaincodeBaseTest.setLogLevelForChaincode(environmentVariables, cb, "DEBUG"); Chaincode.ChaincodeID chaincodeId = Chaincode.ChaincodeID.newBuilder().setName("mycc").build(); Handler handler = new Handler(chaincodeId, cb); diff --git a/fabric-contract-example/maven/pom.xml b/fabric-contract-example/maven/pom.xml index 7a867cb1..08cd56d0 100644 --- a/fabric-contract-example/maven/pom.xml +++ b/fabric-contract-example/maven/pom.xml @@ -27,7 +27,7 @@ jitpack.io - https://jitpack.io + https://www.jitpack.io nexus From c7efeb45fac5b56ff1ad76f16282b16e5549f1a7 Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Thu, 17 Oct 2019 20:40:06 +0100 Subject: [PATCH 22/61] [FAB-16871] Deprecate Logger interface Signed-off-by: Matthew B. White Change-Id: Ieba3fc7fea8753e3de0748b93eef13975eef66fc --- .../java/org/hyperledger/fabric/Logger.java | 96 +++++++++++++++++++ .../java/org/hyperledger/fabric/Logging.java | 68 ++++++++++++- .../org/hyperledger/fabric/LoggerTest.java | 51 ++++++++++ .../org/hyperledger/fabric/LoggingTest.java | 88 +++++++++++++++++ 4 files changed, 299 insertions(+), 4 deletions(-) create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java 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 index 1d796861..d69e7663 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java @@ -7,31 +7,91 @@ import java.io.PrintWriter; import java.io.StringWriter; -import java.util.logging.Logger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.logging.Level; +import java.util.logging.LogManager; /** - * Logger class to use throughout the Contract Implementation + * 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()); + buffer.append(throwable.getMessage()).append(System.lineSeparator()); + throwable.printStackTrace(new PrintWriter(buffer)); final Throwable cause = throwable.getCause(); if (cause != null) { - buffer.append(".. caused by .."); + 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/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)); + + } +} From baaaef83d712e3bad460ba34a885169a51ed1474 Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Wed, 21 Aug 2019 14:29:30 +0100 Subject: [PATCH 23/61] [FAB-16315] Improved Load Ability A fairly sizeable CR for improving the load handling ability of the Java chaincode. This required a rework of the threading model within the core shim layer. Plus adding configuration and metrics to support this. The configuration is a simple Java props file should the need be to ever modify the default thread pool settings. Metrics are basic stats on the thread pool are written to the log Change-Id: I31b05585a0aa650f7e2a7e2b0389799e90adc2c3 Signed-off-by: Matthew B. White --- .gitignore | 2 +- build.gradle | 23 +- fabric-chaincode-docker/.gitignore | 1 + fabric-chaincode-docker/build.gradle | 2 +- .../fabric/example/SimpleAsset.java | 1 + .../fabric/example/EndorsementCC.java | 8 +- .../bin/.gitignore | 1 - .../integration/SBECCIntegrationTest.java | 39 +- .../first-network/base/peer-base.yaml | 2 +- fabric-chaincode-protos/bin/.gitignore | 1 - fabric-chaincode-shim/bin/.gitignore | 2 - fabric-chaincode-shim/build.gradle | 19 +- .../src/main/java/commons-logging.properties | 33 - .../java/org/hyperledger/fabric/Logging.java | 1 - .../fabric/contract/ContractRouter.java | 11 +- .../impl/ContractExecutionService.java | 3 +- .../fabric/contract/package-info.java | 20 + .../hyperledger/fabric/metrics/Metrics.java | 63 ++ .../fabric/metrics/MetricsProvider.java | 43 + .../fabric/metrics/TaskMetricsCollector.java | 59 ++ .../fabric/metrics/impl/DefaultProvider.java | 62 ++ .../fabric/metrics/impl/NullProvider.java | 18 + .../fabric/metrics/package-info.java | 37 + .../org/hyperledger/fabric/package-info.java | 19 + .../fabric/shim/ChaincodeBase.java | 105 +- .../fabric/shim/ChaincodeStub.java | 2 +- .../shim/ext/sbe/StateBasedEndorsement.java | 2 +- .../fabric/shim/helper/Channel.java | 55 - .../shim/impl/ChaincodeInnvocationTask.java | 200 ++++ .../shim/impl/ChaincodeMessageFactory.java | 150 +++ .../shim/impl/ChaincodeSupportClient.java | 122 ++- .../shim/impl/ChaincodeSupportStream.java | 68 -- .../hyperledger/fabric/shim/impl/Handler.java | 606 ----------- ...StubImpl.java => InnvocationStubImpl.java} | 308 ++++-- .../shim/impl/InnvocationTaskExecutor.java | 51 + .../shim/impl/InnvocationTaskManager.java | 302 ++++++ .../shim/impl/QueryResultsIteratorImpl.java | 156 ++- .../QueryResultsIteratorWithMetadataImpl.java | 17 +- .../hyperledger/fabric/shim/package-info.java | 16 + .../src/test/java/contract/Greeting.java | 2 - .../ContractExecutionServiceTest.java | 8 +- .../metadata/MetadataBuilderTest.java | 2 +- .../contract/routing/TxFunctionTest.java | 2 +- .../contract/routing/TypeRegistryTest.java | 4 +- .../simplepath/ContractSimplePath.java | 7 +- .../fabric/metrics/MetricsTest.java | 83 ++ .../metrics/impl/DefaultProviderTest.java | 88 ++ .../fabric/shim/ChaincodeBaseTest.java | 6 +- .../fabric/shim/ChaincodeStubTest.java | 296 ++++++ .../fabric/shim/helper/ChannelTest.java | 32 - .../impl/ChaincodeMessageFactoryTest.java | 94 ++ .../shim/impl/ChaincodeStubImplTest.java | 940 ------------------ .../fabric/shim/impl/HandlerTest.java | 98 -- ...ryResultsIteratorWithMetadataImplTest.java | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 55 files changed, 2237 insertions(+), 2061 deletions(-) create mode 100644 fabric-chaincode-docker/.gitignore delete mode 100644 fabric-chaincode-integration-test/bin/.gitignore delete mode 100644 fabric-chaincode-protos/bin/.gitignore delete mode 100644 fabric-chaincode-shim/bin/.gitignore delete mode 100644 fabric-chaincode-shim/src/main/java/commons-logging.properties create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/package-info.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/Metrics.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/MetricsProvider.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/TaskMetricsCollector.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/DefaultProvider.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/NullProvider.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/package-info.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/package-info.java delete mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/helper/Channel.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInnvocationTask.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactory.java delete mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportStream.java delete mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/Handler.java rename fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/{ChaincodeStubImpl.java => InnvocationStubImpl.java} (54%) create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationTaskExecutor.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManager.java create mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/package-info.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/MetricsTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/impl/DefaultProviderTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeStubTest.java delete mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/helper/ChannelTest.java create mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactoryTest.java delete mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeStubImplTest.java delete mode 100644 fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/HandlerTest.java diff --git a/.gitignore b/.gitignore index 5a44b8f7..6c808ad0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ *.swp .gradletasknamecache .classpath -/bin/ +**/bin/ /build/ build/* diff --git a/build.gradle b/build.gradle index 72ba7d2e..730f8d16 100644 --- a/build.gradle +++ b/build.gradle @@ -6,8 +6,18 @@ apply plugin: 'idea' apply plugin: 'eclipse-wtp' - +apply plugin: 'com.dorongold.task-tree' version = '1.4.4-SNAPSHOT' +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "gradle.plugin.com.dorongold.plugins:task-tree:1.4" + } +} allprojects { repositories { @@ -31,11 +41,16 @@ 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' } @@ -43,6 +58,10 @@ subprojects { options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" } + test { + useJUnitPlatform() + } + } task printVersionName() { 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/build.gradle b/fabric-chaincode-docker/build.gradle index 1426563d..b55f4f90 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -80,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.4', 'hyperledger/fabric-javaenv:amd64-latest'] } 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 f869832a..daf321f2 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 @@ -26,6 +26,7 @@ public Response init(ChaincodeStub stub) { if (args.size() != 2) { 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)); 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 8103fcf3..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 @@ -216,10 +216,12 @@ public Response getVal(ChaincodeStub stub) { if ("pub".equals(parameters.get(0))) { _logger.info(stub.getState("pub")); - return newSuccessResponse(stub.getState("pub")); + return newSuccessResponse((byte[])stub.getState("pub")); } else if ("priv".equals(parameters.get(0))) { - _logger.info("get privateData" +stub.getPrivateData("col", "priv")); - 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"); } diff --git a/fabric-chaincode-integration-test/bin/.gitignore b/fabric-chaincode-integration-test/bin/.gitignore deleted file mode 100644 index 19337860..00000000 --- a/fabric-chaincode-integration-test/bin/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/test/ 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 db72ec4c..209d3cb5 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 @@ -54,62 +54,53 @@ public void RunSBE_pub_setget() throws NoSuchAlgorithmException, InvalidKeySpecE String text; r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "foo" }).build().run(true); - text = filter(r.stderr); - assertThat(text, containsString("result: status:200")); - + assertThat(filter(r.stderr), containsString("result: status:200")); + r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); - text = filter(r.stderr); - assertThat(text, containsString("result: status:200 payload:\"foo\"")); + assertThat(filter(r.stderr), containsString("result: status:200")); r = coreBuilder.duplicate().argsTx(new String[] { "addorgs", mode, "Org1MSP" }).build().run(true); - text = filter(r.stderr); - assertThat(text, containsString("result: status:200")); + assertThat(filter(r.stderr), containsString("result: status:200")); r = coreBuilder.duplicate().argsTx(new String[] { "listorgs", mode }).build().run(true); - text = filter(r.stderr); - assertThat(text, containsString("result: status:200 payload:\"[\\\"Org1MSP\\\"]\" ")); + assertThat(filter(r.stderr), containsString("result: status:200")); r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val1" }).build().run(true); - text = filter(r.stderr); - assertThat(text, containsString("result: status:200")); + assertThat(filter(r.stderr), containsString("result: status:200")); r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); - text = filter(r.stderr); - assertThat(text, containsString("result: status:200 payload:\"val1\"")); + assertThat(filter(r.stderr), containsString("result: status:200")); r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val2" }).build().run(true); - text = filter(r.stderr); - assertThat(text, containsString("result: status:200")); + assertThat(filter(r.stderr), containsString("result: status:200")); r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); - text = filter(r.stderr); - assertThat(text, containsString("result: status:200 payload:\"val2\"")); + assertThat(filter(r.stderr), containsString("result: status:200")); r = coreBuilder.duplicate().argsTx(new String[] { "addorgs", mode, "Org2MSP" }).build().run(true); - text = filter(r.stderr); - assertThat(text, containsString("result: status:200")); + 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 payload:\"[\\\"Org2MSP\\\",\\\"Org1MSP\\\"]\"")); + 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 payload:\"val3\"")); + 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 payload:\"val4\"")); + 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 payload:\"[\\\"Org2MSP\\\"]\"")); + assertThat(filter(r.stderr), containsString("result: status:200")); } @@ -130,7 +121,7 @@ public void RunSBE_priv() throws NoSuchAlgorithmException, InvalidKeySpecExcepti r = coreBuilder.duplicate().argsTx(new String[] { "getval", mode }).build().run(true); text = filter(r.stderr); - assertThat(text, containsString("result: status:200 payload:\"foo\"")); + assertThat(text, containsString("result: status:200")); r = coreBuilder.duplicate().argsTx(new String[] { "addorgs", mode, "Org1MSP" }).build().run(true); text = filter(r.stderr); 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 4062ad62..aee55f58 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 @@ -22,6 +22,6 @@ services: - 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 working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: peer node start diff --git a/fabric-chaincode-protos/bin/.gitignore b/fabric-chaincode-protos/bin/.gitignore deleted file mode 100644 index ddf9c656..00000000 --- a/fabric-chaincode-protos/bin/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/main/ diff --git a/fabric-chaincode-shim/bin/.gitignore b/fabric-chaincode-shim/bin/.gitignore deleted file mode 100644 index 7eed456b..00000000 --- a/fabric-chaincode-shim/bin/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/main/ -/test/ diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 5e8a4ab4..e6875368 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -94,7 +94,15 @@ jacocoTestCoverageVerification { 'org.hyperledger.fabric.contract.routing.RoutingRegistry', 'org.hyperledger.fabric.contract.execution.impl.ContractInvocationRequest', 'org.hyperledger.fabric.contract.routing.TransactionType', - 'org.hyperledger.fabric.contract.metadata.MetadataBuilder'] + '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 } @@ -108,7 +116,12 @@ jacocoTestCoverageVerification { 'org.hyperledger.fabric.contract.routing.impl.ContractDefinitionImpl', 'org.hyperledger.fabric.contract.routing.RoutingRegistry', 'org.hyperledger.fabric.shim.impl.Handler', - 'org.hyperledger.fabric.contract.metadata.MetadataBuilder'] + '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.71 } @@ -186,7 +199,7 @@ javadoc { 'org/hyperledger/fabric/contract/metadata/**', 'org/hyperledger/fabric/contract/routing/**', 'org/hyperledger/fabric/contract/systemcontract/**', - 'org/hyperledger/fabric/shim/impl/**', + 'org/hyperledger/fabric/**/impl/**', 'org/hyperledger/fabric/shim/helper/**', 'org/hyperledger/fabric/shim/ChaincodeBase.java'] source = sourceSets.main.allJava 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/Logging.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java index d69e7663..08719a83 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java @@ -93,5 +93,4 @@ private static Level mapLevel(final String level) { } return Level.INFO; } - } 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 index fb0ead77..4edd4587 100644 --- 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 @@ -5,7 +5,11 @@ */ 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; @@ -17,6 +21,7 @@ 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; @@ -40,16 +45,20 @@ public class ContractRouter extends ChaincodeBase { * * @param args */ - public ContractRouter(String[] 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); + } /** 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 index 175fc1e9..3bef4cda 100644 --- 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 @@ -13,7 +13,6 @@ 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; @@ -91,7 +90,7 @@ private byte[] convertReturn(Object obj, TxFunction txFn) { private List convertArgs(List stubArgs, TxFunction txFn) { List schemaParams = txFn.getParamsList(); - List args = new ArrayList<>(stubArgs.size() + 1); // allow for context as the first arguement + 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())); } 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/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/ChaincodeBase.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java index 8e7f52f0..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,5 +1,5 @@ /* -Copyright IBM Corp., DTCC All Rights Reserved. +Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,7 @@ 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; @@ -20,6 +21,8 @@ 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; @@ -32,9 +35,14 @@ 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.shim.impl.ChaincodeSupportStream; -import org.hyperledger.fabric.shim.impl.Handler; +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; @@ -73,6 +81,7 @@ 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 { @@ -84,11 +93,15 @@ public abstract class ChaincodeBase implements Chaincode { * * @param args command line arguments */ - public void start(final String[] args) { + + public void start(String[] args) { try { processEnvironmentOptions(); processCommandLineOptions(args); initializeLogging(); + + Properties props = getChaincodeConfig(); + Metrics.initialize(props); validateOptions(); connectToPeer(); } catch (final Exception e) { @@ -99,17 +112,30 @@ public void start(final String[] args) { } 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(); - final Handler handler = new Handler(chaincodeId, this); - new ChaincodeSupportStream(channelBuilder, handler::onChaincodeMessage, handler::nextOutboundChaincodeMessage); + ChaincodeSupportClient chaincodeSupportClient = new ChaincodeSupportClient(channelBuilder); + + InnvocationTaskManager itm = InnvocationTaskManager.getManager(this, chaincodeId); + chaincodeSupportClient.start(itm); + } protected void initializeLogging() { - final LogManager logManager = LogManager.getLogManager(); + LogManager logManager = LogManager.getLogManager(); - final Formatter f = new Formatter() { + 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"; @@ -285,11 +311,45 @@ protected void processEnvironmentOptions() { 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." + host + ":" + port + " tlsenabled " + tlsEnabled); @@ -299,6 +359,11 @@ 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; } @@ -384,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/ChaincodeStub.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java index 7594cbcb..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 @@ -365,7 +365,7 @@ public interface ChaincodeStub { /** * @param collection name of the collection * @param key name of the value - * @return + * @return hash */ byte[] getPrivateDataHash(String collection, String key); 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 75c9fdaa..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(); 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 b91aa795..00000000 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/helper/Channel.java +++ /dev/null @@ -1,55 +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; - -@SuppressWarnings("serial") -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 4f5ad102..00000000 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/Handler.java +++ /dev/null @@ -1,606 +0,0 @@ -/* -Copyright IBM Corp., DTCC All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package org.hyperledger.fabric.shim.impl; - -import static java.lang.String.format; -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_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; -import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.GET_STATE_BY_RANGE; -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.KEEPALIVE; -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.QUERY_STATE_CLOSE; -import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.QUERY_STATE_NEXT; -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.REGISTERED; -import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.RESPONSE; - -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 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.ChaincodeMessage; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.DelState; -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.GetStateMetadata; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.PutState; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.PutStateMetadata; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryResponse; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryStateClose; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryStateNext; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.StateMetadata; -import org.hyperledger.fabric.protos.peer.ChaincodeShim.StateMetadataResult; -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 com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.util.JsonFormat; - -public class Handler { - - private static Logger logger = Logger.getLogger(Handler.class.getName()); - private final Chaincode chaincode; - 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)); - } - } - - /** - * 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()); - - // 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)); - } - }).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()); - - // 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)); - } - }).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)); - } - - ByteString getPrivateDataHash(String channelId, String txId, String collection, String key) { - return invokeChaincodeSupport(newGetPrivateDataHashEventMessage(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); - } - } - - 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\")", txId, collection, key, value)); - } - invokeChaincodeSupport(newPutStateEventMessage(channelId, txId, collection, key, value)); - } - - void putStateMetadata(String channelId, String txId, String collection, String key, String metakey, ByteString value) { - invokeChaincodeSupport(newPutStateMatadateEventMessage(channelId, txId, collection, key, metakey, value)); - } - - void deleteState(String channelId, String txId, String collection, String key) { - 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 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()); - } - - 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 54% 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 1d4f59c5..211caa88 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,5 +1,5 @@ /* -Copyright IBM Corp., DTCC All Rights Reserved. +Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,11 @@ package org.hyperledger.fabric.shim.impl; 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; @@ -14,9 +19,11 @@ 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; @@ -26,13 +33,23 @@ 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.CompositeKey; @@ -45,13 +62,15 @@ 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; @@ -60,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; @@ -78,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()); @@ -91,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); @@ -105,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()))); } } @@ -139,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(); } } @@ -167,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 @@ -210,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() { @@ -228,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; } @@ -238,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(); + + ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_STATE_BY_RANGE, startKey, endKey, + 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) { @@ -285,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 @@ -312,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() { @@ -351,22 +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); - return handler.getPrivateDataHash(channelId, txId, collection, key).toByteArray(); + + 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; } @@ -374,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 @@ -423,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); @@ -435,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) { @@ -458,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 @@ -473,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..1a7ba2ec --- /dev/null +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManager.java @@ -0,0 +1,302 @@ +/* +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", "1")); + maximumPoolSize = Integer.parseInt((String) props.getOrDefault("TP_MAX_POOL_SIZE", "1")); + corePoolSize = Integer.parseInt((String) props.getOrDefault("TP_CORE_POOL_SIZE", "1")); + keepAliveTime = Long.parseLong((String) props.getOrDefault("TP_KEEP_ALIVE_MS", "5000")); + + workQueue = new LinkedBlockingQueue(queueSize); + + logger.info(() -> "Max Pool Size" + maximumPoolSize); + + 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/test/java/contract/Greeting.java b/fabric-chaincode-shim/src/test/java/contract/Greeting.java index 49446792..d4e4d088 100644 --- a/fabric-chaincode-shim/src/test/java/contract/Greeting.java +++ b/fabric-chaincode-shim/src/test/java/contract/Greeting.java @@ -18,8 +18,6 @@ public class Greeting { @Property() private int textLength; - private String notPartOfExternalContract; - public String getText() { return text; } 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 index 8a75fba7..e8b1009a 100644 --- 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 @@ -36,7 +36,7 @@ public class ContractExecutionServiceTest { @Rule public ExpectedException thrown = ExpectedException.none(); - @SuppressWarnings("rawtypes") + @SuppressWarnings({ "serial" }) @Test public void noReturnValue() throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException { @@ -52,7 +52,7 @@ public void noReturnValue() ChaincodeStub stub = new ChaincodeStubNaiveImpl(); when(txFn.getRouting()).thenReturn(routing); - when(req.getArgs()).thenReturn(new ArrayList() { + when(req.getArgs()).thenReturn(new ArrayList() { }); when(routing.getMethod()).thenReturn(SampleContract.class.getMethod("noReturn", new Class[] { Context.class })); when(routing.getContractInstance()).thenReturn(contract); @@ -62,7 +62,7 @@ public void noReturnValue() } - @SuppressWarnings("rawtypes") + @SuppressWarnings({ "serial" }) @Test() public void failureToInvoke() throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException { @@ -78,7 +78,7 @@ public void failureToInvoke() ChaincodeStub stub = mock(ChaincodeStub.class); when(txFn.getRouting()).thenReturn(routing); - when(req.getArgs()).thenReturn(new ArrayList() { + when(req.getArgs()).thenReturn(new ArrayList() { }); when(routing.getContractInstance()).thenThrow(IllegalAccessException.class); 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 index 04f967ad..c8135872 100644 --- 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 @@ -56,7 +56,7 @@ public void systemContract() { SystemContract system = new SystemContract(); ChaincodeStub stub = new ChaincodeStubNaiveImpl(); // TODO: Assert something about the returned metadata - String metadataCompressed = system.getMetadata(new Context(stub)); + system.getMetadata(new Context(stub)); } @Test 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 index 12a64ac6..1a43ef16 100644 --- 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 @@ -92,7 +92,7 @@ public void invaldtxfn() throws NoSuchMethodException, SecurityException { ContractDefinition cd = mock(ContractDefinition.class); thrown.expect(ContractRuntimeException.class); - TxFunction txfn = new TxFunctionImpl(test.getClass().getMethod("wibble", new Class[] { String.class }), cd); + new TxFunctionImpl(test.getClass().getMethod("wibble", new Class[] { String.class }), cd); } 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 index 455a90ed..b86a16b6 100644 --- 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 @@ -5,7 +5,7 @@ */ package org.hyperledger.fabric.contract.routing; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; import java.util.Collection; @@ -52,7 +52,7 @@ public void getAllDataTypes() { tr.addDataType(Integer.class); tr.addDataType(Float.class); - Collection c = tr.getAllDataTypes(); + 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 index dd407aab..99c385c3 100644 --- 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 @@ -6,7 +6,6 @@ package org.hyperledger.fabric.contract.simplepath; 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.READY; import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.REGISTER; import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.TRANSACTION; @@ -16,17 +15,13 @@ import java.util.List; import java.util.concurrent.TimeUnit; -import com.google.protobuf.ByteString; - 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; 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.CompleteStep; import org.hyperledger.fabric.shim.mock.peer.RegisterStep; import org.hyperledger.fabric.shim.mock.peer.ScenarioStep; import org.hyperledger.fabric.shim.utils.MessageUtil; @@ -36,6 +31,8 @@ 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(); 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 bc03bb39..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 @@ -16,7 +16,9 @@ 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; @@ -196,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); @@ -207,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); } 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/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 dda43314..00000000 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeStubImplTest.java +++ /dev/null @@ -1,940 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ -package org.hyperledger.fabric.shim.impl; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; -import static org.hyperledger.fabric.protos.common.Common.HeaderType.ENDORSER_TRANSACTION_VALUE; -import static org.junit.Assert.assertNotNull; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.xml.bind.DatatypeConverter; - -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.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; -import org.mockito.quality.Strictness; - -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Timestamp; - -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_withAttributesWithSplitParams() { - - 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 testGetPrivateDataHash() { - final ChaincodeStubImpl stub = new ChaincodeStubImpl("myc", "txId", handler, Collections.emptyList(), null); - final byte[] value = new byte[]{0x10, 0x20, 0x30}; - when(handler.getPrivateDataHash("myc", "txId", "testcoll", "key")).thenReturn(ByteString.copyFrom(value)); - assertThat(stub.getPrivateDataHash("testcoll", "key"), is(value)); - try { - stub.getPrivateDataHash(null, "key"); - Assert.fail("Null collection check fails"); - } catch (NullPointerException e) { - } - try { - stub.getPrivateDataHash("", "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_withAttributesWithSplitParams() { - - 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 baa3b3f6..00000000 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/HandlerTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* -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; -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; - -import com.google.protobuf.ByteString; - - -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"); - - 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/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 From 96f08b7c79ca003f4a486b6ebd433492cc7801a3 Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Tue, 29 Oct 2019 13:18:04 +0000 Subject: [PATCH 24/61] Permit daily builds to occur Signed-off-by: Matthew B White --- ci/azure-pipelines.yml | 13 +++++++++++++ .../resources/first-network/base/peer-base.yaml | 1 + .../fabric/shim/fvt/ChaincodeFVTest.java | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index d60162c4..91ebe5fc 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -4,6 +4,19 @@ # # fabric-chaincode-java azure pipeline configuration. # +# Daily build for final quality +# cf https://crontab.guru/#0_23_*_*_* +schedules: + - cron: "0 23 * * *" + displayName: 'Chaincode Java Nightly Driver' + branches: + include: + - master + - release-1.4 + always: true + + + trigger: branches: include: 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 aee55f58..e0df016e 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 @@ -23,5 +23,6 @@ services: - 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-latest + - CORE_CHAINCODE_EXECUTETIMEOUT=300s working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: peer node start 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 9817b11b..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 @@ -330,7 +330,7 @@ public Response invoke(ChaincodeStub stub) { server.send(invokeMsg); - ChaincodeMockPeer.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")); From df7b7254152de12ff60d1c0b79772e7777d24646 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 7 Nov 2019 11:15:41 +0000 Subject: [PATCH 25/61] Fix builds Backport timeout change from master Signed-off-by: James Taylor --- .../hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3c1f5356..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 @@ -190,7 +190,7 @@ public static void checkScenarioStepEnded(final ChaincodeMockPeer s, final int s while (true) { if (s.getLastExecutedStep() == step) return; try { - Thread.sleep(1); + Thread.sleep(500); } catch (InterruptedException e) { } } From 5ce56dfa00be94f82fa2bfacbe50d7fc320b3371 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Tue, 5 Nov 2019 17:08:07 +0000 Subject: [PATCH 26/61] [FAB-16712] Update contributing guide Include new azure devops link and github info in contributing guide Signed-off-by: James Taylor --- CONTRIBUTING.md | 55 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 32838a06..a5cd720d 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. ## Folder structure @@ -66,4 +99,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/) From ab9c0df91d1cfc6749b5c3749438f2f463e46724 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 7 Nov 2019 10:59:37 +0000 Subject: [PATCH 27/61] Update readme Combine contributing guide with readme and ensure information is up-to-date Signed-off-by: James Taylor # Conflicts: # README.md --- CONTRIBUTING.md | 51 ------- README.md | 76 ++++++++-- TUTORIAL.md | 370 ------------------------------------------------ 3 files changed, 66 insertions(+), 431 deletions(-) delete mode 100644 TUTORIAL.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5cd720d..ecbb46ff 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,57 +40,6 @@ We use our own forks and [Github Flow](https://guides.github.com/introduction/fl Please to try to be consistent with the rest of the code and conform to checkstyle rules where they are provided. -## Folder structure - -The "fabric-chaincode-protos" folder contains the protobuf definition files used by -Java shim to communicate with Fabric peer. - -The "fabric-chaincode-shim" folder contains the java shim classes that define Java -chaincode API and way to communicate with Fabric peer. - -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. - -#### 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' -} -``` - ## Code of Conduct Guidelines See our [Code of Conduct Guidelines](../blob/master/CODE_OF_CONDUCT.md). diff --git a/README.md b/README.md index 6ffd7acb..de2e43c0 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,75 @@ -# Hyperledger Fabric - Java Contract and Chaincode +# Hyperledger Fabric Chaincode Java -This is a Java implementation of Hyperledger Fabric chaincode shim APIs and contract programming model. This enables development of using Java language or other JVM based languages +[![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) -## Developers +This is a Java based implementation of Hyprledger Fabric chaincode shim APIs, which enables development of smart contracts using the Java language. -Application developers interested in developing smart contracts should read the [introductory tutorial](CONTRACT_TUTORIAL.md) and for a full scenario visit the -[Commercial Paper](https://hyperledger-fabric.readthedocs.io/en/latest/tutorial/commercial_paper.html) tutorial. +This project creates `fabric-chaincode-protos` and `fabric-chaincode-shim` jar +files for developers' consumption and the `hyperledger/fabric-javaenv` docker image +to run Java chaincode. -We recommend using the IBM Blockchain Platform [VSCode extension](https://marketplace.visualstudio.com/items?itemName=IBMBlockchain.ibm-blockchain-platform) to assist you in developing smart contracts. The extension is able to create sample contracts for you, an example of such a contract is in the [fabric-contract-example](./fabric-contract-example) directory; there are folders for using both gradle and maven. +## Getting Started -In addition, this has reference to other tutorials to get you started +Application developers interested in developing Java smart contracts for Hyperledger Fabric should read the [JavaDoc](https://fabric-chaincode-java.github.io/) which inludes download information, and links to documentation and samples. -## Contributors +## Project structure -Contributors or early adopters who need to be able to build and test recent builds, should reference the [contributing](CONTRIBUTING.md) guide. +### fabric-chaincode-protos -This project creates `fabric-chaincode-protos` and `fabric-chaincode-shim` jar files for developers consumption and the `hyperledger/fabric-javaenv` docker image to run the Java chaincode and contracts. +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. + +Build javaenv docker image, to have it locally. + +``` +./gradlew buildImage +``` + +--- + +[![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/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:/# -``` From e19aadf13cbd3391e963fb1cb1c73d86be6da456 Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Mon, 11 Nov 2019 16:22:51 +0000 Subject: [PATCH 28/61] [FAB-17045] Release v1.4.4 Java Chaincode - Bug fix release. Please see CHANGELOG.md Change-Id: Iaa6e4d8ebdfb59f733964caedca1b892df23203e Signed-off-by: Matthew B. White --- CHANGELOG.md | 16 +++ build.gradle | 2 +- ci/azure-pipelines.yml | 125 ++++++++++++++++--- fabric-chaincode-example-gradle/build.gradle | 2 +- fabric-chaincode-example-maven/pom.xml | 2 +- fabric-chaincode-example-sacc/build.gradle | 2 +- fabric-chaincode-example-sbe/build.gradle | 2 +- fabric-contract-example/gradle/build.gradle | 2 +- fabric-contract-example/maven/pom.xml | 2 +- release_notes/v1.4.4.txt | 31 +++++ 10 files changed, 159 insertions(+), 27 deletions(-) create mode 100644 release_notes/v1.4.4.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f6d9b85..e254d0e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## 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 diff --git a/build.gradle b/build.gradle index 730f8d16..3971f509 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ apply plugin: 'idea' apply plugin: 'eclipse-wtp' apply plugin: 'com.dorongold.task-tree' -version = '1.4.4-SNAPSHOT' +version = '1.4.4' buildscript { repositories { maven { diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 91ebe5fc..898a723c 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -8,10 +8,9 @@ # cf https://crontab.guru/#0_23_*_*_* schedules: - cron: "0 23 * * *" - displayName: 'Chaincode Java Nightly Driver' + displayName: 'Chaincode 1.4 Java Nightly Driver' branches: include: - - master - release-1.4 always: true @@ -21,7 +20,6 @@ trigger: branches: include: - 'master' - - 'release-1.4' tags: include: - '*' @@ -31,8 +29,16 @@ trigger: # this isn't set so command line output is given # variables: - component: fabric-chaincode-node - pipeline: ci + - group: Chaincode_Java_Creds + - group: JARSigningPublish + - name: component + value: fabric-chaincode-java + - name: pipeline + value: ci + - name: NEXUS_REPO_URL + value: nexus3.hyperledger.org:10003 + - name: PUSH_VERSION + value: stable pool: vmImage: 'ubuntu-latest' @@ -45,7 +51,9 @@ stages: jobs: - job: main steps: - - script: env + - script: | + env | sort + java -version - task: Gradle@2 inputs: workingDirectory: '' @@ -60,24 +68,101 @@ stages: - 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 + + + # Publish the snapshot images etc. + # Original source of these is https://github.com/hyperledger/ci-management/blob/master/jjb/fabric-chaincode-java/shell/include-raw-publish-docker-jar.sh + - job: + dependsOn: main + condition: and(succeeded(),eq(variables['Build.Reason'], 'IndividualCI')) + steps: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: java-docker-image + path: $(Build.SourcesDirectory)/build + - script: | + docker image load --input build/fabric-javaenv.tar.gz + docker images + # Publish docker images to nexus repository + docker login ${DOCKER_REGISTRY_URL} --username=${DOCKER_REGISTRY_USERNAME} --password=${DOCKER_REGISTRY_PASSWORD} + echo "Logged in to docker registry" + # tag javaenv image to $PUSH_VERSION + docker tag hyperledger/fabric-javaenv ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION} + # push javaenv to nexus repository + docker push ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION} + env: + DOCKER_REGISTRY_USERNAME: $(GITHUB_REGISTRY_USER) + DOCKER_REGISTRY_PASSWORD: $(GITHUB_REGISTRY_PWD_TOKEN) + DOCKER_REGISTRY_URL: docker.pkg.github.com/hyperledger/fabric-chaincode-java + MAPPED_VERSION: $(PUSH_VERSION) + + # 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: update_version + - job: publish_release steps: + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: java-docker-image + path: $(Build.SourcesDirectory)/build + - task: DownloadSecureFile@1 + name: keyring + inputs: + secureFile: secring.gpg - script: | env | sort - echo "Update the version number" - echo "Make sure release notes are present" - echo "Make sure change history is present" - - job: npm_publish - steps: - - script: | - echo "Setup .npmrc" - echo "Use pipeline secret to login" - echo "publish" - - job: jsdoc_publish - steps: + + # 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 + # Publish docker images to nexus repository + docker login ${DOCKER_REGISTRY_URL} --username=${DOCKER_REGISTRY_USERNAME} --password=${DOCKER_REGISTRY_PASSWORD} + echo "Logged in to docker registry" + # tag javaenv image to $PUSH_VERSION + docker tag hyperledger/fabric-javaenv fabric-javaenv:amd64-${VERSION} + # push javaenv to nexus repository + docker push fabric-javaenv:amd64-${VERSION} + env: + DOCKER_REGISTRY_USERNAME: $(DockerHub-Username) + DOCKER_REGISTRY_PASSWORD: $(DockerHub-Password) - script: | - echo "checkout docs branch" - echo "checking" \ No newline at end of file + 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) \ No newline at end of file diff --git a/fabric-chaincode-example-gradle/build.gradle b/fabric-chaincode-example-gradle/build.gradle index befed338..88acfba1 100644 --- a/fabric-chaincode-example-gradle/build.gradle +++ b/fabric-chaincode-example-gradle/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4-SNAPSHOT' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4' 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 9926719e..d2d9882b 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.4-SNAPSHOT + 1.4.4 1.0.13 diff --git a/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-example-sacc/build.gradle index c9ac43a3..bf3059d9 100644 --- a/fabric-chaincode-example-sacc/build.gradle +++ b/fabric-chaincode-example-sacc/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4-SNAPSHOT' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-example-sbe/build.gradle b/fabric-chaincode-example-sbe/build.gradle index ac7a4270..c41e5e7d 100644 --- a/fabric-chaincode-example-sbe/build.gradle +++ b/fabric-chaincode-example-sbe/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4-SNAPSHOT' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-contract-example/gradle/build.gradle b/fabric-contract-example/gradle/build.gradle index 21087a62..586a1495 100644 --- a/fabric-contract-example/gradle/build.gradle +++ b/fabric-contract-example/gradle/build.gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4-SNAPSHOT' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4' 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' diff --git a/fabric-contract-example/maven/pom.xml b/fabric-contract-example/maven/pom.xml index 08cd56d0..ee4b7b3e 100644 --- a/fabric-contract-example/maven/pom.xml +++ b/fabric-contract-example/maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.4-SNAPSHOT + 1.4.4 1.0.13 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 From 08e19d1fcb2841ddc984d28d49f00b869bd4df21 Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Thu, 14 Nov 2019 12:50:48 +0000 Subject: [PATCH 29/61] Docker image publishing Change-Id: I90a0e3d4bee83e8c34fcb4beb0360955cb82c85e Signed-off-by: Matthew B. White --- ci/azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 898a723c..93f71fde 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -96,7 +96,7 @@ stages: steps: - task: DownloadPipelineArtifact@2 inputs: - artifact: java-docker-image + artifact: javaenv-docker-image path: $(Build.SourcesDirectory)/build - script: | docker image load --input build/fabric-javaenv.tar.gz @@ -124,7 +124,7 @@ stages: - task: DownloadPipelineArtifact@2 inputs: - artifact: java-docker-image + artifact: javaenv-docker-image path: $(Build.SourcesDirectory)/build - task: DownloadSecureFile@1 name: keyring From 228d558715a561953737d961bd88b2593380e7d1 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 11 Nov 2019 13:25:19 +0000 Subject: [PATCH 30/61] Publish javadoc Signed-off-by: James Taylor --- ci/azure-pipelines.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 93f71fde..b6a06dca 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -87,6 +87,25 @@ stages: pathToPublish: $(Build.ArtifactStagingDirectory)/fabric-javaenv.tar.gz artifactName: javaenv-docker-image + - job: javadoc + condition: and(succeeded(),eq(variables['Build.Reason'], 'IndividualCI')) + 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 "Hyperledger Bot" + git config --global user.name "hlfdev.azp@gmail.com" + 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' # Publish the snapshot images etc. # Original source of these is https://github.com/hyperledger/ci-management/blob/master/jjb/fabric-chaincode-java/shell/include-raw-publish-docker-jar.sh From 7433e963a3b3c6890d79ffc3b4fe44beb4fe601e Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 14 Nov 2019 14:25:10 +0000 Subject: [PATCH 31/61] Fix build trigger on release-1.4 Signed-off-by: James Taylor --- ci/azure-pipelines.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index b6a06dca..4ae6553e 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -19,7 +19,7 @@ schedules: trigger: branches: include: - - 'master' + - 'release-1.4' tags: include: - '*' @@ -100,8 +100,8 @@ stages: cp -r fabric-chaincode-shim/build/docs/javadoc/* $(Build.SourceBranchName)/api displayName: 'Update gh-pages branch' - script: | - git config --global user.email "Hyperledger Bot" - git config --global user.name "hlfdev.azp@gmail.com" + 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 From 63c96b6506c24670d2b91979d090d80b64433f41 Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Thu, 14 Nov 2019 15:54:18 +0000 Subject: [PATCH 32/61] Docker image publishing (#32) Change-Id: I90a0e3d4bee83e8c34fcb4beb0360955cb82c85e Signed-off-by: Matthew B. White --- ci/azure-pipelines.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 4ae6553e..6f036b91 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -54,6 +54,9 @@ stages: - 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}: - task: Gradle@2 inputs: workingDirectory: '' @@ -153,7 +156,7 @@ stages: env | sort # temporarily use this approach instead of the gittag - VERSION=$(cat build.gradle | sed -n "s/version =.*'\(.*\)\(-SNAPSHOT\)\?'/\1/p" + VERSION=$(cat build.gradle | sed -n "s/version =.*'\(.*\)\(-SNAPSHOT\)\?'/\1/p") VERSION=${VERSION// } echo Version is :${VERSION}: From 9f88bf035a089b75693dea7de22f783adc69d628 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 14 Nov 2019 15:44:22 +0000 Subject: [PATCH 33/61] Update javadoc location in readme Signed-off-by: James Taylor --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de2e43c0..08346fb2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ to run Java chaincode. ## Getting Started -Application developers interested in developing Java smart contracts for Hyperledger Fabric should read the [JavaDoc](https://fabric-chaincode-java.github.io/) which inludes download information, and links to documentation and samples. +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 From 7d6152f49e915ddd567b3ed31d229b44c00be942 Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Thu, 14 Nov 2019 16:43:23 +0000 Subject: [PATCH 34/61] Update to use new github credentials Signed-off-by: Matthew B. White --- ci/azure-pipelines.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 6f036b91..9187b62b 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -30,6 +30,7 @@ trigger: # variables: - group: Chaincode_Java_Creds + - group: Github-PackageRegistry-Credentials - group: JARSigningPublish - name: component value: fabric-chaincode-java @@ -131,8 +132,8 @@ stages: # push javaenv to nexus repository docker push ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION} env: - DOCKER_REGISTRY_USERNAME: $(GITHUB_REGISTRY_USER) - DOCKER_REGISTRY_PASSWORD: $(GITHUB_REGISTRY_PWD_TOKEN) + DOCKER_REGISTRY_USERNAME: $(Github-PackageRegistry-Username) + DOCKER_REGISTRY_PASSWORD: $(Github-PackageRegistry-Password) DOCKER_REGISTRY_URL: docker.pkg.github.com/hyperledger/fabric-chaincode-java MAPPED_VERSION: $(PUSH_VERSION) From e918e5f2781c00d031c58adecf0180747985a1fc Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Thu, 14 Nov 2019 16:43:23 +0000 Subject: [PATCH 35/61] Update to use new github credentials Signed-off-by: Matthew B. White --- ci/azure-pipelines.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 9187b62b..eec45e6b 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -120,6 +120,7 @@ stages: - task: DownloadPipelineArtifact@2 inputs: artifact: javaenv-docker-image + enabled: false path: $(Build.SourcesDirectory)/build - script: | docker image load --input build/fabric-javaenv.tar.gz @@ -131,6 +132,7 @@ stages: docker tag hyperledger/fabric-javaenv ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION} # push javaenv to nexus repository docker push ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION} + enabled: false env: DOCKER_REGISTRY_USERNAME: $(Github-PackageRegistry-Username) DOCKER_REGISTRY_PASSWORD: $(Github-PackageRegistry-Password) From af14b361c3385b52454f905a920a4c0e4988ee6b Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Thu, 14 Nov 2019 16:43:23 +0000 Subject: [PATCH 36/61] Update to use new github credentials Signed-off-by: Matthew B. White --- ci/azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index eec45e6b..0351091d 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -171,8 +171,8 @@ stages: echo "Logged in to docker registry" # tag javaenv image to $PUSH_VERSION docker tag hyperledger/fabric-javaenv fabric-javaenv:amd64-${VERSION} - # push javaenv to nexus repository - docker push fabric-javaenv:amd64-${VERSION} + # push javaenv to repository + docker push hyperledger/fabric-javaenv:amd64-${VERSION} env: DOCKER_REGISTRY_USERNAME: $(DockerHub-Username) DOCKER_REGISTRY_PASSWORD: $(DockerHub-Password) From 5ff847e9747856045f1dae2f851d430f3dd590b9 Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Tue, 19 Nov 2019 09:58:09 +0000 Subject: [PATCH 37/61] [FAB-17078] Update version number Signed-off-by: Matthew B. White --- build.gradle | 2 +- fabric-chaincode-docker/build.gradle | 2 +- fabric-chaincode-example-gradle/build.gradle | 2 +- fabric-chaincode-example-maven/pom.xml | 2 +- fabric-chaincode-example-sacc/build.gradle | 2 +- fabric-chaincode-example-sbe/build.gradle | 2 +- fabric-chaincode-integration-test/build.gradle | 2 +- fabric-contract-example/gradle/build.gradle | 2 +- fabric-contract-example/maven/pom.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 3971f509..6af405ea 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ apply plugin: 'idea' apply plugin: 'eclipse-wtp' apply plugin: 'com.dorongold.task-tree' -version = '1.4.4' +version = '1.4.5' buildscript { repositories { maven { diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index b55f4f90..fa01c534 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -80,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.4', 'hyperledger/fabric-javaenv:amd64-latest'] + tags = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:amd64-1.4.5', 'hyperledger/fabric-javaenv:amd64-latest'] } diff --git a/fabric-chaincode-example-gradle/build.gradle b/fabric-chaincode-example-gradle/build.gradle index 88acfba1..406c0536 100644 --- a/fabric-chaincode-example-gradle/build.gradle +++ b/fabric-chaincode-example-gradle/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.5' 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 d2d9882b..8891726b 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.4 + 1.4.5 1.0.13 diff --git a/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-example-sacc/build.gradle index bf3059d9..9328e5c8 100644 --- a/fabric-chaincode-example-sacc/build.gradle +++ b/fabric-chaincode-example-sacc/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.5' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-example-sbe/build.gradle b/fabric-chaincode-example-sbe/build.gradle index c41e5e7d..41c46e52 100644 --- a/fabric-chaincode-example-sbe/build.gradle +++ b/fabric-chaincode-example-sbe/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.5' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-integration-test/build.gradle b/fabric-chaincode-integration-test/build.gradle index 4e56f61e..57e74479 100644 --- a/fabric-chaincode-integration-test/build.gradle +++ b/fabric-chaincode-integration-test/build.gradle @@ -1,7 +1,7 @@ dependencies { compile project(':fabric-chaincode-docker') testCompile 'org.testcontainers:testcontainers:1.7.1' - testCompile 'org.hyperledger.fabric-sdk-java:fabric-sdk-java:1.4.4' + testCompile 'org.hyperledger.fabric-sdk-java:fabric-sdk-java:1.4.5' compile project(':fabric-chaincode-shim') implementation group: 'org.json', name: 'json', version: '20180813' } diff --git a/fabric-contract-example/gradle/build.gradle b/fabric-contract-example/gradle/build.gradle index 586a1495..fc0ccd5c 100644 --- a/fabric-contract-example/gradle/build.gradle +++ b/fabric-contract-example/gradle/build.gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.4' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.5' 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' diff --git a/fabric-contract-example/maven/pom.xml b/fabric-contract-example/maven/pom.xml index ee4b7b3e..5585d33e 100644 --- a/fabric-contract-example/maven/pom.xml +++ b/fabric-contract-example/maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.4 + 1.4.5 1.0.13 From 4f03935aa5abaab34ef2c810de26f68eb03be7af Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Tue, 19 Nov 2019 10:33:20 +0000 Subject: [PATCH 38/61] [FAB-17100] Default Thread Pool not set correctly The advertised defaults where not set correctly. Signed-off-by: Matthew B. White --- .../fabric/shim/impl/InnvocationTaskManager.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) 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 index 1a7ba2ec..a5cb09e6 100644 --- 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 @@ -90,15 +90,17 @@ public InnvocationTaskManager(ChaincodeBase chaincode, ChaincodeID chaincodeId) // setup the thread pool here Properties props = chaincode.getChaincodeConfig(); - queueSize = Integer.parseInt((String) props.getOrDefault("TP_QUEUE_SIZE", "1")); - maximumPoolSize = Integer.parseInt((String) props.getOrDefault("TP_MAX_POOL_SIZE", "1")); - corePoolSize = Integer.parseInt((String) props.getOrDefault("TP_CORE_POOL_SIZE", "1")); + 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")); - workQueue = new LinkedBlockingQueue(queueSize); - - logger.info(() -> "Max Pool Size" + maximumPoolSize); + 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); From 5496c6cdfb2b894b3d8843d9afeadd17a57e677a Mon Sep 17 00:00:00 2001 From: "Matthew B. White" Date: Thu, 28 Nov 2019 10:21:49 +0000 Subject: [PATCH 39/61] [FAB-17138] Push to nexus Signed-off-by: Matthew B. White --- ci/azure-pipelines.yml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 0351091d..4cb7ed7b 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -50,14 +50,16 @@ pool: stages: - stage: Build_and_test jobs: - - job: main - steps: + - 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: '' @@ -116,6 +118,8 @@ stages: - job: dependsOn: main condition: and(succeeded(),eq(variables['Build.Reason'], 'IndividualCI')) + variables: + PACKAGE_VERSION: $[ dependencies.main.outputs['builddata.PACKAGE_VERSION'] ] steps: - task: DownloadPipelineArtifact@2 inputs: @@ -123,21 +127,22 @@ stages: enabled: false path: $(Build.SourcesDirectory)/build - script: | + docker image load --input build/fabric-javaenv.tar.gz docker images # Publish docker images to nexus repository docker login ${DOCKER_REGISTRY_URL} --username=${DOCKER_REGISTRY_USERNAME} --password=${DOCKER_REGISTRY_PASSWORD} echo "Logged in to docker registry" # tag javaenv image to $PUSH_VERSION - docker tag hyperledger/fabric-javaenv ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION} + docker tag hyperledger/fabric-javaenv ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION}-stable # push javaenv to nexus repository - docker push ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION} + docker push ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION}-stable enabled: false env: - DOCKER_REGISTRY_USERNAME: $(Github-PackageRegistry-Username) - DOCKER_REGISTRY_PASSWORD: $(Github-PackageRegistry-Password) - DOCKER_REGISTRY_URL: docker.pkg.github.com/hyperledger/fabric-chaincode-java - MAPPED_VERSION: $(PUSH_VERSION) + DOCKER_REGISTRY_USERNAME: $(nexus-user) + DOCKER_REGISTRY_PASSWORD: $(nexus-password) + DOCKER_REGISTRY_URL: nexus3.hyperledger.org:10003/hyperledger + MAPPED_VERSION: $(PACKAGE_VERSION) # As the next script is more complex and uses loops, run this descretely in a sh file # Publishing step for git tags From ed5b24756d737952eca4dbed69710504a0c315a4 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 28 Nov 2019 13:40:21 +0000 Subject: [PATCH 40/61] [FAB-17138] Enable push to nexus Signed-off-by: James Taylor --- ci/azure-pipelines.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 4cb7ed7b..a3010dc0 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -115,7 +115,7 @@ stages: # Publish the snapshot images etc. # Original source of these is https://github.com/hyperledger/ci-management/blob/master/jjb/fabric-chaincode-java/shell/include-raw-publish-docker-jar.sh - - job: + - job: publish dependsOn: main condition: and(succeeded(),eq(variables['Build.Reason'], 'IndividualCI')) variables: @@ -124,7 +124,6 @@ stages: - task: DownloadPipelineArtifact@2 inputs: artifact: javaenv-docker-image - enabled: false path: $(Build.SourcesDirectory)/build - script: | @@ -137,12 +136,12 @@ stages: docker tag hyperledger/fabric-javaenv ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION}-stable # push javaenv to nexus repository docker push ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION}-stable - enabled: false env: DOCKER_REGISTRY_USERNAME: $(nexus-user) DOCKER_REGISTRY_PASSWORD: $(nexus-password) DOCKER_REGISTRY_URL: nexus3.hyperledger.org:10003/hyperledger MAPPED_VERSION: $(PACKAGE_VERSION) + displayName: 'docker push to nexus' # As the next script is more complex and uses loops, run this descretely in a sh file # Publishing step for git tags From 8fc5763eafecc02e3187e188a3f372a4e834cb32 Mon Sep 17 00:00:00 2001 From: Secundino Iglesias Date: Thu, 28 Nov 2019 15:20:38 +0100 Subject: [PATCH 41/61] Maven build in batch mode Signed-off-by: Secundino Iglesias --- fabric-chaincode-docker/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-docker/build.sh b/fabric-chaincode-docker/build.sh index 3341495b..99bae925 100644 --- a/fabric-chaincode-docker/build.sh +++ b/fabric-chaincode-docker/build.sh @@ -19,7 +19,7 @@ buildGradle() { buildMaven() { cd "$1" > /dev/null echo "Maven build" - mvn compile package -DskipTests -Dmaven.test.skip=true + mvn -B compile package -DskipTests -Dmaven.test.skip=true retval=$? if [ $retval -ne 0 ]; then exit $retval From bc99f738777bfd44203797334f193fc48f8fc1bd Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Mon, 16 Dec 2019 11:16:04 +0000 Subject: [PATCH 42/61] [FABCJ-259] Pagination Fix Minor fix to pagination - arguments wrong Fix pulls in the new test code that was written in the master branch. Signed-off-by: Matthew B White --- fabric-chaincode-example-sacc/build.gradle | 2 +- .../fabric/example/SimpleAsset.java | 2 +- .../getDockerImages.sh | 44 +++ .../build.gradle | 30 ++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 55616 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + .../fabric-chaincode-example-sacc/gradlew | 188 +++++++++++++ .../fabric-chaincode-example-sacc/gradlew.bat | 100 +++++++ .../settings.gradle | 2 + .../hyperledger/fabric/example/AllAPI.java | 99 +++++++ .../fabric-chaincode-example-sbe/build.gradle | 30 ++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 55616 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + .../fabric-chaincode-example-sbe/gradlew | 188 +++++++++++++ .../fabric-chaincode-example-sbe/gradlew.bat | 100 +++++++ .../settings.gradle | 2 + .../fabric/example/EndorsementCC.java | 256 ++++++++++++++++++ .../shim/integration/CommandSingleton.java | 58 ++++ .../shim/integration/SACCIntegrationTest.java | 79 +++--- .../integration/SBECCIntegrationTest.java | 6 +- .../first-network/docker-compose-cli.yaml | 4 +- .../resources/first-network/scripts/script.sh | 20 +- .../resources/first-network/scripts/utils.sh | 32 ++- .../fabric/shim/impl/InnvocationStubImpl.java | 2 +- 24 files changed, 1186 insertions(+), 68 deletions(-) create mode 100755 fabric-chaincode-integration-test/getDockerImages.sh create mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/build.gradle create mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradle/wrapper/gradle-wrapper.jar create mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradle/wrapper/gradle-wrapper.properties create mode 100755 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradlew create mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradlew.bat create mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/settings.gradle create mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/src/main/java/org/hyperledger/fabric/example/AllAPI.java create mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/build.gradle create mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradle/wrapper/gradle-wrapper.jar create mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradle/wrapper/gradle-wrapper.properties create mode 100755 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradlew create mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/gradlew.bat create mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/settings.gradle create mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/src/main/java/org/hyperledger/fabric/example/EndorsementCC.java create mode 100644 fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/CommandSingleton.java diff --git a/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-example-sacc/build.gradle index 9328e5c8..d7737b64 100644 --- a/fabric-chaincode-example-sacc/build.gradle +++ b/fabric-chaincode-example-sacc/build.gradle @@ -25,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 daf321f2..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 @@ -32,7 +32,7 @@ public Response init(ChaincodeStub stub) { 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-integration-test/getDockerImages.sh b/fabric-chaincode-integration-test/getDockerImages.sh new file mode 100755 index 00000000..c5d0e689 --- /dev/null +++ b/fabric-chaincode-integration-test/getDockerImages.sh @@ -0,0 +1,44 @@ +#!/bin/bash -e +set -o pipefail + +echo "======== PULL DOCKER IMAGES ========" + +########################################################## +# Pull and Tag the fabric and fabric-ca images from Nexus +########################################################## +echo "Fetching images from Nexus" +# NEXUS_URL=nexus3.hyperledger.org:10001 +NEXUS_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 IMAGES in peer orderer ca tools orderer ccenv; do + echo "Images: $IMAGES" + echo + docker pull $NEXUS_URL/$ORG_NAME-$IMAGES:$STABLE_TAG + if [ $? != 0 ]; then + echo "FAILED: Docker Pull Failed on $IMAGES" + exit 1 + fi + docker tag $NEXUS_URL/$ORG_NAME-$IMAGES:$STABLE_TAG $ORG_NAME-$IMAGES + docker tag $NEXUS_URL/$ORG_NAME-$IMAGES:$STABLE_TAG $ORG_NAME-$IMAGES:$MASTER_TAG + docker tag $NEXUS_URL/$ORG_NAME-$IMAGES:$STABLE_TAG $ORG_NAME-$IMAGES:$VERSION + echo "$ORG_NAME-$IMAGES:$MASTER_TAG" + echo "Deleting Nexus docker images: $IMAGES" + docker rmi -f $NEXUS_URL/$ORG_NAME-$IMAGES:$STABLE_TAG + done +} + +dockerTag + +echo +docker images | grep "hyperledger*" +echo \ No newline at end of file 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..d7737b64 --- /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.5' + 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/gradle/wrapper/gradle-wrapper.jar b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..5c2d1cf016b3885f6930543d57b744ea8c220a1a GIT binary patch literal 55616 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 \(.*\)$'` + 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-sacc/gradlew.bat b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradlew.bat new file mode 100644 index 00000000..24467a14 --- /dev/null +++ b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/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-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..41c46e52 --- /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 '2.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.5' + 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 0000000000000000000000000000000000000000..5c2d1cf016b3885f6930543d57b744ea8c220a1a GIT binary patch literal 55616 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 \(.*\)$'` + 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/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/SACCIntegrationTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/SACCIntegrationTest.java index 559c7ccc..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,7 +4,8 @@ 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; @@ -25,58 +26,42 @@ public class SACCIntegrationTest { @BeforeClass - public static void setUp() throws Exception { - - // 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(); + public static void setUp() { + CommandSingleton.setup(); } - @Test - public void TestSACCChaincodeInstallInstantiateInvokeQuery() { - - // Need to send a number of 'peer chaincode invoke' commands - // Setup the core buider command and then duplicate per test + private String invoke(String... args){ PeerBuilder coreBuilder = Peer.newBuilder().ccname("javacc").channel("mychannel"); - Result r; - String text; - // 2019-10-02 13:05:59.812 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 004 Chaincode invoke successful. result: status:200 message:"200" - - r = coreBuilder.duplicate().argsTx(new String[] { "set", "b", "200" }).build().run(); - text = r.stderr.stream() + 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())); - assertThat(text, containsString("result: status:200 message:\"200\"")); + .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"; + } - r = coreBuilder.duplicate().argsTx(new String[] { "get", "a" }).build().run(); - text = r.stderr.stream() - .filter(line -> line.matches(".*chaincodeInvokeOrQuery.*")) - .collect(Collectors.joining(System.lineSeparator())); - assertThat(text, containsString("result: status:200 message:\"100\"")); + @Test + public void TestQuery(){ - r = coreBuilder.duplicate().argsTx(new String[] { "get", "b" }).build().run(); - text = r.stderr.stream() - .filter(line -> line.matches(".*chaincodeInvokeOrQuery.*")) - .collect(Collectors.joining(System.lineSeparator())); - assertThat(text, containsString("result: status:200 message:\"200\"")); + String text = invoke(new String[]{"putBulkStates"}); + assertThat(text, containsString("status:200")); + + text = invoke(new String[]{"getByRange","key120","key170"}); + assertThat(text, containsString("50")); + + text = invoke(new String[]{"getByRangePaged","key120","key170","10",""}); + System.out.println(text); + assertThat(text, containsString("key130")); } 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 209d3cb5..48a97ade 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 @@ -28,10 +28,7 @@ public class SBECCIntegrationTest { @BeforeClass public static void setUp() throws Exception { - // Call the inbuilt script to install/instantiate - DockerBuilder dockerBuilder = new Docker.DockerBuilder(); - Docker docker = dockerBuilder.exec().container("cli").script("./scripts/script-sbe.sh").build(); - docker.run(); + CommandSingleton.setup(); } private String filter(List lines){ @@ -155,6 +152,7 @@ public void RunSBE_priv() throws NoSuchAlgorithmException, InvalidKeySpecExcepti text = filter(r.stderr); assertThat(text, containsString("result: status:200 payload:\"[\\\"Org2MSP\\\",\\\"Org1MSP\\\"]\"")); + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val3" }).build().run(true); text = filter(r.stderr); assertThat(text, containsString("result: status:200")); 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 65c1cea3..51f1aeab 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 @@ -81,8 +81,8 @@ services: - ./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 - - ./../../../../../fabric-chaincode-example-sacc:/opt/gopath/src/github.com/hyperledger/fabric/peer/chaincodes/sacc - - ./../../../../../fabric-chaincode-example-sbe:/opt/gopath/src/github.com/hyperledger/fabric/peer/chaincodes/sbe + - ./../../../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/script.sh b/fabric-chaincode-integration-test/src/test/resources/first-network/scripts/script.sh index ce98f3d2..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 @@ -75,12 +75,26 @@ updateAnchorPeers 0 2 CC_SRC_PATH="/opt/gopath/src/github.com/hyperledger/fabric/peer/chaincodes/sacc" CC_NAME="javacc" -echo "Installing chaincode on peer 0, org 1" +echo "Installing chaincode ${CC_NAME} on peer 0, org 1" installChaincode 0 1 -echo "Installing chaincode on peer 0, org 2" +echo "Installing chaincode ${CC_NAME} on peer 0, org 2" installChaincode 0 2 -echo "Instantiating chaincode on peer 0, org 1" +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 4dd4190f..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 @@ -165,16 +165,30 @@ instantiateChaincode() { # 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 "$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 javacc -l ${LANGUAGE} -v ${VERSION} -c '{"Args":["init","a","100"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt - res=$? - set +x + 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 - 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 1.0 -c '{"Args":["init","a","100"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt - res=$? - set +x + 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" diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationStubImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationStubImpl.java index 211caa88..3e79d365 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationStubImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InnvocationStubImpl.java @@ -298,7 +298,7 @@ private QueryResultsIteratorWithMetadataImpl executeGetStateByRangeWit ByteString payload = GetStateByRange.newBuilder().setCollection(collection).setStartKey(startKey) .setEndKey(endKey).setMetadata(metadata).build().toByteString(); - ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_STATE_BY_RANGE, startKey, endKey, + final ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_STATE_BY_RANGE, channelId, txId, payload); ByteString response = this.handler.invoke(requestMessage); From 2b5f33a7778f9d96e3f1789fbfa6229f57ee8458 Mon Sep 17 00:00:00 2001 From: Brett Logan Date: Fri, 20 Dec 2019 10:51:24 +0300 Subject: [PATCH 43/61] [FABCI-482] Update Nexus URL's to Artifactory Signed-off-by: Brett Logan --- ci/azure-pipelines.yml | 33 ------- fabric-chaincode-docker/Dockerfile | 8 +- fabric-chaincode-example-maven/pom.xml | 4 +- .../getDockerImages.sh | 27 +++--- .../integration/SBECCIntegrationTest.java | 4 +- fabric-contract-example/gradle/build.gradle | 2 +- fabric-contract-example/maven/pom.xml | 4 +- scripts/multiarch.sh | 90 ------------------- 8 files changed, 24 insertions(+), 148 deletions(-) delete mode 100755 scripts/multiarch.sh diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index a3010dc0..7ece43f8 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -36,8 +36,6 @@ variables: value: fabric-chaincode-java - name: pipeline value: ci - - name: NEXUS_REPO_URL - value: nexus3.hyperledger.org:10003 - name: PUSH_VERSION value: stable @@ -113,36 +111,6 @@ stages: git push https://$(GITHUB-PAT)@github.com/hyperledger/fabric-chaincode-java.git gh-pages displayName: 'Commit gh-pages changes' - # Publish the snapshot images etc. - # Original source of these is https://github.com/hyperledger/ci-management/blob/master/jjb/fabric-chaincode-java/shell/include-raw-publish-docker-jar.sh - - job: publish - dependsOn: main - condition: and(succeeded(),eq(variables['Build.Reason'], 'IndividualCI')) - variables: - PACKAGE_VERSION: $[ dependencies.main.outputs['builddata.PACKAGE_VERSION'] ] - steps: - - task: DownloadPipelineArtifact@2 - inputs: - artifact: javaenv-docker-image - path: $(Build.SourcesDirectory)/build - - script: | - - docker image load --input build/fabric-javaenv.tar.gz - docker images - # Publish docker images to nexus repository - docker login ${DOCKER_REGISTRY_URL} --username=${DOCKER_REGISTRY_USERNAME} --password=${DOCKER_REGISTRY_PASSWORD} - echo "Logged in to docker registry" - # tag javaenv image to $PUSH_VERSION - docker tag hyperledger/fabric-javaenv ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION}-stable - # push javaenv to nexus repository - docker push ${DOCKER_REGISTRY_URL}/fabric-javaenv:amd64-${MAPPED_VERSION}-stable - env: - DOCKER_REGISTRY_USERNAME: $(nexus-user) - DOCKER_REGISTRY_PASSWORD: $(nexus-password) - DOCKER_REGISTRY_URL: nexus3.hyperledger.org:10003/hyperledger - MAPPED_VERSION: $(PACKAGE_VERSION) - displayName: 'docker push to nexus' - # 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 @@ -170,7 +138,6 @@ stages: docker image load --input build/fabric-javaenv.tar.gz docker images - # Publish docker images to nexus repository docker login ${DOCKER_REGISTRY_URL} --username=${DOCKER_REGISTRY_USERNAME} --password=${DOCKER_REGISTRY_PASSWORD} echo "Logged in to docker registry" # tag javaenv image to $PUSH_VERSION diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index 8c52cfca..ebe34d6a 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -48,10 +48,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 diff --git a/fabric-chaincode-example-maven/pom.xml b/fabric-chaincode-example-maven/pom.xml index 8891726b..5df0a603 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -29,8 +29,8 @@ https://www.jitpack.io - nexus - https://nexus.hyperledger.org/content/repositories/snapshots/ + artifactory + https://hyperledger.jfrog.io/hyperledger/fabric-maven diff --git a/fabric-chaincode-integration-test/getDockerImages.sh b/fabric-chaincode-integration-test/getDockerImages.sh index c5d0e689..92836464 100755 --- a/fabric-chaincode-integration-test/getDockerImages.sh +++ b/fabric-chaincode-integration-test/getDockerImages.sh @@ -4,11 +4,10 @@ set -o pipefail echo "======== PULL DOCKER IMAGES ========" ########################################################## -# Pull and Tag the fabric and fabric-ca images from Nexus +# Pull and Tag the fabric and fabric-ca images from Artifactory ########################################################## -echo "Fetching images from Nexus" -# NEXUS_URL=nexus3.hyperledger.org:10001 -NEXUS_URL=hyperledger-fabric.jfrog.io +echo "Fetching images from Artifactory" +ARTIFACTORY_URL=hyperledger-fabric.jfrog.io ORG_NAME="fabric" VERSION=2.0.0 @@ -20,20 +19,20 @@ MASTER_TAG=$ARCH-master echo "---------> STABLE_VERSION:" $STABLE_VERSION dockerTag() { - for IMAGES in peer orderer ca tools orderer ccenv; do - echo "Images: $IMAGES" + for IMAGE in peer orderer ca tools orderer ccenv; do + echo "Images: $IMAGE" echo - docker pull $NEXUS_URL/$ORG_NAME-$IMAGES:$STABLE_TAG + docker pull $ARTIFACTORY_URL/fabric-$IMAGE:$STABLE_TAG if [ $? != 0 ]; then echo "FAILED: Docker Pull Failed on $IMAGES" exit 1 fi - docker tag $NEXUS_URL/$ORG_NAME-$IMAGES:$STABLE_TAG $ORG_NAME-$IMAGES - docker tag $NEXUS_URL/$ORG_NAME-$IMAGES:$STABLE_TAG $ORG_NAME-$IMAGES:$MASTER_TAG - docker tag $NEXUS_URL/$ORG_NAME-$IMAGES:$STABLE_TAG $ORG_NAME-$IMAGES:$VERSION - echo "$ORG_NAME-$IMAGES:$MASTER_TAG" - echo "Deleting Nexus docker images: $IMAGES" - docker rmi -f $NEXUS_URL/$ORG_NAME-$IMAGES:$STABLE_TAG + 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 } @@ -41,4 +40,4 @@ dockerTag echo docker images | grep "hyperledger*" -echo \ No newline at end of file +echo 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 48a97ade..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 @@ -52,7 +52,7 @@ public void RunSBE_pub_setget() throws NoSuchAlgorithmException, InvalidKeySpecE r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "foo" }).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")); @@ -152,7 +152,7 @@ public void RunSBE_priv() throws NoSuchAlgorithmException, InvalidKeySpecExcepti text = filter(r.stderr); assertThat(text, containsString("result: status:200 payload:\"[\\\"Org2MSP\\\",\\\"Org1MSP\\\"]\"")); - + r = coreBuilder.duplicate().argsTx(new String[] { "setval", mode, "val3" }).build().run(true); text = filter(r.stderr); assertThat(text, containsString("result: status:200")); diff --git a/fabric-contract-example/gradle/build.gradle b/fabric-contract-example/gradle/build.gradle index fc0ccd5c..d609f2a4 100644 --- a/fabric-contract-example/gradle/build.gradle +++ b/fabric-contract-example/gradle/build.gradle @@ -14,7 +14,7 @@ repositories { url "https://www.jitpack.io" } maven { - url "https://nexus.hyperledger.org/content/repositories/snapshots/" + url "https://hyperledger.jfrog.io/hyperledger/fabric-maven" } } diff --git a/fabric-contract-example/maven/pom.xml b/fabric-contract-example/maven/pom.xml index 5585d33e..a7737209 100644 --- a/fabric-contract-example/maven/pom.xml +++ b/fabric-contract-example/maven/pom.xml @@ -30,8 +30,8 @@ https://www.jitpack.io - nexus - https://nexus.hyperledger.org/content/repositories/snapshots/ + artifactory + https://hyperledger.jfrog.io/hyperledger/fabric-maven 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 From 410024813fda6a4e2a02a193a3ccf830b7c7d6ae Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Thu, 16 Jan 2020 16:21:12 +0000 Subject: [PATCH 44/61] Release 1.4.5 Signed-off-by: Matthew B White --- CHANGELOG.md | 8 ++++++++ release_notes/v1.4.5.txt | 33 +++++++++++++++++++++++++++++++++ scripts/changelog.sh | 5 +++-- 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 release_notes/v1.4.5.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index e254d0e1..6d5a7b8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 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 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/scripts/changelog.sh b/scripts/changelog.sh index 1ea8328e..15b31313 100755 --- a/scripts/changelog.sh +++ b/scripts/changelog.sh @@ -6,9 +6,10 @@ # -echo "## $2\n$(date)" >> CHANGELOG.new +echo "## $2" >> 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 $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 echo "" >> CHANGELOG.new cat CHANGELOG.md >> CHANGELOG.new mv -f CHANGELOG.new CHANGELOG.md From 88e2da209e79a82a45cb2570d953c8df589cacab Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Fri, 17 Jan 2020 10:39:23 +0000 Subject: [PATCH 45/61] [FABCJ-270] Prepare release 1.4.6 - version update - template releases notes - add mising ) to JAR release script - align docker image tagging with other branches Signed-off-by: Matthew B White --- build.gradle | 2 +- ci/azure-pipelines.yml | 11 ++++++--- fabric-chaincode-docker/build.gradle | 2 +- fabric-chaincode-example-gradle/build.gradle | 2 +- fabric-chaincode-example-maven/pom.xml | 2 +- fabric-chaincode-example-sacc/build.gradle | 2 +- fabric-chaincode-example-sbe/build.gradle | 2 +- .../build.gradle | 2 +- .../build.gradle | 2 +- .../fabric-chaincode-example-sbe/build.gradle | 2 +- fabric-contract-example/gradle/build.gradle | 2 +- fabric-contract-example/maven/pom.xml | 2 +- release_notes/v1.4.6.txt | 23 +++++++++++++++++++ 13 files changed, 42 insertions(+), 14 deletions(-) create mode 100644 release_notes/v1.4.6.txt diff --git a/build.gradle b/build.gradle index 6af405ea..cd0c88f6 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ apply plugin: 'idea' apply plugin: 'eclipse-wtp' apply plugin: 'com.dorongold.task-tree' -version = '1.4.5' +version = '1.4.6' buildscript { repositories { maven { diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 7ece43f8..c2cc8aaf 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -128,7 +128,8 @@ stages: inputs: secureFile: secring.gpg - script: | - env | sort + 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") @@ -140,10 +141,14 @@ stages: docker images docker login ${DOCKER_REGISTRY_URL} --username=${DOCKER_REGISTRY_USERNAME} --password=${DOCKER_REGISTRY_PASSWORD} echo "Logged in to docker registry" - # tag javaenv image to $PUSH_VERSION + + # 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) @@ -151,7 +156,7 @@ stages: env | sort # temporarily use this approach instead of the gittag - VERSION=$(cat build.gradle | sed -n "s/version =.*'\(.*\)\(-SNAPSHOT\)\?'/\1/p" + VERSION=$(cat build.gradle | sed -n "s/version =.*'\(.*\)\(-SNAPSHOT\)\?'/\1/p") VERSION=${VERSION// } echo Version is :${VERSION}: diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index fa01c534..aff83d52 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -80,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.5', 'hyperledger/fabric-javaenv:amd64-latest'] + tags = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:amd64-1.4.6', 'hyperledger/fabric-javaenv:amd64-latest'] } diff --git a/fabric-chaincode-example-gradle/build.gradle b/fabric-chaincode-example-gradle/build.gradle index 406c0536..b83bfb41 100644 --- a/fabric-chaincode-example-gradle/build.gradle +++ b/fabric-chaincode-example-gradle/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.5' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.6' 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 5df0a603..b25d8773 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.5 + 1.4.6 1.0.13 diff --git a/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-example-sacc/build.gradle index d7737b64..00904ed5 100644 --- a/fabric-chaincode-example-sacc/build.gradle +++ b/fabric-chaincode-example-sacc/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.5' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.6' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-example-sbe/build.gradle b/fabric-chaincode-example-sbe/build.gradle index 41c46e52..4fd93408 100644 --- a/fabric-chaincode-example-sbe/build.gradle +++ b/fabric-chaincode-example-sbe/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.5' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.6' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-integration-test/build.gradle b/fabric-chaincode-integration-test/build.gradle index 57e74479..5090c1d7 100644 --- a/fabric-chaincode-integration-test/build.gradle +++ b/fabric-chaincode-integration-test/build.gradle @@ -1,7 +1,7 @@ dependencies { compile project(':fabric-chaincode-docker') testCompile 'org.testcontainers:testcontainers:1.7.1' - testCompile 'org.hyperledger.fabric-sdk-java:fabric-sdk-java:1.4.5' + testCompile 'org.hyperledger.fabric-sdk-java:fabric-sdk-java:1.4.6' compile project(':fabric-chaincode-shim') implementation group: 'org.json', name: 'json', version: '20180813' } 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 index d7737b64..00904ed5 100644 --- 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 @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.5' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.6' testCompile group: 'junit', name: 'junit', version: '4.12' } 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 index 41c46e52..4fd93408 100644 --- 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 @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.5' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.6' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-contract-example/gradle/build.gradle b/fabric-contract-example/gradle/build.gradle index d609f2a4..dbcff94e 100644 --- a/fabric-contract-example/gradle/build.gradle +++ b/fabric-contract-example/gradle/build.gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.5' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.6' 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' diff --git a/fabric-contract-example/maven/pom.xml b/fabric-contract-example/maven/pom.xml index a7737209..aa81291c 100644 --- a/fabric-contract-example/maven/pom.xml +++ b/fabric-contract-example/maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.5 + 1.4.6 1.0.13 diff --git a/release_notes/v1.4.6.txt b/release_notes/v1.4.6.txt new file mode 100644 index 00000000..f9e2eb5d --- /dev/null +++ b/release_notes/v1.4.6.txt @@ -0,0 +1,23 @@ +v1.4.6 dd MMMM YYYY +---------------------------- + +Release Notes +------------- + +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 From 540b9ca47c6437aa55db968a4e902235500f2161 Mon Sep 17 00:00:00 2001 From: Simon Stone Date: Wed, 11 Sep 2019 10:04:22 +0100 Subject: [PATCH 46/61] [FAB-6415] Add javax.annotation dependency for Java 11 Java 11 has cut down the modules that are bundled in the core, including javax.annotation which is used by the generated protobuf code. Need to add this as an explicit dependency. Signed-off-by: Simon Stone Change-Id: Ied6e6de9c9a8118e16f32eec9deefae6deb395e0 --- fabric-chaincode-protos/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fabric-chaincode-protos/build.gradle b/fabric-chaincode-protos/build.gradle index 7b49c2c8..6183f1c7 100644 --- a/fabric-chaincode-protos/build.gradle +++ b/fabric-chaincode-protos/build.gradle @@ -52,6 +52,8 @@ dependencies { 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 { From f109d193b9bcd7b91971322184565c189123c9ef Mon Sep 17 00:00:00 2001 From: Simon Stone Date: Wed, 11 Sep 2019 13:17:44 +0100 Subject: [PATCH 47/61] [FAB-6415] Add javax.xml.bind dependency for Java 11 Java 11 has cut down the modules that are bundled in the core, including javax.xml.bind which is used by some of the unit tests. Need to add this as an explicit dependency. Signed-off-by: Simon Stone Change-Id: I6120a477b2f32f22a9708c42b91fbceb05f17279 --- fabric-chaincode-shim/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index e6875368..f81989c1 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -39,6 +39,8 @@ dependencies { 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 { From dac90d2fdab28ccf3b59386c59594b7fbad9cb9e Mon Sep 17 00:00:00 2001 From: Simon Stone Date: Wed, 11 Sep 2019 13:25:39 +0100 Subject: [PATCH 48/61] [FAB-6415] Replace org.reflections with classgraph The org.reflections package we use for finding contract classes does not work with Java 9+, because in Java 9+ classloaders are no longer instances of URLClassLoader. The classgraph package is a heavily maintained, MIT licensed package that does work with Java 9+. Signed-off-by: Simon Stone Change-Id: I2e5938e08779607a4322446cbcb2e3263fb3ee21 --- fabric-chaincode-shim/build.gradle | 8 +- .../routing/impl/RoutingRegistryImpl.java | 108 ++++++++++-------- 2 files changed, 68 insertions(+), 48 deletions(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index f81989c1..9eedb477 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -18,7 +18,7 @@ tasks.withType(org.gradle.api.tasks.testing.Test) { 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" @@ -26,7 +26,7 @@ test { // showCauses true // showStandardStreams true // exceptionFormat "full" - + // } } @@ -35,7 +35,7 @@ dependencies { 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 'org.reflections:reflections:0.9.11' + 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' @@ -94,6 +94,7 @@ jacocoTestCoverageVerification { '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', @@ -117,6 +118,7 @@ jacocoTestCoverageVerification { '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', 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 index ccccff32..0598ce9b 100644 --- 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 @@ -6,13 +6,11 @@ package org.hyperledger.fabric.contract.routing.impl; import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLClassLoader; import java.util.ArrayList; -import java.util.Arrays; 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; @@ -27,9 +25,10 @@ import org.hyperledger.fabric.contract.routing.RoutingRegistry; import org.hyperledger.fabric.contract.routing.TxFunction; import org.hyperledger.fabric.contract.routing.TypeRegistry; -import org.reflections.Reflections; -import org.reflections.util.ClasspathHelper; -import org.reflections.util.ConfigurationBuilder; + +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 @@ -143,61 +142,80 @@ public Collection getAllDefinitions() { */ @SuppressWarnings("unchecked") @Override - public void findAndSetContracts(final TypeRegistry typeRegistry) { - final ArrayList urls = new ArrayList<>(); - final ClassLoader[] classloaders = { getClass().getClassLoader(), - Thread.currentThread().getContextClassLoader() }; - for (int i = 0; i < classloaders.length; i++) { - if (classloaders[i] instanceof URLClassLoader) { - urls.addAll(Arrays.asList(((URLClassLoader) classloaders[i]).getURLs())); - } else { - throw new RuntimeException("classLoader is not an instanceof URLClassLoader"); + 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); + } } } - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); - configurationBuilder.addUrls(urls); - configurationBuilder.addUrls(ClasspathHelper.forJavaClassPath()); - configurationBuilder.addUrls(ClasspathHelper.forManifest()); - final Reflections ref = new Reflections(configurationBuilder); - - logger.info("Searching chaincode class in urls: " + configurationBuilder.getUrls()); - // 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 (final Class cl : ref.getTypesAnnotatedWith(Contract.class)) { - logger.info("Found class: " + cl.getCanonicalName()); - if (ContractInterface.class.isAssignableFrom(cl)) { - logger.fine("Inheritance ok"); - final String className = cl.getCanonicalName(); - - if (!seenClass.contains(className)) { - final ContractDefinition contract = addNewContract((Class) cl); + for (Class contractClass : contractClasses) { + String className = contractClass.getCanonicalName(); + if (!seenClass.contains(className)) { + ContractDefinition contract = addNewContract((Class) contractClass); - logger.fine("Searching annotated methods"); - for (final Method m : cl.getMethods()) { - if (m.getAnnotation(Transaction.class) != null) { - logger.fine("Found annotated method " + m.getName()); + 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); + contract.addTxFunction(m); - } } - - seenClass.add(className); } - } else { - logger.fine("Class is not assignabled from Contract"); + + seenClass.add(className); } } // now need to look for the data types have been set with the - logger.info("Looking for the data types"); - final Set> czs = ref.getTypesAnnotatedWith(DataType.class); - logger.info("found " + czs.size()); - czs.forEach(typeRegistry::addDataType); + dataTypeClasses.forEach(typeRegistry::addDataType); } From b54d8bb15b1423add12926566cb7659c98251c5a Mon Sep 17 00:00:00 2001 From: Simon Stone Date: Tue, 3 Mar 2020 16:26:38 +0000 Subject: [PATCH 49/61] [FABCJ-280] Copy chaincode into temporary directory before building Signed-off-by: Simon Stone --- fabric-chaincode-docker/build.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fabric-chaincode-docker/build.sh b/fabric-chaincode-docker/build.sh index 99bae925..2d0b9934 100644 --- a/fabric-chaincode-docker/build.sh +++ b/fabric-chaincode-docker/build.sh @@ -1,7 +1,12 @@ #!/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 -x test retval=$? @@ -17,7 +22,10 @@ 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 -B compile package -DskipTests -Dmaven.test.skip=true retval=$? From 18c65a68e00ff41b9e0c056e409aab1dd3f5ae79 Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Wed, 4 Mar 2020 10:27:45 +0000 Subject: [PATCH 50/61] [FABCJ-281] Release 1.4.6 Port of fixes to support Java11 Signed-off-by: Matthew B White --- CHANGELOG.md | 9 +++++++++ release_notes/v1.4.6.txt | 6 +++++- scripts/changelog.sh | 11 +++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d5a7b8a..4bb3106d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 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 diff --git a/release_notes/v1.4.6.txt b/release_notes/v1.4.6.txt index f9e2eb5d..3771b8e0 100644 --- a/release_notes/v1.4.6.txt +++ b/release_notes/v1.4.6.txt @@ -1,9 +1,13 @@ -v1.4.6 dd MMMM YYYY +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" diff --git a/scripts/changelog.sh b/scripts/changelog.sh index 15b31313..b74634c4 100755 --- a/scripts/changelog.sh +++ b/scripts/changelog.sh @@ -4,12 +4,19 @@ # # SPDX-License-Identifier: Apache-2.0 # +set -ev +PREVIOUS_TAG=$1 +NEW_VERSION=$2 -echo "## $2" >> 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 + From 674f4edcfe473dbd610e0283641c3827a481b791 Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Thu, 5 Mar 2020 13:41:51 +0000 Subject: [PATCH 51/61] [FABCJ-281] Set to the next version 1.4.7 Signed-off-by: Matthew B White --- build.gradle | 2 +- fabric-chaincode-docker/build.gradle | 2 +- fabric-chaincode-example-gradle/build.gradle | 2 +- fabric-chaincode-example-maven/pom.xml | 2 +- fabric-chaincode-example-sacc/build.gradle | 2 +- fabric-chaincode-example-sbe/build.gradle | 2 +- fabric-chaincode-integration-test/build.gradle | 2 +- .../src/contracts/fabric-chaincode-example-sacc/build.gradle | 2 +- .../src/contracts/fabric-chaincode-example-sbe/build.gradle | 2 +- fabric-contract-example/gradle/build.gradle | 2 +- fabric-contract-example/maven/pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index cd0c88f6..11d97887 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ apply plugin: 'idea' apply plugin: 'eclipse-wtp' apply plugin: 'com.dorongold.task-tree' -version = '1.4.6' +version = '1.4.7' buildscript { repositories { maven { diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index aff83d52..6d630bac 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -80,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.6', 'hyperledger/fabric-javaenv:amd64-latest'] + tags = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:amd64-1.4.7', 'hyperledger/fabric-javaenv:amd64-latest'] } diff --git a/fabric-chaincode-example-gradle/build.gradle b/fabric-chaincode-example-gradle/build.gradle index b83bfb41..90c1f830 100644 --- a/fabric-chaincode-example-gradle/build.gradle +++ b/fabric-chaincode-example-gradle/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.6' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.7' 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 b25d8773..87e61539 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.6 + 1.4.7 1.0.13 diff --git a/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-example-sacc/build.gradle index 00904ed5..3ba80437 100644 --- a/fabric-chaincode-example-sacc/build.gradle +++ b/fabric-chaincode-example-sacc/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.6' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.7' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-example-sbe/build.gradle b/fabric-chaincode-example-sbe/build.gradle index 4fd93408..caa6b97b 100644 --- a/fabric-chaincode-example-sbe/build.gradle +++ b/fabric-chaincode-example-sbe/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.6' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.7' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-chaincode-integration-test/build.gradle b/fabric-chaincode-integration-test/build.gradle index 5090c1d7..1249a928 100644 --- a/fabric-chaincode-integration-test/build.gradle +++ b/fabric-chaincode-integration-test/build.gradle @@ -1,7 +1,7 @@ dependencies { compile project(':fabric-chaincode-docker') testCompile 'org.testcontainers:testcontainers:1.7.1' - testCompile 'org.hyperledger.fabric-sdk-java:fabric-sdk-java:1.4.6' + testCompile 'org.hyperledger.fabric-sdk-java:fabric-sdk-java:1.4.7' compile project(':fabric-chaincode-shim') implementation group: 'org.json', name: 'json', version: '20180813' } 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 index 00904ed5..3ba80437 100644 --- 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 @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.6' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.7' testCompile group: 'junit', name: 'junit', version: '4.12' } 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 index 4fd93408..caa6b97b 100644 --- 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 @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.6' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.7' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/fabric-contract-example/gradle/build.gradle b/fabric-contract-example/gradle/build.gradle index dbcff94e..f48e63f3 100644 --- a/fabric-contract-example/gradle/build.gradle +++ b/fabric-contract-example/gradle/build.gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.6' + compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.7' 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' diff --git a/fabric-contract-example/maven/pom.xml b/fabric-contract-example/maven/pom.xml index aa81291c..5c2742d7 100644 --- a/fabric-contract-example/maven/pom.xml +++ b/fabric-contract-example/maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.6 + 1.4.7 1.0.13 From c8f3afe21dbca211ce1a3c404681462ed7284529 Mon Sep 17 00:00:00 2001 From: Brett Logan Date: Wed, 1 Apr 2020 07:44:02 -0400 Subject: [PATCH 52/61] add CODEOWNERS to release-1.4 (#82) Signed-off-by: Brett Logan Co-authored-by: Matthew B White Co-authored-by: heatherlp <40789053+heatherlp@users.noreply.github.com> --- CODEOWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CODEOWNERS 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 From 8dc64bef1eaa551662f2e7dfc26a9ab509be17ca Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Wed, 9 Sep 2020 14:25:47 +0100 Subject: [PATCH 53/61] [FABCJ-292] FabricTools - specify exact image version Latest does not exist Signed-off-by: Matthew B White --- .../test/resources/first-network/base/docker-compose-base.yaml | 2 +- .../src/test/resources/first-network/base/peer-base.yaml | 2 +- .../src/test/resources/first-network/docker-compose-cli.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 54dcde48..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 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 e0df016e..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,7 +7,7 @@ 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 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 51f1aeab..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,7 +59,7 @@ services: cli: container_name: cli - image: hyperledger/fabric-tools:latest + image: hyperledger/fabric-tools:amd64-1.4.8 tty: true stdin_open: true environment: From 988e7f2d9e1ca41c7d1bbda03af9562743e3e86e Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Fri, 11 Sep 2020 09:26:24 +0100 Subject: [PATCH 54/61] [FABCJ-293] Remove gradle from image Signed-off-by: Matthew B White --- COMPATIBILITY.md | 53 +++++ fabric-chaincode-docker/Dockerfile | 22 ++ fabric-chaincode-docker/build.sh | 7 +- .../gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - .../fabric-chaincode-example-sacc/gradlew | 188 ------------------ .../fabric-chaincode-example-sacc/gradlew.bat | 100 ---------- 7 files changed, 81 insertions(+), 294 deletions(-) create mode 100644 COMPATIBILITY.md delete mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradle/wrapper/gradle-wrapper.jar delete mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradle/wrapper/gradle-wrapper.properties delete mode 100755 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradlew delete mode 100644 fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradlew.bat 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/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index ebe34d6a..1f4c696c 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -59,3 +59,25 @@ 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 gradle wrapper + +# Creating final javaenv image which will include all required +# dependencies to build and compile java chaincode +FROM adoptopenjdk/openjdk11:jdk-11.0.4_11-alpine +RUN apk add --no-cache bash + +COPY --from=dependencies /root/chaincode-java/gradle /root/chaincode-java/ +COPY --from=dependencies /root/chaincode-java/gradlew /root/chaincode-java/gradlew +COPY --from=builder /root/.sdkman/candidates/maven/current /usr/bin/maven + +SHELL ["/bin/bash", "-c"] +ENV PATH="/usr/bin/maven/bin:/usr/bin/maven/:/usr/bin/gradle:/usr/bin/gradle/bin:${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.sh b/fabric-chaincode-docker/build.sh index 2d0b9934..589d4de6 100644 --- a/fabric-chaincode-docker/build.sh +++ b/fabric-chaincode-docker/build.sh @@ -8,7 +8,12 @@ buildGradle() { tar cf - . | (cd ${TMP_DIR}; tar xf -) cd ${TMP_DIR} echo "Gradle build" - gradle build shadowJar -x test + 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 diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradle/wrapper/gradle-wrapper.jar b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55616 zcmafaW0WS*vSoFbZJS-TZP!<}ZQEV8ZQHihW!tvx>6!c9%-lQoy;&DmfdT@8fB*sl68LLCKtKQ283+jS?^Q-bNq|NIAW8=eB==8_)^)r*{C^$z z{u;{v?IMYnO`JhmPq7|LA_@Iz75S9h~8`iX>QrjrmMeu{>hn4U;+$dor zz+`T8Q0f}p^Ao)LsYq74!W*)&dTnv}E8;7H*Zetclpo2zf_f>9>HT8;`O^F8;M%l@ z57Z8dk34kG-~Wg7n48qF2xwPp;SOUpd1}9Moir5$VSyf4gF)Mp-?`wO3;2x9gYj59oFwG>?Leva43@e(z{mjm0b*@OAYLC`O9q|s+FQLOE z!+*Y;%_0(6Sr<(cxE0c=lS&-FGBFGWd_R<5$vwHRJG=tB&Mi8@hq_U7@IMyVyKkOo6wgR(<% zQw1O!nnQl3T9QJ)Vh=(`cZM{nsEKChjbJhx@UQH+G>6p z;beBQ1L!3Zl>^&*?cSZjy$B3(1=Zyn~>@`!j%5v7IBRt6X`O)yDpVLS^9EqmHxBcisVG$TRwiip#ViN|4( zYn!Av841_Z@Ys=T7w#>RT&iXvNgDq3*d?$N(SznG^wR`x{%w<6^qj&|g})La;iD?`M=p>99p><39r9+e z`dNhQ&tol5)P#;x8{tT47i*blMHaDKqJs8!Pi*F{#)9%USFxTVMfMOy{mp2ZrLR40 z2a9?TJgFyqgx~|j0eA6SegKVk@|Pd|_6P$HvwTrLTK)Re`~%kg8o9`EAE1oAiY5Jgo=H}0*D?tSCn^=SIN~fvv453Ia(<1|s07aTVVtsRxY6+tT3589iQdi^ zC92D$ewm9O6FA*u*{Fe_=b`%q`pmFvAz@hfF@OC_${IPmD#QMpPNo0mE9U=Ch;k0L zZteokPG-h7PUeRCPPYG%H!WswC?cp7M|w42pbtwj!m_&4%hB6MdLQe&}@5-h~! zkOt;w0BbDc0H!RBw;1UeVckHpJ@^|j%FBZlC} zsm?nFOT$`F_i#1_gh4|n$rDe>0md6HvA=B%hlX*3Z%y@a&W>Rq`Fe(8smIgxTGb#8 zZ`->%h!?QCk>v*~{!qp=w?a*};Y**1uH`)OX`Gi+L%-d6{rV?@}MU#qfCU(!hLz;kWH=0A%W7E^pA zD;A%Jg5SsRe!O*0TyYkAHe&O9z*Ij-YA$%-rR?sc`xz_v{>x%xY39!8g#!Z0#03H( z{O=drKfb0cbx1F*5%q81xvTDy#rfUGw(fesh1!xiS2XT;7_wBi(Rh4i(!rR^9=C+- z+**b9;icxfq@<7}Y!PW-0rTW+A^$o*#ZKenSkxLB$Qi$%gJSL>x!jc86`GmGGhai9 zOHq~hxh}KqQHJeN$2U{M>qd*t8_e&lyCs69{bm1?KGTYoj=c0`rTg>pS6G&J4&)xp zLEGIHSTEjC0-s-@+e6o&w=h1sEWWvJUvezID1&exb$)ahF9`(6`?3KLyVL$|c)CjS zx(bsy87~n8TQNOKle(BM^>1I!2-CZ^{x6zdA}qeDBIdrfd-(n@Vjl^9zO1(%2pP9@ zKBc~ozr$+4ZfjmzEIzoth(k?pbI87=d5OfjVZ`Bn)J|urr8yJq`ol^>_VAl^P)>2r)s+*3z5d<3rP+-fniCkjmk=2hTYRa@t zCQcSxF&w%mHmA?!vaXnj7ZA$)te}ds+n8$2lH{NeD4mwk$>xZCBFhRy$8PE>q$wS`}8pI%45Y;Mg;HH+}Dp=PL)m77nKF68FggQ-l3iXlVZuM2BDrR8AQbK;bn1%jzahl0; zqz0(mNe;f~h8(fPzPKKf2qRsG8`+Ca)>|<&lw>KEqM&Lpnvig>69%YQpK6fx=8YFj zHKrfzy>(7h2OhUVasdwKY`praH?>qU0326-kiSyOU_Qh>ytIs^htlBA62xU6xg?*l z)&REdn*f9U3?u4$j-@ndD#D3l!viAUtw}i5*Vgd0Y6`^hHF5R=No7j8G-*$NWl%?t z`7Nilf_Yre@Oe}QT3z+jOUVgYtT_Ym3PS5(D>kDLLas8~F+5kW%~ZYppSrf1C$gL* zCVy}fWpZ3s%2rPL-E63^tA|8OdqKsZ4TH5fny47ENs1#^C`_NLg~H^uf3&bAj#fGV zDe&#Ot%_Vhj$}yBrC3J1Xqj>Y%&k{B?lhxKrtYy;^E9DkyNHk5#6`4cuP&V7S8ce9 zTUF5PQIRO7TT4P2a*4;M&hk;Q7&{(83hJe5BSm=9qt~;U)NTf=4uKUcnxC`;iPJeI zW#~w?HIOM+0j3ptB0{UU{^6_#B*Q2gs;1x^YFey(%DJHNWz@e_NEL?$fv?CDxG`jk zH|52WFdVsZR;n!Up;K;4E$|w4h>ZIN+@Z}EwFXI{w_`?5x+SJFY_e4J@|f8U08%dd z#Qsa9JLdO$jv)?4F@&z_^{Q($tG`?|9bzt8ZfH9P`epY`soPYqi1`oC3x&|@m{hc6 zs0R!t$g>sR@#SPfNV6Pf`a^E?q3QIaY30IO%yKjx#Njj@gro1YH2Q(0+7D7mM~c>C zk&_?9Ye>B%*MA+77$Pa!?G~5tm`=p{NaZsUsOgm6Yzclr_P^2)r(7r%n(0?4B#$e7 z!fP;+l)$)0kPbMk#WOjm07+e?{E)(v)2|Ijo{o1+Z8#8ET#=kcT*OwM#K68fSNo%< zvZFdHrOrr;>`zq!_welWh!X}=oN5+V01WJn7=;z5uo6l_$7wSNkXuh=8Y>`TjDbO< z!yF}c42&QWYXl}XaRr0uL?BNPXlGw=QpDUMo`v8pXzzG(=!G;t+mfCsg8 zJb9v&a)E!zg8|%9#U?SJqW!|oBHMsOu}U2Uwq8}RnWeUBJ>FtHKAhP~;&T4mn(9pB zu9jPnnnH0`8ywm-4OWV91y1GY$!qiQCOB04DzfDDFlNy}S{$Vg9o^AY!XHMueN<{y zYPo$cJZ6f7``tmlR5h8WUGm;G*i}ff!h`}L#ypFyV7iuca!J+C-4m@7*Pmj9>m+jh zlpWbud)8j9zvQ`8-oQF#u=4!uK4kMFh>qS_pZciyq3NC(dQ{577lr-!+HD*QO_zB9 z_Rv<#qB{AAEF8Gbr7xQly%nMA%oR`a-i7nJw95F3iH&IX5hhy3CCV5y>mK4)&5aC*12 zI`{(g%MHq<(ocY5+@OK-Qn-$%!Nl%AGCgHl>e8ogTgepIKOf3)WoaOkuRJQt%MN8W z=N-kW+FLw=1^}yN@*-_c>;0N{-B!aXy#O}`%_~Nk?{e|O=JmU8@+92Q-Y6h)>@omP=9i~ zi`krLQK^!=@2BH?-R83DyFkejZkhHJqV%^} zUa&K22zwz7b*@CQV6BQ9X*RB177VCVa{Z!Lf?*c~PwS~V3K{id1TB^WZh=aMqiws5)qWylK#^SG9!tqg3-)p_o(ABJsC!0;0v36;0tC= z!zMQ_@se(*`KkTxJ~$nIx$7ez&_2EI+{4=uI~dwKD$deb5?mwLJ~ema_0Z z6A8Q$1~=tY&l5_EBZ?nAvn$3hIExWo_ZH2R)tYPjxTH5mAw#3n-*sOMVjpUrdnj1DBm4G!J+Ke}a|oQN9f?!p-TcYej+(6FNh_A? zJ3C%AOjc<8%9SPJ)U(md`W5_pzYpLEMwK<_jgeg-VXSX1Nk1oX-{yHz z-;CW!^2ds%PH{L{#12WonyeK5A=`O@s0Uc%s!@22etgSZW!K<%0(FHC+5(BxsXW@e zAvMWiO~XSkmcz%-@s{|F76uFaBJ8L5H>nq6QM-8FsX08ug_=E)r#DC>d_!6Nr+rXe zzUt30Du_d0oSfX~u>qOVR*BmrPBwL@WhF^5+dHjWRB;kB$`m8|46efLBXLkiF|*W= zg|Hd(W}ZnlJLotYZCYKoL7YsQdLXZ!F`rLqLf8n$OZOyAzK`uKcbC-n0qoH!5-rh&k-`VADETKHxrhK<5C zhF0BB4azs%j~_q_HA#fYPO0r;YTlaa-eb)Le+!IeP>4S{b8&STp|Y0if*`-A&DQ$^ z-%=i73HvEMf_V6zSEF?G>G-Eqn+|k`0=q?(^|ZcqWsuLlMF2!E*8dDAx%)}y=lyMa z$Nn0_f8YN8g<4D>8IL3)GPf#dJYU@|NZqIX$;Lco?Qj=?W6J;D@pa`T=Yh z-ybpFyFr*3^gRt!9NnbSJWs2R-S?Y4+s~J8vfrPd_&_*)HBQ{&rW(2X>P-_CZU8Y9 z-32><7|wL*K+3{ZXE5}nn~t@NNT#Bc0F6kKI4pVwLrpU@C#T-&f{Vm}0h1N3#89@d zgcx3QyS;Pb?V*XAq;3(W&rjLBazm69XX;%^n6r}0!CR2zTU1!x#TypCr`yrII%wk8 z+g)fyQ!&xIX(*>?T}HYL^>wGC2E}euj{DD_RYKK@w=yF+44367X17)GP8DCmBK!xS zE{WRfQ(WB-v>DAr!{F2-cQKHIjIUnLk^D}7XcTI#HyjSiEX)BO^GBI9NjxojYfQza zWsX@GkLc7EqtP8(UM^cq5zP~{?j~*2T^Bb={@PV)DTkrP<9&hxDwN2@hEq~8(ZiF! z3FuQH_iHyQ_s-#EmAC5~K$j_$cw{+!T>dm#8`t%CYA+->rWp09jvXY`AJQ-l%C{SJ z1c~@<5*7$`1%b}n7ivSo(1(j8k+*Gek(m^rQ!+LPvb=xA@co<|(XDK+(tb46xJ4) zcw7w<0p3=Idb_FjQ@ttoyDmF?cT4JRGrX5xl&|ViA@Lg!vRR}p#$A?0=Qe+1)Mizl zn;!zhm`B&9t0GA67GF09t_ceE(bGdJ0mbXYrUoV2iuc3c69e;!%)xNOGG*?x*@5k( zh)snvm0s&gRq^{yyeE)>hk~w8)nTN`8HJRtY0~1f`f9ue%RV4~V(K*B;jFfJY4dBb z*BGFK`9M-tpWzayiD>p_`U(29f$R|V-qEB;+_4T939BPb=XRw~8n2cGiRi`o$2qm~ zN&5N7JU{L*QGM@lO8VI)fUA0D7bPrhV(GjJ$+@=dcE5vAVyCy6r&R#4D=GyoEVOnu z8``8q`PN-pEy>xiA_@+EN?EJpY<#}BhrsUJC0afQFx7-pBeLXR9Mr+#w@!wSNR7vxHy@r`!9MFecB4O zh9jye3iSzL0@t3)OZ=OxFjjyK#KSF|zz@K}-+HaY6gW+O{T6%Zky@gD$6SW)Jq;V0 zt&LAG*YFO^+=ULohZZW*=3>7YgND-!$2}2)Mt~c>JO3j6QiPC-*ayH2xBF)2m7+}# z`@m#q{J9r~Dr^eBgrF(l^#sOjlVNFgDs5NR*Xp;V*wr~HqBx7?qBUZ8w)%vIbhhe) zt4(#1S~c$Cq7b_A%wpuah1Qn(X9#obljoY)VUoK%OiQZ#Fa|@ZvGD0_oxR=vz{>U* znC(W7HaUDTc5F!T77GswL-jj7e0#83DH2+lS-T@_^SaWfROz9btt*5zDGck${}*njAwf}3hLqKGLTeV&5(8FC+IP>s;p{L@a~RyCu)MIa zs~vA?_JQ1^2Xc&^cjDq02tT_Z0gkElR0Aa$v@VHi+5*)1(@&}gEXxP5Xon?lxE@is z9sxd|h#w2&P5uHJxWgmtVZJv5w>cl2ALzri;r57qg){6`urTu(2}EI?D?##g=!Sbh z*L*>c9xN1a3CH$u7C~u_!g81`W|xp=54oZl9CM)&V9~ATCC-Q!yfKD@vp#2EKh0(S zgt~aJ^oq-TM0IBol!w1S2j7tJ8H7;SR7yn4-H}iz&U^*zW95HrHiT!H&E|rSlnCYr z7Y1|V7xebn=TFbkH;>WIH6H>8;0?HS#b6lCke9rSsH%3AM1#2U-^*NVhXEIDSFtE^ z=jOo1>j!c__Bub(R*dHyGa)@3h?!ls1&M)d2{?W5#1|M@6|ENYYa`X=2EA_oJUw=I zjQ)K6;C!@>^i7vdf`pBOjH>Ts$97}B=lkb07<&;&?f#cy3I0p5{1=?O*#8m$C_5TE zh}&8lOWWF7I@|pRC$G2;Sm#IJfhKW@^jk=jfM1MdJP(v2fIrYTc{;e5;5gsp`}X8-!{9{S1{h+)<@?+D13s^B zq9(1Pu(Dfl#&z|~qJGuGSWDT&u{sq|huEsbJhiqMUae}K*g+R(vG7P$p6g}w*eYWn zQ7luPl1@{vX?PMK%-IBt+N7TMn~GB z!Ldy^(2Mp{fw_0;<$dgHAv1gZgyJAx%}dA?jR=NPW1K`FkoY zNDgag#YWI6-a2#&_E9NMIE~gQ+*)i<>0c)dSRUMHpg!+AL;a;^u|M1jp#0b<+#14z z+#LuQ1jCyV_GNj#lHWG3e9P@H34~n0VgP#(SBX=v|RSuOiY>L87 z#KA{JDDj2EOBX^{`a;xQxHtY1?q5^B5?up1akjEPhi1-KUsK|J9XEBAbt%^F`t0I- zjRYYKI4OB7Zq3FqJFBZwbI=RuT~J|4tA8x)(v2yB^^+TYYJS>Et`_&yge##PuQ%0I z^|X!Vtof}`UuIxPjoH8kofw4u1pT5h`Ip}d8;l>WcG^qTe>@x63s#zoJiGmDM@_h= zo;8IZR`@AJRLnBNtatipUvL^(1P_a;q8P%&voqy#R!0(bNBTlV&*W9QU?kRV1B*~I zWvI?SNo2cB<7bgVY{F_CF$7z!02Qxfw-Ew#p!8PC#! z1sRfOl`d-Y@&=)l(Sl4CS=>fVvor5lYm61C!!iF3NMocKQHUYr0%QM}a4v2>rzPfM zUO}YRDb7-NEqW+p_;e0{Zi%0C$&B3CKx6|4BW`@`AwsxE?Vu}@Jm<3%T5O&05z+Yq zkK!QF(vlN}Rm}m_J+*W4`8i~R&`P0&5!;^@S#>7qkfb9wxFv@(wN@$k%2*sEwen$a zQnWymf+#Uyv)0lQVd?L1gpS}jMQZ(NHHCKRyu zjK|Zai0|N_)5iv)67(zDBCK4Ktm#ygP|0(m5tU`*AzR&{TSeSY8W=v5^=Ic`ahxM-LBWO+uoL~wxZmgcSJMUF9q%<%>jsvh9Dnp^_e>J_V=ySx4p?SF0Y zg4ZpZt@!h>WR76~P3_YchYOak7oOzR|`t+h!BbN}?zd zq+vMTt0!duALNWDwWVIA$O=%{lWJEj;5(QD()huhFL5=6x_=1h|5ESMW&S|*oxgF# z-0GRIb ziolwI13hJ-Rl(4Rj@*^=&Zz3vD$RX8bFWvBM{niz(%?z0gWNh_vUvpBDoa>-N=P4c zbw-XEJ@txIbc<`wC883;&yE4ayVh>+N($SJ01m}fumz!#!aOg*;y4Hl{V{b;&ux3& zBEmSq2jQ7#IbVm3TPBw?2vVN z0wzj|Y6EBS(V%Pb+@OPkMvEKHW~%DZk#u|A18pZMmCrjWh%7J4Ph>vG61 zRBgJ6w^8dNRg2*=K$Wvh$t>$Q^SMaIX*UpBG)0bqcvY%*by=$EfZAy{ZOA#^tB(D( zh}T(SZgdTj?bG9u+G{Avs5Yr1x=f3k7%K|eJp^>BHK#~dsG<&+=`mM@>kQ-cAJ2k) zT+Ht5liXdc^(aMi9su~{pJUhe)!^U&qn%mV6PS%lye+Iw5F@Xv8E zdR4#?iz+R4--iiHDQmQWfNre=iofAbF~1oGTa1Ce?hId~W^kPuN(5vhNx++ZLkn?l zUA7L~{0x|qA%%%P=8+-Ck{&2$UHn#OQncFS@uUVuE39c9o~#hl)v#!$X(X*4ban2c z{buYr9!`H2;6n73n^W3Vg(!gdBV7$e#v3qubWALaUEAf@`ava{UTx%2~VVQbEE(*Q8_ zv#me9i+0=QnY)$IT+@3vP1l9Wrne+MlZNGO6|zUVG+v&lm7Xw3P*+gS6e#6mVx~(w zyuaXogGTw4!!&P3oZ1|4oc_sGEa&m3Jsqy^lzUdJ^y8RlvUjDmbC^NZ0AmO-c*&m( zSI%4P9f|s!B#073b>Eet`T@J;3qY!NrABuUaED6M^=s-Q^2oZS`jVzuA z>g&g$!Tc>`u-Q9PmKu0SLu-X(tZeZ<%7F+$j3qOOftaoXO5=4!+P!%Cx0rNU+@E~{ zxCclYb~G(Ci%o{}4PC(Bu>TyX9slm5A^2Yi$$kCq-M#Jl)a2W9L-bq5%@Pw^ zh*iuuAz`x6N_rJ1LZ7J^MU9~}RYh+EVIVP+-62u+7IC%1p@;xmmQ`dGCx$QpnIUtK z0`++;Ddz7{_R^~KDh%_yo8WM$IQhcNOALCIGC$3_PtUs?Y44@Osw;OZ()Lk=(H&Vc zXjkHt+^1@M|J%Q&?4>;%T-i%#h|Tb1u;pO5rKst8(Cv2!3U{TRXdm&>fWTJG)n*q&wQPjRzg%pS1RO9}U0*C6fhUi&f#qoV`1{U<&mWKS<$oVFW>{&*$6)r6Rx)F4W zdUL8Mm_qNk6ycFVkI5F?V+cYFUch$92|8O^-Z1JC94GU+Nuk zA#n3Z1q4<6zRiv%W5`NGk*Ym{#0E~IA6*)H-=RmfWIY%mEC0? zSih7uchi`9-WkF2@z1ev6J_N~u;d$QfSNLMgPVpHZoh9oH-8D*;EhoCr~*kJ<|-VD z_jklPveOxWZq40E!SV@0XXy+~Vfn!7nZ1GXsn~U$>#u0d*f?RL9!NMlz^qxYmz|xt zz6A&MUAV#eD%^GcP#@5}QH5e7AV`}(N2#(3xpc!7dDmgu7C3TpgX5Z|$%Vu8=&SQI zdxUk*XS-#C^-cM*O>k}WD5K81e2ayyRA)R&5>KT1QL!T!%@}fw{>BsF+-pzu>;7{g z^CCSWfH;YtJGT@+An0Ded#zM9>UEFOdR_Xq zS~!5R*{p1Whq62ynHo|n$4p7&d|bal{iGsxAY?opi3R${)Zt*8YyOU!$TWMYXF?|i zPXYr}wJp#EH;keSG5WYJ*(~oiu#GDR>C4%-HpIWr7v`W`lzQN-lb?*vpoit z8FqJ)`LC4w8fO8Fu}AYV`awF2NLMS4$f+?=KisU4P6@#+_t)5WDz@f*qE|NG0*hwO z&gv^k^kC6Fg;5>Gr`Q46C{6>3F(p0QukG6NM07rxa&?)_C*eyU(jtli>9Zh#eUb(y zt9NbC-bp0>^m?i`?$aJUyBmF`N0zQ% zvF_;vLVI{tq%Ji%u*8s2p4iBirv*uD(?t~PEz$CfxVa=@R z^HQu6-+I9w>a35kX!P)TfnJDD!)j8!%38(vWNe9vK0{k*`FS$ABZ`rdwfQe@IGDki zssfXnsa6teKXCZUTd^qhhhUZ}>GG_>F0~LG7*<*x;8e39nb-0Bka(l)%+QZ_IVy3q zcmm2uKO0p)9|HGxk*e_$mX2?->&-MXe`=Fz3FRTFfM!$_y}G?{F9jmNgD+L%R`jM1 zIP-kb=3Hlsb35Q&qo(%Ja(LwQj>~!GI|Hgq65J9^A!ibChYB3kxLn@&=#pr}BwON0Q=e5;#sF8GGGuzx6O}z%u3l?jlKF&8Y#lUA)Cs6ZiW8DgOk|q z=YBPAMsO7AoAhWgnSKae2I7%7*Xk>#AyLX-InyBO?OD_^2^nI4#;G|tBvg3C0ldO0 z*`$g(q^es4VqXH2t~0-u^m5cfK8eECh3Rb2h1kW%%^8A!+ya3OHLw$8kHorx4(vJO zAlVu$nC>D{7i?7xDg3116Y2e+)Zb4FPAdZaX}qA!WW{$d?u+sK(iIKqOE-YM zH7y^hkny24==(1;qEacfFU{W{xSXhffC&DJV&oqw`u~WAl@=HIel>KC-mLs2ggFld zsSm-03=Jd^XNDA4i$vKqJ|e|TBc19bglw{)QL${Q(xlN?E;lPumO~;4w_McND6d+R zsc2p*&uRWd`wTDszTcWKiii1mNBrF7n&LQp$2Z<}zkv=8k2s6-^+#siy_K1`5R+n( z++5VOU^LDo(kt3ok?@$3drI`<%+SWcF*`CUWqAJxl3PAq!X|q{al;8%HfgxxM#2Vb zeBS756iU|BzB>bN2NP=AX&!{uZXS;|F`LLd9F^97UTMnNks_t7EPnjZF`2ocD2*u+ z?oKP{xXrD*AKGYGkZtlnvCuazg6g16ZAF{Nu%w+LCZ+v_*`0R$NK)tOh_c#cze;o$ z)kY(eZ5Viv<5zl1XfL(#GO|2FlXL#w3T?hpj3BZ&OAl^L!7@ zy;+iJWYQYP?$(`li_!|bfn!h~k#=v-#XXyjTLd+_txOqZZETqSEp>m+O0ji7MxZ*W zSdq+yqEmafrsLErZG8&;kH2kbCwluSa<@1yU3^Q#5HmW(hYVR0E6!4ZvH;Cr<$`qf zSvqRc`Pq_9b+xrtN3qLmds9;d7HdtlR!2NV$rZPCh6>(7f7M}>C^LeM_5^b$B~mn| z#)?`E=zeo9(9?{O_ko>51~h|c?8{F=2=_-o(-eRc z9p)o51krhCmff^U2oUi#$AG2p-*wSq8DZ(i!Jmu1wzD*)#%J&r)yZTq`3e|v4>EI- z=c|^$Qhv}lEyG@!{G~@}Wbx~vxTxwKoe9zn%5_Z^H$F1?JG_Kadc(G8#|@yaf2-4< zM1bdQF$b5R!W1f`j(S>Id;CHMzfpyjYEC_95VQ*$U3y5piVy=9Rdwg7g&)%#6;U%b2W}_VVdh}qPnM4FY9zFP(5eR zWuCEFox6e;COjs$1RV}IbpE0EV;}5IP}Oq|zcb*77PEDIZU{;@_;8*22{~JRvG~1t zc+ln^I+)Q*+Ha>(@=ra&L&a-kD;l$WEN;YL0q^GE8+})U_A_StHjX_gO{)N>tx4&F zRK?99!6JqktfeS-IsD@74yuq*aFJoV{5&K(W`6Oa2Qy0O5JG>O`zZ-p7vBGh!MxS;}}h6(96Wp`dci3DY?|B@1p8fVsDf$|0S zfE{WL5g3<9&{~yygYyR?jK!>;eZ2L#tpL2)H#89*b zycE?VViXbH7M}m33{#tI69PUPD=r)EVPTBku={Qh{ zKi*pht1jJ+yRhVE)1=Y()iS9j`FesMo$bjLSqPMF-i<42Hxl6%y7{#vw5YT(C}x0? z$rJU7fFmoiR&%b|Y*pG?7O&+Jb#Z%S8&%o~fc?S9c`Dwdnc4BJC7njo7?3bp#Yonz zPC>y`DVK~nzN^n}jB5RhE4N>LzhCZD#WQseohYXvqp5^%Ns!q^B z&8zQN(jgPS(2ty~g2t9!x9;Dao~lYVujG-QEq{vZp<1Nlp;oj#kFVsBnJssU^p-4% zKF_A?5sRmA>d*~^og-I95z$>T*K*33TGBPzs{OMoV2i+(P6K|95UwSj$Zn<@Rt(g%|iY z$SkSjYVJ)I<@S(kMQ6md{HxAa8S`^lXGV?ktLX!ngTVI~%WW+p#A#XTWaFWeBAl%U z&rVhve#Yse*h4BC4nrq7A1n>Rlf^ErbOceJC`o#fyCu@H;y)`E#a#)w)3eg^{Hw&E7);N5*6V+z%olvLj zp^aJ4`h*4L4ij)K+uYvdpil(Z{EO@u{BcMI&}5{ephilI%zCkBhBMCvOQT#zp|!18 zuNl=idd81|{FpGkt%ty=$fnZnWXxem!t4x{ zat@68CPmac(xYaOIeF}@O1j8O?2jbR!KkMSuix;L8x?m01}|bS2=&gsjg^t2O|+0{ zlzfu5r5_l4)py8uPb5~NHPG>!lYVynw;;T-gk1Pl6PQ39Mwgd2O+iHDB397H)2grN zHwbd>8i%GY>Pfy7;y5X7AN>qGLZVH>N_ZuJZ-`z9UA> zfyb$nbmPqxyF2F;UW}7`Cu>SS%0W6h^Wq5e{PWAjxlh=#Fq+6SiPa-L*551SZKX&w zc9TkPv4eao?kqomkZ#X%tA{`UIvf|_=Y7p~mHZKqO>i_;q4PrwVtUDTk?M7NCssa?Y4uxYrsXj!+k@`Cxl;&{NLs*6!R<6k9$Bq z%grLhxJ#G_j~ytJpiND8neLfvD0+xu>wa$-%5v;4;RYYM66PUab)c9ruUm%d{^s{# zTBBY??@^foRv9H}iEf{w_J%rV<%T1wv^`)Jm#snLTIifjgRkX``x2wV(D6(=VTLL4 zI-o}&5WuwBl~(XSLIn5~{cGWorl#z+=(vXuBXC#lp}SdW=_)~8Z(Vv!#3h2@pdA3d z{cIPYK@Ojc9(ph=H3T7;aY>(S3~iuIn05Puh^32WObj%hVN(Y{Ty?n?Cm#!kGNZFa zW6Ybz!tq|@erhtMo4xAus|H8V_c+XfE5mu|lYe|{$V3mKnb1~fqoFim;&_ZHN_=?t zysQwC4qO}rTi}k8_f=R&i27RdBB)@bTeV9Wcd}Rysvod}7I%ujwYbTI*cN7Kbp_hO z=eU521!#cx$0O@k9b$;pnCTRtLIzv){nVW6Ux1<0@te6`S5%Ew3{Z^9=lbL5$NFvd4eUtK?%zgmB;_I&p`)YtpN`2Im(?jPN<(7Ua_ZWJRF(CChv`(gHfWodK%+joy>8Vaa;H1w zIJ?!kA|x7V;4U1BNr(UrhfvjPii7YENLIm`LtnL9Sx z5E9TYaILoB2nSwDe|BVmrpLT43*dJ8;T@1l zJE)4LEzIE{IN}+Nvpo3=ZtV!U#D;rB@9OXYw^4QH+(52&pQEcZq&~u9bTg63ikW9! z=!_RjN2xO=F+bk>fSPhsjQA;)%M1My#34T`I7tUf>Q_L>DRa=>Eo(sapm>}}LUsN% zVw!C~a)xcca`G#g*Xqo>_uCJTz>LoWGSKOwp-tv`yvfqw{17t`9Z}U4o+q2JGP^&9 z(m}|d13XhYSnEm$_8vH-Lq$A^>oWUz1)bnv|AVn_0FwM$vYu&8+qUg$+qP}nwrykD zwmIF?wr$()X@33oz1@B9zi+?Th^nZnsES)rb@O*K^JL~ZH|pRRk$i0+ohh?Il)y&~ zQaq{}9YxPt5~_2|+r#{k#~SUhO6yFq)uBGtYMMg4h1qddg!`TGHocYROyNFJtYjNe z3oezNpq6%TP5V1g(?^5DMeKV|i6vdBq)aGJ)BRv;K(EL0_q7$h@s?BV$)w31*c(jd z{@hDGl3QdXxS=#?0y3KmPd4JL(q(>0ikTk6nt98ptq$6_M|qrPi)N>HY>wKFbnCKY z%0`~`9p)MDESQJ#A`_>@iL7qOCmCJ(p^>f+zqaMuDRk!z01Nd2A_W^D%~M73jTqC* zKu8u$$r({vP~TE8rPk?8RSjlRvG*BLF}ye~Su%s~rivmjg2F z24dhh6-1EQF(c>Z1E8DWY)Jw#9U#wR<@6J)3hjA&2qN$X%piJ4s={|>d-|Gzl~RNu z##iR(m;9TN3|zh+>HgTI&82iR>$YVoOq$a(2%l*2mNP(AsV=lR^>=tIP-R9Tw!BYnZROx`PN*JiNH>8bG}&@h0_v$yOTk#@1;Mh;-={ZU7e@JE(~@@y0AuETvsqQV@7hbKe2wiWk@QvV=Kz`%@$rN z_0Hadkl?7oEdp5eaaMqBm;#Xj^`fxNO^GQ9S3|Fb#%{lN;1b`~yxLGEcy8~!cz{!! z=7tS!I)Qq%w(t9sTSMWNhoV#f=l5+a{a=}--?S!rA0w}QF!_Eq>V4NbmYKV&^OndM z4WiLbqeC5+P@g_!_rs01AY6HwF7)$~%Ok^(NPD9I@fn5I?f$(rcOQjP+z?_|V0DiN zb}l0fy*el9E3Q7fVRKw$EIlb&T0fG~fDJZL7Qn8*a5{)vUblM)*)NTLf1ll$ zpQ^(0pkSTol`|t~`Y4wzl;%NRn>689mpQrW=SJ*rB;7}w zVHB?&sVa2%-q@ANA~v)FXb`?Nz8M1rHKiZB4xC9<{Q3T!XaS#fEk=sXI4IFMnlRqG+yaFw< zF{}7tcMjV04!-_FFD8(FtuOZx+|CjF@-xl6-{qSFF!r7L3yD()=*Ss6fT?lDhy(h$ zt#%F575$U(3-e2LsJd>ksuUZZ%=c}2dWvu8f!V%>z3gajZ!Dlk zm=0|(wKY`c?r$|pX6XVo6padb9{EH}px)jIsdHoqG^(XH(7}r^bRa8BC(%M+wtcB? z6G2%tui|Tx6C3*#RFgNZi9emm*v~txI}~xV4C`Ns)qEoczZ>j*r zqQCa5k90Gntl?EX!{iWh=1t$~jVoXjs&*jKu0Ay`^k)hC^v_y0xU~brMZ6PPcmt5$ z@_h`f#qnI$6BD(`#IR0PrITIV^~O{uo=)+Bi$oHA$G* zH0a^PRoeYD3jU_k%!rTFh)v#@cq`P3_y=6D(M~GBud;4 zCk$LuxPgJ5=8OEDlnU!R^4QDM4jGni}~C zy;t2E%Qy;A^bz_5HSb5pq{x{g59U!ReE?6ULOw58DJcJy;H?g*ofr(X7+8wF;*3{rx>j&27Syl6A~{|w{pHb zeFgu0E>OC81~6a9(2F13r7NZDGdQxR8T68&t`-BK zE>ZV0*0Ba9HkF_(AwfAds-r=|dA&p`G&B_zn5f9Zfrz9n#Rvso`x%u~SwE4SzYj!G zVQ0@jrLwbYP=awX$21Aq!I%M{x?|C`narFWhp4n;=>Sj!0_J!k7|A0;N4!+z%Oqlk z1>l=MHhw3bi1vT}1!}zR=6JOIYSm==qEN#7_fVsht?7SFCj=*2+Ro}B4}HR=D%%)F z?eHy=I#Qx(vvx)@Fc3?MT_@D))w@oOCRR5zRw7614#?(-nC?RH`r(bb{Zzn+VV0bm zJ93!(bfrDH;^p=IZkCH73f*GR8nDKoBo|!}($3^s*hV$c45Zu>6QCV(JhBW=3(Tpf z=4PT6@|s1Uz+U=zJXil3K(N6;ePhAJhCIo`%XDJYW@x#7Za);~`ANTvi$N4(Fy!K- z?CQ3KeEK64F0@ykv$-0oWCWhYI-5ZC1pDqui@B|+LVJmU`WJ=&C|{I_))TlREOc4* zSd%N=pJ_5$G5d^3XK+yj2UZasg2) zXMLtMp<5XWWfh-o@ywb*nCnGdK{&S{YI54Wh2|h}yZ})+NCM;~i9H@1GMCgYf`d5n zwOR(*EEkE4-V#R2+Rc>@cAEho+GAS2L!tzisLl${42Y=A7v}h;#@71_Gh2MV=hPr0_a% z0!={Fcv5^GwuEU^5rD|sP;+y<%5o9;#m>ssbtVR2g<420(I-@fSqfBVMv z?`>61-^q;M(b3r2z{=QxSjyH=-%99fpvb}8z}d;%_8$$J$qJg1Sp3KzlO_!nCn|g8 zzg8skdHNsfgkf8A7PWs;YBz_S$S%!hWQ@G>guCgS--P!!Ui9#%GQ#Jh?s!U-4)7ozR?i>JXHU$| zg0^vuti{!=N|kWorZNFX`dJgdphgic#(8sOBHQdBkY}Qzp3V%T{DFb{nGPgS;QwnH9B9;-Xhy{? z(QVwtzkn9I)vHEmjY!T3ifk1l5B?%%TgP#;CqG-?16lTz;S_mHOzu#MY0w}XuF{lk z*dt`2?&plYn(B>FFXo+fd&CS3q^hquSLVEn6TMAZ6e*WC{Q2e&U7l|)*W;^4l~|Q= zt+yFlLVqPz!I40}NHv zE2t1meCuGH%<`5iJ(~8ji#VD{?uhP%F(TnG#uRZW-V}1=N%ev&+Gd4v!0(f`2Ar-Y z)GO6eYj7S{T_vxV?5^%l6TF{ygS_9e2DXT>9caP~xq*~oE<5KkngGtsv)sdCC zaQH#kSL%c*gLj6tV)zE6SGq|0iX*DPV|I`byc9kn_tNQkPU%y<`rj zMC}lD<93=Oj+D6Y2GNMZb|m$^)RVdi`&0*}mxNy0BW#0iq!GGN2BGx5I0LS>I|4op z(6^xWULBr=QRpbxIJDK~?h;K#>LwQI4N<8V?%3>9I5l+e*yG zFOZTIM0c3(q?y9f7qDHKX|%zsUF%2zN9jDa7%AK*qrI5@z~IruFP+IJy7!s~TE%V3 z_PSSxXlr!FU|Za>G_JL>DD3KVZ7u&}6VWbwWmSg?5;MabycEB)JT(eK8wg`^wvw!Q zH5h24_E$2cuib&9>Ue&@%Cly}6YZN-oO_ei5#33VvqV%L*~ZehqMe;)m;$9)$HBsM zfJ96Hk8GJyWwQ0$iiGjwhxGgQX$sN8ij%XJzW`pxqgwW=79hgMOMnC|0Q@ed%Y~=_ z?OnjUB|5rS+R$Q-p)vvM(eFS+Qr{_w$?#Y;0Iknw3u(+wA=2?gPyl~NyYa3me{-Su zhH#8;01jEm%r#5g5oy-f&F>VA5TE_9=a0aO4!|gJpu470WIrfGo~v}HkF91m6qEG2 zK4j=7C?wWUMG$kYbIp^+@)<#ArZ$3k^EQxraLk0qav9TynuE7T79%MsBxl3|nRn?L zD&8kt6*RJB6*a7=5c57wp!pg)p6O?WHQarI{o9@3a32zQ3FH8cK@P!DZ?CPN_LtmC6U4F zlv8T2?sau&+(i@EL6+tvP^&=|aq3@QgL4 zOu6S3wSWeYtgCnKqg*H4ifIQlR4hd^n{F+3>h3;u_q~qw-Sh;4dYtp^VYymX12$`? z;V2_NiRt82RC=yC+aG?=t&a81!gso$hQUb)LM2D4Z{)S zI1S9f020mSm(Dn$&Rlj0UX}H@ zv={G+fFC>Sad0~8yB%62V(NB4Z|b%6%Co8j!>D(VyAvjFBP%gB+`b*&KnJ zU8s}&F+?iFKE(AT913mq;57|)q?ZrA&8YD3Hw*$yhkm;p5G6PNiO3VdFlnH-&U#JH zEX+y>hB(4$R<6k|pt0?$?8l@zeWk&1Y5tlbgs3540F>A@@rfvY;KdnVncEh@N6Mfi zY)8tFRY~Z?Qw!{@{sE~vQy)0&fKsJpj?yR`Yj+H5SDO1PBId3~d!yjh>FcI#Ug|^M z7-%>aeyQhL8Zmj1!O0D7A2pZE-$>+-6m<#`QX8(n)Fg>}l404xFmPR~at%$(h$hYD zoTzbxo`O{S{E}s8Mv6WviXMP}(YPZoL11xfd>bggPx;#&pFd;*#Yx%TtN1cp)MuHf z+Z*5CG_AFPwk624V9@&aL0;=@Ql=2h6aJoqWx|hPQQzdF{e7|fe(m){0==hk_!$ou zI|p_?kzdO9&d^GBS1u+$>JE-6Ov*o{mu@MF-?$r9V>i%;>>Fo~U`ac2hD*X}-gx*v z1&;@ey`rA0qNcD9-5;3_K&jg|qvn@m^+t?8(GTF0l#|({Zwp^5Ywik@bW9mN+5`MU zJ#_Ju|jtsq{tv)xA zY$5SnHgHj}c%qlQG72VS_(OSv;H~1GLUAegygT3T-J{<#h}))pk$FjfRQ+Kr%`2ZiI)@$96Nivh82#K@t>ze^H?R8wHii6Pxy z0o#T(lh=V>ZD6EXf0U}sG~nQ1dFI`bx;vivBkYSVkxXn?yx1aGxbUiNBawMGad;6? zm{zp?xqAoogt=I2H0g@826=7z^DmTTLB11byYvAO;ir|O0xmNN3Ec0w%yHO({-%q(go%?_X{LP?=E1uXoQgrEGOfL1?~ zI%uPHC23dn-RC@UPs;mxq6cFr{UrgG@e3ONEL^SoxFm%kE^LBhe_D6+Ia+u0J=)BC zf8FB!0J$dYg33jb2SxfmkB|8qeN&De!%r5|@H@GiqReK(YEpnXC;-v~*o<#JmYuze zW}p-K=9?0=*fZyYTE7A}?QR6}m_vMPK!r~y*6%My)d;x4R?-=~MMLC_02KejX9q6= z4sUB4AD0+H4ulSYz4;6mL8uaD07eXFvpy*i5X@dmx--+9`ur@rcJ5<L#s%nq3MRi4Dpr;#28}dl36M{MkVs4+Fm3Pjo5qSV)h}i(2^$Ty|<7N z>*LiBzFKH30D!$@n^3B@HYI_V1?yM(G$2Ml{oZ}?frfPU+{i|dHQOP^M0N2#NN_$+ zs*E=MXUOd=$Z2F4jSA^XIW=?KN=w6{_vJ4f(ZYhLxvFtPozPJv9k%7+z!Zj+_0|HC zMU0(8`8c`Sa=%e$|Mu2+CT22Ifbac@7Vn*he`|6Bl81j`44IRcTu8aw_Y%;I$Hnyd zdWz~I!tkWuGZx4Yjof(?jM;exFlUsrj5qO=@2F;56&^gM9D^ZUQ!6TMMUw19zslEu zwB^^D&nG96Y+Qwbvgk?Zmkn9%d{+V;DGKmBE(yBWX6H#wbaAm&O1U^ zS4YS7j2!1LDC6|>cfdQa`}_^satOz6vc$BfFIG07LoU^IhVMS_u+N=|QCJao0{F>p z-^UkM)ODJW9#9*o;?LPCRV1y~k9B`&U)jbTdvuxG&2%!n_Z&udT=0mb@e;tZ$_l3bj6d0K2;Ya!&)q`A${SmdG_*4WfjubB)Mn+vaLV+)L5$yD zYSTGxpVok&fJDG9iS8#oMN{vQneO|W{Y_xL2Hhb%YhQJgq7j~X7?bcA|B||C?R=Eo z!z;=sSeKiw4mM$Qm>|aIP3nw36Tbh6Eml?hL#&PlR5xf9^vQGN6J8op1dpLfwFg}p zlqYx$610Zf?=vCbB_^~~(e4IMic7C}X(L6~AjDp^;|=d$`=!gd%iwCi5E9<6Y~z0! zX8p$qprEadiMgq>gZ_V~n$d~YUqqqsL#BE6t9ufXIUrs@DCTfGg^-Yh5Ms(wD1xAf zTX8g52V!jr9TlWLl+whcUDv?Rc~JmYs3haeG*UnV;4bI=;__i?OSk)bF3=c9;qTdP zeW1exJwD+;Q3yAw9j_42Zj9nuvs%qGF=6I@($2Ue(a9QGRMZTd4ZAlxbT5W~7(alP1u<^YY!c3B7QV z@jm$vn34XnA6Gh1I)NBgTmgmR=O1PKp#dT*mYDPRZ=}~X3B8}H*e_;;BHlr$FO}Eq zJ9oWk0y#h;N1~ho724x~d)A4Z-{V%F6#e5?Z^(`GGC}sYp5%DKnnB+i-NWxwL-CuF+^JWNl`t@VbXZ{K3#aIX+h9-{T*+t(b0BM&MymW9AA*{p^&-9 zWpWQ?*z(Yw!y%AoeoYS|E!(3IlLksr@?Z9Hqlig?Q4|cGe;0rg#FC}tXTmTNfpE}; z$sfUYEG@hLHUb$(K{A{R%~%6MQN|Bu949`f#H6YC*E(p3lBBKcx z-~Bsd6^QsKzB0)$FteBf*b3i7CN4hccSa-&lfQz4qHm>eC|_X!_E#?=`M(bZ{$cvU zZpMbr|4omp`s9mrgz@>4=Fk3~8Y7q$G{T@?oE0<(I91_t+U}xYlT{c&6}zPAE8ikT z3DP!l#>}i!A(eGT+@;fWdK#(~CTkwjs?*i4SJVBuNB2$6!bCRmcm6AnpHHvnN8G<| zuh4YCYC%5}Zo;BO1>L0hQ8p>}tRVx~O89!${_NXhT!HUoGj0}bLvL2)qRNt|g*q~B z7U&U7E+8Ixy1U`QT^&W@ZSRN|`_Ko$-Mk^^c%`YzhF(KY9l5))1jSyz$&>mWJHZzHt0Jje%BQFxEV}C00{|qo5_Hz7c!FlJ|T(JD^0*yjkDm zL}4S%JU(mBV|3G2jVWU>DX413;d+h0C3{g3v|U8cUj`tZL37Sf@1d*jpwt4^B)`bK zZdlwnPB6jfc7rIKsldW81$C$a9BukX%=V}yPnaBz|i6(h>S)+Bn44@i8RtBZf0XetH&kAb?iAL zD%Ge{>Jo3sy2hgrD?15PM}X_)(6$LV`&t*D`IP)m}bzM)+x-xRJ zavhA)>hu2cD;LUTvN38FEtB94ee|~lIvk~3MBPzmTsN|7V}Kzi!h&za#NyY zX^0BnB+lfBuW!oR#8G&S#Er2bCVtA@5FI`Q+a-e?G)LhzW_chWN-ZQmjtR

eWu-UOPu^G}|k=o=;ffg>8|Z*qev7qS&oqA7%Z{4Ezb!t$f3& z^NuT8CSNp`VHScyikB1YO{BgaBVJR&>dNIEEBwYkfOkWN;(I8CJ|vIfD}STN z{097)R9iC@6($s$#dsb*4BXBx7 zb{6S2O}QUk>upEfij9C2tjqWy7%%V@Xfpe)vo6}PG+hmuY1Tc}peynUJLLmm)8pshG zb}HWl^|sOPtYk)CD-7{L+l(=F zOp}fX8)|n{JDa&9uI!*@jh^^9qP&SbZ(xxDhR)y|bjnn|K3MeR3gl6xcvh9uqzb#K zYkVjnK$;lUky~??mcqN-)d5~mk{wXhrf^<)!Jjqc zG~hX0P_@KvOKwV=X9H&KR3GnP3U)DfqafBt$e10}iuVRFBXx@uBQ)sn0J%%c<;R+! zQz;ETTVa+ma>+VF%U43w?_F6s0=x@N2(oisjA7LUOM<$|6iE|$WcO67W|KY8JUV_# zg7P9K3Yo-c*;EmbsqT!M4(WT`%9uk+s9Em-yB0bE{B%F4X<8fT!%4??vezaJ(wJhj zfOb%wKfkY3RU}7^FRq`UEbB-#A-%7)NJQwQd1As=!$u#~2vQ*CE~qp`u=_kL<`{OL zk>753UqJVx1-4~+d@(pnX-i zV4&=eRWbJ)9YEGMV53poXpv$vd@^yd05z$$@i5J7%>gYKBx?mR2qGv&BPn!tE-_aW zg*C!Z&!B zH>3J16dTJC(@M0*kIc}Jn}jf=f*agba|!HVm|^@+7A?V>Woo!$SJko*Jv1mu>;d}z z^vF{3u5Mvo_94`4kq2&R2`32oyoWc2lJco3`Ls0Ew4E7*AdiMbn^LCV%7%mU)hr4S3UVJjDLUoIKRQ)gm?^{1Z}OYzd$1?a~tEY ztjXmIM*2_qC|OC{7V%430T?RsY?ZLN$w!bkDOQ0}wiq69){Kdu3SqW?NMC))S}zq^ zu)w!>E1!;OrXO!RmT?m&PA;YKUjJy5-Seu=@o;m4*Vp$0OipBl4~Ub)1xBdWkZ47=UkJd$`Z}O8ZbpGN$i_WtY^00`S8=EHG#Ff{&MU1L(^wYjTchB zMTK%1LZ(eLLP($0UR2JVLaL|C2~IFbWirNjp|^=Fl48~Sp9zNOCZ@t&;;^avfN(NpNfq}~VYA{q%yjHo4D>JB>XEv(~Z!`1~SoY=9v zTq;hrjObE_h)cmHXLJ>LC_&XQ2BgGfV}e#v}ZF}iF97bG`Nog&O+SA`2zsn%bbB309}I$ zYi;vW$k@fC^muYBL?XB#CBuhC&^H)F4E&vw(5Q^PF{7~}(b&lF4^%DQzL0(BVk?lM zTHXTo4?Ps|dRICEiux#y77_RF8?5!1D-*h5UY&gRY`WO|V`xxB{f{DHzBwvt1W==r zdfAUyd({^*>Y7lObr;_fO zxDDw7X^dO`n!PLqHZ`by0h#BJ-@bAFPs{yJQ~Ylj^M5zWsxO_WFHG}8hH>OK{Q)9` zSRP94d{AM(q-2x0yhK@aNMv!qGA5@~2tB;X?l{Pf?DM5Y*QK`{mGA? zjx;gwnR~#Nep12dFk<^@-U{`&`P1Z}Z3T2~m8^J&7y}GaMElsTXg|GqfF3>E#HG=j zMt;6hfbfjHSQ&pN9(AT8q$FLKXo`N(WNHDY!K6;JrHZCO&ISBdX`g8sXvIf?|8 zX$-W^ut!FhBxY|+R49o44IgWHt}$1BuE|6|kvn1OR#zhyrw}4H*~cpmFk%K(CTGYc zNkJ8L$eS;UYDa=ZHWZy`rO`!w0oIcgZnK&xC|93#nHvfb^n1xgxf{$LB`H1ao+OGb zKG_}>N-RHSqL(RBdlc7J-Z$Gaay`wEGJ_u-lo88{`aQ*+T~+x(H5j?Q{uRA~>2R+} zB+{wM2m?$->unwg8-GaFrG%ZmoHEceOj{W21)Mi2lAfT)EQuNVo+Do%nHPuq7Ttt7 z%^6J5Yo64dH671tOUrA7I2hL@HKZq;S#Ejxt;*m-l*pPj?=i`=E~FAXAb#QH+a}-% z#3u^pFlg%p{hGiIp>05T$RiE*V7bPXtkz(G<+^E}Risi6F!R~Mbf(Qz*<@2&F#vDr zaL#!8!&ughWxjA(o9xtK{BzzYwm_z2t*c>2jI)c0-xo8ahnEqZ&K;8uF*!Hg0?Gd* z=eJK`FkAr>7$_i$;kq3Ks5NNJkNBnw|1f-&Ys56c9Y@tdM3VTTuXOCbWqye9va6+ZSeF0eh} zYb^ct&4lQTfNZ3M3(9?{;s><(zq%hza7zcxlZ+`F8J*>%4wq8s$cC6Z=F@ zhbvdv;n$%vEI$B~B)Q&LkTse!8Vt};7Szv2@YB!_Ztp@JA>rc(#R1`EZcIdE+JiI% zC2!hgYt+~@%xU?;ir+g92W`*j z3`@S;I6@2rO28zqj&SWO^CvA5MeNEhBF+8-U0O0Q1Co=I^WvPl%#}UFDMBVl z5iXV@d|`QTa$>iw;m$^}6JeuW zjr;{)S2TfK0Q%xgHvONSJb#NA|LOmg{U=k;R?&1tQbylMEY4<1*9mJh&(qo`G#9{X zYRs)#*PtEHnO;PV0G~6G`ca%tpKgb6<@)xc^SQY58lTo*S$*sv5w7bG+8YLKYU`8{ zNBVlvgaDu7icvyf;N&%42z2L4(rR<*Jd48X8Jnw zN>!R$%MZ@~Xu9jH?$2Se&I|ZcW>!26BJP?H7og0hT(S`nXh6{sR36O^7%v=31T+eL z)~BeC)15v>1m#(LN>OEwYFG?TE0_z)MrT%3SkMBBjvCd6!uD+03Jz#!s#Y~b1jf>S z&Rz5&8rbLj5!Y;(Hx|UY(2aw~W(8!3q3D}LRE%XX(@h5TnP@PhDoLVQx;6|r^+Bvs zaR55cR%Db9hZ<<|I%dDkone+8Sq7dqPOMnGoHk~-R*#a8w$c)`>4U`k+o?2|E>Sd4 zZ0ZVT{95pY$qKJ54K}3JB!(WcES>F+x56oJBRg))tMJ^#Qc(2rVcd5add=Us6vpBNkIg9b#ulk%!XBU zV^fH1uY(rGIAiFew|z#MM!qsVv%ZNb#why9%9In4Kj-hDYtMdirWLFzn~de!nnH(V zv0>I3;X#N)bo1$dFzqo(tzmvqNUKraAz~?)OSv42MeM!OYu;2VKn2-s7#fucX`|l~ zplxtG1Pgk#(;V=`P_PZ`MV{Bt4$a7;aLvG@KQo%E=;7ZO&Ws-r@XL+AhnPn>PAKc7 zQ_iQ4mXa-a4)QS>cJzt_j;AjuVCp8g^|dIV=DI0>v-f_|w5YWAX61lNBjZEZax3aV znher(j)f+a9_s8n#|u=kj0(unR1P-*L7`{F28xv054|#DMh}q=@rs@-fbyf(2+52L zN>hn3v!I~%jfOV=j(@xLOsl$Jv-+yR5{3pX)$rIdDarl7(C3)})P`QoHN|y<<2n;` zJ0UrF=Zv}d=F(Uj}~Yv9(@1pqUSRa5_bB*AvQ|Z-6YZ*N%p(U z<;Bpqr9iEBe^LFF!t{1UnRtaH-9=@p35fMQJ~1^&)(2D|^&z?m z855r&diVS6}jmt2)A7LZDiv;&Ys6@W5P{JHY!!n7W zvj3(2{1R9Y=TJ|{^2DK&be*ZaMiRHw>WVI^701fC) zAp1?8?oiU%Faj?Qhou6S^d11_7@tEK-XQ~%q!!7hha-Im^>NcRF7OH7s{IO7arZQ{ zE8n?2><7*!*lH}~usWPWZ}2&M+)VQo7C!AWJSQc>8g_r-P`N&uybK5)p$5_o;+58Q z-Ux2l<3i|hxqqur*qAfHq=)?GDchq}ShV#m6&w|mi~ar~`EO_S=fb~<}66U>5i7$H#m~wR;L~4yHL2R&;L*u7-SPdHxLS&Iy76q$2j#Pe)$WulRiCICG*t+ zeehM8`!{**KRL{Q{8WCEFLXu3+`-XF(b?c1Z~wg?c0lD!21y?NLq?O$STk3NzmrHM zsCgQS5I+nxDH0iyU;KKjzS24GJmG?{D`08|N-v+Egy92lBku)fnAM<}tELA_U`)xKYb=pq|hejMCT1-rg0Edt6(*E9l9WCKI1a=@c99swp2t6Tx zFHy`8Hb#iXS(8c>F~({`NV@F4w0lu5X;MH6I$&|h*qfx{~DJ*h5e|61t1QP}tZEIcjC%!Fa)omJTfpX%aI+OD*Y(l|xc0$1Zip;4rx; zV=qI!5tSuXG7h?jLR)pBEx!B15HCoVycD&Z2dlqN*MFQDb!|yi0j~JciNC!>){~ zQQgmZvc}0l$XB0VIWdg&ShDTbTkArryp3x)T8%ulR;Z?6APx{JZyUm=LC-ACkFm`6 z(x7zm5ULIU-xGi*V6x|eF~CN`PUM%`!4S;Uv_J>b#&OT9IT=jx5#nydC4=0htcDme zDUH*Hk-`Jsa>&Z<7zJ{K4AZE1BVW%zk&MZ^lHyj8mWmk|Pq8WwHROz0Kwj-AFqvR)H2gDN*6dzVk>R3@_CV zw3Z@6s^73xW)XY->AFwUlk^4Q=hXE;ckW=|RcZFchyOM0vqBW{2l*QR#v^SZNnT6j zZv|?ZO1-C_wLWVuYORQryj29JA; zS4BsxfVl@X!W{!2GkG9fL4}58Srv{$-GYngg>JuHz!7ZPQbfIQr4@6ZC4T$`;Vr@t zD#-uJ8A!kSM*gA&^6yWi|F}&59^*Rx{qn3z{(JYxrzg!X2b#uGd>&O0e=0k_2*N?3 zYXV{v={ONL{rW~z_FtFj7kSSJZ?s);LL@W&aND7blR8rlvkAb48RwJZlOHA~t~RfC zOD%ZcOzhYEV&s9%qns0&ste5U!^MFWYn`Od()5RwIz6%@Ek+Pn`s79unJY-$7n-Uf z&eUYvtd)f7h7zG_hDiFC!psCg#q&0c=GHKOik~$$>$Fw*k z;G)HS$IR)Cu72HH|JjeeauX;U6IgZ_IfxFCE_bGPAU25$!j8Etsl0Rk@R`$jXuHo8 z3Hhj-rTR$Gq(x)4Tu6;6rHQhoCvL4Q+h0Y+@Zdt=KTb0~wj7-(Z9G%J+aQu05@k6JHeCC|YRFWGdDCV}ja;-yl^9<`>f=AwOqML1a~* z9@cQYb?!+Fmkf}9VQrL8$uyq8k(r8)#;##xG9lJ-B)Fg@15&To(@xgk9SP*bkHlxiy8I*wJQylh(+9X~H-Is!g&C!q*eIYuhl&fS&|w)dAzXBdGJ&Mp$+8D| zZaD<+RtjI90QT{R0YLk6_dm=GfCg>7;$ zlyLsNYf@MfLH<}ott5)t2CXiQos zFLt^`%ygB2Vy^I$W3J_Rt4olRn~Gh}AW(`F@LsUN{d$sR%bU&3;rsD=2KCL+4c`zv zlI%D>9-)U&R3;>d1Vdd5b{DeR!HXDm44Vq*u?`wziLLsFUEp4El;*S0;I~D#TgG0s zBXYZS{o|Hy0A?LVNS)V4c_CFwyYj-E#)4SQq9yaf`Y2Yhk7yHSdos~|fImZG5_3~~o<@jTOH@Mc7`*xn-aO5F zyFT-|LBsm(NbWkL^oB-Nd31djBaYebhIGXhsJyn~`SQ6_4>{fqIjRp#Vb|~+Qi}Mdz!Zsw= zz?5L%F{c{;Cv3Q8ab>dsHp)z`DEKHf%e9sT(aE6$az?A}3P`Lm(~W$8Jr=;d8#?dm_cmv>2673NqAOenze z=&QW`?TQAu5~LzFLJvaJ zaBU3mQFtl5z?4XQDBWNPaH4y)McRpX#$(3o5Nx@hVoOYOL&-P+gqS1cQ~J;~1roGH zVzi46?FaI@w-MJ0Y7BuAg*3;D%?<_OGsB3)c|^s3A{UoAOLP8scn`!5?MFa|^cTvq z#%bYG3m3UO9(sH@LyK9-LSnlVcm#5^NRs9BXFtRN9kBY2mPO|@b7K#IH{B{=0W06) zl|s#cIYcreZ5p3j>@Ly@35wr-q8z5f9=R42IsII=->1stLo@Q%VooDvg@*K(H@*5g zUPS&cM~k4oqp`S+qp^*nxzm^0mg3h8ppEHQ@cXyQ=YKV-6)FB*$KCa{POe2^EHr{J zOxcVd)s3Mzs8m`iV?MSp=qV59blW9$+$P+2;PZDRUD~sr*CQUr&EDiCSfH@wuHez+ z`d5p(r;I7D@8>nbZ&DVhT6qe+accH;<}q$8Nzz|d1twqW?UV%FMP4Y@NQ`3(+5*i8 zP9*yIMP7frrneG3M9 zf>GsjA!O#Bifr5np-H~9lR(>#9vhE6W-r`EjjeQ_wdWp+rt{{L5t5t(Ho|4O24@}4 z_^=_CkbI`3;~sXTnnsv=^b3J}`;IYyvb1gM>#J9{$l#Zd*W!;meMn&yXO7x`Epx_Y zm-1wlu~@Ii_7D}>%tzlXW;zQT=uQXSG@t$<#6-W*^vy7Vr2TCpnix@7!_|aNXEnN<-m?Oq;DpN*x6f>w za1Wa5entFEDtA0SD%iZv#3{wl-S`0{{i3a9cmgNW`!TH{J*~{@|5f%CKy@uk*8~af zt_d34U4y&3y9IZ5cXxLQ?(XjH5?q3Z0KxK~y!-CUyWG6{<)5lkhbox0HnV&7^zNBn zjc|?X!Y=63(Vg>#&Wx%=LUr5{i@~OdzT#?P8xu#P*I_?Jl7xM4dq)4vi}3Wj_c=XI zSbc)@Q2Et4=(nBDU{aD(F&*%Ix!53_^0`+nOFk)}*34#b0Egffld|t_RV91}S0m)0 zap{cQDWzW$geKzYMcDZDAw480!1e1!1Onpv9fK9Ov~sfi!~OeXb(FW)wKx335nNY! za6*~K{k~=pw`~3z!Uq%?MMzSl#s%rZM{gzB7nB*A83XIGyNbi|H8X>a5i?}Rs+z^; z2iXrmK4|eDOu@{MdS+?@(!-Ar4P4?H_yjTEMqm7`rbV4P275(-#TW##v#Dt14Yn9UB-Sg3`WmL0+H~N;iC`Mg%pBl?1AAOfZ&e; z*G=dR>=h_Mz@i;lrGpIOQwezI=S=R8#);d*;G8I(39ZZGIpWU)y?qew(t!j23B9fD z?Uo?-Gx3}6r8u1fUy!u)7LthD2(}boE#uhO&mKBau8W8`XV7vO>zb^ZVWiH-DOjl2 zf~^o1CYVU8eBdmpAB=T%i(=y}!@3N%G-*{BT_|f=egqtucEtjRJJhSf)tiBhpPDpgzOpG12UgvOFnab&16Zn^2ZHjs)pbd&W1jpx%%EXmE^ zdn#R73^BHp3w%&v!0~azw(Fg*TT*~5#dJw%-UdxX&^^(~V&C4hBpc+bPcLRZizWlc zjR;$4X3Sw*Rp4-o+a4$cUmrz05RucTNoXRINYG*DPpzM&;d1GNHFiyl(_x#wspacQ zL)wVFXz2Rh0k5i>?Ao5zEVzT)R(4Pjmjv5pzPrav{T(bgr|CM4jH1wDp6z*_jnN{V ziN56m1T)PBp1%`OCFYcJJ+T09`=&=Y$Z#!0l0J2sIuGQtAr>dLfq5S;{XGJzNk@a^ zk^eHlC4Gch`t+ue3RviiOlhz81CD9z~d|n5;A>AGtkZMUQ#f>5M14f2d}2 z8<*LNZvYVob!p9lbmb!0jt)xn6O&JS)`}7v}j+csS3e;&Awj zoNyjnqLzC(QQ;!jvEYUTy73t_%16p)qMb?ihbU{y$i?=a7@JJoXS!#CE#y}PGMK~3 zeeqqmo7G-W_S97s2eed^erB2qeh4P25)RO1>MH7ai5cZJTEevogLNii=oKG)0(&f` z&hh8cO{of0;6KiNWZ6q$cO(1)9r{`}Q&%p*O0W7N--sw3Us;)EJgB)6iSOg(9p_mc zRw{M^qf|?rs2wGPtjVKTOMAfQ+ZNNkb$Ok0;Pe=dNc7__TPCzw^H$5J0l4D z%p(_0w(oLmn0)YDwrcFsc*8q)J@ORBRoZ54GkJpxSvnagp|8H5sxB|ZKirp%_mQt_ z81+*Y8{0Oy!r8Gmih48VuRPwoO$dDW@h53$C)duL4_(osryhwZSj%~KsZ?2n?b`Z* z#C8aMdZxYmCWSM{mFNw1ov*W}Dl=%GQpp90qgZ{(T}GOS8#>sbiEU;zYvA?=wbD5g+ahbd1#s`=| zV6&f#ofJC261~Ua6>0M$w?V1j##jh-lBJ2vQ%&z`7pO%frhLP-1l)wMs=3Q&?oth1 zefkPr@3Z(&OL@~|<0X-)?!AdK)ShtFJ;84G2(izo3cCuKc{>`+aDoziL z6gLTL(=RYeD7x^FYA%sPXswOKhVa4i(S4>h&mLvS##6-H?w8q!B<8Alk>nQEwUG)SFXK zETfcTwi=R3!ck|hSM`|-^N3NWLav&UTO{a9=&Tuz-Kq963;XaRFq#-1R18fi^Gb-; zVO>Q{Oe<^b0WA!hkBi9iJp3`kGwacXX2CVQ0xQn@Y2OhrM%e4)Ea7Y*Df$dY2BpbL zv$kX}*#`R1uNA(7lk_FAk~{~9Z*Si5xd(WKQdD&I?8Y^cK|9H&huMU1I(251D7(LL z+){kRc=ALmD;#SH#YJ+|7EJL6e~w!D7_IrK5Q=1DCulUcN(3j`+D_a|GP}?KYx}V+ zx_vLTYCLb0C?h;e<{K0`)-|-qfM16y{mnfX(GGs2H-;-lRMXyb@kiY^D;i1haxoEk zsQ7C_o2wv?;3KS_0w^G5#Qgf*>u)3bT<3kGQL-z#YiN9QH7<(oDdNlSdeHD zQJN-U*_wJM_cU}1YOH=m>DW~{%MAPxL;gLdU6S5xLb$gJt#4c2KYaEaL8ORWf=^(l z-2`8^J;&YG@vb9em%s~QpU)gG@24BQD69;*y&-#0NBkxumqg#YYomd2tyo0NGCr8N z5<5-E%utH?Ixt!(Y4x>zIz4R^9SABVMpLl(>oXnBNWs8w&xygh_e4*I$y_cVm?W-^ ze!9mPy^vTLRclXRGf$>g%Y{(#Bbm2xxr_Mrsvd7ci|X|`qGe5=54Zt2Tb)N zlykxE&re1ny+O7g#`6e_zyjVjRi5!DeTvSJ9^BJqQ*ovJ%?dkaQl!8r{F`@KuDEJB3#ho5 zmT$A&L=?}gF+!YACb=%Y@}8{SnhaGCHRmmuAh{LxAn0sg#R6P_^cJ-9)+-{YU@<^- zlYnH&^;mLVYE+tyjFj4gaAPCD4CnwP75BBXA`O*H(ULnYD!7K14C!kGL_&hak)udZ zkQN8)EAh&9I|TY~F{Z6mBv7sz3?<^o(#(NXGL898S3yZPTaT|CzZpZ~pK~*9Zcf2F zgwuG)jy^OTZD`|wf&bEdq4Vt$ir-+qM7BosXvu`>W1;iFN7yTvcpN_#at)Q4n+(Jh zYX1A-24l9H5jgY?wdEbW{(6U1=Kc?Utren80bP`K?J0+v@{-RDA7Y8yJYafdI<7-I z_XA!xeh#R4N7>rJ_?(VECa6iWhMJ$qdK0Ms27xG&$gLAy(|SO7_M|AH`fIY)1FGDp zlsLwIDshDU;*n`dF@8vV;B4~jRFpiHrJhQ6TcEm%OjWTi+KmE7+X{19 z>e!sg0--lE2(S0tK}zD&ov-{6bMUc%dNFIn{2^vjXWlt>+uxw#d)T6HNk6MjsfN~4 zDlq#Jjp_!wn}$wfs!f8NX3Rk#9)Q6-jD;D9D=1{$`3?o~caZjXU*U32^JkJ$ZzJ_% zQWNfcImxb!AV1DRBq`-qTV@g1#BT>TlvktYOBviCY!13Bv?_hGYDK}MINVi;pg)V- z($Bx1Tj`c?1I3pYg+i_cvFtcQ$SV9%%9QBPg&8R~Ig$eL+xKZY!C=;M1|r)$&9J2x z;l^a*Ph+isNl*%y1T4SviuK1Nco_spQ25v5-}7u?T9zHB5~{-+W*y3p{yjn{1obqf zYL`J^Uz8zZZN8c4Dxy~)k3Ws)E5eYi+V2C!+7Sm0uu{xq)S8o{9uszFTnE>lPhY=5 zdke-B8_*KwWOd%tQs_zf0x9+YixHp+Qi_V$aYVc$P-1mg?2|_{BUr$6WtLdIX2FaF zGmPRTrdIz)DNE)j*_>b9E}sp*(1-16}u za`dgT`KtA3;+e~9{KV48RT=CGPaVt;>-35}%nlFUMK0y7nOjoYds7&Ft~#>0$^ciZ zM}!J5Mz{&|&lyG^bnmh?YtR z*Z5EfDxkrI{QS#Iq752aiA~V)DRlC*2jlA|nCU!@CJwxO#<=j6ssn;muv zhBT9~35VtwsoSLf*(7vl&{u7d_K_CSBMbzr zzyjt&V5O#8VswCRK3AvVbS7U5(KvTPyUc0BhQ}wy0z3LjcdqH8`6F3!`)b3(mOSxL z>i4f8xor(#V+&#ph~ycJMcj#qeehjxt=~Na>dx#Tcq6Xi4?BnDeu5WBBxt603*BY& zZ#;o1kv?qpZjwK-E{8r4v1@g*lwb|8w@oR3BTDcbiGKs)a>Fpxfzh&b ziQANuJ_tNHdx;a*JeCo^RkGC$(TXS;jnxk=dx++D8|dmPP<0@ z$wh#ZYI%Rx$NKe-)BlJzB*bot0ras3I%`#HTMDthGtM_G6u-(tSroGp1Lz+W1Y`$@ zP`9NK^|IHbBrJ#AL3!X*g3{arc@)nuqa{=*2y+DvSwE=f*{>z1HX(>V zNE$>bbc}_yAu4OVn;8LG^naq5HZY zh{Hec==MD+kJhy6t=Nro&+V)RqORK&ssAxioc7-L#UQuPi#3V2pzfh6Ar400@iuV5 z@r>+{-yOZ%XQhsSfw%;|a4}XHaloW#uGluLKux0II9S1W4w=X9J=(k&8KU()m}b{H zFtoD$u5JlGfpX^&SXHlp$J~wk|DL^YVNh2w(oZ~1*W156YRmenU;g=mI zw({B(QVo2JpJ?pJqu9vijk$Cn+%PSw&b4c@uU6vw)DjGm2WJKt!X}uZ43XYlDIz%& z=~RlgZpU-tu_rD`5!t?289PTyQ zZgAEp=zMK>RW9^~gyc*x%vG;l+c-V?}Bm;^{RpgbEnt_B!FqvnvSy)T=R zGa!5GACDk{9801o@j>L8IbKp#!*Td5@vgFKI4w!5?R{>@^hd8ax{l=vQnd2RDHopo zwA+qb2cu4Rx9^Bu1WNYT`a(g}=&&vT`&Sqn-irxzX_j1=tIE#li`Hn=ht4KQXp zzZj`JO+wojs0dRA#(bXBOFn**o+7rPY{bM9m<+UBF{orv$#yF8)AiOWfuas5Fo`CJ zqa;jAZU^!bh8sjE7fsoPn%Tw11+vufr;NMm3*zC=;jB{R49e~BDeMR+H6MGzDlcA^ zKg>JEL~6_6iaR4i`tSfUhkgPaLXZ<@L7poRF?dw_DzodYG{Gp7#24<}=18PBT}aY` z{)rrt`g}930jr3^RBQNA$j!vzTh#Mo1VL`QCA&US?;<2`P+xy8b9D_Hz>FGHC2r$m zW>S9ywTSdQI5hh%7^e`#r#2906T?))i59O(V^Rpxw42rCAu-+I3y#Pg6cm#&AX%dy ze=hv0cUMxxxh1NQEIYXR{IBM&Bk8FK3NZI3z+M>r@A$ocd*e%x-?W;M0pv50p+MVt zugo<@_ij*6RZ;IPtT_sOf2Zv}-3R_1=sW37GgaF9Ti(>V z1L4ju8RzM%&(B}JpnHSVSs2LH#_&@`4Kg1)>*)^i`9-^JiPE@=4l$+?NbAP?44hX&XAZy&?}1;=8c(e0#-3bltVWg6h=k!(mCx=6DqOJ-I!-(g;*f~DDe={{JGtH7=UY|0F zNk(YyXsGi;g%hB8x)QLpp;;`~4rx>zr3?A|W$>xj>^D~%CyzRctVqtiIz7O3pc@r@JdGJiH@%XR_9vaYoV?J3K1cT%g1xOYqhXfSa`fg=bCLy% zWG74UTdouXiH$?H()lyx6QXt}AS)cOa~3IdBxddcQp;(H-O}btpXR-iwZ5E)di9Jf zfToEu%bOR11xf=Knw7JovRJJ#xZDgAvhBDF<8mDu+Q|!}Z?m_=Oy%Ur4p<71cD@0OGZW+{-1QT?U%_PJJ8T!0d2*a9I2;%|A z9LrfBU!r9qh4=3Mm3nR_~X-EyNc<;?m`?dKUNetCnS)}_-%QcWuOpw zAdZF`4c_24z&m{H9-LIL`=Hrx%{IjrNZ~U<7k6p{_wRkR84g>`eUBOQd3x5 zT^kISYq)gGw?IB8(lu1=$#Vl?iZdrx$H0%NxW)?MO$MhRHn8$F^&mzfMCu>|`{)FL z`ZgOt`z%W~^&kzMAuWy9=q~$ldBftH0}T#(K5e8;j~!x$JjyspJ1IISI?ON5OIPB$ z-5_|YUMb+QUsiv3R%Ys4tVYW+x$}dg;hw%EdoH%SXMp`)v?cxR4wic{X9pVBH>=`#`Kcj!}x4 zV!`6tj|*q?jZdG(CSevn(}4Ogij5 z-kp;sZs}7oNu0x+NHs~(aWaKGV@l~TBkmW&mPj==N!f|1e1SndS6(rPxsn7dz$q_{ zL0jSrihO)1t?gh8N zosMjR3n#YC()CVKv zos2TbnL&)lHEIiYdz|%6N^vAUvTs6?s|~kwI4uXjc9fim`KCqW3D838Xu{48p$2?I zOeEqQe1}JUZECrZSO_m=2<$^rB#B6?nrFXFpi8jw)NmoKV^*Utg6i8aEW|^QNJuW& z4cbXpHSp4|7~TW(%JP%q9W2~@&@5Y5%cXL#fMhV59AGj<3$Hhtfa>24DLk{7GZUtr z5ql**-e58|mbz%5Kk~|f!;g+Ze^b);F+5~^jdoq#m+s?Y*+=d5ruym%-Tnn8htCV; zDyyUrWydgDNM&bI{yp<_wd-q&?Ig+BN-^JjWo6Zu3%Eov^Ja>%eKqrk&7kUqeM8PL zs5D}lTe_Yx;e=K`TDya!-u%y$)r*Cr4bSfN*eZk$XT(Lv2Y}qj&_UaiTevxs_=HXjnOuBpmT> zBg|ty8?|1rD1~Ev^6=C$L9%+RkmBSQxlnj3j$XN?%QBstXdx+Vl!N$f2Ey`i3p@!f zzqhI3jC(TZUx|sP%yValu^nzEV96o%*CljO>I_YKa8wMfc3$_L()k4PB6kglP@IT#wBd*3RITYADL}g+hlzLYxFmCt=_XWS}=jg8`RgJefB57z(2n&&q>m ze&F(YMmoRZW7sQ;cZgd(!A9>7mQ2d#!-?$%G8IQ0`p1|*L&P$GnU0i0^(S;Rua4v8 z_7Qhmv#@+kjS-M|($c*ZOo?V2PgT;GKJyP1REABlZhPyf!kR(0UA7Bww~R<7_u6#t z{XNbiKT&tjne(&=UDZ+gNxf&@9EV|fblS^gxNhI-DH;|`1!YNlMcC{d7I{u_E~cJOalFEzDY|I?S3kHtbrN&}R3k zK(Ph_Ty}*L3Et6$cUW`0}**BY@44KtwEy(jW@pAt`>g> z&8>-TmJiDwc;H%Ae%k6$ndZlfKruu1GocgZrLN=sYI52}_I%d)~ z6z40!%W4I6ch$CE2m>Dl3iwWIbcm27QNY#J!}3hqc&~(F8K{^gIT6E&L!APVaQhj^ zjTJEO&?**pivl^xqfD(rpLu;`Tm1MV+Wtd4u>X6u5V{Yp%)xH$k410o{pGoKdtY0t@GgqFN zO=!hTcYoa^dEPKvPX4ukgUTmR#q840gRMMi%{3kvh9gt(wK;Fniqu9A%BMsq?U&B5DFXC8t8FBN1&UIwS#=S zF(6^Eyn8T}p)4)yRvs2rCXZ{L?N6{hgE_dkH_HA#L3a0$@UMoBw6RE9h|k_rx~%rB zUqeEPL|!Pbp|up2Q=8AcUxflck(fPNJYP1OM_4I(bc24a**Qnd-@;Bkb^2z8Xv?;3yZp*| zoy9KhLo=;8n0rPdQ}yAoS8eb zAtG5QYB|~z@Z(Fxdu`LmoO>f&(JzsO|v0V?1HYsfMvF!3| zka=}6U13(l@$9&=1!CLTCMS~L01CMs@Abl4^Q^YgVgizWaJa%{7t)2sVcZg0mh7>d z(tN=$5$r?s={yA@IX~2ot9`ZGjUgVlul$IU4N}{ zIFBzY3O0;g$BZ#X|VjuTPKyw*|IJ+&pQ` z(NpzU`o=D86kZ3E5#!3Ry$#0AW!6wZe)_xZ8EPidvJ0f+MQJZ6|ZJ$CEV6;Yt{OJnL`dewc1k>AGbkK9Gf5BbB-fg? zgC4#CPYX+9%LLHg@=c;_Vai_~#ksI~)5|9k(W()g6ylc(wP2uSeJ$QLATtq%e#zpT zp^6Y)bV+e_pqIE7#-hURQhfQvIZpMUzD8&-t$esrKJ}4`ZhT|woYi>rP~y~LRf`*2!6 z6prDzJ~1VOlYhYAuBHcu9m>k_F>;N3rpLg>pr;{EDkeQPHfPv~woj$?UTF=txmaZy z?RrVthxVcqUM;X*(=UNg4(L|0d250Xk)6GF&DKD@r6{aZo;(}dnO5@CP7pMmdsI)- zeYH*@#+|)L8x7)@GNBu0Npyyh6r z^~!3$x&w8N)T;|LVgnwx1jHmZn{b2V zO|8s#F0NZhvux?0W9NH5;qZ?P_JtPW86)4J>AS{0F1S0d}=L2`{F z_y;o;17%{j4I)znptnB z%No1W>o}H2%?~CFo~0j?pzWk?dV4ayb!s{#>Yj`ZJ!H)xn}*Z_gFHy~JDis)?9-P=z4iOQg{26~n?dTms7)+F}? zcXvnHHnnbNTzc!$t+V}=<2L<7l(84v1I3b;-)F*Q?cwLNlgg{zi#iS)*rQ5AFWe&~ zWHPPGy{8wEC9JSL?qNVY76=es`bA{vUr~L7f9G@mP}2MNF0Qhv6Sgs`r_k!qRbSXK zv16Qqq`rFM9!4zCrCeiVS~P2e{Pw^A8I?p?NSVR{XfwlQo*wj|Ctqz4X-j+dU7eGkC(2y`(P?FM?P4gKki3Msw#fM6paBq#VNc>T2@``L{DlnnA-_*i10Kre&@-H!Z7gzn9pRF61?^^ z8dJ5kEeVKb%Bly}6NLV}<0(*eZM$QTLcH#+@iWS^>$Of_@Mu1JwM!>&3evymgY6>C_)sK+n|A5G6(3RJz0k>(z2uLdzXeTw)e4*g!h} zn*UvIx-Ozx<3rCF#C`khSv`Y-b&R4gX>d5osr$6jlq^8vi!M$QGx05pJZoY#RGr*J zsJmOhfodAzYQxv-MoU?m_|h^aEwgEHt5h_HMkHwtE+OA03(7{hm1V?AlYAS7G$u5n zO+6?51qo@aQK5#l6pM`kD5OmI28g!J2Z{5kNlSuKl=Yj3QZ|bvVHU}FlM+{QV=<=) z+b|%Q!R)FE z@ycDMSKV2?*XfcAc5@IOrSI&3&aR$|oAD8WNA6O;p~q-J@ll{x`jP<*eEpIYOYnT zer_t=dYw6a0avjQtKN&#n&(KJ5Kr$RXPOp1@Fq#0Of zTXQkq4qQxKWR>x#d{Hyh?6Y)U07;Q$?BTl7mx2bSPY_juXub1 z%-$)NKXzE<%}q>RX25*oeMVjiz&r_z;BrQV-(u>!U>C*OisXNU*UftsrH6vAhTEm@ zoKA`?fZL1sdd!+G@*NNvZa>}37u^x8^T>VH0_6Bx{3@x5NAg&55{2jUE-w3zCJNJi z^IlU=+DJz-9K&4c@7iKj(zlj@%V}27?vYmxo*;!jZVXJMeDg;5T!4Y1rxNV-e$WAu zkk6^Xao8HC=w2hpLvM(!xwo|~$eG6jJj39zyQHf)E+NPJlfspUhzRv&_qr8+Z1`DA zz`EV=A)d=;2&J;eypNx~q&Ir_7e_^xXg(L9>k=X4pxZ3y#-ch$^TN}i>X&uwF%75c(9cjO6`E5 z16vbMYb!lEIM?jxn)^+Ld8*hmEXR4a8TSfqwBg1(@^8$p&#@?iyGd}uhWTVS`Mlpa zGc+kV)K7DJwd46aco@=?iASsx?sDjbHoDVU9=+^tk46|Fxxey1u)_}c1j z^(`5~PU%og1LdSBE5x4N&5&%Nh$sy0oANXwUcGa>@CCMqP`4W$ZPSaykK|giiuMIw zu#j)&VRKWP55I(5K1^cog|iXgaK1Z%wm%T;;M3X`-`TTWaI}NtIZj;CS)S%S(h}qq zRFQ#{m4Qk$7;1i*0PC^|X1@a1pcMq1aiRSCHq+mnfj^FS{oxWs0McCN-lK4>SDp#` z7=Duh)kXC;lr1g3dqogzBBDg6>et<<>m>KO^|bI5X{+eMd^-$2xfoP*&e$vdQc7J% zmFO~OHf7aqlIvg%P`Gu|3n;lKjtRd@;;x#$>_xU(HpZos7?ShZlQSU)bY?qyQM3cHh5twS6^bF8NBKDnJgXHa)? zBYv=GjsZuYC2QFS+jc#uCsaEPEzLSJCL=}SIk9!*2Eo(V*SAUqKw#?um$mUIbqQQb zF1Nn(y?7;gP#@ws$W76>TuGcG=U_f6q2uJq?j#mv7g;llvqu{Yk~Mo>id)jMD7;T> zSB$1!g)QpIf*f}IgmV;!B+3u(ifW%xrD=`RKt*PDC?M5KI)DO`VXw(7X-OMLd3iVU z0CihUN(eNrY;m?vwK{55MU`p1;JDF=6ITN$+!q8W#`iIsN8;W7H?`htf%RS9Lh+KQ z_p_4?qO4#*`t+8l-N|kAKDcOt zoHsqz_oO&n?@4^Mr*4YrkDX44BeS*0zaA1j@*c}{$;jUxRXx1rq7z^*NX6d`DcQ}L z6*cN7e%`2#_J4z8=^GM6>%*i>>X^_0u9qn%0JTUo)c0zIz|7a`%_UnB)-I1cc+ z0}jAK0}jBl|6-2VT759oxBnf%-;7vs>7Mr}0h3^$0`5FAy}2h{ps5%RJA|^~6uCqg zxBMK5bQVD{Aduh1lu4)`Up*&( zCJQ>nafDb#MuhSZ5>YmD@|TcrNv~Q%!tca;tyy8Iy2vu2CeA+AsV^q*Wohg%69XYq zP0ppEDEYJ9>Se&X(v=U#ibxg()m=83pLc*|otbG;`CYZ z*YgsakGO$E$E_$|3bns7`m9ARe%myU3$DE;RoQ<6hR8e;%`pxO1{GXb$cCZl9lVnJ$(c` z``G?|PhXaz`>)rb7jm2#v7=(W?@ zjUhrNndRFMQ}%^^(-nmD&J>}9w@)>l;mhRr@$}|4ueOd?U9ZfO-oi%^n4{#V`i}#f zqh<@f^%~(MnS?Z0xsQI|Fghrby<&{FA+e4a>c(yxFL!Pi#?DW!!YI{OmR{xEC7T7k zS_g*9VWI}d0IvIXx*d5<7$5Vs=2^=ews4qZGmAVyC^9e;wxJ%BmB(F5*&!yyABCtLVGL@`qW>X9K zpv=W~+EszGef=am3LG+#yIq5oLXMnZ_dxSLQ_&bwjC^0e8qN@v!p?7mg02H<9`uaJ zy0GKA&YQV2CxynI3T&J*m!rf4@J*eo235*!cB1zEMQZ%h5>GBF;8r37K0h?@|E*0A zIHUg0y7zm(rFKvJS48W7RJwl!i~<6X2Zw+Fbm9ekev0M;#MS=Y5P(kq^(#q11zsvq zDIppe@xOMnsOIK+5BTFB=cWLalK#{3eE>&7fd11>l2=MpNKjsZT2kmG!jCQh`~Fu0 z9P0ab`$3!r`1yz8>_7DYsO|h$kIsMh__s*^KXv?Z1O8|~sEz?Y{+GDzze^GPjk$E$ zXbA-1gd77#=tn)YKU=;JE?}De0)WrT%H9s3`fn|%YibEdyZov3|MJ>QWS>290eCZj z58i<*>dC9=kz?s$sP_9kK1p>nV3qvbleExyq56|o+oQsb{ZVmuu1n~JG z0sUvo_i4fSM>xRs8rvG$*+~GZof}&ISxn(2JU*K{L<3+b{bBw{68H&Uiup@;fWWl5 zgB?IWMab0LkXK(Hz#yq>scZbd2%=B?DO~^q9tarlzZysN+g}n0+v);JhbjUT8AYrt z3?;0r%p9zLJv1r$%q&HKF@;3~0wVwO!U5m;J`Mm|`Nc^80sZd+Wj}21*SPoF82hCF zoK?Vw;4ioafdAkZxT1er-LLVi-*0`@2Ur&*!b?0U>R;no+S%)xoBuBxRw$?weN-u~tKE}8xb@7Gs%(aC;e1-LIlSfXDK(faFW)mnHdrLc3`F z6ZBsT^u0uVS&il=>YVX^*5`k!P4g1)2LQmz{?&dgf`7JrA4ZeE0sikL`k!Eb6r=g0 z{aCy_0I>fxSAXQYz3lw5G|ivg^L@(x-uch!AphH+d;E4`175`R0#b^)Zp>EM1Ks=zx6_261>!7 z{7F#a{Tl@Tpw9S`>7_i|PbScS-(dPJv9_0-FBP_aa@Gg^2IoKNZM~#=sW$SH3MJ|{ zsQy8F43lX7hYx<{v^Q9`2QsMzeen3cGpiTgzVp- z`aj3&Wv0(he1qKI!2jpGpO-i0Wpcz%vdn`2o9x&3;^nsZPt3c \(.*\)$'` - 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-sacc/gradlew.bat b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradlew.bat deleted file mode 100644 index 24467a14..00000000 --- a/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sacc/gradlew.bat +++ /dev/null @@ -1,100 +0,0 @@ -@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 From 27141a0ab14a439f975d13c9fc9aa065797045d9 Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Fri, 25 Sep 2020 09:56:53 +0100 Subject: [PATCH 55/61] Gradle update Signed-off-by: Matthew B White --- fabric-chaincode-docker/Dockerfile | 14 +++++++------- .../fabric-chaincode-example-sbe/build.gradle | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index 1f4c696c..8fdfeb4d 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -1,4 +1,4 @@ -FROM hyperledger/fabric-baseimage:amd64-0.4.16 +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 @@ -60,19 +60,19 @@ WORKDIR /root/chaincode-java RUN rm -rf example-src/* RUN rm -rf shim-src -RUN gradle wrapper +RUN source /root/.sdkman/bin/sdkman-init.sh; gradle wrapper --gradle-version 4.6 # Creating final javaenv image which will include all required # dependencies to build and compile java chaincode -FROM adoptopenjdk/openjdk11:jdk-11.0.4_11-alpine -RUN apk add --no-cache bash +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=builder /root/.sdkman/candidates/maven/current /usr/bin/maven - +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/:/usr/bin/gradle:/usr/bin/gradle/bin:${PATH}" +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 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 index caa6b97b..f0f3f981 100644 --- 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 @@ -1,5 +1,5 @@ plugins { - id 'com.github.johnrengelman.shadow' version '2.0.3' + id 'com.github.johnrengelman.shadow' version '4.0.3' id 'java' } From 37587c6e0540579797e05b37f03468c514d20258 Mon Sep 17 00:00:00 2001 From: Kestutis Gudynas <44440041+kemi04@users.noreply.github.com> Date: Thu, 8 Oct 2020 10:22:49 +0100 Subject: [PATCH 56/61] Prepare 1.4.7 release Signed-off-by: Kestutis Gudynas <44440041+kemi04@users.noreply.github.com> --- CHANGELOG.md | 5 +++++ release_notes/v1.4.7.txt | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 release_notes/v1.4.7.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bb3106d..6a04b531 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,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 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 From a2707b194a44a5870cb1e5de0192d6e27a3e6cfc Mon Sep 17 00:00:00 2001 From: Kestutis Gudynas <44440041+kemi04@users.noreply.github.com> Date: Mon, 12 Oct 2020 10:42:16 +0100 Subject: [PATCH 57/61] Bump version to 1.4.8 Signed-off-by: Kestutis Gudynas <44440041+kemi04@users.noreply.github.com> --- build.gradle | 2 +- fabric-chaincode-docker/build.gradle | 2 +- fabric-chaincode-example-gradle/build.gradle | 2 +- fabric-chaincode-example-maven/pom.xml | 2 +- fabric-chaincode-example-sacc/build.gradle | 2 +- fabric-chaincode-example-sbe/build.gradle | 2 +- fabric-chaincode-integration-test/build.gradle | 2 +- .../src/contracts/fabric-chaincode-example-sacc/build.gradle | 2 +- .../src/contracts/fabric-chaincode-example-sbe/build.gradle | 2 +- fabric-contract-example/gradle/build.gradle | 2 +- fabric-contract-example/maven/pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 11d97887..91956a12 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ apply plugin: 'idea' apply plugin: 'eclipse-wtp' apply plugin: 'com.dorongold.task-tree' -version = '1.4.7' +version = '1.4.8' buildscript { repositories { maven { diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index 6d630bac..5fd963c3 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -80,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.7', '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-example-gradle/build.gradle b/fabric-chaincode-example-gradle/build.gradle index 90c1f830..6ef6ee23 100644 --- a/fabric-chaincode-example-gradle/build.gradle +++ b/fabric-chaincode-example-gradle/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.7' + 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 87e61539..66ac3c65 100644 --- a/fabric-chaincode-example-maven/pom.xml +++ b/fabric-chaincode-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.7 + 1.4.8 1.0.13 diff --git a/fabric-chaincode-example-sacc/build.gradle b/fabric-chaincode-example-sacc/build.gradle index 3ba80437..b3f08af2 100644 --- a/fabric-chaincode-example-sacc/build.gradle +++ b/fabric-chaincode-example-sacc/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.7' + 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/build.gradle b/fabric-chaincode-example-sbe/build.gradle index caa6b97b..b18cbfe1 100644 --- a/fabric-chaincode-example-sbe/build.gradle +++ b/fabric-chaincode-example-sbe/build.gradle @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.7' + 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-integration-test/build.gradle b/fabric-chaincode-integration-test/build.gradle index 1249a928..5c9f5234 100644 --- a/fabric-chaincode-integration-test/build.gradle +++ b/fabric-chaincode-integration-test/build.gradle @@ -1,7 +1,7 @@ dependencies { compile project(':fabric-chaincode-docker') testCompile 'org.testcontainers:testcontainers:1.7.1' - testCompile 'org.hyperledger.fabric-sdk-java:fabric-sdk-java:1.4.7' + 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' } 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 index 3ba80437..b3f08af2 100644 --- 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 @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.7' + 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-integration-test/src/contracts/fabric-chaincode-example-sbe/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-chaincode-example-sbe/build.gradle index f0f3f981..37eed64f 100644 --- 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 @@ -15,7 +15,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.7' + 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-contract-example/gradle/build.gradle b/fabric-contract-example/gradle/build.gradle index f48e63f3..bbdfc56c 100644 --- a/fabric-contract-example/gradle/build.gradle +++ b/fabric-contract-example/gradle/build.gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.4.7' + 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' diff --git a/fabric-contract-example/maven/pom.xml b/fabric-contract-example/maven/pom.xml index 5c2742d7..3e976b60 100644 --- a/fabric-contract-example/maven/pom.xml +++ b/fabric-contract-example/maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 1.4.7 + 1.4.8 1.0.13 From 3c1d0fac16d192cf2e1239754cf1577cd27e249f Mon Sep 17 00:00:00 2001 From: James Taylor Date: Fri, 9 Oct 2020 16:36:37 +0100 Subject: [PATCH 58/61] [FABCJ-290] Add release guide Signed-off-by: James Taylor --- RELEASING.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 RELEASING.md 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. From 7aefaa91c38d69ac2677c607e08ffe8b72564c33 Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Tue, 3 Nov 2020 16:54:18 +0000 Subject: [PATCH 59/61] [FABCJ-295] Clean sdkman cache This includes the full gradle build, that we don't need Signed-off-by: Matthew B White --- fabric-chaincode-docker/Dockerfile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index 8fdfeb4d..2c65614d 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -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 @@ -61,6 +67,7 @@ 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 1557ce1a28ba5058c79b818b32235018be7295c8 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 4 Nov 2020 14:33:33 +0000 Subject: [PATCH 60/61] Prepare 1.4.8 release Signed-off-by: James Taylor --- CHANGELOG.md | 7 +++++++ release_notes/v1.4.8.txt | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 release_notes/v1.4.8.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a04b531..f9c2b09d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 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 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 From 878d6824be0bca96b8797b6d7e43eda02097afe7 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 14 Jan 2021 11:06:40 +0000 Subject: [PATCH 61/61] Fix javadoc build Signed-off-by: James Taylor --- ci/azure-pipelines.yml | 5 +++-- fabric-chaincode-shim/build.gradle | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index c2cc8aaf..09af5a79 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -66,6 +66,7 @@ stages: javaHomeOption: 'JDKVersion' jdkVersionOption: '1.8' jdkArchitectureOption: 'x64' + options: '-x javadoc' publishJUnitResults: true testResultsFiles: '$(System.DefaultWorkingDirectory)/**/TEST-*.xml' tasks: 'build' @@ -92,7 +93,6 @@ stages: artifactName: javaenv-docker-image - job: javadoc - condition: and(succeeded(),eq(variables['Build.Reason'], 'IndividualCI')) steps: - script: ./gradlew javadoc displayName: 'Build JavaDoc' @@ -110,6 +110,7 @@ stages: 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 @@ -166,4 +167,4 @@ stages: SIGNING_PASSWORD: $(JAR-Signing-Password) KEYRING_FILE: $(keyring.secureFilePath) OSSRH_USER: $(OSSRH-User) - OSSRH_PASSWORD: $(OSSRH-Password) \ No newline at end of file + OSSRH_PASSWORD: $(OSSRH-Password) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 9eedb477..4b096116 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -195,7 +195,7 @@ task licenseCheck { javadoc { - failOnError = false + failOnError = true excludes = ['org/hyperledger/fabric/contract/ContextFactory.java', 'org/hyperledger/fabric/contract/ContractRouter.java', 'org/hyperledger/fabric/contract/ContractRuntimeException.java', @@ -204,11 +204,13 @@ javadoc { 'org/hyperledger/fabric/contract/routing/**', 'org/hyperledger/fabric/contract/systemcontract/**', 'org/hyperledger/fabric/**/impl/**', - 'org/hyperledger/fabric/shim/helper/**', - 'org/hyperledger/fabric/shim/ChaincodeBase.java'] + '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()) {